From b01cbc1aa417d87de618e80bbd3fff8a34d43425 Mon Sep 17 00:00:00 2001 From: MK Date: Thu, 8 Oct 2026 13:50:06 +0800 Subject: [PATCH] fix: require explicit registry input for generated auth --- README.md | 47 ++++++++------------ dist/azure/index.mjs | 4 +- dist/gitlab/index.mjs | 4 +- dist/index.mjs | 2 +- src/auth.test.ts | 95 +++++++++------------------------------- src/auth.ts | 50 +++------------------ src/azure/parity.test.ts | 19 ++++++++ src/ci/auth.test.ts | 42 +++++++++++++++--- src/ci/auth.ts | 24 ++-------- src/ci/npmrc.ts | 20 --------- src/gitlab/index.test.ts | 22 ++++++++++ 11 files changed, 129 insertions(+), 200 deletions(-) diff --git a/README.md b/README.md index 844190e..79d3974 100644 --- a/README.md +++ b/README.md @@ -225,47 +225,36 @@ steps: ### With Private Registry (GitHub Packages) -If your repo has a `.npmrc` that declares the registry, pass `NODE_AUTH_TOKEN` -via `env` and let the default `vp install` run — no `registry-url` needed. -When `NODE_AUTH_TOKEN` is set, the action auto-generates a matching -`_authToken` entry at `$RUNNER_TEMP/.npmrc` for each registry declared in your -repo `.npmrc` that doesn't already have one, so your repo `.npmrc` can stay -minimal: +Set `registry-url` explicitly and pass `NODE_AUTH_TOKEN` via `env` to configure +authentication for that registry: ```yaml -# .npmrc in the repo (auth line not required — action adds it): -# @myorg:registry=https://npm.pkg.github.com - steps: - uses: actions/checkout@v7 - uses: voidzero-dev/setup-vp@v1.21.1 with: node-version: "lts" + registry-url: "https://npm.pkg.github.com" + scope: "@myorg" env: NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} ``` -If you already have the `_authToken` line in your repo `.npmrc` (e.g. for local -dev symmetry), that's respected as-is and the action won't overwrite it. - -Alternatively, pass `registry-url` explicitly to bypass the action's repo-level -`.npmrc` detection and auth propagation logic (the package manager may still -read the repo `.npmrc` per its own config resolution): +Without `registry-url`, the action respects existing auth entries in the project +`.npmrc` and propagates their referenced environment variables. It does not +create token entries from registry URLs in repository files, even when +`NODE_AUTH_TOKEN` is set. Jobs that relied on automatic token entries must set +`registry-url` or supply an explicit auth entry: -```yaml -steps: - - uses: actions/checkout@v7 - - uses: voidzero-dev/setup-vp@v1.21.1 - with: - node-version: "lts" - registry-url: "https://npm.pkg.github.com" - scope: "@myorg" - run-install: false - - run: vp install - env: - NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} +```ini +@myorg:registry=https://npm.pkg.github.com +//npm.pkg.github.com/:_authToken=${NODE_AUTH_TOKEN} ``` +An explicit `registry-url` bypasses project `.npmrc` auth propagation in the +action. The package manager still reads the project `.npmrc` according to its +own configuration rules. + ### With Socket Firewall Free (sfw) Set `sfw: true` to wrap `vp install` with [Socket Firewall Free](https://docs.socket.dev/docs/socket-firewall-free). The action downloads the matching `sfw` binary from the upstream [releases](https://github.com/SocketDev/sfw-free/releases) (auto-detected per OS/arch, with musl support on Alpine) and runs `sfw vp install …` so the underlying npm / pnpm / yarn fetches are inspected before packages are installed. Works on Linux, macOS, and Windows: @@ -623,7 +612,7 @@ Include `gitlab/setup-vp-windows.yml` instead of `gitlab/setup-vp.yml` on a Powe - The template expects a Unix-like runner image with Node.js, `bash`, and either `curl` or `wget`. - Node.js must be available to start the bootstrap. Set `node-version` or `node-version-file` to select the project runtime with `vp env use`. Neither can be combined with `node-manager: "false"`; omit both to retain Vite+'s normal project-based resolution. - Vite+ version precedence matches GitHub Actions: explicit `version`, explicit `version-file`, project package/catalog pin, lockfile, then `latest`. Paths are relative to `working-directory`. An unresolvable explicit `version-file` warns and falls back to `latest`. -- Without `registry-url`, an existing project `.npmrc` is inspected for registry auth. Missing token entries use `NODE_AUTH_TOKEN` when available; existing entries and referenced token variables are preserved. +- Without `registry-url`, existing project `.npmrc` auth entries and referenced token variables are preserved. Registry URLs in repository files do not receive automatic token entries. Set `registry-url` to generate auth configuration for a registry. ## Azure Pipelines @@ -697,7 +686,7 @@ On refs containing these changes, `nodeVersion` selects the managed project runt Finalize tasks also expose `version` and `cacheHit` as named outputs. Use `$(setupVpUnix.version)` on Linux/macOS or `$(setupVpWindows.version)` on Windows; `stepName` changes the prefix. `cacheHit` is `true` only for an exact match, while the job variable retains Azure's `inexact` value. Cross-job consumers use Azure's `dependencies..outputs['setupVpUnix.version']` syntax. [Azure output variables](https://learn.microsoft.com/en-us/azure/devops/pipelines/process/set-variables-scripts?view=azure-devops) -Without `registryUrl`, the runtime can supplement the project's `.npmrc` with `NODE_AUTH_TOKEN`. Other referenced token variables are propagated as secret pipeline variables, not public outputs. Pass custom secret mappings through `authEnv`, for example `authEnv: { CUSTOM_TOKEN: "$(CUSTOM_TOKEN)" }`. Azure does not automatically put secret pipeline variables in task environments. +Without `registryUrl`, the runtime preserves existing project `.npmrc` auth entries but does not generate token entries for its registry URLs. Set `registryUrl` to generate auth configuration for a registry. Referenced custom token variables are propagated as secret pipeline variables, not public outputs. Pass custom secret mappings through `authEnv`, for example `authEnv: { CUSTOM_TOKEN: "$(CUSTOM_TOKEN)" }`. Azure does not automatically put secret pipeline variables in task environments. ### Azure Notes diff --git a/dist/azure/index.mjs b/dist/azure/index.mjs index 2834b43..aaad74e 100644 --- a/dist/azure/index.mjs +++ b/dist/azure/index.mjs @@ -138,9 +138,7 @@ n?this.stack.push(n):(yield*this.pop(),yield*this.step())}else{let t=this.peek(2 `)+1;for(;e!==0;)this.onNewLine(this.offset+e),e=this.source.indexOf(` `,e)+1}return{type:e,offset:this.offset,indent:this.indent,source:this.source}}startBlockValue(e){switch(this.type){case`alias`:case`scalar`:case`single-quoted-scalar`:case`double-quoted-scalar`:return this.flowScalar(this.type);case`block-scalar-header`:return{type:`block-scalar`,offset:this.offset,indent:this.indent,props:[this.sourceToken],source:``};case`flow-map-start`:case`flow-seq-start`:return{type:`flow-collection`,offset:this.offset,indent:this.indent,start:this.sourceToken,items:[],end:[]};case`seq-item-ind`:return{type:`block-seq`,offset:this.offset,indent:this.indent,items:[{start:[this.sourceToken]}]};case`explicit-key-ind`:{this.onKeyLine=!0;let t=getFirstKeyStartProps(getPrevProps(e));return t.push(this.sourceToken),{type:`block-map`,offset:this.offset,indent:this.indent,items:[{start:t,explicitKey:!0}]}}case`map-value-ind`:{this.onKeyLine=!0;let t=getFirstKeyStartProps(getPrevProps(e));return{type:`block-map`,offset:this.offset,indent:this.indent,items:[{start:t,key:null,sep:[this.sourceToken]}]}}}return null}atIndentedComment(e,t){return this.type!==`comment`||this.indent<=t?!1:e.every(e=>e.type===`newline`||e.type===`space`)}*documentEnd(e){this.type!==`doc-mode`&&(e.end?e.end.push(this.sourceToken):e.end=[this.sourceToken],this.type===`newline`&&(yield*this.pop()))}*lineEnd(e){switch(this.type){case`comma`:case`doc-start`:case`doc-end`:case`flow-seq-end`:case`flow-map-end`:case`map-value-ind`:yield*this.pop(),yield*this.step();break;case`newline`:this.onKeyLine=!1;default:e.end?e.end.push(this.sourceToken):e.end=[this.sourceToken],this.type===`newline`&&(yield*this.pop())}}}})),Qe=/* @__PURE__ */ __commonJSMin((e=>{var t=We(),n=G(),r=K(),i=le(),a=O(),o=Xe(),s=Ze();function parseOptions(e){let t=e.prettyErrors!==!1;return{lineCounter:e.lineCounter||t&&new o.LineCounter||null,prettyErrors:t}}function parseAllDocuments(e,n={}){let{lineCounter:i,prettyErrors:a}=parseOptions(n),o=new s.Parser(i?.addNewLine),c=new t.Composer(n),l=Array.from(c.compose(o.parse(e)));if(a&&i)for(let t of l)t.errors.forEach(r.prettifyError(e,i)),t.warnings.forEach(r.prettifyError(e,i));return l.length>0?l:Object.assign([],{empty:!0},c.streamInfo())}function parseDocument(e,n={}){let{lineCounter:i,prettyErrors:a}=parseOptions(n),o=new s.Parser(i?.addNewLine),c=new t.Composer(n),l=null;for(let t of c.compose(o.parse(e),!0,e.length))if(!l)l=t;else if(l.options.logLevel!==`silent`){l.errors.push(new r.YAMLParseError(t.range.slice(0,2),`MULTIPLE_DOCS`,`Source contains multiple documents; please use YAML.parseAllDocuments()`));break}return a&&i&&(l.errors.forEach(r.prettifyError(e,i)),l.warnings.forEach(r.prettifyError(e,i))),l}function parse(e,t,n){let r;typeof t==`function`?r=t:n===void 0&&t&&typeof t==`object`&&(n=t);let a=parseDocument(e,n);if(!a)return null;if(a.warnings.forEach(e=>i.warn(a.options.logLevel,e)),a.errors.length>0){if(a.options.logLevel!==`silent`)throw a.errors[0];a.errors=[]}return a.toJS(Object.assign({reviver:r},n))}function stringify(e,t,r){let i=null;if(typeof t==`function`||Array.isArray(t)?i=t:r===void 0&&t&&(r=t),typeof r==`string`&&(r=r.length),typeof r==`number`){let e=Math.round(r);r=e<1?void 0:e>8?{indent:8}:{indent:e}}if(e===void 0){let{keepUndefined:e}=r??t??{};if(!e)return}return a.isDocument(e)&&!i?e.toString(r):new n.Document(e,i,r).toString(r)}e.parse=parse,e.parseAllDocuments=parseAllDocuments,e.parseDocument=parseDocument,e.stringify=stringify})),Y=(/* @__PURE__ */ __commonJSMin((e=>{var t=We(),n=G(),r=ke(),i=K(),a=M(),o=O(),s=R(),c=N(),l=z(),u=V();Je();var d=Ye(),f=Xe(),p=Ze(),m=Qe(),h=k();e.Composer=t.Composer,e.Document=n.Document,e.Schema=r.Schema,e.YAMLError=i.YAMLError,e.YAMLParseError=i.YAMLParseError,e.YAMLWarning=i.YAMLWarning,e.Alias=a.Alias,e.isAlias=o.isAlias,e.isCollection=o.isCollection,e.isDocument=o.isDocument,e.isMap=o.isMap,e.isNode=o.isNode,e.isPair=o.isPair,e.isScalar=o.isScalar,e.isSeq=o.isSeq,e.Pair=s.Pair,e.Scalar=c.Scalar,e.YAMLMap=l.YAMLMap,e.YAMLSeq=u.YAMLSeq,e.Lexer=d.Lexer,e.LineCounter=f.LineCounter,e.Parser=p.Parser,e.parse=m.parse,e.parseAllDocuments=m.parseAllDocuments,e.parseDocument=m.parseDocument,e.stringify=m.stringify,e.visit=h.visit,e.visitAsync=h.visitAsync})))();function parseInstalledVpVersion(e){return(e.match(/^\s*vp\s+v?(\d[^\s]*)/im)??e.match(/Global:\s*v?(\d[^\s]*)/i))?.[1]??`unknown`}const $e=/* @__PURE__ */ new Set([`true`,`True`,`TRUE`]),et=/* @__PURE__ */ new Set([`false`,`False`,`FALSE`]);function parseNodeManager(e){if(e){if($e.has(e))return!0;if(et.has(e))return!1;throw Error(`Invalid node-manager input: "${e}". Expected "true", "false", or unset.`)}}function supportsScopedEnv(e){let t=parseInstalledVpVersion(e);if(t.startsWith(`0.0.0-commit.`))return!0;let n=t.match(/^(\d+)\.(\d+)\.(\d+)/);if(!n)throw Error(`Could not determine the installed Vite+ version for env configuration.`);let[,r,i,a]=n.map(Number);return r>0||i>3||i===3&&a>=1}function nodeManagerOffArgs(e){return parseInstalledVpVersion(e).startsWith(`0.0.0-commit.`)&&console.info("setup-vp: node-manager: false requires a preview build that supports `vp env off node`. If this command is unsupported, use a newer preview or a stable release. setup-vp will not fall back to disabling package-manager management."),supportsScopedEnv(e)?[`env`,`off`,`node`]:[`env`,`off`]}const tt=[`npm`,`pnpm`,`yarn`,`bun`];function parsePackageManager(e){if(!e?.trim())return;let t;try{t=(0,Y.parse)(e)}catch(e){throw Error(`Invalid package-manager input: ${String(e)}`)}if(t!==``){if(typeof t==`boolean`)return t;if(t&&typeof t==`object`&&!Array.isArray(t)){for(let[e,n]of Object.entries(t))if(!tt.includes(e)||typeof n!=`boolean`)throw Error(`Invalid package-manager input: ${e} must be npm, pnpm, yarn, or bun with a boolean value.`);return t}throw Error(`Invalid package-manager input: expected a boolean or a mapping of npm, pnpm, yarn, and bun to booleans.`)}}function packageManagerArgs(e,t){if(e===void 0)return[];if(!supportsScopedEnv(t))throw Error(`package-manager configuration requires Vite+ 0.3.1 or newer.`);return typeof e==`boolean`?e?[]:[[`env`,`off`,`pm`]]:tt.filter(t=>e[t]===!1).map(e=>[`env`,`off`,e])}const X=`Vite+`,Z=`vite-plus`;function resolvePath$1(e,t){return u.isAbsolute(e)?e:u.join(t,e)}function isWithin(e,t){let n=u.relative(t,e);return!u.isAbsolute(n)&&n!==`..`&&!n.startsWith(`..${u.sep}`)}function resolveProjectDirectory(e){let{workingDirectory:t,workspaceRoot:n}=e,r=u.isAbsolute(t)?t:u.join(n,t);try{if(!c(r).isDirectory())throw Error(`working-directory is not a directory: ${t} (resolved to ${r})`)}catch(e){throw e instanceof Error&&`code`in e&&e.code===`ENOENT`?Error(`working-directory not found: ${t} (resolved to ${r})`):e}return r}function isWindows(e=process.platform){return e===`win32`}function run(e,t,n={}){let r=y(e,t,{stdio:`inherit`,...n});if(r.error)throw r.error;if(r.status!==0)throw Error(`${e} ${t.join(` `)} exited with code ${r.status??1}`)}function runWithOutput(e,t,n={}){return new Promise((r,i)=>{let a=v(e,t,{...n,stdio:[`ignore`,`pipe`,`pipe`]}),o=``,s=``;a.stdout.on(`data`,e=>{process.stdout.write(e),o=(o+e.toString()).slice(-4e3)}),a.stderr.on(`data`,e=>{process.stderr.write(e),s=(s+e.toString()).slice(-4e3)}),a.on(`error`,i),a.on(`close`,e=>r({exitCode:e??1,stdout:o,stderr:s}))})}function commandPath(e){if(isWindows()){let t=y(`where`,[e],{encoding:`utf8`});return t.status===0&&t.stdout.trim().split(/\r?\n/)[0]?.trim()||void 0}let t=y(`sh`,[`-c`,`command -v "$1"`,`sh`,e],{encoding:`utf8`});if(t.status===0)return t.stdout.trim()}function getCommandOutput(e,t,n){let r=y(e,t,{cwd:n?.cwd,encoding:`utf8`,stdio:[`ignore`,`pipe`,`pipe`]});if(r.status===0)return r.stdout.trim()}const nt=[{filename:`pnpm-lock.yaml`,type:`pnpm`},{filename:`bun.lockb`,type:`bun`},{filename:`bun.lock`,type:`bun`},{filename:`package-lock.json`,type:`npm`},{filename:`npm-shrinkwrap.json`,type:`npm`},{filename:`yarn.lock`,type:`yarn`}];function resolvePath(e,t){return p(e)?e:m(t,e)}function inferLockFileType(e,t){return t.includes(`pnpm`)?{type:`pnpm`,path:e,filename:t}:t.includes(`yarn`)?{type:`yarn`,path:e,filename:t}:t.startsWith(`bun.`)?{type:`bun`,path:e,filename:t}:{type:`npm`,path:e,filename:t}}function detectLockFile(e,t){if(e){let r=resolvePath(e,t);if(n(r)){let e=d(r),t=nt.find(t=>t.filename===e);return t?{type:t.type,path:r,filename:e}:inferLockFileType(r,e)}return}let r=o(t);for(let e of nt)if(r.includes(e.filename)){let n=m(t,e.filename);return{type:e.type,path:n,filename:e.filename}}}function prepareCacheMetadata(e){let{projectDir:t,cacheDependencyPath:n,logWarning:r}=e,i=detectLockFile(n||void 0,t);if(!i)return r?.(`setup-vp: cache is enabled but no supported lock file was found; skipping cache.`),{ready:!1};let a=getCommandOutput(`vp`,[`pm`,`cache`,`dir`],{cwd:u.dirname(i.path)});return a?{ready:!0,cachePath:a,lockFile:i.path,lockType:i.type}:(r?.(`setup-vp: could not resolve package-manager cache directory for ${i.filename}; skipping cache.`),{ready:!1})}function createLockfileResolver(e){let{getWorkspaceDir:t,info:r,debug:i}=e,o=/^\d+\.\d+\.\d+/;function tryResolveVitePlusVersionFromLockfile(e,t){let n=detectLockfileForProject(e,t);if(!n)return;let a=n.filename.endsWith(`.lockb`)?textBunLockBeside(n):n;if(!a){i(`Cannot read ${n.filename} (binary) to resolve the ${X} version; using "latest". Use the text bun.lock, or set the \`version\` input.`);return}let o=parseVitePlusVersionFromLockfile(a,workspaceSubPath(f(a.path),e));if(o)return r(`Resolved ${X} version '${o}' from ${a.filename}`),o;i(`No ${X} version found in ${a.path}`)}function detectLockfileForProject(e,n){if(n)return detectLockFile(n,e);let r=t(),i=e;for(;;){let e=detectLockFile(void 0,i);if(e)return e;let t=f(i);if(i===r||t===i||!isWithin(t,r))break;i=t}}function textBunLockBeside(e){let t=m(f(e.path),`bun.lock`);return n(t)?{type:`bun`,path:t,filename:`bun.lock`}:void 0}function workspaceSubPath(e,t){if(!isWithin(t,e))return``;let n=h(e,t);return n?n.split(g).join(`/`):``}function parseVitePlusVersionFromLockfile(e,t=``){if(e.filename.endsWith(`.lockb`))return;let n;try{n=a(e.path,`utf-8`)}catch{return}let r;switch(e.type){case`npm`:r=fromNpmLock(n,t);break;case`pnpm`:r=fromPnpmLock(n,t);break;case`yarn`:r=fromYarnLock(n);break;case`bun`:r=fromBunTextLock(n);break;default:return}return r&&o.test(r)?r:void 0}function fromNpmLock(e,t){let n;try{n=JSON.parse(e)}catch{return}let r=n.packages;if(t){let e=r?.[`${t}/node_modules/${Z}`]?.version;if(typeof e==`string`)return e;if(!npmPackageDeclaresVitePlus(r?.[t]))return}let i=r?.[`node_modules/${Z}`]?.version;if(typeof i==`string`)return i;let a=n.dependencies?.[Z]?.version;return typeof a==`string`?a:void 0}function npmPackageDeclaresVitePlus(e){if(!e)return!1;for(let t of[`dependencies`,`devDependencies`]){let n=e[t];if(n&&typeof n==`object`&&`vite-plus`in n)return!0}return!1}function fromPnpmLock(e,t){let n;try{n=(0,Y.parse)(e)}catch{return}if(!n||typeof n!=`object`)return;let r=n,i=r.importers;if(i&&typeof i==`object`){let e=t||`.`;return e in i?pnpmImporterVersion(i[e]):void 0}return pnpmImporterVersion(r)||e.match(/^\s*\/?vite-plus@(\d+\.\d+\.\d+[^\s():'"]*)/m)?.[1]}function pnpmImporterVersion(e){if(!e||typeof e!=`object`)return;let t=e;for(let e of[`dependencies`,`devDependencies`,`optionalDependencies`]){let n=t[e];if(n&&typeof n==`object`){let e=n[Z],t=typeof e==`string`?e:e?.version;if(typeof t==`string`){let e=t.replace(/\(.*$/,``).trim();if(o.test(e))return e}}}}function fromYarnLock(e){let t=/* @__PURE__ */ new Set,n=e.split(/\r?\n/);for(let e=0;ee,info:console.info,debug:()=>{},warning:console.warn}}const rt=`https://raw.githubusercontent.com/voidzero-dev/vite-plus`,it=`packages/cli`,at=/^0\.0\.0-commit\.([0-9a-f]{40})$/i,ot=/^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/;function pkgPrNewCommitSha(e){return e.match(at)?.[1]}function getInstallScriptUrls(e,t=process.platform){let n=isWindows(t)?`install.ps1`:`install.sh`,r=installScriptRef(e);return{pinned:r?[`${rt}/${r}/${it}/${n}`,`https://cdn.jsdelivr.net/gh/voidzero-dev/vite-plus@${r}/${it}/${n}`]:[],latest:[`https://viteplus.dev/${n}`,`${rt}/main/${it}/${n}`]}}function installScriptRef(e){let t=pkgPrNewCommitSha(e);if(t)return t.toLowerCase();if(ot.test(e))return`v${e}`}function readNpmrc(e){try{return a(e,`utf8`)}catch(e){if(e.code===`ENOENT`)return``;throw e}}function authKeyFor(e){return(e.replace(/^\w+:/,``)+`:_authtoken`).toLowerCase()}function analyzeProjectNpmrc(e){let t=/* @__PURE__ */ new Set,n=/* @__PURE__ */ new Set,r=/* @__PURE__ */ new Set;for(let i of e.split(/\r?\n/)){let e=i.trim();if(!e||e.startsWith(`;`)||e.startsWith(`#`))continue;let a=e.indexOf(`=`);if(a<0)continue;let o=e.slice(0,a).trim().toLowerCase(),s=e.slice(a+1).trim();(o===`registry`||o.endsWith(`:registry`))&&(s.includes("${")||t.add(s.endsWith(`/`)?s:s+`/`)),o.startsWith(`//`)&&o.endsWith(`:_authtoken`)&&n.add(o);for(let e of s.matchAll(/\$\{(\w+)\}/g))r.add(e[1])}return{registriesNeedingAuth:[...t].filter(e=>!n.has(authKeyFor(e))),envVarRefs:r}}function readUserConfigLines(e,t){let n=e.HOME||e.USERPROFILE,r=e.NPM_CONFIG_USERCONFIG||e.PNPM_CONFIG_USERCONFIG||n&&u.join(n,`.npmrc`);return(r?readNpmrc(r):``).split(/\r?\n/).filter(e=>!t.has(e.split(`=`)[0].trim().toLowerCase()))}function isReservedAuthVariable(e){return[`GITHUB_TOKEN`,`CI_JOB_TOKEN`,`SYSTEM_ACCESSTOKEN`].includes(e)?!1:/^(?:PATH|HOME|USERPROFILE|TMPDIR|CI)$/i.test(e)||/^(?:SETUP_VP_|RUNNER_|GITHUB_|CI_|SYSTEM_|AGENT_|BUILD_|RELEASE_)/i.test(e)}function writeUserConfig(e,t,n){let r=i(u.join(x(),`setup-vp-npmrc-`)),a=u.join(r,`.npmrc`);l(a,e,{encoding:`utf8`,mode:384});for(let e of[`NPM_CONFIG_USERCONFIG`,`PNPM_CONFIG_USERCONFIG`])t[e]=a,n?.(e,a);return a}function configureAuth(e,t,n,r,i){if(!e){if(!i)return;let{registriesNeedingAuth:e,envVarRefs:t}=analyzeProjectNpmrc(readNpmrc(u.join(i,`.npmrc`))),a;if(n.NODE_AUTH_TOKEN&&e.length>0){let i=readUserConfigLines(n,new Set(e.map(e=>(e.replace(/^\w+:/,``)+`:_authtoken`).toLowerCase())));i.push(...e.map(e=>e.replace(/^\w+:/,``)+":_authToken=${NODE_AUTH_TOKEN}")),a=writeUserConfig(i.join(` -`)+` -`,n,r),t.add(`NODE_AUTH_TOKEN`)}for(let e of t)!isReservedAuthVariable(e)&&n[e]&&r?.(e,n[e]);return a}let a;try{a=new URL(e)}catch{throw Error(`Invalid registry-url: "${e}". Must be a valid URL.`)}let o=a.href.endsWith(`/`)?a.href:`${a.href}/`,s=``;t&&(s=`${(t.startsWith(`@`)?t:`@${t}`).toLowerCase()}:`);let c=o.replace(/^\w+:/,``).toLowerCase(),l=readUserConfigLines(n,/* @__PURE__ */ new Set([`${s}registry`,`${c}:_authtoken`]));l.push(`${c}:_authToken=\${NODE_AUTH_TOKEN}`,`${s}registry=${o}`);let d=writeUserConfig(l.filter(Boolean).join(` +`)){let e=t.trim();if(!e||e.startsWith(`#`))continue;let[n,...r]=e.split(/\s+/);if(n===`nodejs`||n===`node`){for(let e of r)if(isAsdfInstallableVersion(e))return e}}}function isAsdfInstallableVersion(e){return!!e&&e!==`system`&&!e.startsWith(`ref:`)&&!e.startsWith(`path:`)}function parsePackageJson(e){let t;try{t=JSON.parse(e)}catch{throw Error(`Failed to parse package.json: invalid JSON`)}let n=t.devEngines;if(n?.runtime){let e=findNodeRuntime(n.runtime);if(e)return e}let r=t.engines;if(r?.node&&typeof r.node==`string`)return r.node}function findNodeRuntime(e){let t=Array.isArray(e)?e:[e];for(let e of t)if(e?.name===`node`&&typeof e.version==`string`)return e.version}return{resolveNodeVersionFile}}function resolutionContext(e){return{getWorkspaceDir:()=>e,info:console.info,debug:()=>{},warning:console.warn}}const rt=`https://raw.githubusercontent.com/voidzero-dev/vite-plus`,it=`packages/cli`,at=/^0\.0\.0-commit\.([0-9a-f]{40})$/i,ot=/^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/;function pkgPrNewCommitSha(e){return e.match(at)?.[1]}function getInstallScriptUrls(e,t=process.platform){let n=isWindows(t)?`install.ps1`:`install.sh`,r=installScriptRef(e);return{pinned:r?[`${rt}/${r}/${it}/${n}`,`https://cdn.jsdelivr.net/gh/voidzero-dev/vite-plus@${r}/${it}/${n}`]:[],latest:[`https://viteplus.dev/${n}`,`${rt}/main/${it}/${n}`]}}function installScriptRef(e){let t=pkgPrNewCommitSha(e);if(t)return t.toLowerCase();if(ot.test(e))return`v${e}`}function readNpmrc(e){try{return a(e,`utf8`)}catch(e){if(e.code===`ENOENT`)return``;throw e}}function analyzeProjectNpmrc(e){let t=/* @__PURE__ */ new Set;for(let n of e.split(/\r?\n/)){let e=n.trim();if(!e||e.startsWith(`;`)||e.startsWith(`#`))continue;let r=e.indexOf(`=`);if(r<0)continue;let i=e.slice(r+1).trim();for(let e of i.matchAll(/\$\{(\w+)\}/g))t.add(e[1])}return{envVarRefs:t}}function readUserConfigLines(e,t){let n=e.HOME||e.USERPROFILE,r=e.NPM_CONFIG_USERCONFIG||e.PNPM_CONFIG_USERCONFIG||n&&u.join(n,`.npmrc`);return(r?readNpmrc(r):``).split(/\r?\n/).filter(e=>!t.has(e.split(`=`)[0].trim().toLowerCase()))}function isReservedAuthVariable(e){return[`GITHUB_TOKEN`,`CI_JOB_TOKEN`,`SYSTEM_ACCESSTOKEN`].includes(e)?!1:/^(?:PATH|HOME|USERPROFILE|TMPDIR|CI)$/i.test(e)||/^(?:SETUP_VP_|RUNNER_|GITHUB_|CI_|SYSTEM_|AGENT_|BUILD_|RELEASE_)/i.test(e)}function writeUserConfig(e,t,n){let r=i(u.join(x(),`setup-vp-npmrc-`)),a=u.join(r,`.npmrc`);l(a,e,{encoding:`utf8`,mode:384});for(let e of[`NPM_CONFIG_USERCONFIG`,`PNPM_CONFIG_USERCONFIG`])t[e]=a,n?.(e,a);return a}function configureAuth(e,t,n,r,i){if(!e){if(!i)return;let{envVarRefs:e}=analyzeProjectNpmrc(readNpmrc(u.join(i,`.npmrc`)));for(let t of e)!isReservedAuthVariable(t)&&n[t]&&r?.(t,n[t]);return}let a;try{a=new URL(e)}catch{throw Error(`Invalid registry-url: "${e}". Must be a valid URL.`)}let o=a.href.endsWith(`/`)?a.href:`${a.href}/`,s=``;t&&(s=`${(t.startsWith(`@`)?t:`@${t}`).toLowerCase()}:`);let c=o.replace(/^\w+:/,``).toLowerCase(),l=readUserConfigLines(n,/* @__PURE__ */ new Set([`${s}registry`,`${c}:_authtoken`]));l.push(`${c}:_authToken=\${NODE_AUTH_TOKEN}`,`${s}registry=${o}`);let d=writeUserConfig(l.filter(Boolean).join(` `)+` `,n,r);return n.NODE_AUTH_TOKEN=n.NODE_AUTH_TOKEN||`XXXXX-XXXXX-XXXXX-XXXXX`,r?.(`NODE_AUTH_TOKEN`,n.NODE_AUTH_TOKEN),d}function resolveSfwEnabled(e,t,n){return e?!pkgPrNewCommitSha(t)||(n(`sfw was requested but is automatically disabled for Vite+ preview build ${t}; Socket Firewall Free will not be used.`),!1):!1}const Q=`v1.15.4`,st=`https://github.com/SocketDev/sfw-free/releases/download/${Q}`;function isMuslLinux(){if(process.platform!==`linux`)return!1;try{let e=process.report?.getReport();if(e?.header&&!e.header.glibcVersionRuntime)return!0}catch{}return n(`/etc/alpine-release`)}function getSfwAssetName(e,t,n){if(e===`darwin`){if(t===`arm64`)return`sfw-free-macos-arm64`;if(t===`x64`)return`sfw-free-macos-x86_64`}else if(e===`linux`){if(t===`arm64`)return n?`sfw-free-musl-linux-arm64`:`sfw-free-linux-arm64`;if(t===`x64`)return n?`sfw-free-musl-linux-x86_64`:`sfw-free-linux-x86_64`}else if(isWindows(e)){if(t===`arm64`)return`sfw-free-windows-arm64.exe`;if(t===`x64`)return`sfw-free-windows-x86_64.exe`}throw Error(`Unsupported platform/arch for sfw: ${e}/${t}${e===`linux`?` (${n?`musl`:`glibc`})`:``}`)}function downloadFileWithShell(e,t,n){let r=Math.max(1,Math.ceil(n/1e3)),i=commandPath(`curl`);if(i){let n=y(i,[`-fsSL`,`--connect-timeout`,`5`,`--max-time`,String(r),e,`-o`,t],{stdio:`ignore`});if(n.status===0)return;throw n.error||/* @__PURE__ */ Error(`curl failed while downloading ${e}`)}let a=commandPath(`wget`);if(a){let n=y(a,[`-q`,`-T`,String(r),`-t`,`2`,`-O`,t,e],{stdio:`ignore`});if(n.status===0)return;throw n.error||/* @__PURE__ */ Error(`wget failed while downloading ${e}`)}throw Error(`curl or wget is required to download sfw`)}function downloadFile(e,n,r=0,i=6e4,a){return r>5?Promise.reject(/* @__PURE__ */ Error(`too many redirects while downloading ${e}`)):a?new Promise((o,s)=>{let c=!1,finish=e=>{c||(c=!0,clearTimeout(u),e?s(e):o())},l=a(e,o=>{let s=o.statusCode??0,c=o.headers.location;if(s>=300&&s<400&&c){o.resume(),downloadFile(new URL(c,e).toString(),n,r+1,i,a).then(()=>finish(),finish);return}if(s!==200){o.resume(),finish(/* @__PURE__ */ Error(`download failed with HTTP ${s}: ${e}`));return}let l=t(n);o.pipe(l),l.on(`finish`,()=>l.close(()=>finish())),l.on(`error`,finish)}),u=setTimeout(()=>{l.destroy(/* @__PURE__ */ Error(`download timed out after ${i}ms: ${e}`))},i);l.on(`error`,finish)}):(downloadFileWithShell(e,n,i),Promise.resolve())}async function setupSfw(e,t={}){let n=t.env??process.env,r=t.sfwEnabled??n.SETUP_VP_SFW===`true`,i=t.platform??process.platform,a=t.arch??process.arch,o=t.isMusl??isMuslLinux(),s=t.download??downloadFile;if(!resolveSfwEnabled(r,t.vitePlusVersion??``,t.logWarning??console.warn))return`vp`;if(e.length===0)return console.log(`setup-vp: sfw was requested but run-install is disabled; sfw will not be invoked.`),`vp`;let c=commandPath(`sfw`);if(c)return console.log(`setup-vp: using existing sfw on PATH: ${c}`),`sfw`;let l;try{l=getSfwAssetName(i,a,o)}catch{return console.error(`setup-vp: sfw has no published binary for this runner's platform/architecture (process.platform=${i}, process.arch=${a}, musl=${o}) and none was found on PATH; falling back to plain vp install.`),`vp`}let d=t.cacheDirectory||n.SETUP_VP_SFW_CACHE_DIR,f=d?u.join(d,Q,l):await w(u.join(x(),`setup-vp-sfw-`));await C(f,{recursive:!0});let p=u.join(f,isWindows(i)?`sfw.exe`:`sfw`),m=`${st}/${l}`;function activate(){let e=isWindows(i)?`;`:`:`;return n.PATH=`${f}${e}${n.PATH||``}`,t.exportVariable?.(`PATH`,n.PATH),`sfw`}if(await ee(p).then(e=>e.isFile()&&e.size>0,()=>!1))return console.log(`setup-vp: using cached sfw ${Q}: ${p}`),activate();for(let e=1;e<=2;e+=1){let t=await w(u.join(f,`.download-`)),n=u.join(t,`sfw`);try{if(console.log(`setup-vp: installing sfw ${Q} from ${m}`),await s(m,n),(await ee(n)).size===0)throw Error(`Downloaded sfw binary is empty`);return await S(n,493),await T(n,p),activate()}catch(t){if(e===2)throw t;await new Promise(e=>setTimeout(e,2e3))}finally{await E(t,{recursive:!0,force:!0})}}throw Error(`failed to install sfw after retrying`)}function isRecord(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function validateRunInstallEntry(e){if(!isRecord(e))throw Error(`run-install entries must be objects`);for(let t of Object.keys(e))if(t!==`cwd`&&t!==`args`)throw Error(`unsupported run-install key: ${t}`);let t={};if(e.cwd!==void 0){if(typeof e.cwd!=`string`)throw Error(`run-install.cwd must be a string`);t.cwd=e.cwd}if(e.args!==void 0){if(!Array.isArray(e.args)||e.args.some(e=>typeof e!=`string`))throw Error(`run-install.args must be an array of strings`);t.args=e.args}return t}function validateRunInstallInput(e){return e===null||typeof e==`boolean`?e:Array.isArray(e)?e.map(validateRunInstallEntry):validateRunInstallEntry(e)}function parseRunInstall(e){let t=validateRunInstallInput((0,Y.parse)(e)??null);return t?t===!0?[{}]:Array.isArray(t)?t:[t]:[]}function isSfwVpNotFoundFlake(e,t){return/Command 'vp' not found in PATH/.test(e+` `+t)}async function runInstall(e,t,n,r=process.env,i={}){let a={...r};delete a.SETUP_VP_ENV_FILE;let o=i.execute??runWithOutput,s=[];for(let r of e){let e=r.cwd?u.resolve(t,r.cwd):t,c=[`install`,...r.args||[]],l=n===`sfw`?[`vp`,...c]:c,d=`${n} ${l.join(` `)} (cwd: ${e})`;console.log(`setup-vp: running ${d}`);try{let t=await o(n,l,{cwd:e,env:a});if(t.exitCode!==0&&n===`sfw`&&isSfwVpNotFoundFlake(t.stdout,t.stderr)){let r=isWindows(i.platform);if(console.warn(r?`setup-vp: sfw could not resolve vp; warming the PowerShell command cache and retrying once.`:`setup-vp: sfw could not resolve vp; retrying once.`),r)try{await o(`powershell.exe`,[`-NoProfile`,`-Command`,`Get-Command vp`],{cwd:e,env:a})}catch{}t=await o(n,l,{cwd:e,env:a})}t.exitCode!==0&&s.push(`${d} exited with code ${t.exitCode}\n${t.stderr.trim()||t.stdout.trim()}`)}catch(e){s.push(`${d}: ${String(e)}`)}}if(s.length)throw Error(s.join(` diff --git a/dist/gitlab/index.mjs b/dist/gitlab/index.mjs index 6cc67f4..5785bd0 100644 --- a/dist/gitlab/index.mjs +++ b/dist/gitlab/index.mjs @@ -184,9 +184,7 @@ fi set +u set -o pipefail ${r} | bash -`.trim()]}}const dt=2e3;function getVitePlusHome(e=process.platform,t=process.env){let n=isWindows(e)?t.USERPROFILE||T():t.HOME||T();return y(n,`.vite-plus`)}function runInstallCommand(e,t,n=process.platform){let{command:r,args:i}=getInstallScriptCommand(e,n,t.VP_VPDIRS_AWARE===`1`),a={env:{...process.env,...t},stdio:`inherit`},o=w(r,i,a);if(isWindows(n)&&o.error?.code===`ENOENT`&&(o=w(`powershell.exe`,i,a)),o.error)throw o.error;return o.status??1}async function installVitePlus(e,t={}){let n=t.platform??process.platform,r=t.env??process.env,i=t.prependPath,a=t.sleep??ee,o=t.runInstall??runInstallCommand,s=t.logWarningFn??console.warn,c={...Object.fromEntries(Object.entries(r).filter(e=>e[1]!==void 0)),VP_VERSION:e,VITE_PLUS_VERSION:e},l=supportsVitePlusDirs(e)?createVitePlusDirsFile():void 0;l?(c.VP_VPDIRS_AWARE=`1`,c[Q]=l):(delete c.VP_VPDIRS_AWARE,delete c[Q]);let u=pkgPrNewCommitSha(e);u&&(c.VP_PR_VERSION=u);let{pinned:d,latest:f}=getInstallScriptUrls(e,n),p=d.length+f.length,m=2*p,h=``,g=0;async function tryUrls(e){for(let t=0;t<2;t+=1)for(let t of e){g+=1;try{let e=o(t,c,n);if(e===0)return!0;h=`exit code ${e}`}catch(e){h=e instanceof Error?e.message:String(e)}g0){if(await tryUrls(d)){ensureBinInPath();return}s(`setup-vp: could not fetch the install script pinned to Vite+ ${e}. Falling back to the latest install script. The latest script may not be compatible with ${e}.`)}if(await tryUrls(f)){ensureBinInPath();return}throw Error(`Failed to install Vite+ after ${m} attempts across ${p} URL(s): ${h}`)}finally{l&&removeVitePlusDirsFile(l)}}function copyCacheDirectory(e,t,r){e=h.resolve(e),t=h.resolve(t),n(e,t,{recursive:!0,force:r,errorOnExist:!1,filter:(n,i)=>{let s=a(i,{throwIfNoEntry:!1}),c=a(n);if(s&&!r)return c.isDirectory()&&s.isDirectory();if(s&&(s.isSymbolicLink()||c.isSymbolicLink())&&d(i,{recursive:!0,force:!0}),c.isSymbolicLink()){let r=h.resolve(h.dirname(n),u(n)),a=r;if(isWithin(r,e)){let n=h.join(t,h.relative(e,r));a=h.relative(h.dirname(i),n)||`.`}return o(h.dirname(i),{recursive:!0}),p(a,i,f(r,{throwIfNoEntry:!1})?.isDirectory()?`dir`:`file`),!1}return!0}})}function restoreCacheSnapshot(e,t,n=console.warn,r=!0){if(!e.ready||!e.cachePath||!e.lockFile||!e.lockType)return{hit:!1,save:()=>{}};let a=e.cachePath;if(isWithin(h.resolve(a),h.resolve(t))||isWithin(h.resolve(t),h.resolve(a)))return n(`setup-vp: package-manager cache overlaps the snapshot directory; skipping cache.`),{hit:!1,save:()=>{}};let s=h.join(t,process.platform,process.arch,e.lockType),l=h.join(s,`packages`),u=h.join(s,`lock-hash`),d=e.lockFile;function hashLockFile(){return te(`sha256`).update(c(d)).digest(`hex`)}let f;try{f=hashLockFile()}catch(e){return n(`setup-vp: could not read cache lock file: ${String(e)}`),{hit:!1,save:()=>{}}}let p=!1;try{r&&i(l)&&(o(a,{recursive:!0}),copyCacheDirectory(l,a,!1),p=c(u,`utf8`)===f)}catch(e){n(`setup-vp: could not restore package-manager cache: ${String(e)}`)}return{hit:p,save:()=>{try{if(!i(a))return;let e=hashLockFile();o(s,{recursive:!0}),copyCacheDirectory(a,l,!0),m(u,e,`utf8`)}catch(e){n(`setup-vp: could not save package-manager cache: ${String(e)}`)}}}}const ft=/* @__PURE__ */ new Set([`true`,`True`,`TRUE`]),pt=/* @__PURE__ */ new Set([`false`,`False`,`FALSE`]);function parseNodeManager(e){if(e){if(ft.has(e))return!0;if(pt.has(e))return!1;throw Error(`Invalid node-manager input: "${e}". Expected "true", "false", or unset.`)}}function supportsScopedEnv(e){let t=parseInstalledVpVersion(e);if(t.startsWith(`0.0.0-commit.`))return!0;let n=t.match(/^(\d+)\.(\d+)\.(\d+)/);if(!n)throw Error(`Could not determine the installed Vite+ version for env configuration.`);let[,r,i,a]=n.map(Number);return r>0||i>3||i===3&&a>=1}function nodeManagerOffArgs(e){return parseInstalledVpVersion(e).startsWith(`0.0.0-commit.`)&&console.info("setup-vp: node-manager: false requires a preview build that supports `vp env off node`. If this command is unsupported, use a newer preview or a stable release. setup-vp will not fall back to disabling package-manager management."),supportsScopedEnv(e)?[`env`,`off`,`node`]:[`env`,`off`]}const mt=[`npm`,`pnpm`,`yarn`,`bun`];function parsePackageManager(e){if(!e?.trim())return;let t;try{t=(0,Y.parse)(e)}catch(e){throw Error(`Invalid package-manager input: ${String(e)}`)}if(t!==``){if(typeof t==`boolean`)return t;if(t&&typeof t==`object`&&!Array.isArray(t)){for(let[e,n]of Object.entries(t))if(!mt.includes(e)||typeof n!=`boolean`)throw Error(`Invalid package-manager input: ${e} must be npm, pnpm, yarn, or bun with a boolean value.`);return t}throw Error(`Invalid package-manager input: expected a boolean or a mapping of npm, pnpm, yarn, and bun to booleans.`)}}function packageManagerArgs(e,t){if(e===void 0)return[];if(!supportsScopedEnv(t))throw Error(`package-manager configuration requires Vite+ 0.3.1 or newer.`);return typeof e==`boolean`?e?[]:[[`env`,`off`,`pm`]]:mt.filter(t=>e[t]===!1).map(e=>[`env`,`off`,e])}function readNpmrc(e){try{return c(e,`utf8`)}catch(e){if(e.code===`ENOENT`)return``;throw e}}function authKeyFor(e){return(e.replace(/^\w+:/,``)+`:_authtoken`).toLowerCase()}function analyzeProjectNpmrc(e){let t=/* @__PURE__ */ new Set,n=/* @__PURE__ */ new Set,r=/* @__PURE__ */ new Set;for(let i of e.split(/\r?\n/)){let e=i.trim();if(!e||e.startsWith(`;`)||e.startsWith(`#`))continue;let a=e.indexOf(`=`);if(a<0)continue;let o=e.slice(0,a).trim().toLowerCase(),s=e.slice(a+1).trim();(o===`registry`||o.endsWith(`:registry`))&&(s.includes("${")||t.add(s.endsWith(`/`)?s:s+`/`)),o.startsWith(`//`)&&o.endsWith(`:_authtoken`)&&n.add(o);for(let e of s.matchAll(/\$\{(\w+)\}/g))r.add(e[1])}return{registriesNeedingAuth:[...t].filter(e=>!n.has(authKeyFor(e))),envVarRefs:r}}function readUserConfigLines(e,t){let n=e.HOME||e.USERPROFILE,r=e.NPM_CONFIG_USERCONFIG||e.PNPM_CONFIG_USERCONFIG||n&&h.join(n,`.npmrc`);return(r?readNpmrc(r):``).split(/\r?\n/).filter(e=>!t.has(e.split(`=`)[0].trim().toLowerCase()))}function isReservedAuthVariable(e){return[`GITHUB_TOKEN`,`CI_JOB_TOKEN`,`SYSTEM_ACCESSTOKEN`].includes(e)?!1:/^(?:PATH|HOME|USERPROFILE|TMPDIR|CI)$/i.test(e)||/^(?:SETUP_VP_|RUNNER_|GITHUB_|CI_|SYSTEM_|AGENT_|BUILD_|RELEASE_)/i.test(e)}function writeUserConfig(e,t,n){let r=s(h.join(E(),`setup-vp-npmrc-`)),i=h.join(r,`.npmrc`);m(i,e,{encoding:`utf8`,mode:384});for(let e of[`NPM_CONFIG_USERCONFIG`,`PNPM_CONFIG_USERCONFIG`])t[e]=i,n?.(e,i);return i}function configureAuth$1(e,t,n,r,i){if(!e){if(!i)return;let{registriesNeedingAuth:e,envVarRefs:t}=analyzeProjectNpmrc(readNpmrc(h.join(i,`.npmrc`))),a;if(n.NODE_AUTH_TOKEN&&e.length>0){let i=readUserConfigLines(n,new Set(e.map(e=>(e.replace(/^\w+:/,``)+`:_authtoken`).toLowerCase())));i.push(...e.map(e=>e.replace(/^\w+:/,``)+":_authToken=${NODE_AUTH_TOKEN}")),a=writeUserConfig(i.join(` -`)+` -`,n,r),t.add(`NODE_AUTH_TOKEN`)}for(let e of t)!isReservedAuthVariable(e)&&n[e]&&r?.(e,n[e]);return a}let a;try{a=new URL(e)}catch{throw Error(`Invalid registry-url: "${e}". Must be a valid URL.`)}let o=a.href.endsWith(`/`)?a.href:`${a.href}/`,s=``;t&&(s=`${(t.startsWith(`@`)?t:`@${t}`).toLowerCase()}:`);let c=o.replace(/^\w+:/,``).toLowerCase(),l=readUserConfigLines(n,/* @__PURE__ */ new Set([`${s}registry`,`${c}:_authtoken`]));l.push(`${c}:_authToken=\${NODE_AUTH_TOKEN}`,`${s}registry=${o}`);let u=writeUserConfig(l.filter(Boolean).join(` +`.trim()]}}const dt=2e3;function getVitePlusHome(e=process.platform,t=process.env){let n=isWindows(e)?t.USERPROFILE||T():t.HOME||T();return y(n,`.vite-plus`)}function runInstallCommand(e,t,n=process.platform){let{command:r,args:i}=getInstallScriptCommand(e,n,t.VP_VPDIRS_AWARE===`1`),a={env:{...process.env,...t},stdio:`inherit`},o=w(r,i,a);if(isWindows(n)&&o.error?.code===`ENOENT`&&(o=w(`powershell.exe`,i,a)),o.error)throw o.error;return o.status??1}async function installVitePlus(e,t={}){let n=t.platform??process.platform,r=t.env??process.env,i=t.prependPath,a=t.sleep??ee,o=t.runInstall??runInstallCommand,s=t.logWarningFn??console.warn,c={...Object.fromEntries(Object.entries(r).filter(e=>e[1]!==void 0)),VP_VERSION:e,VITE_PLUS_VERSION:e},l=supportsVitePlusDirs(e)?createVitePlusDirsFile():void 0;l?(c.VP_VPDIRS_AWARE=`1`,c[Q]=l):(delete c.VP_VPDIRS_AWARE,delete c[Q]);let u=pkgPrNewCommitSha(e);u&&(c.VP_PR_VERSION=u);let{pinned:d,latest:f}=getInstallScriptUrls(e,n),p=d.length+f.length,m=2*p,h=``,g=0;async function tryUrls(e){for(let t=0;t<2;t+=1)for(let t of e){g+=1;try{let e=o(t,c,n);if(e===0)return!0;h=`exit code ${e}`}catch(e){h=e instanceof Error?e.message:String(e)}g0){if(await tryUrls(d)){ensureBinInPath();return}s(`setup-vp: could not fetch the install script pinned to Vite+ ${e}. Falling back to the latest install script. The latest script may not be compatible with ${e}.`)}if(await tryUrls(f)){ensureBinInPath();return}throw Error(`Failed to install Vite+ after ${m} attempts across ${p} URL(s): ${h}`)}finally{l&&removeVitePlusDirsFile(l)}}function copyCacheDirectory(e,t,r){e=h.resolve(e),t=h.resolve(t),n(e,t,{recursive:!0,force:r,errorOnExist:!1,filter:(n,i)=>{let s=a(i,{throwIfNoEntry:!1}),c=a(n);if(s&&!r)return c.isDirectory()&&s.isDirectory();if(s&&(s.isSymbolicLink()||c.isSymbolicLink())&&d(i,{recursive:!0,force:!0}),c.isSymbolicLink()){let r=h.resolve(h.dirname(n),u(n)),a=r;if(isWithin(r,e)){let n=h.join(t,h.relative(e,r));a=h.relative(h.dirname(i),n)||`.`}return o(h.dirname(i),{recursive:!0}),p(a,i,f(r,{throwIfNoEntry:!1})?.isDirectory()?`dir`:`file`),!1}return!0}})}function restoreCacheSnapshot(e,t,n=console.warn,r=!0){if(!e.ready||!e.cachePath||!e.lockFile||!e.lockType)return{hit:!1,save:()=>{}};let a=e.cachePath;if(isWithin(h.resolve(a),h.resolve(t))||isWithin(h.resolve(t),h.resolve(a)))return n(`setup-vp: package-manager cache overlaps the snapshot directory; skipping cache.`),{hit:!1,save:()=>{}};let s=h.join(t,process.platform,process.arch,e.lockType),l=h.join(s,`packages`),u=h.join(s,`lock-hash`),d=e.lockFile;function hashLockFile(){return te(`sha256`).update(c(d)).digest(`hex`)}let f;try{f=hashLockFile()}catch(e){return n(`setup-vp: could not read cache lock file: ${String(e)}`),{hit:!1,save:()=>{}}}let p=!1;try{r&&i(l)&&(o(a,{recursive:!0}),copyCacheDirectory(l,a,!1),p=c(u,`utf8`)===f)}catch(e){n(`setup-vp: could not restore package-manager cache: ${String(e)}`)}return{hit:p,save:()=>{try{if(!i(a))return;let e=hashLockFile();o(s,{recursive:!0}),copyCacheDirectory(a,l,!0),m(u,e,`utf8`)}catch(e){n(`setup-vp: could not save package-manager cache: ${String(e)}`)}}}}const ft=/* @__PURE__ */ new Set([`true`,`True`,`TRUE`]),pt=/* @__PURE__ */ new Set([`false`,`False`,`FALSE`]);function parseNodeManager(e){if(e){if(ft.has(e))return!0;if(pt.has(e))return!1;throw Error(`Invalid node-manager input: "${e}". Expected "true", "false", or unset.`)}}function supportsScopedEnv(e){let t=parseInstalledVpVersion(e);if(t.startsWith(`0.0.0-commit.`))return!0;let n=t.match(/^(\d+)\.(\d+)\.(\d+)/);if(!n)throw Error(`Could not determine the installed Vite+ version for env configuration.`);let[,r,i,a]=n.map(Number);return r>0||i>3||i===3&&a>=1}function nodeManagerOffArgs(e){return parseInstalledVpVersion(e).startsWith(`0.0.0-commit.`)&&console.info("setup-vp: node-manager: false requires a preview build that supports `vp env off node`. If this command is unsupported, use a newer preview or a stable release. setup-vp will not fall back to disabling package-manager management."),supportsScopedEnv(e)?[`env`,`off`,`node`]:[`env`,`off`]}const mt=[`npm`,`pnpm`,`yarn`,`bun`];function parsePackageManager(e){if(!e?.trim())return;let t;try{t=(0,Y.parse)(e)}catch(e){throw Error(`Invalid package-manager input: ${String(e)}`)}if(t!==``){if(typeof t==`boolean`)return t;if(t&&typeof t==`object`&&!Array.isArray(t)){for(let[e,n]of Object.entries(t))if(!mt.includes(e)||typeof n!=`boolean`)throw Error(`Invalid package-manager input: ${e} must be npm, pnpm, yarn, or bun with a boolean value.`);return t}throw Error(`Invalid package-manager input: expected a boolean or a mapping of npm, pnpm, yarn, and bun to booleans.`)}}function packageManagerArgs(e,t){if(e===void 0)return[];if(!supportsScopedEnv(t))throw Error(`package-manager configuration requires Vite+ 0.3.1 or newer.`);return typeof e==`boolean`?e?[]:[[`env`,`off`,`pm`]]:mt.filter(t=>e[t]===!1).map(e=>[`env`,`off`,e])}function readNpmrc(e){try{return c(e,`utf8`)}catch(e){if(e.code===`ENOENT`)return``;throw e}}function analyzeProjectNpmrc(e){let t=/* @__PURE__ */ new Set;for(let n of e.split(/\r?\n/)){let e=n.trim();if(!e||e.startsWith(`;`)||e.startsWith(`#`))continue;let r=e.indexOf(`=`);if(r<0)continue;let i=e.slice(r+1).trim();for(let e of i.matchAll(/\$\{(\w+)\}/g))t.add(e[1])}return{envVarRefs:t}}function readUserConfigLines(e,t){let n=e.HOME||e.USERPROFILE,r=e.NPM_CONFIG_USERCONFIG||e.PNPM_CONFIG_USERCONFIG||n&&h.join(n,`.npmrc`);return(r?readNpmrc(r):``).split(/\r?\n/).filter(e=>!t.has(e.split(`=`)[0].trim().toLowerCase()))}function isReservedAuthVariable(e){return[`GITHUB_TOKEN`,`CI_JOB_TOKEN`,`SYSTEM_ACCESSTOKEN`].includes(e)?!1:/^(?:PATH|HOME|USERPROFILE|TMPDIR|CI)$/i.test(e)||/^(?:SETUP_VP_|RUNNER_|GITHUB_|CI_|SYSTEM_|AGENT_|BUILD_|RELEASE_)/i.test(e)}function writeUserConfig(e,t,n){let r=s(h.join(E(),`setup-vp-npmrc-`)),i=h.join(r,`.npmrc`);m(i,e,{encoding:`utf8`,mode:384});for(let e of[`NPM_CONFIG_USERCONFIG`,`PNPM_CONFIG_USERCONFIG`])t[e]=i,n?.(e,i);return i}function configureAuth$1(e,t,n,r,i){if(!e){if(!i)return;let{envVarRefs:e}=analyzeProjectNpmrc(readNpmrc(h.join(i,`.npmrc`)));for(let t of e)!isReservedAuthVariable(t)&&n[t]&&r?.(t,n[t]);return}let a;try{a=new URL(e)}catch{throw Error(`Invalid registry-url: "${e}". Must be a valid URL.`)}let o=a.href.endsWith(`/`)?a.href:`${a.href}/`,s=``;t&&(s=`${(t.startsWith(`@`)?t:`@${t}`).toLowerCase()}:`);let c=o.replace(/^\w+:/,``).toLowerCase(),l=readUserConfigLines(n,/* @__PURE__ */ new Set([`${s}registry`,`${c}:_authtoken`]));l.push(`${c}:_authToken=\${NODE_AUTH_TOKEN}`,`${s}registry=${o}`);let u=writeUserConfig(l.filter(Boolean).join(` `)+` `,n,r);return n.NODE_AUTH_TOKEN=n.NODE_AUTH_TOKEN||`XXXXX-XXXXX-XXXXX-XXXXX`,r?.(`NODE_AUTH_TOKEN`,n.NODE_AUTH_TOKEN),u}function shellQuote(e){return`'${String(e).replaceAll(`'`,`'\\''`)}'`}function exportShellEnv(e,t,n=process.env){if(!n.SETUP_VP_ENV_FILE||t===void 0)return;if(!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(e))throw Error(`Invalid environment variable name`);let r=n.SETUP_VP_ENV_FORMAT===`powershell`?`$env:${e} = '${t.replaceAll(`'`,`''`)}'\n`:`export ${e}=${shellQuote(t)}\n`;m(n.SETUP_VP_ENV_FILE,r,{encoding:`utf8`,flag:`a`})}function configureAuth(e,t,n=process.env,r){return configureAuth$1(e,t,n,n===process.env?(e,t)=>exportShellEnv(e,t,n):void 0,r)}function resolveSfwEnabled(e,t,n){return e?!pkgPrNewCommitSha(t)||(n(`sfw was requested but is automatically disabled for Vite+ preview build ${t}; Socket Firewall Free will not be used.`),!1):!1}const $=`v1.15.4`,ht=`https://github.com/SocketDev/sfw-free/releases/download/${$}`;function isMuslLinux(){if(process.platform!==`linux`)return!1;try{let e=process.report?.getReport();if(e?.header&&!e.header.glibcVersionRuntime)return!0}catch{}return i(`/etc/alpine-release`)}function getSfwAssetName(e,t,n){if(e===`darwin`){if(t===`arm64`)return`sfw-free-macos-arm64`;if(t===`x64`)return`sfw-free-macos-x86_64`}else if(e===`linux`){if(t===`arm64`)return n?`sfw-free-musl-linux-arm64`:`sfw-free-linux-arm64`;if(t===`x64`)return n?`sfw-free-musl-linux-x86_64`:`sfw-free-linux-x86_64`}else if(isWindows(e)){if(t===`arm64`)return`sfw-free-windows-arm64.exe`;if(t===`x64`)return`sfw-free-windows-x86_64.exe`}throw Error(`Unsupported platform/arch for sfw: ${e}/${t}${e===`linux`?` (${n?`musl`:`glibc`})`:``}`)}function downloadFileWithShell(e,t,n){let r=Math.max(1,Math.ceil(n/1e3)),i=commandPath(`curl`);if(i){let n=w(i,[`-fsSL`,`--connect-timeout`,`5`,`--max-time`,String(r),e,`-o`,t],{stdio:`ignore`});if(n.status===0)return;throw n.error||/* @__PURE__ */ Error(`curl failed while downloading ${e}`)}let a=commandPath(`wget`);if(a){let n=w(a,[`-q`,`-T`,String(r),`-t`,`2`,`-O`,t,e],{stdio:`ignore`});if(n.status===0)return;throw n.error||/* @__PURE__ */ Error(`wget failed while downloading ${e}`)}throw Error(`curl or wget is required to download sfw`)}function downloadFile(e,t,n=0,i=6e4,a){return n>5?Promise.reject(/* @__PURE__ */ Error(`too many redirects while downloading ${e}`)):a?new Promise((o,s)=>{let c=!1,finish=e=>{c||(c=!0,clearTimeout(u),e?s(e):o())},l=a(e,o=>{let s=o.statusCode??0,c=o.headers.location;if(s>=300&&s<400&&c){o.resume(),downloadFile(new URL(c,e).toString(),t,n+1,i,a).then(()=>finish(),finish);return}if(s!==200){o.resume(),finish(/* @__PURE__ */ Error(`download failed with HTTP ${s}: ${e}`));return}let l=r(t);o.pipe(l),l.on(`finish`,()=>l.close(()=>finish())),l.on(`error`,finish)}),u=setTimeout(()=>{l.destroy(/* @__PURE__ */ Error(`download timed out after ${i}ms: ${e}`))},i);l.on(`error`,finish)}):(downloadFileWithShell(e,t,i),Promise.resolve())}async function setupSfw$1(e,t={}){let n=t.env??process.env,r=t.sfwEnabled??n.SETUP_VP_SFW===`true`,i=t.platform??process.platform,a=t.arch??process.arch,o=t.isMusl??isMuslLinux(),s=t.download??downloadFile;if(!resolveSfwEnabled(r,t.vitePlusVersion??``,t.logWarning??console.warn))return`vp`;if(e.length===0)return console.log(`setup-vp: sfw was requested but run-install is disabled; sfw will not be invoked.`),`vp`;let c=commandPath(`sfw`);if(c)return console.log(`setup-vp: using existing sfw on PATH: ${c}`),`sfw`;let l;try{l=getSfwAssetName(i,a,o)}catch{return console.error(`setup-vp: sfw has no published binary for this runner's platform/architecture (process.platform=${i}, process.arch=${a}, musl=${o}) and none was found on PATH; falling back to plain vp install.`),`vp`}let u=t.cacheDirectory||n.SETUP_VP_SFW_CACHE_DIR,d=u?h.join(u,$,l):await ae(h.join(E(),`setup-vp-sfw-`));await ie(d,{recursive:!0});let f=h.join(d,isWindows(i)?`sfw.exe`:`sfw`),p=`${ht}/${l}`;function activate(){let e=isWindows(i)?`;`:`:`;return n.PATH=`${d}${e}${n.PATH||``}`,t.exportVariable?.(`PATH`,n.PATH),`sfw`}if(await ce(f).then(e=>e.isFile()&&e.size>0,()=>!1))return console.log(`setup-vp: using cached sfw ${$}: ${f}`),activate();for(let e=1;e<=2;e+=1){let t=await ae(h.join(d,`.download-`)),n=h.join(t,`sfw`);try{if(console.log(`setup-vp: installing sfw ${$} from ${p}`),await s(p,n),(await ce(n)).size===0)throw Error(`Downloaded sfw binary is empty`);return await re(n,493),await oe(n,f),activate()}catch(t){if(e===2)throw t;await new Promise(e=>setTimeout(e,2e3))}finally{await se(t,{recursive:!0,force:!0})}}throw Error(`failed to install sfw after retrying`)}async function setupSfw(e,t=process.env,n=``){return setupSfw$1(e,{env:t,vitePlusVersion:n,exportVariable:(e,n)=>exportShellEnv(e,n,t)})}function isRecord(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function validateRunInstallEntry(e){if(!isRecord(e))throw Error(`run-install entries must be objects`);for(let t of Object.keys(e))if(t!==`cwd`&&t!==`args`)throw Error(`unsupported run-install key: ${t}`);let t={};if(e.cwd!==void 0){if(typeof e.cwd!=`string`)throw Error(`run-install.cwd must be a string`);t.cwd=e.cwd}if(e.args!==void 0){if(!Array.isArray(e.args)||e.args.some(e=>typeof e!=`string`))throw Error(`run-install.args must be an array of strings`);t.args=e.args}return t}function validateRunInstallInput(e){return e===null||typeof e==`boolean`?e:Array.isArray(e)?e.map(validateRunInstallEntry):validateRunInstallEntry(e)}function parseRunInstall(e){let t=validateRunInstallInput((0,Y.parse)(e)??null);return t?t===!0?[{}]:Array.isArray(t)?t:[t]:[]}function isSfwVpNotFoundFlake(e,t){return/Command 'vp' not found in PATH/.test(e+` `+t)}async function runInstall(e,t,n,r=process.env,i={}){let a={...r};delete a.SETUP_VP_ENV_FILE;let o=i.execute??runWithOutput,s=[];for(let r of e){let e=r.cwd?h.resolve(t,r.cwd):t,c=[`install`,...r.args||[]],l=n===`sfw`?[`vp`,...c]:c,u=`${n} ${l.join(` `)} (cwd: ${e})`;console.log(`setup-vp: running ${u}`);try{let t=await o(n,l,{cwd:e,env:a});if(t.exitCode!==0&&n===`sfw`&&isSfwVpNotFoundFlake(t.stdout,t.stderr)){let r=isWindows(i.platform);if(console.warn(r?`setup-vp: sfw could not resolve vp; warming the PowerShell command cache and retrying once.`:`setup-vp: sfw could not resolve vp; retrying once.`),r)try{await o(`powershell.exe`,[`-NoProfile`,`-Command`,`Get-Command vp`],{cwd:e,env:a})}catch{}t=await o(n,l,{cwd:e,env:a})}t.exitCode!==0&&s.push(`${u} exited with code ${t.exitCode}\n${t.stderr.trim()||t.stdout.trim()}`)}catch(e){s.push(`${u}: ${String(e)}`)}}if(s.length)throw Error(s.join(` diff --git a/dist/index.mjs b/dist/index.mjs index 99fa917..3eea643 100644 --- a/dist/index.mjs +++ b/dist/index.mjs @@ -331,4 +331,4 @@ More info on storage limits: https://docs.github.com/en/billing/managing-billing `)}}})),pv=/* @__PURE__ */ __commonJSMin((e=>{Object.defineProperty(e,"__esModule",{value:!0}),e.mergeRpcOptions=void 0;let t=lv();function mergeRpcOptions(e,n){if(!n)return e;let r={};copy(e,r),copy(n,r);for(let i of Object.keys(n)){let a=n[i];switch(i){case`jsonOptions`:r.jsonOptions=t.mergeJsonOptions(e.jsonOptions,r.jsonOptions);break;case`binaryOptions`:r.binaryOptions=t.mergeBinaryOptions(e.binaryOptions,r.binaryOptions);break;case`meta`:r.meta={},copy(e.meta,r.meta),copy(n.meta,r.meta);break;case`interceptors`:r.interceptors=e.interceptors?e.interceptors.concat(a):a.concat()}}return r}e.mergeRpcOptions=mergeRpcOptions;function copy(e,t){if(!e)return;let n=t;for(let[t,r]of Object.entries(e))n[t]=r instanceof Date?new Date(r.getTime()):Array.isArray(r)?r.concat():r}})),mv=/* @__PURE__ */ __commonJSMin((e=>{Object.defineProperty(e,"__esModule",{value:!0}),e.Deferred=e.DeferredState=void 0;var t;(function(e){e[e.PENDING=0]=`PENDING`,e[e.REJECTED=1]=`REJECTED`,e[e.RESOLVED=2]=`RESOLVED`})(t=e.DeferredState||={}),e.Deferred=class{constructor(e=!0){this._state=t.PENDING,this._promise=new Promise((e,t)=>{this._resolve=e,this._reject=t}),e&&this._promise.catch(e=>{})}get state(){return this._state}get promise(){return this._promise}resolve(e){if(this.state!==t.PENDING)throw Error(`cannot resolve ${t[this.state].toLowerCase()}`);this._resolve(e),this._state=t.RESOLVED}reject(e){if(this.state!==t.PENDING)throw Error(`cannot reject ${t[this.state].toLowerCase()}`);this._reject(e),this._state=t.REJECTED}resolvePending(e){this._state===t.PENDING&&this.resolve(e)}rejectPending(e){this._state===t.PENDING&&this.reject(e)}}})),hv=/* @__PURE__ */ __commonJSMin((e=>{Object.defineProperty(e,"__esModule",{value:!0}),e.RpcOutputStreamController=void 0;let t=mv(),n=lv();e.RpcOutputStreamController=class{constructor(){this._lis={nxt:[],msg:[],err:[],cmp:[]},this._closed=!1,this._itState={q:[]}}onNext(e){return this.addLis(e,this._lis.nxt)}onMessage(e){return this.addLis(e,this._lis.msg)}onError(e){return this.addLis(e,this._lis.err)}onComplete(e){return this.addLis(e,this._lis.cmp)}addLis(e,t){return t.push(e),()=>{let n=t.indexOf(e);n>=0&&t.splice(n,1)}}clearLis(){for(let e of Object.values(this._lis))e.splice(0,e.length)}get closed(){return this._closed!==!1}notifyNext(e,t,r){n.assert(+!!e+ +!!t+ +!!r<=1,`only one emission at a time`),e&&this.notifyMessage(e),t&&this.notifyError(t),r&&this.notifyComplete()}notifyMessage(e){n.assert(!this.closed,`stream is closed`),this.pushIt({value:e,done:!1}),this._lis.msg.forEach(t=>t(e)),this._lis.nxt.forEach(t=>t(e,void 0,!1))}notifyError(e){n.assert(!this.closed,`stream is closed`),this._closed=e,this.pushIt(e),this._lis.err.forEach(t=>t(e)),this._lis.nxt.forEach(t=>t(void 0,e,!1)),this.clearLis()}notifyComplete(){n.assert(!this.closed,`stream is closed`),this._closed=!0,this.pushIt({value:null,done:!0}),this._lis.cmp.forEach(e=>e()),this._lis.nxt.forEach(e=>e(void 0,void 0,!0)),this.clearLis()}[Symbol.asyncIterator](){return this._closed===!0?this.pushIt({value:null,done:!0}):this._closed!==!1&&this.pushIt(this._closed),{next:()=>{let e=this._itState;n.assert(e,`bad state`),n.assert(!e.p,`iterator contract broken`);let r=e.q.shift();return r?`value`in r?Promise.resolve(r):Promise.reject(r):(e.p=new t.Deferred,e.p.promise)}}}pushIt(e){let r=this._itState;if(r.p){let i=r.p;n.assert(i.state==t.DeferredState.PENDING,`iterator contract broken`),`value`in e?i.resolve(e):i.reject(e),delete r.p}else r.q.push(e)}}})),gv=/* @__PURE__ */ __commonJSMin((e=>{var t=e&&e.__awaiter||function(e,t,n,r){function adopt(e){return e instanceof n?e:new n(function(t){t(e)})}return new(n||=Promise)(function(n,i){function fulfilled(e){try{step(r.next(e))}catch(e){i(e)}}function rejected(e){try{step(r.throw(e))}catch(e){i(e)}}function step(e){e.done?n(e.value):adopt(e.value).then(fulfilled,rejected)}step((r=r.apply(e,t||[])).next())})};Object.defineProperty(e,"__esModule",{value:!0}),e.UnaryCall=void 0,e.UnaryCall=class{constructor(e,t,n,r,i,a,o){this.method=e,this.requestHeaders=t,this.request=n,this.headers=r,this.response=i,this.status=a,this.trailers=o}then(e,t){return this.promiseFinished().then(t=>e?Promise.resolve(e(t)):t,e=>t?Promise.resolve(t(e)):Promise.reject(e))}promiseFinished(){return t(this,void 0,void 0,function*(){let[e,t,n,r]=yield Promise.all([this.headers,this.response,this.status,this.trailers]);return{method:this.method,requestHeaders:this.requestHeaders,request:this.request,headers:e,response:t,status:n,trailers:r}})}}})),_v=/* @__PURE__ */ __commonJSMin((e=>{var t=e&&e.__awaiter||function(e,t,n,r){function adopt(e){return e instanceof n?e:new n(function(t){t(e)})}return new(n||=Promise)(function(n,i){function fulfilled(e){try{step(r.next(e))}catch(e){i(e)}}function rejected(e){try{step(r.throw(e))}catch(e){i(e)}}function step(e){e.done?n(e.value):adopt(e.value).then(fulfilled,rejected)}step((r=r.apply(e,t||[])).next())})};Object.defineProperty(e,"__esModule",{value:!0}),e.ServerStreamingCall=void 0,e.ServerStreamingCall=class{constructor(e,t,n,r,i,a,o){this.method=e,this.requestHeaders=t,this.request=n,this.headers=r,this.responses=i,this.status=a,this.trailers=o}then(e,t){return this.promiseFinished().then(t=>e?Promise.resolve(e(t)):t,e=>t?Promise.resolve(t(e)):Promise.reject(e))}promiseFinished(){return t(this,void 0,void 0,function*(){let[e,t,n]=yield Promise.all([this.headers,this.status,this.trailers]);return{method:this.method,requestHeaders:this.requestHeaders,request:this.request,headers:e,status:t,trailers:n}})}}})),vv=/* @__PURE__ */ __commonJSMin((e=>{var t=e&&e.__awaiter||function(e,t,n,r){function adopt(e){return e instanceof n?e:new n(function(t){t(e)})}return new(n||=Promise)(function(n,i){function fulfilled(e){try{step(r.next(e))}catch(e){i(e)}}function rejected(e){try{step(r.throw(e))}catch(e){i(e)}}function step(e){e.done?n(e.value):adopt(e.value).then(fulfilled,rejected)}step((r=r.apply(e,t||[])).next())})};Object.defineProperty(e,"__esModule",{value:!0}),e.ClientStreamingCall=void 0,e.ClientStreamingCall=class{constructor(e,t,n,r,i,a,o){this.method=e,this.requestHeaders=t,this.requests=n,this.headers=r,this.response=i,this.status=a,this.trailers=o}then(e,t){return this.promiseFinished().then(t=>e?Promise.resolve(e(t)):t,e=>t?Promise.resolve(t(e)):Promise.reject(e))}promiseFinished(){return t(this,void 0,void 0,function*(){let[e,t,n,r]=yield Promise.all([this.headers,this.response,this.status,this.trailers]);return{method:this.method,requestHeaders:this.requestHeaders,headers:e,response:t,status:n,trailers:r}})}}})),yv=/* @__PURE__ */ __commonJSMin((e=>{var t=e&&e.__awaiter||function(e,t,n,r){function adopt(e){return e instanceof n?e:new n(function(t){t(e)})}return new(n||=Promise)(function(n,i){function fulfilled(e){try{step(r.next(e))}catch(e){i(e)}}function rejected(e){try{step(r.throw(e))}catch(e){i(e)}}function step(e){e.done?n(e.value):adopt(e.value).then(fulfilled,rejected)}step((r=r.apply(e,t||[])).next())})};Object.defineProperty(e,"__esModule",{value:!0}),e.DuplexStreamingCall=void 0,e.DuplexStreamingCall=class{constructor(e,t,n,r,i,a,o){this.method=e,this.requestHeaders=t,this.requests=n,this.headers=r,this.responses=i,this.status=a,this.trailers=o}then(e,t){return this.promiseFinished().then(t=>e?Promise.resolve(e(t)):t,e=>t?Promise.resolve(t(e)):Promise.reject(e))}promiseFinished(){return t(this,void 0,void 0,function*(){let[e,t,n]=yield Promise.all([this.headers,this.status,this.trailers]);return{method:this.method,requestHeaders:this.requestHeaders,headers:e,status:t,trailers:n}})}}})),bv=/* @__PURE__ */ __commonJSMin((e=>{var t=e&&e.__awaiter||function(e,t,n,r){function adopt(e){return e instanceof n?e:new n(function(t){t(e)})}return new(n||=Promise)(function(n,i){function fulfilled(e){try{step(r.next(e))}catch(e){i(e)}}function rejected(e){try{step(r.throw(e))}catch(e){i(e)}}function step(e){e.done?n(e.value):adopt(e.value).then(fulfilled,rejected)}step((r=r.apply(e,t||[])).next())})};Object.defineProperty(e,"__esModule",{value:!0}),e.TestTransport=void 0;let n=fv(),r=lv(),i=hv(),a=pv(),o=gv(),s=_v(),c=vv(),l=yv();var u=class TestTransport{constructor(e){this.suppressUncaughtRejections=!0,this.headerDelay=10,this.responseDelay=50,this.betweenResponseDelay=10,this.afterResponseDelay=10,this.data=e??{}}get sentMessages(){return this.lastInput instanceof TestInputStream?this.lastInput.sent:typeof this.lastInput==`object`?[this.lastInput.single]:[]}get sendComplete(){return this.lastInput instanceof TestInputStream?this.lastInput.completed:typeof this.lastInput==`object`}promiseHeaders(){let e=this.data.headers??TestTransport.defaultHeaders;return e instanceof n.RpcError?Promise.reject(e):Promise.resolve(e)}promiseSingleResponse(e){if(this.data.response instanceof n.RpcError)return Promise.reject(this.data.response);let t;return Array.isArray(this.data.response)?(r.assert(this.data.response.length>0),t=this.data.response[0]):t=this.data.response===void 0?e.O.create():this.data.response,r.assert(e.O.is(t)),Promise.resolve(t)}streamResponses(e,i,a){return t(this,void 0,void 0,function*(){let t=[];if(this.data.response===void 0)t.push(e.O.create());else if(Array.isArray(this.data.response))for(let n of this.data.response)r.assert(e.O.is(n)),t.push(n);else this.data.response instanceof n.RpcError||(r.assert(e.O.is(this.data.response)),t.push(this.data.response));try{yield delay(this.responseDelay,a)(void 0)}catch(e){i.notifyError(e);return}if(this.data.response instanceof n.RpcError){i.notifyError(this.data.response);return}for(let e of t){i.notifyMessage(e);try{yield delay(this.betweenResponseDelay,a)(void 0)}catch(e){i.notifyError(e);return}}if(this.data.status instanceof n.RpcError){i.notifyError(this.data.status);return}if(this.data.trailers instanceof n.RpcError){i.notifyError(this.data.trailers);return}i.notifyComplete()})}promiseStatus(){let e=this.data.status??TestTransport.defaultStatus;return e instanceof n.RpcError?Promise.reject(e):Promise.resolve(e)}promiseTrailers(){let e=this.data.trailers??TestTransport.defaultTrailers;return e instanceof n.RpcError?Promise.reject(e):Promise.resolve(e)}maybeSuppressUncaught(...e){if(this.suppressUncaughtRejections)for(let t of e)t.catch(()=>{})}mergeOptions(e){return a.mergeRpcOptions({},e)}unary(e,t,n){let r=n.meta??{},i=this.promiseHeaders().then(delay(this.headerDelay,n.abort)),a=i.catch(e=>{}).then(delay(this.responseDelay,n.abort)).then(t=>this.promiseSingleResponse(e)),s=a.catch(e=>{}).then(delay(this.afterResponseDelay,n.abort)).then(e=>this.promiseStatus()),c=a.catch(e=>{}).then(delay(this.afterResponseDelay,n.abort)).then(e=>this.promiseTrailers());return this.maybeSuppressUncaught(s,c),this.lastInput={single:t},new o.UnaryCall(e,r,t,i,a,s,c)}serverStreaming(e,t,n){let r=n.meta??{},a=this.promiseHeaders().then(delay(this.headerDelay,n.abort)),o=new i.RpcOutputStreamController,c=a.then(delay(this.responseDelay,n.abort)).catch(()=>{}).then(()=>this.streamResponses(e,o,n.abort)).then(delay(this.afterResponseDelay,n.abort)),l=c.then(()=>this.promiseStatus()),u=c.then(()=>this.promiseTrailers());return this.maybeSuppressUncaught(l,u),this.lastInput={single:t},new s.ServerStreamingCall(e,r,t,a,o,l,u)}clientStreaming(e,t){let n=t.meta??{},r=this.promiseHeaders().then(delay(this.headerDelay,t.abort)),i=r.catch(e=>{}).then(delay(this.responseDelay,t.abort)).then(t=>this.promiseSingleResponse(e)),a=i.catch(e=>{}).then(delay(this.afterResponseDelay,t.abort)).then(e=>this.promiseStatus()),o=i.catch(e=>{}).then(delay(this.afterResponseDelay,t.abort)).then(e=>this.promiseTrailers());return this.maybeSuppressUncaught(a,o),this.lastInput=new TestInputStream(this.data,t.abort),new c.ClientStreamingCall(e,n,this.lastInput,r,i,a,o)}duplex(e,t){let n=t.meta??{},r=this.promiseHeaders().then(delay(this.headerDelay,t.abort)),a=new i.RpcOutputStreamController,o=r.then(delay(this.responseDelay,t.abort)).catch(()=>{}).then(()=>this.streamResponses(e,a,t.abort)).then(delay(this.afterResponseDelay,t.abort)),s=o.then(()=>this.promiseStatus()),c=o.then(()=>this.promiseTrailers());return this.maybeSuppressUncaught(s,c),this.lastInput=new TestInputStream(this.data,t.abort),new l.DuplexStreamingCall(e,n,this.lastInput,r,a,s,c)}};e.TestTransport=u,u.defaultHeaders={responseHeader:`test`},u.defaultStatus={code:`OK`,detail:`all good`},u.defaultTrailers={responseTrailer:`test`};function delay(e,t){return r=>new Promise((i,a)=>{if(t?.aborted)a(new n.RpcError(`user cancel`,`CANCELLED`));else{let o=setTimeout(()=>i(r),e);t&&t.addEventListener(`abort`,e=>{clearTimeout(o),a(new n.RpcError(`user cancel`,`CANCELLED`))})}})}var TestInputStream=class{constructor(e,t){this._completed=!1,this._sent=[],this.data=e,this.abort=t}get sent(){return this._sent}get completed(){return this._completed}send(e){if(this.data.inputMessage instanceof n.RpcError)return Promise.reject(this.data.inputMessage);let t=this.data.inputMessage===void 0?10:this.data.inputMessage;return Promise.resolve(void 0).then(()=>{this._sent.push(e)}).then(delay(t,this.abort))}complete(){if(this.data.inputComplete instanceof n.RpcError)return Promise.reject(this.data.inputComplete);let e=this.data.inputComplete===void 0?10:this.data.inputComplete;return Promise.resolve(void 0).then(()=>{this._completed=!0}).then(delay(e,this.abort))}}})),xv=/* @__PURE__ */ __commonJSMin((e=>{Object.defineProperty(e,"__esModule",{value:!0}),e.stackDuplexStreamingInterceptors=e.stackClientStreamingInterceptors=e.stackServerStreamingInterceptors=e.stackUnaryInterceptors=e.stackIntercept=void 0;let t=lv();function stackIntercept(e,n,r,i,a){if(e==`unary`){let tail=(e,t,r)=>n.unary(e,t,r);for(let e of(i.interceptors??[]).filter(e=>e.interceptUnary).reverse()){let t=tail;tail=(n,r,i)=>e.interceptUnary(t,n,r,i)}return tail(r,a,i)}if(e==`serverStreaming`){let tail=(e,t,r)=>n.serverStreaming(e,t,r);for(let e of(i.interceptors??[]).filter(e=>e.interceptServerStreaming).reverse()){let t=tail;tail=(n,r,i)=>e.interceptServerStreaming(t,n,r,i)}return tail(r,a,i)}if(e==`clientStreaming`){let tail=(e,t)=>n.clientStreaming(e,t);for(let e of(i.interceptors??[]).filter(e=>e.interceptClientStreaming).reverse()){let t=tail;tail=(n,r)=>e.interceptClientStreaming(t,n,r)}return tail(r,i)}if(e==`duplex`){let tail=(e,t)=>n.duplex(e,t);for(let e of(i.interceptors??[]).filter(e=>e.interceptDuplex).reverse()){let t=tail;tail=(n,r)=>e.interceptDuplex(t,n,r)}return tail(r,i)}t.assertNever(e)}e.stackIntercept=stackIntercept;function stackUnaryInterceptors(e,t,n,r){return stackIntercept(`unary`,e,t,r,n)}e.stackUnaryInterceptors=stackUnaryInterceptors;function stackServerStreamingInterceptors(e,t,n,r){return stackIntercept(`serverStreaming`,e,t,r,n)}e.stackServerStreamingInterceptors=stackServerStreamingInterceptors;function stackClientStreamingInterceptors(e,t,n){return stackIntercept(`clientStreaming`,e,t,n)}e.stackClientStreamingInterceptors=stackClientStreamingInterceptors;function stackDuplexStreamingInterceptors(e,t,n){return stackIntercept(`duplex`,e,t,n)}e.stackDuplexStreamingInterceptors=stackDuplexStreamingInterceptors})),Sv=/* @__PURE__ */ __commonJSMin((e=>{Object.defineProperty(e,"__esModule",{value:!0}),e.ServerCallContextController=void 0,e.ServerCallContextController=class{constructor(e,t,n,r,i={code:`OK`,detail:``}){this._cancelled=!1,this._listeners=[],this.method=e,this.headers=t,this.deadline=n,this.trailers={},this._sendRH=r,this.status=i}notifyCancelled(){if(!this._cancelled){this._cancelled=!0;for(let e of this._listeners)e()}}sendResponseHeaders(e){this._sendRH(e)}get cancelled(){return this._cancelled}onCancel(e){let t=this._listeners;return t.push(e),()=>{let n=t.indexOf(e);n>=0&&t.splice(n,1)}}}})),Cv=(/* @__PURE__ */ __commonJSMin((e=>{Object.defineProperty(e,"__esModule",{value:!0});var t=dv();Object.defineProperty(e,"ServiceType",{enumerable:!0,get:function(){return t.ServiceType}});var n=uv();Object.defineProperty(e,"readMethodOptions",{enumerable:!0,get:function(){return n.readMethodOptions}}),Object.defineProperty(e,"readMethodOption",{enumerable:!0,get:function(){return n.readMethodOption}}),Object.defineProperty(e,"readServiceOption",{enumerable:!0,get:function(){return n.readServiceOption}});var r=fv();Object.defineProperty(e,"RpcError",{enumerable:!0,get:function(){return r.RpcError}});var i=pv();Object.defineProperty(e,"mergeRpcOptions",{enumerable:!0,get:function(){return i.mergeRpcOptions}});var a=hv();Object.defineProperty(e,"RpcOutputStreamController",{enumerable:!0,get:function(){return a.RpcOutputStreamController}});var o=bv();Object.defineProperty(e,"TestTransport",{enumerable:!0,get:function(){return o.TestTransport}});var s=mv();Object.defineProperty(e,"Deferred",{enumerable:!0,get:function(){return s.Deferred}}),Object.defineProperty(e,"DeferredState",{enumerable:!0,get:function(){return s.DeferredState}});var c=yv();Object.defineProperty(e,"DuplexStreamingCall",{enumerable:!0,get:function(){return c.DuplexStreamingCall}});var l=vv();Object.defineProperty(e,"ClientStreamingCall",{enumerable:!0,get:function(){return l.ClientStreamingCall}});var u=_v();Object.defineProperty(e,"ServerStreamingCall",{enumerable:!0,get:function(){return u.ServerStreamingCall}});var d=gv();Object.defineProperty(e,"UnaryCall",{enumerable:!0,get:function(){return d.UnaryCall}});var f=xv();Object.defineProperty(e,"stackIntercept",{enumerable:!0,get:function(){return f.stackIntercept}}),Object.defineProperty(e,"stackDuplexStreamingInterceptors",{enumerable:!0,get:function(){return f.stackDuplexStreamingInterceptors}}),Object.defineProperty(e,"stackClientStreamingInterceptors",{enumerable:!0,get:function(){return f.stackClientStreamingInterceptors}}),Object.defineProperty(e,"stackServerStreamingInterceptors",{enumerable:!0,get:function(){return f.stackServerStreamingInterceptors}}),Object.defineProperty(e,"stackUnaryInterceptors",{enumerable:!0,get:function(){return f.stackUnaryInterceptors}});var p=Sv();Object.defineProperty(e,"ServerCallContextController",{enumerable:!0,get:function(){return p.ServerCallContextController}})})))(),$=lv();const wv=new class extends $.MessageType{constructor(){super(`github.actions.results.entities.v1.CacheScope`,[{no:1,name:`scope`,kind:`scalar`,T:9},{no:2,name:`permission`,kind:`scalar`,T:3}])}create(e){let t={scope:``,permission:`0`};return globalThis.Object.defineProperty(t,$.MESSAGE_TYPE,{enumerable:!1,value:this}),e!==void 0&&(0,$.reflectionMergePartial)(this,t,e),t}internalBinaryRead(e,t,n,r){let i=r??this.create(),a=e.pos+t;for(;e.poswv}])}create(e){let t={repositoryId:`0`,scope:[]};return globalThis.Object.defineProperty(t,$.MESSAGE_TYPE,{enumerable:!1,value:this}),e!==void 0&&(0,$.reflectionMergePartial)(this,t,e),t}internalBinaryRead(e,t,n,r){let i=r??this.create(),a=e.pos+t;for(;e.posTv},{no:2,name:`key`,kind:`scalar`,T:9},{no:3,name:`version`,kind:`scalar`,T:9}])}create(e){let t={key:``,version:``};return globalThis.Object.defineProperty(t,$.MESSAGE_TYPE,{enumerable:!1,value:this}),e!==void 0&&(0,$.reflectionMergePartial)(this,t,e),t}internalBinaryRead(e,t,n,r){let i=r??this.create(),a=e.pos+t;for(;e.posTv},{no:2,name:`key`,kind:`scalar`,T:9},{no:3,name:`size_bytes`,kind:`scalar`,T:3},{no:4,name:`version`,kind:`scalar`,T:9}])}create(e){let t={key:``,sizeBytes:`0`,version:``};return globalThis.Object.defineProperty(t,$.MESSAGE_TYPE,{enumerable:!1,value:this}),e!==void 0&&(0,$.reflectionMergePartial)(this,t,e),t}internalBinaryRead(e,t,n,r){let i=r??this.create(),a=e.pos+t;for(;e.posTv},{no:2,name:`key`,kind:`scalar`,T:9},{no:3,name:`restore_keys`,kind:`scalar`,repeat:2,T:9},{no:4,name:`version`,kind:`scalar`,T:9}])}create(e){let t={key:``,restoreKeys:[],version:``};return globalThis.Object.defineProperty(t,$.MESSAGE_TYPE,{enumerable:!1,value:this}),e!==void 0&&(0,$.reflectionMergePartial)(this,t,e),t}internalBinaryRead(e,t,n,r){let i=r??this.create(),a=e.pos+t;for(;e.posDv.fromJson(e,{ignoreUnknownFields:!0}))}FinalizeCacheEntryUpload(e){let t=Ov.toJson(e,{useProtoFieldName:!0,emitDefaultValues:!1});return this.rpc.request(`github.actions.results.api.v1.CacheService`,`FinalizeCacheEntryUpload`,`application/json`,t).then(e=>kv.fromJson(e,{ignoreUnknownFields:!0}))}GetCacheEntryDownloadURL(e){let t=Av.toJson(e,{useProtoFieldName:!0,emitDefaultValues:!1});return this.rpc.request(`github.actions.results.api.v1.CacheService`,`GetCacheEntryDownloadURL`,`application/json`,t).then(e=>jv.fromJson(e,{ignoreUnknownFields:!0}))}};function maskSigUrl(e){if(e)try{let t=new URL(e).searchParams.get(`sig`);t&&(setSecret(t),setSecret(encodeURIComponent(t)))}catch(t){debug(`Failed to parse URL: ${e} ${t instanceof Error?t.message:String(t)}`)}}function maskSecretUrls(e){if(typeof e!=`object`||!e){debug(`body is not an object or is null`);return}`signed_upload_url`in e&&typeof e.signed_upload_url==`string`&&maskSigUrl(e.signed_upload_url),`signed_download_url`in e&&typeof e.signed_download_url==`string`&&maskSigUrl(e.signed_download_url)}var __awaiter$2=function(e,t,n,r){function adopt(e){return e instanceof n?e:new n(function(t){t(e)})}return new(n||=Promise)(function(n,i){function fulfilled(e){try{step(r.next(e))}catch(e){i(e)}}function rejected(e){try{step(r.throw(e))}catch(e){i(e)}}function step(e){e.done?n(e.value):adopt(e.value).then(fulfilled,rejected)}step((r=r.apply(e,t||[])).next())})},CacheServiceClient=class{constructor(e,t,n,r){this.maxAttempts=5,this.baseRetryIntervalMilliseconds=3e3,this.retryMultiplier=1.5;let i=getRuntimeToken();this.baseUrl=getCacheServiceURL(),t&&(this.maxAttempts=t),n&&(this.baseRetryIntervalMilliseconds=n),r&&(this.retryMultiplier=r),this.httpClient=new HttpClient(e,[new BearerCredentialHandler(i)])}request(e,t,n,r){return __awaiter$2(this,void 0,void 0,function*(){let i=new URL(`/twirp/${e}/${t}`,this.baseUrl).href;debug(`[Request] ${t} ${i}`);let a={"Content-Type":n};try{let{body:e}=yield this.retryableRequest(()=>__awaiter$2(this,void 0,void 0,function*(){return this.httpClient.post(i,JSON.stringify(r),a)}));return e}catch(e){throw Error(`Failed to ${t}: ${e.message}`)}})}retryableRequest(e){return __awaiter$2(this,void 0,void 0,function*(){let t=0,n=``,r=``;for(;t0&&warning(`You've hit a rate limit, your rate limit will reset in ${t} seconds`)}throw new RateLimitError(`Rate limited: ${n}`)}}catch(e){if(e instanceof SyntaxError&&debug(`Raw Body: ${r}`),e instanceof UsageError||e instanceof RateLimitError)throw e;if(NetworkError.isNetworkErrorCode(e?.code))throw new NetworkError(e?.code);i=!0,n=e.message}if(!i)throw Error(`Received non-retryable error: ${n}`);if(t+1===this.maxAttempts)throw Error(`Failed to make request after ${this.maxAttempts} attempts: ${n}`);let a=this.getExponentialRetryTimeMilliseconds(t);info(`Attempt ${t+1} of ${this.maxAttempts} failed with error: ${n}. Retrying request in ${a} ms...`),yield this.sleep(a),t++}throw Error(`Request failed`)})}isSuccessStatusCode(e){return e?e>=200&&e<300:!1}isRetryableHttpStatusCode(e){return e?[On.BadGateway,On.GatewayTimeout,On.InternalServerError,On.ServiceUnavailable].includes(e):!1}sleep(e){return __awaiter$2(this,void 0,void 0,function*(){return new Promise(t=>setTimeout(t,e))})}getExponentialRetryTimeMilliseconds(e){if(e<0)throw Error(`attempt should be a positive integer`);if(e===0)return this.baseRetryIntervalMilliseconds;let t=this.baseRetryIntervalMilliseconds*this.retryMultiplier**+e,n=t*this.retryMultiplier;return Math.trunc(Math.random()*(n-t)+t)}};function internalCacheTwirpClient(e){return new CacheServiceClientJSON(new CacheServiceClient(getUserAgentString(),e?.maxAttempts,e?.retryIntervalMs,e?.retryMultiplier))}var __awaiter$1=function(e,t,n,r){function adopt(e){return e instanceof n?e:new n(function(t){t(e)})}return new(n||=Promise)(function(n,i){function fulfilled(e){try{step(r.next(e))}catch(e){i(e)}}function rejected(e){try{step(r.throw(e))}catch(e){i(e)}}function step(e){e.done?n(e.value):adopt(e.value).then(fulfilled,rejected)}step((r=r.apply(e,t||[])).next())})};const Mv=process.platform===`win32`;function getTarPath(){return __awaiter$1(this,void 0,void 0,function*(){switch(process.platform){case`win32`:{let e=yield getGnuTarPathOnWindows(),t=ps;if(e)return{path:e,type:ls.GNU};if(s(t))return{path:t,type:ls.BSD};break}case`darwin`:{let e=yield which(`gtar`,!1);return e?{path:e,type:ls.GNU}:{path:yield which(`tar`,!0),type:ls.BSD}}}return{path:yield which(`tar`,!0),type:ls.GNU}})}function getTarArgs(e,t,n){return __awaiter$1(this,arguments,void 0,function*(e,t,n,r=``){let i=[`"${e.path}"`],a=getCacheFileName(t),o=`cache.tar`,s=getWorkingDirectory(),c=e.type===ls.BSD&&t!==cs.Gzip&&Mv;switch(n){case`create`:i.push(`--posix`,`-cf`,c?o:a.replace(RegExp(`\\${u.sep}`,`g`),`/`),`--exclude`,c?o:a.replace(RegExp(`\\${u.sep}`,`g`),`/`),`-P`,`-C`,s.replace(RegExp(`\\${u.sep}`,`g`),`/`),`--files-from`,hs);break;case`extract`:i.push(`-xf`,c?o:r.replace(RegExp(`\\${u.sep}`,`g`),`/`),`-P`,`-C`,c?quoteAbsolutePath(s):s.replace(RegExp(`\\${u.sep}`,`g`),`/`));break;case`list`:i.push(`-tf`,c?o:r.replace(RegExp(`\\${u.sep}`,`g`),`/`),`-P`)}if(e.type===ls.GNU)switch(process.platform){case`win32`:i.push(`--force-local`);break;case`darwin`:i.push(`--delay-directory-restore`)}return i})}function getCommands(e,t){return __awaiter$1(this,arguments,void 0,function*(e,t,n=``){let r,i=yield getTarPath(),a=yield getTarArgs(i,e,t,n),o=t===`create`?yield getCompressionProgram(i,e):yield getDecompressionProgram(i,e,n),s=i.type===ls.BSD&&e!==cs.Gzip&&Mv;return r=s&&t!==`create`?[[...o].join(` `),[...a].join(` `)]:[[...a].join(` `),[...o].join(` `)],{commands:s?r:[r.join(` `)],requiresTempDirectory:s&&t!==`create`}})}function getWorkingDirectory(){return process.env.GITHUB_WORKSPACE??process.cwd()}function quoteAbsolutePath(e){return`"${u.resolve(e).replace(RegExp(`\\${u.sep}`,`g`),`/`)}"`}function getDecompressionProgram(e,t,n){return __awaiter$1(this,void 0,void 0,function*(){let r=e.type===ls.BSD&&t!==cs.Gzip&&Mv;switch(t){case cs.Zstd:return r?[`zstd -d --long=30 --force -o`,ms,quoteAbsolutePath(n)]:[`--use-compress-program`,Mv?`"zstd -d --long=30"`:`unzstd --long=30`];case cs.ZstdWithoutLong:return r?[`zstd -d --force -o`,ms,quoteAbsolutePath(n)]:[`--use-compress-program`,Mv?`"zstd -d"`:`unzstd`];default:return[`-z`]}})}function getCompressionProgram(e,t){return __awaiter$1(this,void 0,void 0,function*(){let n=getCacheFileName(t),r=e.type===ls.BSD&&t!==cs.Gzip&&Mv;switch(t){case cs.Zstd:return r?[`zstd -T0 --long=30 --force -o`,n.replace(RegExp(`\\${u.sep}`,`g`),`/`),ms]:[`--use-compress-program`,Mv?`"zstd -T0 --long=30"`:`zstdmt --long=30`];case cs.ZstdWithoutLong:return r?[`zstd -T0 --force -o`,n.replace(RegExp(`\\${u.sep}`,`g`),`/`),ms]:[`--use-compress-program`,Mv?`"zstd -T0"`:`zstdmt`];default:return[`-z`]}})}function execCommands(e,t){return __awaiter$1(this,void 0,void 0,function*(){for(let n of e)try{yield exec(n,void 0,{cwd:t,env:Object.assign(Object.assign({},process.env),{MSYS:`winsymlinks:nativestrict`})})}catch(e){throw Error(`${n.split(` `)[0]} failed with error: ${e?.message}`)}})}function execReadCommands(e,t,n){return __awaiter$1(this,void 0,void 0,function*(){let{commands:r,requiresTempDirectory:i}=yield getCommands(t,n,e),a=i?yield createTempDirectory():void 0;try{yield execCommands(r,a)}finally{if(a)try{yield rmRF(a)}catch(e){debug(`Failed to delete temporary tar directory: ${e}`)}}})}function listTar(e,t){return __awaiter$1(this,void 0,void 0,function*(){yield execReadCommands(e,t,`list`)})}function extractTar(e,t){return __awaiter$1(this,void 0,void 0,function*(){yield mkdirP(getWorkingDirectory()),yield execReadCommands(e,t,`extract`)})}function createTar(e,t,n){return __awaiter$1(this,void 0,void 0,function*(){l(u.join(e,hs),t.join(` `));let{commands:r}=yield getCommands(n,`create`);yield execCommands(r,e)})}var __awaiter=function(e,t,n,r){function adopt(e){return e instanceof n?e:new n(function(t){t(e)})}return new(n||=Promise)(function(n,i){function fulfilled(e){try{step(r.next(e))}catch(e){i(e)}}function rejected(e){try{step(r.throw(e))}catch(e){i(e)}}function step(e){e.done?n(e.value):adopt(e.value).then(fulfilled,rejected)}step((r=r.apply(e,t||[])).next())})},Nv=class ValidationError extends Error{constructor(e){super(e),this.name=`ValidationError`,Object.setPrototypeOf(this,ValidationError.prototype)}},Pv=class ReserveCacheError extends Error{constructor(e){super(e),this.name=`ReserveCacheError`,Object.setPrototypeOf(this,ReserveCacheError.prototype)}},Fv=class CacheWriteDeniedError extends Pv{constructor(e){super(e),this.name=`CacheWriteDeniedError`,Object.setPrototypeOf(this,CacheWriteDeniedError.prototype)}};const Iv=`cache read denied:`;var Lv=class CacheReadDeniedError extends Error{constructor(e){super(e),this.name=`CacheReadDeniedError`,Object.setPrototypeOf(this,CacheReadDeniedError.prototype)}},Rv=class FinalizeCacheError extends Error{constructor(e){super(e),this.name=`FinalizeCacheError`,Object.setPrototypeOf(this,FinalizeCacheError.prototype)}};function checkPaths(e){if(!e||e.length===0)throw new Nv(`Path Validation Error: At least one directory or file path is required`)}function checkKey(e){if(e.length>512)throw new Nv(`Key Validation Error: ${e} cannot be larger than 512 characters.`);if(!/^[^,]*$/.test(e))throw new Nv(`Key Validation Error: ${e} cannot contain commas.`)}function restoreCache$1(e,t,n,r){return __awaiter(this,arguments,void 0,function*(e,t,n,r,i=!1){let a=getCacheServiceVersion();debug(`Cache service version: ${a}`),checkPaths(e);let o=getCacheMode();if(!isCacheReadable(o)){info(`Cache restore skipped: the effective cache-mode '${o}' does not permit reads.`),debug(`Skipped restore for paths [${e.join(`, `)}] with primary key '${t}'.`);return}switch(a){case`v2`:return yield restoreCacheV2(e,t,n,r,i);default:return yield restoreCacheV1(e,t,n,r,i)}})}function restoreCacheV1(e,t,n,r){return __awaiter(this,arguments,void 0,function*(e,t,n,r,i=!1){n||=[];let a=[t,...n];if(debug(`Resolved Keys:`),debug(JSON.stringify(a)),a.length>10)throw new Nv(`Key Validation Error: Keys are limited to a maximum of 10.`);for(let e of a)checkKey(e);let o=yield getCompressionMethod(),s=``;try{let t;try{t=yield getCacheEntry(a,e,{compressionMethod:o,enableCrossOsArchive:i})}catch(e){let t=e?.message??``;throw t.includes(Iv)?new Lv(t):e}if(!t?.archiveLocation)return;if(r?.lookupOnly)return info(`Lookup only - skipping download`),t.cacheKey;s=u.join(yield createTempDirectory(),getCacheFileName(o)),debug(`Archive Path: ${s}`),yield downloadCache(t.archiveLocation,s,r),isDebug()&&(yield listTar(s,o));let n=getArchiveFileSizeInBytes(s);return info(`Cache Size: ~${Math.round(n/1048576)} MB (${n} B)`),yield extractTar(s,o),info(`Cache restored successfully`),t.cacheKey}catch(e){let t=e;if(t.name===Nv.name)throw e;t instanceof Pn&&typeof t.statusCode==`number`&&t.statusCode>=500?error(`Failed to restore: ${e.message}`):warning(`Failed to restore: ${e.message}`)}finally{try{yield unlinkFile(s)}catch(e){debug(`Failed to delete archive: ${e}`)}}})}function restoreCacheV2(e,t,n,r){return __awaiter(this,arguments,void 0,function*(e,t,n,r,i=!1){r=Object.assign(Object.assign({},r),{useAzureSdk:!0}),n||=[];let a=[t,...n];if(debug(`Resolved Keys:`),debug(JSON.stringify(a)),a.length>10)throw new Nv(`Key Validation Error: Keys are limited to a maximum of 10.`);for(let e of a)checkKey(e);let o=``;try{let s=internalCacheTwirpClient(),c=yield getCompressionMethod(),l={key:t,restoreKeys:n,version:getCacheVersion(e,c,i)},d;try{d=yield s.GetCacheEntryDownloadURL(l)}catch(e){let t=e?.message??``;throw t.includes(Iv)?new Lv(t):e}if(!d.ok){debug(`Cache not found for version ${l.version} of keys: ${a.join(`, `)}`);return}if(l.key===d.matchedKey?info(`Cache hit for: ${d.matchedKey}`):info(`Cache hit for restore-key: ${d.matchedKey}`),r?.lookupOnly)return info(`Lookup only - skipping download`),d.matchedKey;o=u.join(yield createTempDirectory(),getCacheFileName(c)),debug(`Archive path: ${o}`),debug(`Starting download of archive to: ${o}`),yield downloadCache(d.signedDownloadUrl,o,r);let f=getArchiveFileSizeInBytes(o);return info(`Cache Size: ~${Math.round(f/1048576)} MB (${f} B)`),isDebug()&&(yield listTar(o,c)),yield extractTar(o,c),info(`Cache restored successfully`),d.matchedKey}catch(e){let t=e;if(t.name===Nv.name)throw e;t instanceof Pn&&typeof t.statusCode==`number`&&t.statusCode>=500?error(`Failed to restore: ${e.message}`):warning(`Failed to restore: ${e.message}`)}finally{try{o&&(yield unlinkFile(o))}catch(e){debug(`Failed to delete archive: ${e}`)}}})}function saveCache$1(e,t,n){return __awaiter(this,arguments,void 0,function*(e,t,n,r=!1){let i=getCacheServiceVersion();debug(`Cache service version: ${i}`),checkPaths(e),checkKey(t);let a=getCacheMode();if(!isCacheWritable(a))return info(`Cache save skipped: the effective cache-mode '${a}' does not permit writes.`),debug(`Skipped save for paths [${e.join(`, `)}] with key '${t}'.`),-1;switch(i){case`v2`:return yield saveCacheV2(e,t,n,r);default:return yield saveCacheV1(e,t,n,r)}})}function saveCacheV1(e,t,n){return __awaiter(this,arguments,void 0,function*(e,t,n,r=!1){let i=yield getCompressionMethod(),a=-1,o=yield resolvePaths(e);if(debug(`Cache Paths:`),debug(`${JSON.stringify(o)}`),o.length===0)throw Error(`Path Validation Error: Path(s) specified in the action for caching do(es) not exist, hence no cache is being saved.`);let s=yield createTempDirectory(),c=u.join(s,getCacheFileName(i));debug(`Archive Path: ${c}`);try{yield createTar(s,o,i),isDebug()&&(yield listTar(c,i));let l=getArchiveFileSizeInBytes(c);if(debug(`File Size: ${l}`),l>10737418240&&!isGhes())throw Error(`Cache size of ~${Math.round(l/1048576)} MB (${l} B) is over the 10GB limit, not saving cache.`);debug(`Reserving Cache`);let u=yield reserveCache(t,e,{compressionMethod:i,enableCrossOsArchive:r,cacheSize:l});if(u?.result?.cacheId)a=u?.result?.cacheId;else if(u?.statusCode===400)throw Error(u?.error?.message??`Cache size of ~${Math.round(l/1048576)} MB (${l} B) is over the data cap limit, not saving cache.`);else{let e=u?.error?.message;throw e?.startsWith(`cache write denied:`)?new Fv(`Unable to reserve cache with key ${t}. More details: ${e}`):new Pv(`Unable to reserve cache with key ${t}, another job may be creating this cache. More details: ${u?.error?.message}`)}debug(`Saving Cache (ID: ${a})`),yield saveCache$2(a,c,``,n)}catch(e){let t=e;if(t.name===Nv.name)throw e;t.name===Pv.name?info(`Failed to save: ${t.message}`):t instanceof Pn&&typeof t.statusCode==`number`&&t.statusCode>=500?error(`Failed to save: ${t.message}`):warning(`Failed to save: ${t.message}`)}finally{try{yield unlinkFile(c)}catch(e){debug(`Failed to delete archive: ${e}`)}}return a})}function saveCacheV2(e,t,n){return __awaiter(this,arguments,void 0,function*(e,t,n,r=!1){n=Object.assign(Object.assign({},n),{uploadChunkSize:67108864,uploadConcurrency:8,useAzureSdk:!0});let i=yield getCompressionMethod(),a=internalCacheTwirpClient(),o=-1,s=yield resolvePaths(e);if(debug(`Cache Paths:`),debug(`${JSON.stringify(s)}`),s.length===0)throw Error(`Path Validation Error: Path(s) specified in the action for caching do(es) not exist, hence no cache is being saved.`);let c=yield createTempDirectory(),l=u.join(c,getCacheFileName(i));debug(`Archive Path: ${l}`);try{yield createTar(c,s,i),isDebug()&&(yield listTar(l,i));let u=getArchiveFileSizeInBytes(l);debug(`File Size: ${u}`),n.archiveSizeBytes=u,debug(`Reserving Cache`);let d=getCacheVersion(e,i,r),f={key:t,version:d},p;try{let e=yield a.CreateCacheEntry(f);if(!e.ok)throw e.message&&!e.message.startsWith(`cache write denied:`)&&warning(`Cache reservation failed: ${e.message}`),Error(e.message||`Response was not ok`);p=e.signedUploadUrl}catch(e){debug(`Failed to reserve cache: ${e}`);let n=e?.message??``;throw n.startsWith(`cache write denied:`)?new Fv(`Unable to reserve cache with key ${t}. More details: ${n}`):new Pv(`Unable to reserve cache with key ${t}, another job may be creating this cache.`)}debug(`Attempting to upload cache located at: ${l}`),yield saveCache$2(o,l,p,n);let m={key:t,version:d,sizeBytes:`${u}`},h=yield a.FinalizeCacheEntryUpload(m);if(debug(`FinalizeCacheEntryUploadResponse: ${h.ok}`),!h.ok)throw h.message?new Rv(h.message):Error(`Unable to finalize cache with key ${t}, another job may be finalizing this cache.`);o=parseInt(h.entryId)}catch(e){let t=e;if(t.name===Nv.name)throw e;t.name===Pv.name?info(`Failed to save: ${t.message}`):t.name===Rv.name?warning(t.message):t instanceof Pn&&typeof t.statusCode==`number`&&t.statusCode>=500?error(`Failed to save: ${t.message}`):warning(`Failed to save: ${t.message}`)}finally{try{yield unlinkFile(l)}catch(e){debug(`Failed to delete archive: ${e}`)}}return o})}function resolveSfwEnabled(e,t,n){return e?!pkgPrNewCommitSha(t)||(n(`sfw was requested but is automatically disabled for Vite+ preview build ${t}; Socket Firewall Free will not be used.`),!1):!1}const zv=`v1.15.4`,Bv=`https://github.com/SocketDev/sfw-free/releases/download/${zv}`;function isMuslLinux(){if(process.platform!==`linux`)return!1;try{let e=process.report?.getReport();if(e?.header&&!e.header.glibcVersionRuntime)return!0}catch{}return F(`/etc/alpine-release`)}function getSfwAssetName(e,t,n){if(e===`darwin`){if(t===`arm64`)return`sfw-free-macos-arm64`;if(t===`x64`)return`sfw-free-macos-x86_64`}else if(e===`linux`){if(t===`arm64`)return n?`sfw-free-musl-linux-arm64`:`sfw-free-linux-arm64`;if(t===`x64`)return n?`sfw-free-musl-linux-x86_64`:`sfw-free-linux-x86_64`}else if(isWindows(e)){if(t===`arm64`)return`sfw-free-windows-arm64.exe`;if(t===`x64`)return`sfw-free-windows-x86_64.exe`}throw Error(`Unsupported platform/arch for sfw: ${e}/${t}${e===`linux`?` (${n?`musl`:`glibc`})`:``}`)}const Vv=2e3;function isSfwSupported(e=process.platform,t=process.arch,n=isMuslLinux()){try{return!!getSfwAssetName(e,t,n)}catch{return!1}}function getSfwBinDir(){let e=process.env.RUNNER_TEMP||process.env.TMPDIR||process.env.TEMP||`/tmp`;return P(e,`sfw-bin`)}async function installSfw(){let e=getSfwAssetName(process.platform,process.arch,isMuslLinux()),t=`${Bv}/${e}`,n=getSfwBinDir();fe(n,{recursive:!0});let r=P(n,isWindows()?`sfw.exe`:`sfw`),i=`sfw-${zv}-${process.platform}-${process.arch}-${isMuslLinux()?`musl`:`glibc`}`;try{let e=await restoreCache$1([n],i);if(e&&F(r)){isWindows()||ue(r,493),addPath(n),info(`sfw restored from cache: ${e}`);return}}catch(e){warning(`sfw cache restore failed (${e instanceof Error?e.message:String(e)}); falling through to download.`)}info(`Installing sfw from ${t}...`);let a=``;for(let e=1;e<=2;e++){try{let e=await runDownloadCommand(t,r);if(e===0&&F(r)){isWindows()||ue(r,493),addPath(n),info(`sfw installed at ${r}`);try{await saveCache$1([n],i),info(`sfw cached under key: ${i}`)}catch(e){warning(`sfw cache save failed (${e instanceof Error?e.message:String(e)}); continuing.`)}return}a=`exit code ${e}`}catch(e){a=e instanceof Error?e.message:String(e)}e<2&&(warning(`Failed to install sfw from ${t} (${a}). Retrying in ${Vv}ms... (attempt ${e+1}/2)`),await se(Vv))}throw Error(`Failed to install sfw from ${t} after 2 attempts: ${a}`)}function findSfwOnPath(){let e=isWindows()?`where`:`which`;try{let t=we(e,[`sfw`],{encoding:`utf8`,stdio:[`ignore`,`pipe`,`ignore`]}).split(/\r?\n/).find(e=>e.trim().length>0);return t?t.trim():null}catch{return null}}async function setupSfw(e){if(!resolveSfwEnabled(e.sfw,e.version,warning))return!1;if(e.runInstall.length===0)return info("sfw was requested but `run-install` is disabled; sfw will not be invoked."),!1;let t=findSfwOnPath();return t?(info(`Using existing sfw on PATH: ${t}`),!0):isSfwSupported()?(await installSfw(),!0):(warning(`sfw has no published binary for this runner's platform/architecture (${`process.platform=${process.platform}, process.arch=${process.arch}, musl=${isMuslLinux()}`}) and none was found on PATH; falling back to plain \`vp install\`. To enable sfw here, install a working sfw binary on PATH in an earlier step (e.g. via \`socketdev/action@\` or a custom install).`),!1)}async function runDownloadCommand(e,t){let n={ignoreReturnCode:!0};return isWindows()?exec(`pwsh`,[`-Command`,`Invoke-WebRequest -UseBasicParsing -Uri '${e}' -OutFile '${t}' -TimeoutSec 60`],n):exec(`bash`,[`-c`,`set -o pipefail; curl -fsSL --connect-timeout 5 --max-time 60 -o '${t}' '${e}'`],n)}const Hv=/Command 'vp' not found in PATH/;function isSfwVpNotFoundFlake(e,t){return Hv.test(t)||Hv.test(e)}async function warmPowerShellCommandCache(){if(isWindows())try{await getExecOutput(`powershell.exe`,[`-NoProfile`,`-Command`,`Get-Command vp`],{ignoreReturnCode:!0})}catch(e){info(`PowerShell warm-up failed (${String(e)}); retrying sfw anyway.`)}}function tailOutput(e,t){let n=e.trim();return n.length<=t?n:`…(truncated, showing last ${t} chars)…\n${n.slice(-t)}`}async function runViteInstall(e){let t=getConfiguredProjectDir(e);for(let n of e.runInstall){let r=[`install`];n.args&&r.push(...n.args);let i=e.sfw?`sfw`:`vp`,a=e.sfw?[`vp`,...r]:r,o=getInstallCwd(t,n.cwd),s=`${i} ${a.join(` `)}`,attempt=async e=>{startGroup(`Running ${e} in ${o}...`);try{return await getExecOutput(i,a,{cwd:o,ignoreReturnCode:!0})}finally{endGroup()}};try{let t=await attempt(s);if(t.exitCode!==0&&e.sfw&&isSfwVpNotFoundFlake(t.stdout,t.stderr)&&(warning(`sfw reported vp as not found even though it is on PATH. This is a known sfw flake on Windows: a cold PowerShell start exceeds sfw's 10s command-resolution timeout and the timeout is misreported as not-found. Warming the PowerShell command cache and retrying once.`),await warmPowerShellCommandCache(),t=await attempt(`${s} (retry)`)),t.exitCode===0){info(`Successfully ran ${s}`);continue}let n=t.stderr.trim()||t.stdout.trim();n&&error(tailOutput(n,4e3),{title:`${s} failed`}),setFailed(`Command "${s}" (cwd: ${o}) exited with code ${t.exitCode}`)}catch(e){setFailed(`Failed to run ${s}: ${String(e)}`)}}}async function restoreCache(e){let t=getConfiguredProjectDir(e),n=detectLockFile$1(e.cacheDependencyPath,t);if(!n){warning(e.cacheDependencyPath?`No lock file found for cache-dependency-path: ${e.cacheDependencyPath}. Skipping cache restore.`:`No lock file found in project directory: ${t}. Skipping cache restore.`),setOutput(`cache-hit`,!1);return}info(`Using lock file: ${n.path}`);let r=ne(n.path);info(`Resolving dependency cache directory in: ${r}`);let i=await getCacheDirectories(n.type,r);if(!i.length){warning(`No cache directories found for ${n.type} in ${r}. Skipping cache restore.`),setOutput(`cache-hit`,!1);return}debug(`Cache paths: ${i.join(`, `)}`),saveState(`CACHE_PATHS`,JSON.stringify(i));let a=process.env.RUNNER_OS||Se(),o=be(),s=await hashFiles(n.path);if(!s)throw Error(`Failed to generate hash for lock file: ${n.path}`);let c=`vite-plus-${a}-${o}-${n.type}-${s}`,l=[`vite-plus-${a}-${o}-${n.type}-`,`vite-plus-${a}-${o}-`];debug(`Primary key: ${c}`),debug(`Restore keys: ${l.join(`, `)}`),saveState(`CACHE_PRIMARY_KEY`,c);let u=await restoreCache$1(i,c,l);u?(info(`Cache restored from key: ${u}`),saveState(`CACHE_MATCHED_KEY`,u),setOutput(`cache-hit`,!0)):(info(`Cache not found`),setOutput(`cache-hit`,!1))}async function saveCache(){let e=getState(`CACHE_PRIMARY_KEY`),t=getState(`CACHE_MATCHED_KEY`),n=getState(`CACHE_PATHS`);if(!e){info(`No cache key found. Skipping cache save.`);return}if(!n){info(`No cache paths found. Skipping cache save.`);return}if(e===t){info(`Cache hit on primary key "${e}". Skipping save.`);return}let r=JSON.parse(n);if(!r.length){info(`Empty cache paths. Skipping cache save.`);return}try{if(await saveCache$1(r,e)===-1){info(`Cache not saved (key already reserved by a concurrent job, or save was skipped).`);return}info(`Cache saved with key: ${e}`)}catch(e){warning(`Failed to save cache: ${String(e)}`)}}function resolvePath$1(e,t){return M.isAbsolute(e)?e:M.join(t,e)}function isWithin(e,t){let n=M.relative(t,e);return!M.isAbsolute(n)&&n!==`..`&&!n.startsWith(`..${M.sep}`)}function createNodeVersionResolver(e){let{getWorkspaceDir:t,info:n}=e;function resolveNodeVersionFile(e,r){let i=resolvePath$1(e,r||t()),a;try{a=pe(i,`utf-8`)}catch{throw Error(`node-version-file not found: ${i}`)}let o=te(i),s;if(s=o===`.tool-versions`?parseToolVersions(a):o===`package.json`?parsePackageJson(a):parsePlainVersionFile(a),!s)throw Error(`No Node.js version found in ${e}`);return s=s.replace(/^v/i,``),n(`Resolved Node.js version '${s}' from ${e}`),s}function parsePlainVersionFile(e){for(let t of e.split(` `)){let e=(t.includes(`#`)?t.slice(0,t.indexOf(`#`)):t).trim();if(e)return normalizeNvmAlias(e)}}function normalizeNvmAlias(e){let t=e.toLowerCase();return t===`node`||t===`stable`?`latest`:e}function parseToolVersions(e){for(let t of e.split(` -`)){let e=t.trim();if(!e||e.startsWith(`#`))continue;let[n,...r]=e.split(/\s+/);if(n===`nodejs`||n===`node`){for(let e of r)if(isAsdfInstallableVersion(e))return e}}}function isAsdfInstallableVersion(e){return!!e&&e!==`system`&&!e.startsWith(`ref:`)&&!e.startsWith(`path:`)}function parsePackageJson(e){let t;try{t=JSON.parse(e)}catch{throw Error(`Failed to parse package.json: invalid JSON`)}let n=t.devEngines;if(n?.runtime){let e=findNodeRuntime(n.runtime);if(e)return e}let r=t.engines;if(r?.node&&typeof r.node==`string`)return r.node}function findNodeRuntime(e){let t=Array.isArray(e)?e:[e];for(let e of t)if(e?.name===`node`&&typeof e.version==`string`)return e.version}return{resolveNodeVersionFile}}const{resolveNodeVersionFile:Uv}=createNodeVersionResolver({getWorkspaceDir,info}),Wv=[{filename:`pnpm-lock.yaml`,type:`pnpm`},{filename:`bun.lockb`,type:`bun`},{filename:`bun.lock`,type:`bun`},{filename:`package-lock.json`,type:`npm`},{filename:`npm-shrinkwrap.json`,type:`npm`},{filename:`yarn.lock`,type:`yarn`}];function resolvePath(e,t){return re(e)?e:P(t,e)}function inferLockFileType(e,t){return t.includes(`pnpm`)?{type:`pnpm`,path:e,filename:t}:t.includes(`yarn`)?{type:`yarn`,path:e,filename:t}:t.startsWith(`bun.`)?{type:`bun`,path:e,filename:t}:{type:`npm`,path:e,filename:t}}function detectLockFile(e,t){if(e){let n=resolvePath(e,t);if(F(n)){let e=te(n),t=Wv.find(t=>t.filename===e);return t?{type:t.type,path:n,filename:e}:inferLockFileType(n,e)}return}let n=me(t);for(let e of Wv)if(n.includes(e.filename)){let n=P(t,e.filename);return{type:e.type,path:n,filename:e.filename}}}function createLockfileResolver(e){let{getWorkspaceDir:t,info:n,debug:r}=e,i=/^\d+\.\d+\.\d+/;function tryResolveVitePlusVersionFromLockfile(e,t){let i=detectLockfileForProject(e,t);if(!i)return;let a=i.filename.endsWith(`.lockb`)?textBunLockBeside(i):i;if(!a){r(`Cannot read ${i.filename} (binary) to resolve the ${aa} version; using "latest". Use the text bun.lock, or set the \`version\` input.`);return}let o=parseVitePlusVersionFromLockfile(a,workspaceSubPath(ne(a.path),e));if(o)return n(`Resolved ${aa} version '${o}' from ${a.filename}`),o;r(`No ${aa} version found in ${a.path}`)}function detectLockfileForProject(e,n){if(n)return detectLockFile(n,e);let r=t(),i=e;for(;;){let e=detectLockFile(void 0,i);if(e)return e;let t=ne(i);if(i===r||t===i||!isWithin(t,r))break;i=t}}function textBunLockBeside(e){let t=P(ne(e.path),`bun.lock`);return F(t)?{type:`bun`,path:t,filename:`bun.lock`}:void 0}function workspaceSubPath(e,t){if(!isWithin(t,e))return``;let n=ie(e,t);return n?n.split(oe).join(`/`):``}function parseVitePlusVersionFromLockfile(e,t=``){if(e.filename.endsWith(`.lockb`))return;let n;try{n=pe(e.path,`utf-8`)}catch{return}let r;switch(e.type){case`npm`:r=fromNpmLock(n,t);break;case`pnpm`:r=fromPnpmLock(n,t);break;case`yarn`:r=fromYarnLock(n);break;case`bun`:r=fromBunTextLock(n);break;default:return}return r&&i.test(r)?r:void 0}function fromNpmLock(e,t){let n;try{n=JSON.parse(e)}catch{return}let r=n.packages;if(t){let e=r?.[`${t}/node_modules/${oa}`]?.version;if(typeof e==`string`)return e;if(!npmPackageDeclaresVitePlus(r?.[t]))return}let i=r?.[`node_modules/${oa}`]?.version;if(typeof i==`string`)return i;let a=n.dependencies?.[oa]?.version;return typeof a==`string`?a:void 0}function npmPackageDeclaresVitePlus(e){if(!e)return!1;for(let t of[`dependencies`,`devDependencies`]){let n=e[t];if(n&&typeof n==`object`&&`vite-plus`in n)return!0}return!1}function fromPnpmLock(e,t){let n;try{n=(0,_i.parse)(e)}catch{return}if(!n||typeof n!=`object`)return;let r=n,i=r.importers;if(i&&typeof i==`object`){let e=t||`.`;return e in i?pnpmImporterVersion(i[e]):void 0}return pnpmImporterVersion(r)||e.match(/^\s*\/?vite-plus@(\d+\.\d+\.\d+[^\s():'"]*)/m)?.[1]}function pnpmImporterVersion(e){if(!e||typeof e!=`object`)return;let t=e;for(let e of[`dependencies`,`devDependencies`,`optionalDependencies`]){let n=t[e];if(n&&typeof n==`object`){let e=n[oa],t=typeof e==`string`?e:e?.version;if(typeof t==`string`){let e=t.replace(/\(.*$/,``).trim();if(i.test(e))return e}}}}function fromYarnLock(e){let t=/* @__PURE__ */ new Set,n=e.split(/\r?\n/);for(let e=0;e!n.has(authKeyFor$1(e))),envVarRefs:r}}function getRunnerNpmrcPath(){return ae(process.env.RUNNER_TEMP||process.cwd(),`.npmrc`)}function stripProtocol(e){return e.replace(/^\w+:/,``)}function authKeyFor(e){return(stripProtocol(e)+`:_authtoken`).toLowerCase()}function buildAuthLine(e){return`${stripProtocol(e)}:_authToken=\${NODE_AUTH_TOKEN}`}function readNpmrc(e){try{return pe(e,`utf8`)}catch(e){if(e.code===`ENOENT`)return;throw e}}function configAuthentication(e,t){let n;try{n=new URL(e)}catch{throw Error(`Invalid registry-url: "${e}". Must be a valid URL.`)}writeRegistryToFile(n.href.endsWith(`/`)?n.href:n.href+`/`,getRunnerNpmrcPath(),t)}function writeRegistryToFile(e,t,n){n||new URL(e).hostname===`npm.pkg.github.com`&&(n=process.env.GITHUB_REPOSITORY_OWNER);let r=``;n&&(r=(n.startsWith(`@`)?n:`@`+n).toLowerCase()+`:`),debug(`Setting auth in ${t}`);let i=stripProtocol(e).toLowerCase(),a=[],o=readNpmrc(t);if(o!==void 0)for(let e of o.split(/\r?\n/)){let t=e.toLowerCase();t.startsWith(`${r}registry`)||t.startsWith(i)&&t.includes(`_authtoken`)||a.push(e)}a.push(buildAuthLine(e),`${r}registry=${e}`),_e(t,a.join(ye)),exportVariable(`NPM_CONFIG_USERCONFIG`,t),exportVariable(`PNPM_CONFIG_USERCONFIG`,t),exportVariable(`NODE_AUTH_TOKEN`,process.env.NODE_AUTH_TOKEN||`XXXXX-XXXXX-XXXXX-XXXXX`)}const Yv=/* @__PURE__ */ new Set([`GITHUB_TOKEN`]),Xv=/* @__PURE__ */ new Set([`PATH`,`HOME`,`USERPROFILE`,`TMPDIR`,`CI`]);function isReservedEnvVar(e){return Xv.has(e)||e.startsWith(`RUNNER_`)?!0:e.startsWith(`GITHUB_`)?!Yv.has(e):!1}function writeSupplementalAuth(e){let t=getRunnerNpmrcPath(),n=new Set(e.map(authKeyFor)),r=readNpmrc(t),i=[...(r===void 0?[]:r.split(/\r?\n/)).filter(e=>{let t=e.indexOf(`=`);return t<=0||!n.has(e.slice(0,t).trim().toLowerCase())}),...e.map(buildAuthLine)].join(ye);if(exportVariable(`NPM_CONFIG_USERCONFIG`,t),exportVariable(`PNPM_CONFIG_USERCONFIG`,t),r===i){debug(`Supplemental .npmrc at ${t} already current`);return}_e(t,i),info(`Wrote _authToken entries to ${t} for registries: ${e.join(`, `)}`)}function propagateProjectNpmrcAuth(e){let t=P(e,`.npmrc`),n=readNpmrc(t);if(n===void 0)return;let{registriesNeedingAuth:r,envVarRefs:i}=analyzeProjectNpmrc(n);process.env.NODE_AUTH_TOKEN&&r.length>0&&(writeSupplementalAuth(r),i.add(`NODE_AUTH_TOKEN`));let a=[...i].filter(e=>!isReservedEnvVar(e)&&!!process.env[e]);if(a.length===0){debug(`Project .npmrc at ${t}: no auth env vars to propagate`);return}info(`Detected project .npmrc at ${t}. Propagating auth env vars: ${a.join(`, `)}`);for(let e of a)exportVariable(e,process.env[e])}async function runMain(e){saveState(`IS_POST`,`true`);let t=getConfiguredProjectDir(e),n=e.nodeVersion;!n&&e.nodeVersionFile&&(n=Uv(e.nodeVersionFile,t));let r=Gv(e,t);await installVitePlus({...e,version:r});let i=e.nodeManager===!1||e.packageManager!==void 0?(await getExecOutput(`vp`,[`--version`],{silent:!0})).stdout:``,a=packageManagerArgs(e.packageManager,i);e.nodeManager===!1?(info(`Disabling Vite+ Node.js version management...`),await exec(`vp`,nodeManagerOffArgs(i))):n&&(info(`Setting up Node.js ${n} via vp env use...`),await exec(`vp`,[`env`,`use`,n]));for(let e of a)await exec(`vp`,e);e.registryUrl?configAuthentication(e.registryUrl,e.scope):propagateProjectNpmrcAuth(t),e.cache&&await restoreCache(e);let o=await setupSfw({...e,version:r});e.runInstall.length>0&&await runViteInstall({...e,sfw:o}),await printViteVersion(t)}async function printViteVersion(e){try{let t=(await getExecOutput(`vp`,[`--version`],{cwd:e,silent:!0})).stdout.trim();info(t);let n=parseInstalledVpVersion(t);saveState(`INSTALLED_VERSION`,n),setOutput(`version`,n)}catch(e){warning(`Could not get vp version: ${String(e)}`),setOutput(`version`,`unknown`)}}async function runPost(e){if(e.cache){if(!e.cacheSave){info(`Cache saving is disabled. Skipping cache save.`);return}await saveCache()}}async function main(){let e=getInputs();getState(`IS_POST`)===`true`?await runPost(e):await runMain(e)}main().catch(e=>{console.error(e),setFailed(e instanceof Error?e.message:String(e))});export{runMain,runPost}; \ No newline at end of file +`)){let e=t.trim();if(!e||e.startsWith(`#`))continue;let[n,...r]=e.split(/\s+/);if(n===`nodejs`||n===`node`){for(let e of r)if(isAsdfInstallableVersion(e))return e}}}function isAsdfInstallableVersion(e){return!!e&&e!==`system`&&!e.startsWith(`ref:`)&&!e.startsWith(`path:`)}function parsePackageJson(e){let t;try{t=JSON.parse(e)}catch{throw Error(`Failed to parse package.json: invalid JSON`)}let n=t.devEngines;if(n?.runtime){let e=findNodeRuntime(n.runtime);if(e)return e}let r=t.engines;if(r?.node&&typeof r.node==`string`)return r.node}function findNodeRuntime(e){let t=Array.isArray(e)?e:[e];for(let e of t)if(e?.name===`node`&&typeof e.version==`string`)return e.version}return{resolveNodeVersionFile}}const{resolveNodeVersionFile:Uv}=createNodeVersionResolver({getWorkspaceDir,info}),Wv=[{filename:`pnpm-lock.yaml`,type:`pnpm`},{filename:`bun.lockb`,type:`bun`},{filename:`bun.lock`,type:`bun`},{filename:`package-lock.json`,type:`npm`},{filename:`npm-shrinkwrap.json`,type:`npm`},{filename:`yarn.lock`,type:`yarn`}];function resolvePath(e,t){return re(e)?e:P(t,e)}function inferLockFileType(e,t){return t.includes(`pnpm`)?{type:`pnpm`,path:e,filename:t}:t.includes(`yarn`)?{type:`yarn`,path:e,filename:t}:t.startsWith(`bun.`)?{type:`bun`,path:e,filename:t}:{type:`npm`,path:e,filename:t}}function detectLockFile(e,t){if(e){let n=resolvePath(e,t);if(F(n)){let e=te(n),t=Wv.find(t=>t.filename===e);return t?{type:t.type,path:n,filename:e}:inferLockFileType(n,e)}return}let n=me(t);for(let e of Wv)if(n.includes(e.filename)){let n=P(t,e.filename);return{type:e.type,path:n,filename:e.filename}}}function createLockfileResolver(e){let{getWorkspaceDir:t,info:n,debug:r}=e,i=/^\d+\.\d+\.\d+/;function tryResolveVitePlusVersionFromLockfile(e,t){let i=detectLockfileForProject(e,t);if(!i)return;let a=i.filename.endsWith(`.lockb`)?textBunLockBeside(i):i;if(!a){r(`Cannot read ${i.filename} (binary) to resolve the ${aa} version; using "latest". Use the text bun.lock, or set the \`version\` input.`);return}let o=parseVitePlusVersionFromLockfile(a,workspaceSubPath(ne(a.path),e));if(o)return n(`Resolved ${aa} version '${o}' from ${a.filename}`),o;r(`No ${aa} version found in ${a.path}`)}function detectLockfileForProject(e,n){if(n)return detectLockFile(n,e);let r=t(),i=e;for(;;){let e=detectLockFile(void 0,i);if(e)return e;let t=ne(i);if(i===r||t===i||!isWithin(t,r))break;i=t}}function textBunLockBeside(e){let t=P(ne(e.path),`bun.lock`);return F(t)?{type:`bun`,path:t,filename:`bun.lock`}:void 0}function workspaceSubPath(e,t){if(!isWithin(t,e))return``;let n=ie(e,t);return n?n.split(oe).join(`/`):``}function parseVitePlusVersionFromLockfile(e,t=``){if(e.filename.endsWith(`.lockb`))return;let n;try{n=pe(e.path,`utf-8`)}catch{return}let r;switch(e.type){case`npm`:r=fromNpmLock(n,t);break;case`pnpm`:r=fromPnpmLock(n,t);break;case`yarn`:r=fromYarnLock(n);break;case`bun`:r=fromBunTextLock(n);break;default:return}return r&&i.test(r)?r:void 0}function fromNpmLock(e,t){let n;try{n=JSON.parse(e)}catch{return}let r=n.packages;if(t){let e=r?.[`${t}/node_modules/${oa}`]?.version;if(typeof e==`string`)return e;if(!npmPackageDeclaresVitePlus(r?.[t]))return}let i=r?.[`node_modules/${oa}`]?.version;if(typeof i==`string`)return i;let a=n.dependencies?.[oa]?.version;return typeof a==`string`?a:void 0}function npmPackageDeclaresVitePlus(e){if(!e)return!1;for(let t of[`dependencies`,`devDependencies`]){let n=e[t];if(n&&typeof n==`object`&&`vite-plus`in n)return!0}return!1}function fromPnpmLock(e,t){let n;try{n=(0,_i.parse)(e)}catch{return}if(!n||typeof n!=`object`)return;let r=n,i=r.importers;if(i&&typeof i==`object`){let e=t||`.`;return e in i?pnpmImporterVersion(i[e]):void 0}return pnpmImporterVersion(r)||e.match(/^\s*\/?vite-plus@(\d+\.\d+\.\d+[^\s():'"]*)/m)?.[1]}function pnpmImporterVersion(e){if(!e||typeof e!=`object`)return;let t=e;for(let e of[`dependencies`,`devDependencies`,`optionalDependencies`]){let n=t[e];if(n&&typeof n==`object`){let e=n[oa],t=typeof e==`string`?e:e?.version;if(typeof t==`string`){let e=t.replace(/\(.*$/,``).trim();if(i.test(e))return e}}}}function fromYarnLock(e){let t=/* @__PURE__ */ new Set,n=e.split(/\r?\n/);for(let e=0;e!isReservedEnvVar(e)&&!!process.env[e]);if(i.length===0){debug(`Project .npmrc at ${t}: no auth env vars to propagate`);return}info(`Detected project .npmrc at ${t}. Propagating auth env vars: ${i.join(`, `)}`);for(let e of i)exportVariable(e,process.env[e])}async function runMain(e){saveState(`IS_POST`,`true`);let t=getConfiguredProjectDir(e),n=e.nodeVersion;!n&&e.nodeVersionFile&&(n=Uv(e.nodeVersionFile,t));let r=Gv(e,t);await installVitePlus({...e,version:r});let i=e.nodeManager===!1||e.packageManager!==void 0?(await getExecOutput(`vp`,[`--version`],{silent:!0})).stdout:``,a=packageManagerArgs(e.packageManager,i);e.nodeManager===!1?(info(`Disabling Vite+ Node.js version management...`),await exec(`vp`,nodeManagerOffArgs(i))):n&&(info(`Setting up Node.js ${n} via vp env use...`),await exec(`vp`,[`env`,`use`,n]));for(let e of a)await exec(`vp`,e);e.registryUrl?configAuthentication(e.registryUrl,e.scope):propagateProjectNpmrcAuth(t),e.cache&&await restoreCache(e);let o=await setupSfw({...e,version:r});e.runInstall.length>0&&await runViteInstall({...e,sfw:o}),await printViteVersion(t)}async function printViteVersion(e){try{let t=(await getExecOutput(`vp`,[`--version`],{cwd:e,silent:!0})).stdout.trim();info(t);let n=parseInstalledVpVersion(t);saveState(`INSTALLED_VERSION`,n),setOutput(`version`,n)}catch(e){warning(`Could not get vp version: ${String(e)}`),setOutput(`version`,`unknown`)}}async function runPost(e){if(e.cache){if(!e.cacheSave){info(`Cache saving is disabled. Skipping cache save.`);return}await saveCache()}}async function main(){let e=getInputs();getState(`IS_POST`)===`true`?await runPost(e):await runMain(e)}main().catch(e=>{console.error(e),setFailed(e instanceof Error?e.message:String(e))});export{runMain,runPost}; \ No newline at end of file diff --git a/src/auth.test.ts b/src/auth.test.ts index 75d6b37..cb96948 100644 --- a/src/auth.test.ts +++ b/src/auth.test.ts @@ -315,36 +315,24 @@ describe("propagateProjectNpmrcAuth", () => { expect(() => propagateProjectNpmrcAuth(projectDir)).toThrow("EACCES"); }); - it("auto-writes _authToken for a scoped registry when NODE_AUTH_TOKEN is set", () => { - mockNpmrc("@myorg:registry=https://npm.pkg.github.com"); - vi.stubEnv("NODE_AUTH_TOKEN", "ghp_xxx"); - - propagateProjectNpmrcAuth(projectDir); - - expect(writeFileSync).toHaveBeenCalledWith( - supplementalPath, - expect.stringContaining("//npm.pkg.github.com/:_authToken=${NODE_AUTH_TOKEN}"), - ); - expect(exportVariable).toHaveBeenCalledWith("NPM_CONFIG_USERCONFIG", supplementalPath); - expect(exportVariable).toHaveBeenCalledWith("PNPM_CONFIG_USERCONFIG", supplementalPath); - expect(exportVariable).toHaveBeenCalledWith("NODE_AUTH_TOKEN", "ghp_xxx"); - }); - - it("auto-writes _authToken for the default registry", () => { - mockNpmrc("registry=https://registry.example.com"); - vi.stubEnv("NODE_AUTH_TOKEN", "tok"); + it.each([ + "registry=https://attacker.invalid/", + "@scope:registry=https://attacker.invalid/npm/", + "registry=https://registry.npmjs.org/\n@scope:registry=https://attacker.invalid/", + ])("does not add auth for repository-controlled registries: %s", (content) => { + mockNpmrc(content); + vi.stubEnv("NODE_AUTH_TOKEN", "secret"); propagateProjectNpmrcAuth(projectDir); - expect(writeFileSync).toHaveBeenCalledWith( - supplementalPath, - expect.stringContaining("//registry.example.com/:_authToken=${NODE_AUTH_TOKEN}"), - ); + expect(writeFileSync).not.toHaveBeenCalled(); + expect(exportVariable).not.toHaveBeenCalled(); }); - it("does not overwrite existing _authToken entries in the project .npmrc", () => { + it("preserves explicit auth without adding tokens for other project registries", () => { mockNpmrc( [ + "registry=https://attacker.invalid/", "@myorg:registry=https://npm.pkg.github.com", "//npm.pkg.github.com/:_authToken=${GITHUB_TOKEN}", ].join("\n"), @@ -355,7 +343,7 @@ describe("propagateProjectNpmrcAuth", () => { propagateProjectNpmrcAuth(projectDir); expect(writeFileSync).not.toHaveBeenCalled(); - expect(exportVariable).toHaveBeenCalledWith("GITHUB_TOKEN", "gh-token"); + expect(exportVariable).toHaveBeenCalledExactlyOnceWith("GITHUB_TOKEN", "gh-token"); }); it("does not write supplemental .npmrc when NODE_AUTH_TOKEN is not set", () => { @@ -368,63 +356,21 @@ describe("propagateProjectNpmrcAuth", () => { expect(exportVariable).not.toHaveBeenCalledWith("PNPM_CONFIG_USERCONFIG", expect.anything()); }); - it("writes _authToken for multiple missing registries", () => { + it("leaves the runner user config unchanged for project registries", () => { mockNpmrc( - ["@a:registry=https://one.example.com", "@b:registry=https://two.example.com"].join("\n"), + "@scope:registry=https://attacker.invalid/", + "strict-ssl=true\n//trusted.example/:_authToken=${CUSTOM_TOKEN}", ); - vi.stubEnv("NODE_AUTH_TOKEN", "tok"); - - propagateProjectNpmrcAuth(projectDir); - - const written = vi.mocked(writeFileSync).mock.calls[0]![1] as string; - expect(written).toContain("//one.example.com/:_authToken=${NODE_AUTH_TOKEN}"); - expect(written).toContain("//two.example.com/:_authToken=${NODE_AUTH_TOKEN}"); - }); - - it("preserves unrelated lines already in RUNNER_TEMP/.npmrc", () => { - mockNpmrc( - "@myorg:registry=https://npm.pkg.github.com", - "always-auth=true\n//other.example.com/:_authToken=preserved", - ); - vi.stubEnv("NODE_AUTH_TOKEN", "tok"); - - propagateProjectNpmrcAuth(projectDir); - - const written = vi.mocked(writeFileSync).mock.calls[0]![1] as string; - expect(written).toContain("always-auth=true"); - expect(written).toContain("//other.example.com/:_authToken=preserved"); - expect(written).toContain("//npm.pkg.github.com/:_authToken=${NODE_AUTH_TOKEN}"); - }); - - it("replaces stale _authToken for the same registry in RUNNER_TEMP/.npmrc", () => { - mockNpmrc( - "@myorg:registry=https://npm.pkg.github.com", - "//npm.pkg.github.com/:_authToken=old-value", - ); - vi.stubEnv("NODE_AUTH_TOKEN", "tok"); - - propagateProjectNpmrcAuth(projectDir); - - const written = vi.mocked(writeFileSync).mock.calls[0]![1] as string; - expect(written).not.toContain("old-value"); - expect(written).toContain("//npm.pkg.github.com/:_authToken=${NODE_AUTH_TOKEN}"); - }); - - it("skips the write on re-run when RUNNER_TEMP/.npmrc already matches", () => { - mockNpmrc( - "@myorg:registry=https://npm.pkg.github.com", - `//npm.pkg.github.com/:_authToken=\${NODE_AUTH_TOKEN}`, - ); - vi.stubEnv("NODE_AUTH_TOKEN", "tok"); + vi.stubEnv("NODE_AUTH_TOKEN", "secret"); propagateProjectNpmrcAuth(projectDir); expect(writeFileSync).not.toHaveBeenCalled(); - expect(exportVariable).toHaveBeenCalledWith("NPM_CONFIG_USERCONFIG", supplementalPath); - expect(exportVariable).toHaveBeenCalledWith("PNPM_CONFIG_USERCONFIG", supplementalPath); + expect(exportVariable).not.toHaveBeenCalled(); + expect(readFileSync).toHaveBeenCalledExactlyOnceWith(npmrcPath, "utf8"); }); - it("skips registries whose value contains ${VAR} (cannot synthesize a valid auth key)", () => { + it("propagates environment references in registry values without adding auth", () => { mockNpmrc("@myorg:registry=${CUSTOM_REGISTRY}"); vi.stubEnv("NODE_AUTH_TOKEN", "tok"); vi.stubEnv("CUSTOM_REGISTRY", "https://npm.example.com"); @@ -435,7 +381,7 @@ describe("propagateProjectNpmrcAuth", () => { expect(exportVariable).toHaveBeenCalledWith("CUSTOM_REGISTRY", "https://npm.example.com"); }); - it("treats _authToken key case-insensitively when checking project .npmrc", () => { + it("propagates token references from uppercase auth keys without adding auth", () => { mockNpmrc( [ "@myorg:registry=https://npm.pkg.github.com", @@ -447,5 +393,6 @@ describe("propagateProjectNpmrcAuth", () => { propagateProjectNpmrcAuth(projectDir); expect(writeFileSync).not.toHaveBeenCalled(); + expect(exportVariable).toHaveBeenCalledExactlyOnceWith("NODE_AUTH_TOKEN", "tok"); }); }); diff --git a/src/auth.ts b/src/auth.ts index 3f44fb6..cd26713 100644 --- a/src/auth.ts +++ b/src/auth.ts @@ -15,10 +15,6 @@ function stripProtocol(url: string): string { return url.replace(/^\w+:/, ""); } -function authKeyFor(registryUrl: string): string { - return (stripProtocol(registryUrl) + ":_authtoken").toLowerCase(); -} - function buildAuthLine(registryUrl: string): string { return `${stripProtocol(registryUrl)}:_authToken=${NODE_AUTH_TOKEN_REF}`; } @@ -101,55 +97,19 @@ function isReservedEnvVar(name: string): boolean { return false; } -function writeSupplementalAuth(registries: string[]): void { - const npmrcPath = getRunnerNpmrcPath(); - const authKeysToReplace = new Set(registries.map(authKeyFor)); - - const existing = readNpmrc(npmrcPath); - const existingLines = existing === undefined ? [] : existing.split(/\r?\n/); - - const keepLines = existingLines.filter((line) => { - const eq = line.indexOf("="); - if (eq <= 0) return true; - return !authKeysToReplace.has(line.slice(0, eq).trim().toLowerCase()); - }); - - const nextContent = [...keepLines, ...registries.map(buildAuthLine)].join(EOL); - exportVariable("NPM_CONFIG_USERCONFIG", npmrcPath); - exportVariable("PNPM_CONFIG_USERCONFIG", npmrcPath); // For pnpm 11+ - - if (existing === nextContent) { - debug(`Supplemental .npmrc at ${npmrcPath} already current`); - return; - } - - writeFileSync(npmrcPath, nextContent); - info(`Wrote _authToken entries to ${npmrcPath} for registries: ${registries.join(", ")}`); -} - /** - * Handle auth for the project's existing `.npmrc` without requiring - * `registry-url` in the workflow. + * Re-export environment references already present in the project's `.npmrc` + * so they remain visible to package-manager subprocesses and subsequent steps. * - * - If `.npmrc` declares a custom registry but no matching `_authToken` entry - * and `NODE_AUTH_TOKEN` is set, write a supplemental `_authToken=${NODE_AUTH_TOKEN}` - * line to `$RUNNER_TEMP/.npmrc` and point `NPM_CONFIG_USERCONFIG` at it, so the - * repo `.npmrc` can stay to just `@scope:registry=`. - * - For any `${VAR}` references already in the project `.npmrc`, re-export those - * env vars via `GITHUB_ENV` so they remain visible to package-manager - * subprocesses and subsequent steps. + * Do not add auth for repository-controlled registry URLs. Generating token + * entries requires an explicit `registry-url` input via configAuthentication. */ export function propagateProjectNpmrcAuth(projectDir: string): void { const npmrcPath = join(projectDir, ".npmrc"); const content = readNpmrc(npmrcPath); if (content === undefined) return; - const { registriesNeedingAuth, envVarRefs } = analyzeProjectNpmrc(content); - - if (process.env.NODE_AUTH_TOKEN && registriesNeedingAuth.length > 0) { - writeSupplementalAuth(registriesNeedingAuth); - envVarRefs.add("NODE_AUTH_TOKEN"); - } + const { envVarRefs } = analyzeProjectNpmrc(content); const propagatable = [...envVarRefs].filter( (name) => !isReservedEnvVar(name) && !!process.env[name], diff --git a/src/azure/parity.test.ts b/src/azure/parity.test.ts index 2a91925..bb99741 100644 --- a/src/azure/parity.test.ts +++ b/src/azure/parity.test.ts @@ -118,6 +118,25 @@ describe("Azure parity", () => { ); }); + it("does not attach NODE_AUTH_TOKEN to repository-controlled registries", async () => { + const { project, env, ports } = fixture(); + writeFileSync( + path.join(project, ".npmrc"), + "registry=https://attacker.invalid/\n@scope:registry=https://other.invalid/npm/\n", + ); + const target: NodeJS.ProcessEnv = { ...env, NODE_AUTH_TOKEN: "secret" }; + + await runFinalize(target, ports); + if (target.NPM_CONFIG_USERCONFIG) directories.push(path.dirname(target.NPM_CONFIG_USERCONFIG)); + + expect(target.NPM_CONFIG_USERCONFIG).toBeUndefined(); + expect(target.PNPM_CONFIG_USERCONFIG).toBeUndefined(); + expect(ports.setVariable.mock.calls.some(([name]) => name.endsWith("CONFIG_USERCONFIG"))).toBe( + false, + ); + expect(ports.runInstall).toHaveBeenCalledWith(expect.anything(), project, "vp", target); + }); + it("prepares a version/platform-specific sfw cache only when an install will run", async () => { const { env, ports } = fixture(); await runPrepare({ ...env, SETUP_VP_SFW: "true", SETUP_VP_RUN_INSTALL: "false" }, ports); diff --git a/src/ci/auth.test.ts b/src/ci/auth.test.ts index 60f21df..8768213 100644 --- a/src/ci/auth.test.ts +++ b/src/ci/auth.test.ts @@ -16,7 +16,35 @@ afterEach(() => { }); describe("portable project auth", () => { - it("supplements scoped registries, preserves user config, and never writes secret values", () => { + it.each([ + "registry=https://attacker.invalid/", + "@scope:registry=https://attacker.invalid/npm/", + "registry=https://registry.npmjs.org/\n@scope:registry=https://attacker.invalid/", + ])("does not add auth for repository-controlled registries: %s", (content) => { + const project = tempDir(); + const projectNpmrc = path.join(project, ".npmrc"); + const userConfig = path.join(tempDir(), ".npmrc"); + writeFileSync(projectNpmrc, content); + writeFileSync(userConfig, "strict-ssl=true\n"); + const env: RuntimeEnv = { + NODE_AUTH_TOKEN: "secret", + NPM_CONFIG_USERCONFIG: userConfig, + PNPM_CONFIG_USERCONFIG: userConfig, + }; + const originalEnv = { ...env }; + const exporter = vi.fn(); + + const npmrc = configureAuth("", "", env, exporter, project); + if (npmrc) directories.push(path.dirname(npmrc)); + + expect(npmrc).toBeUndefined(); + expect(env).toEqual(originalEnv); + expect(exporter).not.toHaveBeenCalled(); + expect(readFileSync(userConfig, "utf8")).toBe("strict-ssl=true\n"); + expect(readFileSync(projectNpmrc, "utf8")).toBe(content); + }); + + it("authenticates only the explicit registry and preserves existing user config", () => { const project = tempDir(); const userConfig = path.join(tempDir(), ".npmrc"); const content = @@ -29,17 +57,20 @@ describe("portable project auth", () => { NPM_CONFIG_USERCONFIG: userConfig, }; const exporter = vi.fn(); - const npmrc = configureAuth("", "", env, exporter, project)!; + const npmrc = configureAuth("https://trusted.example/npm/", "trusted", env, exporter, project)!; directories.push(path.dirname(npmrc)); const result = readFileSync(npmrc, "utf8"); expect(result).toContain("strict-ssl=true"); - expect(result).toContain("//registry.example/npm/:_authToken=${NODE_AUTH_TOKEN}"); + expect(result).toContain("//trusted.example/npm/:_authToken=${NODE_AUTH_TOKEN}"); + expect(result).toContain("@trusted:registry=https://trusted.example/npm/"); + expect(result).not.toContain("registry.example"); + expect(result).not.toContain("other.example"); expect(result).not.toContain("secret"); expect(readFileSync(path.join(project, ".npmrc"), "utf8")).toBe(content); // Windows does not expose POSIX owner/group permission bits. if (process.platform !== "win32") expect(statSync(npmrc).mode & 0o777).toBe(0o600); expect(exporter).toHaveBeenCalledWith("NODE_AUTH_TOKEN", "secret"); - expect(exporter).toHaveBeenCalledWith("CUSTOM_TOKEN", "other-secret"); + expect(exporter).not.toHaveBeenCalledWith("CUSTOM_TOKEN", expect.anything()); expect(env.PNPM_CONFIG_USERCONFIG).toBe(npmrc); }); @@ -48,7 +79,8 @@ describe("portable project auth", () => { writeFileSync( path.join(project, ".npmrc"), [ - "registry=https://registry.example/", + "registry=https://attacker.invalid/", + "@scope:registry=https://registry.example/", "//registry.example/:_authToken=${CUSTOM_TOKEN}", "@other:registry=https://${REGISTRY_HOST}/", "cache=${PATH}", diff --git a/src/ci/auth.ts b/src/ci/auth.ts index b17dceb..281beac 100644 --- a/src/ci/auth.ts +++ b/src/ci/auth.ts @@ -50,29 +50,13 @@ export function configureAuth( ): string | undefined { if (!registryUrlInput) { if (!projectDir) return; - const { registriesNeedingAuth, envVarRefs } = analyzeProjectNpmrc( - readNpmrc(path.join(projectDir, ".npmrc")), - ); - let npmrc: string | undefined; - if (targetEnv.NODE_AUTH_TOKEN && registriesNeedingAuth.length > 0) { - const authKeys = new Set( - registriesNeedingAuth.map((url) => - (url.replace(/^\w+:/, "") + ":_authtoken").toLowerCase(), - ), - ); - const lines = readUserConfigLines(targetEnv, authKeys); - lines.push( - ...registriesNeedingAuth.map( - (url) => url.replace(/^\w+:/, "") + ":_authToken=" + NODE_AUTH_TOKEN_REF, - ), - ); - npmrc = writeUserConfig(lines.join("\n") + "\n", targetEnv, exportVariable); - envVarRefs.add("NODE_AUTH_TOKEN"); - } + // Repository-controlled registry URLs must not implicitly receive NODE_AUTH_TOKEN. + // Only preserve environment references already present in the project config. + const { envVarRefs } = analyzeProjectNpmrc(readNpmrc(path.join(projectDir, ".npmrc"))); for (const name of envVarRefs) { if (!isReservedAuthVariable(name) && targetEnv[name]) exportVariable?.(name, targetEnv[name]); } - return npmrc; + return; } let url: URL; diff --git a/src/ci/npmrc.ts b/src/ci/npmrc.ts index 3d9b6d8..44f6d9f 100644 --- a/src/ci/npmrc.ts +++ b/src/ci/npmrc.ts @@ -9,16 +9,9 @@ export function readNpmrc(file: string): string { } } -function authKeyFor(registryUrl: string): string { - return (registryUrl.replace(/^\w+:/, "") + ":_authtoken").toLowerCase(); -} - export function analyzeProjectNpmrc(content: string): { - registriesNeedingAuth: string[]; envVarRefs: Set; } { - const registries = new Set(); - const authKeys = new Set(); const envVarRefs = new Set(); for (const rawLine of content.split(/\r?\n/)) { @@ -27,27 +20,14 @@ export function analyzeProjectNpmrc(content: string): { const eq = line.indexOf("="); if (eq < 0) continue; - const lowerKey = line.slice(0, eq).trim().toLowerCase(); const value = line.slice(eq + 1).trim(); - if (lowerKey === "registry" || lowerKey.endsWith(":registry")) { - // Skip values that rely on env-var expansion — the key for the matching - // `_authToken` line must be a literal URL, and `${VAR}` isn't expanded - // inside `.npmrc` keys by npm/pnpm. - if (!value.includes("${")) { - registries.add(value.endsWith("/") ? value : value + "/"); - } - } - if (lowerKey.startsWith("//") && lowerKey.endsWith(":_authtoken")) { - authKeys.add(lowerKey); - } for (const m of value.matchAll(/\$\{(\w+)\}/g)) { envVarRefs.add(m[1]!); } } return { - registriesNeedingAuth: [...registries].filter((url) => !authKeys.has(authKeyFor(url))), envVarRefs, }; } diff --git a/src/gitlab/index.test.ts b/src/gitlab/index.test.ts index 2acba69..ab1071e 100644 --- a/src/gitlab/index.test.ts +++ b/src/gitlab/index.test.ts @@ -96,6 +96,28 @@ describe("GitLab setup parity", () => { expect(run).toHaveBeenCalledWith("vp", ["env", "use", "22"], expect.any(Object)); }); + it("does not attach NODE_AUTH_TOKEN to repository-controlled registries", async () => { + const root = fixture(); + const content = + "registry=https://attacker.invalid/\n@scope:registry=https://other.invalid/npm/\n"; + const npmrc = path.join(root, "app/.npmrc"); + writeFileSync(npmrc, content); + vi.stubEnv("NODE_AUTH_TOKEN", "secret"); + vi.stubEnv("NPM_CONFIG_USERCONFIG", undefined); + vi.stubEnv("PNPM_CONFIG_USERCONFIG", undefined); + + await main(); + if (process.env.NPM_CONFIG_USERCONFIG) + directories.push(path.dirname(process.env.NPM_CONFIG_USERCONFIG)); + + expect(process.env.NPM_CONFIG_USERCONFIG).toBeUndefined(); + expect(process.env.PNPM_CONFIG_USERCONFIG).toBeUndefined(); + expect(readFileSync(npmrc, "utf8")).toBe(content); + const exports = readFileSync(path.join(root, "shell.env"), "utf8"); + expect(exports).not.toContain("CONFIG_USERCONFIG"); + expect(exports).not.toContain("NODE_AUTH_TOKEN"); + }); + it.each(["explicit", "package.json"])( "disables sfw for a preview resolved from %s and warns once", async (source) => {