@vercel/cli-exec
Advanced tools
| /** | ||
| * Full diagnostic payload produced during CLI resolution. | ||
| */ | ||
| export interface ResolutionDiagnostics { | ||
| localBinSearch: LocalBinSearchDiagnostics; | ||
| skippedLocalBins: SkippedLocalBin[]; | ||
| } | ||
| /** | ||
| * Diagnostics from walking ancestor `node_modules/.bin` directories. | ||
| */ | ||
| export interface LocalBinSearchDiagnostics { | ||
| searchRoot: string; | ||
| stoppedAt: string; | ||
| stopReason: 'project-root-marker' | 'filesystem-root'; | ||
| markerPath?: string; | ||
| skippedNodeModules: SkippedNodeModules[]; | ||
| } | ||
| /** | ||
| * A skipped `node_modules` directory and the reason it was rejected. | ||
| */ | ||
| export interface SkippedNodeModules { | ||
| directory: string; | ||
| reason: string; | ||
| } | ||
| /** | ||
| * A skipped local bin candidate and the reason it was rejected. | ||
| */ | ||
| export interface SkippedLocalBin { | ||
| candidate: string; | ||
| reason: string; | ||
| } |
| "use strict"; | ||
| var __defProp = Object.defineProperty; | ||
| var __getOwnPropDesc = Object.getOwnPropertyDescriptor; | ||
| var __getOwnPropNames = Object.getOwnPropertyNames; | ||
| var __hasOwnProp = Object.prototype.hasOwnProperty; | ||
| var __copyProps = (to, from, except, desc) => { | ||
| if (from && typeof from === "object" || typeof from === "function") { | ||
| for (let key of __getOwnPropNames(from)) | ||
| if (!__hasOwnProp.call(to, key) && key !== except) | ||
| __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); | ||
| } | ||
| return to; | ||
| }; | ||
| var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); | ||
| var diagnostics_exports = {}; | ||
| module.exports = __toCommonJS(diagnostics_exports); | ||
| //# sourceMappingURL=diagnostics.js.map |
| { | ||
| "version": 3, | ||
| "sources": ["../src/diagnostics.ts"], | ||
| "sourcesContent": ["/**\n * Full diagnostic payload produced during CLI resolution.\n */\nexport interface ResolutionDiagnostics {\n localBinSearch: LocalBinSearchDiagnostics;\n skippedLocalBins: SkippedLocalBin[];\n}\n\n/**\n * Diagnostics from walking ancestor `node_modules/.bin` directories.\n */\nexport interface LocalBinSearchDiagnostics {\n searchRoot: string;\n stoppedAt: string;\n stopReason: 'project-root-marker' | 'filesystem-root';\n markerPath?: string;\n skippedNodeModules: SkippedNodeModules[];\n}\n\n/**\n * A skipped `node_modules` directory and the reason it was rejected.\n */\nexport interface SkippedNodeModules {\n directory: string;\n reason: string;\n}\n\n/**\n * A skipped local bin candidate and the reason it was rejected.\n */\nexport interface SkippedLocalBin {\n candidate: string;\n reason: string;\n}\n"], | ||
| "mappings": ";;;;;;;;;;;;;;AAAA;AAAA;", | ||
| "names": [] | ||
| } |
| /** | ||
| * Prepends path entries while preserving existing entries and order. | ||
| */ | ||
| export declare function prependPathEntries(pathValue: string, directories: string[]): string; | ||
| /** | ||
| * Splits a PATH value into non-empty directory entries. | ||
| */ | ||
| export declare function splitPath(pathValue: string): string[]; | ||
| /** | ||
| * Reads PATH from an environment object with Windows casing compatibility. | ||
| */ | ||
| export declare function getEnvPath(env?: NodeJS.ProcessEnv): string; | ||
| /** | ||
| * Writes PATH to an environment object with normalized Windows casing. | ||
| */ | ||
| export declare function setEnvPath(env: NodeJS.ProcessEnv | undefined, pathValue: string): NodeJS.ProcessEnv; |
| "use strict"; | ||
| var __create = Object.create; | ||
| var __defProp = Object.defineProperty; | ||
| var __getOwnPropDesc = Object.getOwnPropertyDescriptor; | ||
| var __getOwnPropNames = Object.getOwnPropertyNames; | ||
| var __getProtoOf = Object.getPrototypeOf; | ||
| var __hasOwnProp = Object.prototype.hasOwnProperty; | ||
| var __export = (target, all) => { | ||
| for (var name in all) | ||
| __defProp(target, name, { get: all[name], enumerable: true }); | ||
| }; | ||
| var __copyProps = (to, from, except, desc) => { | ||
| if (from && typeof from === "object" || typeof from === "function") { | ||
| for (let key of __getOwnPropNames(from)) | ||
| if (!__hasOwnProp.call(to, key) && key !== except) | ||
| __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); | ||
| } | ||
| return to; | ||
| }; | ||
| var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( | ||
| // If the importer is in node compatibility mode or this is not an ESM | ||
| // file that has been converted to a CommonJS file using a Babel- | ||
| // compatible transform (i.e. "__esModule" has not been set), then set | ||
| // "default" to the CommonJS "module.exports" for node compatibility. | ||
| isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, | ||
| mod | ||
| )); | ||
| var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); | ||
| var envpath_exports = {}; | ||
| __export(envpath_exports, { | ||
| getEnvPath: () => getEnvPath, | ||
| prependPathEntries: () => prependPathEntries, | ||
| setEnvPath: () => setEnvPath, | ||
| splitPath: () => splitPath | ||
| }); | ||
| module.exports = __toCommonJS(envpath_exports); | ||
| var import_node_path = __toESM(require("node:path")); | ||
| function prependPathEntries(pathValue, directories) { | ||
| const pathParts = pathValue.split(import_node_path.default.delimiter).filter(Boolean); | ||
| const prepended = []; | ||
| for (const directory of directories) { | ||
| if (!pathParts.includes(directory) && !prepended.includes(directory)) { | ||
| prepended.push(directory); | ||
| } | ||
| } | ||
| if (prepended.length === 0) { | ||
| return pathValue; | ||
| } | ||
| return pathValue === "" || pathValue === import_node_path.default.delimiter ? `${prepended.join(import_node_path.default.delimiter)}${pathValue}` : [...prepended, pathValue].join(import_node_path.default.delimiter); | ||
| } | ||
| function splitPath(pathValue) { | ||
| return pathValue.split(import_node_path.default.delimiter).filter(Boolean); | ||
| } | ||
| function getEnvPath(env = process.env) { | ||
| if (process.platform !== "win32") { | ||
| return env.PATH ?? ""; | ||
| } | ||
| const pathKeys = Object.keys(env).filter((key) => key.toLowerCase() === "path"); | ||
| for (let index = pathKeys.length - 1; index >= 0; index--) { | ||
| const value = env[pathKeys[index]]; | ||
| if (value !== void 0) { | ||
| return value; | ||
| } | ||
| } | ||
| return ""; | ||
| } | ||
| function setEnvPath(env = process.env, pathValue) { | ||
| if (process.platform !== "win32") { | ||
| return { | ||
| ...env, | ||
| PATH: pathValue | ||
| }; | ||
| } | ||
| const normalizedEnv = { ...env }; | ||
| for (const key of Object.keys(normalizedEnv)) { | ||
| if (key !== "PATH" && key.toLowerCase() === "path") { | ||
| delete normalizedEnv[key]; | ||
| } | ||
| } | ||
| normalizedEnv.PATH = pathValue; | ||
| return normalizedEnv; | ||
| } | ||
| // Annotate the CommonJS export names for ESM import in node: | ||
| 0 && (module.exports = { | ||
| getEnvPath, | ||
| prependPathEntries, | ||
| setEnvPath, | ||
| splitPath | ||
| }); | ||
| //# sourceMappingURL=envpath.js.map |
| { | ||
| "version": 3, | ||
| "sources": ["../src/envpath.ts"], | ||
| "sourcesContent": ["import path from 'node:path';\n\n/**\n * Prepends path entries while preserving existing entries and order.\n */\nexport function prependPathEntries(\n pathValue: string,\n directories: string[]\n): string {\n const pathParts = pathValue.split(path.delimiter).filter(Boolean);\n const prepended: string[] = [];\n\n for (const directory of directories) {\n if (!pathParts.includes(directory) && !prepended.includes(directory)) {\n prepended.push(directory);\n }\n }\n\n if (prepended.length === 0) {\n return pathValue;\n }\n\n return pathValue === '' || pathValue === path.delimiter\n ? `${prepended.join(path.delimiter)}${pathValue}`\n : [...prepended, pathValue].join(path.delimiter);\n}\n\n/**\n * Splits a PATH value into non-empty directory entries.\n */\nexport function splitPath(pathValue: string): string[] {\n return pathValue.split(path.delimiter).filter(Boolean);\n}\n\n/**\n * Reads PATH from an environment object with Windows casing compatibility.\n */\nexport function getEnvPath(env: NodeJS.ProcessEnv = process.env): string {\n if (process.platform !== 'win32') {\n return env.PATH ?? '';\n }\n\n const pathKeys = Object.keys(env).filter(key => key.toLowerCase() === 'path');\n\n for (let index = pathKeys.length - 1; index >= 0; index--) {\n const value = env[pathKeys[index]];\n if (value !== undefined) {\n return value;\n }\n }\n\n return '';\n}\n\n/**\n * Writes PATH to an environment object with normalized Windows casing.\n */\nexport function setEnvPath(\n env: NodeJS.ProcessEnv = process.env,\n pathValue: string\n): NodeJS.ProcessEnv {\n if (process.platform !== 'win32') {\n return {\n ...env,\n PATH: pathValue,\n };\n }\n\n const normalizedEnv = { ...env };\n\n for (const key of Object.keys(normalizedEnv)) {\n if (key !== 'PATH' && key.toLowerCase() === 'path') {\n delete normalizedEnv[key];\n }\n }\n\n normalizedEnv.PATH = pathValue;\n return normalizedEnv;\n}\n"], | ||
| "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,uBAAiB;AAKV,SAAS,mBACd,WACA,aACQ;AACR,QAAM,YAAY,UAAU,MAAM,iBAAAA,QAAK,SAAS,EAAE,OAAO,OAAO;AAChE,QAAM,YAAsB,CAAC;AAE7B,aAAW,aAAa,aAAa;AACnC,QAAI,CAAC,UAAU,SAAS,SAAS,KAAK,CAAC,UAAU,SAAS,SAAS,GAAG;AACpE,gBAAU,KAAK,SAAS;AAAA,IAC1B;AAAA,EACF;AAEA,MAAI,UAAU,WAAW,GAAG;AAC1B,WAAO;AAAA,EACT;AAEA,SAAO,cAAc,MAAM,cAAc,iBAAAA,QAAK,YAC1C,GAAG,UAAU,KAAK,iBAAAA,QAAK,SAAS,CAAC,GAAG,SAAS,KAC7C,CAAC,GAAG,WAAW,SAAS,EAAE,KAAK,iBAAAA,QAAK,SAAS;AACnD;AAKO,SAAS,UAAU,WAA6B;AACrD,SAAO,UAAU,MAAM,iBAAAA,QAAK,SAAS,EAAE,OAAO,OAAO;AACvD;AAKO,SAAS,WAAW,MAAyB,QAAQ,KAAa;AACvE,MAAI,QAAQ,aAAa,SAAS;AAChC,WAAO,IAAI,QAAQ;AAAA,EACrB;AAEA,QAAM,WAAW,OAAO,KAAK,GAAG,EAAE,OAAO,SAAO,IAAI,YAAY,MAAM,MAAM;AAE5E,WAAS,QAAQ,SAAS,SAAS,GAAG,SAAS,GAAG,SAAS;AACzD,UAAM,QAAQ,IAAI,SAAS,KAAK,CAAC;AACjC,QAAI,UAAU,QAAW;AACvB,aAAO;AAAA,IACT;AAAA,EACF;AAEA,SAAO;AACT;AAKO,SAAS,WACd,MAAyB,QAAQ,KACjC,WACmB;AACnB,MAAI,QAAQ,aAAa,SAAS;AAChC,WAAO;AAAA,MACL,GAAG;AAAA,MACH,MAAM;AAAA,IACR;AAAA,EACF;AAEA,QAAM,gBAAgB,EAAE,GAAG,IAAI;AAE/B,aAAW,OAAO,OAAO,KAAK,aAAa,GAAG;AAC5C,QAAI,QAAQ,UAAU,IAAI,YAAY,MAAM,QAAQ;AAClD,aAAO,cAAc,GAAG;AAAA,IAC1B;AAAA,EACF;AAEA,gBAAc,OAAO;AACrB,SAAO;AACT;", | ||
| "names": ["path"] | ||
| } |
| import type { ResolutionDiagnostics } from './diagnostics'; | ||
| import type { VercelCliErrorCode, VercelCliInvocation } from './types'; | ||
| /** | ||
| * Error returned when CLI resolution or execution fails. | ||
| * | ||
| * `code` is always set. The remaining fields are populated when the failure | ||
| * happened after a CLI invocation was resolved or started. | ||
| */ | ||
| export declare class VercelCliError extends Error { | ||
| /** | ||
| * Stable machine-readable error code. | ||
| */ | ||
| code: VercelCliErrorCode; | ||
| /** | ||
| * Resolved CLI command and arguments, when available. | ||
| */ | ||
| invocation?: VercelCliInvocation; | ||
| /** | ||
| * Captured standard output from the failed process, when available. | ||
| */ | ||
| stdout?: string; | ||
| /** | ||
| * Captured standard error from the failed process, when available. | ||
| */ | ||
| stderr?: string; | ||
| /** | ||
| * Process exit code for non-zero exits, when available. | ||
| */ | ||
| exitCode?: number; | ||
| constructor(options: { | ||
| code: VercelCliErrorCode; | ||
| message: string; | ||
| invocation?: VercelCliInvocation; | ||
| stdout?: string; | ||
| stderr?: string; | ||
| exitCode?: number; | ||
| cause?: unknown; | ||
| }); | ||
| } | ||
| /** | ||
| * Builds a not-found error message with diagnostics from local bin resolution. | ||
| */ | ||
| export declare function getCliNotFoundMessage(diagnostics: ResolutionDiagnostics): string; | ||
| /** | ||
| * Verifies that the resolved working directory exists and is a directory. | ||
| */ | ||
| export declare function assertValidCwd(cwd: string): Promise<void>; | ||
| /** | ||
| * Converts errors from `execa` into stable `VercelCliError` instances. | ||
| */ | ||
| export declare function toVercelCliError(invocation: VercelCliInvocation, error: unknown): VercelCliError; |
+158
| "use strict"; | ||
| var __defProp = Object.defineProperty; | ||
| var __getOwnPropDesc = Object.getOwnPropertyDescriptor; | ||
| var __getOwnPropNames = Object.getOwnPropertyNames; | ||
| var __hasOwnProp = Object.prototype.hasOwnProperty; | ||
| var __export = (target, all) => { | ||
| for (var name in all) | ||
| __defProp(target, name, { get: all[name], enumerable: true }); | ||
| }; | ||
| var __copyProps = (to, from, except, desc) => { | ||
| if (from && typeof from === "object" || typeof from === "function") { | ||
| for (let key of __getOwnPropNames(from)) | ||
| if (!__hasOwnProp.call(to, key) && key !== except) | ||
| __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); | ||
| } | ||
| return to; | ||
| }; | ||
| var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); | ||
| var errors_exports = {}; | ||
| __export(errors_exports, { | ||
| VercelCliError: () => VercelCliError, | ||
| assertValidCwd: () => assertValidCwd, | ||
| getCliNotFoundMessage: () => getCliNotFoundMessage, | ||
| toVercelCliError: () => toVercelCliError | ||
| }); | ||
| module.exports = __toCommonJS(errors_exports); | ||
| var import_promises = require("node:fs/promises"); | ||
| class VercelCliError extends Error { | ||
| constructor(options) { | ||
| super(options.message); | ||
| this.name = "VercelCliError"; | ||
| this.code = options.code; | ||
| this.invocation = options.invocation; | ||
| this.stdout = options.stdout; | ||
| this.stderr = options.stderr; | ||
| this.exitCode = options.exitCode; | ||
| if (options.cause !== void 0) { | ||
| this.cause = options.cause; | ||
| } | ||
| } | ||
| } | ||
| function getCliNotFoundMessage(diagnostics) { | ||
| const details = []; | ||
| const { localBinSearch } = diagnostics; | ||
| if (localBinSearch.stopReason === "project-root-marker") { | ||
| details.push( | ||
| `Local bin lookup stopped at ${JSON.stringify(localBinSearch.stoppedAt)} (${JSON.stringify(localBinSearch.markerPath)}).` | ||
| ); | ||
| } else if (localBinSearch.stopReason === "filesystem-root") { | ||
| details.push( | ||
| `No project root marker was found from ${JSON.stringify(localBinSearch.searchRoot)}; local bin lookup reached the filesystem root.` | ||
| ); | ||
| } | ||
| for (const skippedNodeModules of localBinSearch.skippedNodeModules) { | ||
| details.push( | ||
| `Skipped ${JSON.stringify(skippedNodeModules.directory)}: ${skippedNodeModules.reason}.` | ||
| ); | ||
| } | ||
| for (const skippedLocalBin of diagnostics.skippedLocalBins) { | ||
| details.push( | ||
| `Skipped ${JSON.stringify(skippedLocalBin.candidate)}: ${skippedLocalBin.reason}.` | ||
| ); | ||
| } | ||
| if (details.length === 0) { | ||
| return "Unable to find a usable Vercel CLI installation."; | ||
| } | ||
| return ["Unable to find a usable Vercel CLI installation.", ...details].join( | ||
| "\n" | ||
| ); | ||
| } | ||
| async function assertValidCwd(cwd) { | ||
| try { | ||
| if (!(await (0, import_promises.stat)(cwd)).isDirectory()) { | ||
| throw new Error("not a directory"); | ||
| } | ||
| } catch { | ||
| throw new VercelCliError({ | ||
| code: "VERCEL_CLI_INVALID_CWD", | ||
| message: `Working directory ${JSON.stringify(cwd)} does not exist or is not a directory.` | ||
| }); | ||
| } | ||
| } | ||
| function toVercelCliError(invocation, error) { | ||
| if (typeof error === "object" && error !== null) { | ||
| const execaError = error; | ||
| if (execaError.code === "ENOENT") { | ||
| return new VercelCliError({ | ||
| code: "VERCEL_CLI_NOT_FOUND", | ||
| message: `Unable to find Vercel CLI command ${JSON.stringify(invocation.command)}.`, | ||
| invocation, | ||
| cause: error | ||
| }); | ||
| } | ||
| if (execaError.code === "EACCES" || execaError.code === "EPERM") { | ||
| return new VercelCliError({ | ||
| code: "VERCEL_CLI_PERMISSION_DENIED", | ||
| message: `Permission denied while executing Vercel CLI command ${JSON.stringify(invocation.command)}.`, | ||
| invocation, | ||
| cause: error | ||
| }); | ||
| } | ||
| if (execaError.timedOut) { | ||
| return new VercelCliError({ | ||
| code: "VERCEL_CLI_TIMED_OUT", | ||
| message: `Timed out while executing Vercel CLI command ${JSON.stringify(invocation.command)}.`, | ||
| invocation, | ||
| stdout: execaError.stdout, | ||
| stderr: execaError.stderr, | ||
| cause: error | ||
| }); | ||
| } | ||
| if (execaError.isCanceled) { | ||
| return new VercelCliError({ | ||
| code: "VERCEL_CLI_CANCELED", | ||
| message: `Canceled while executing Vercel CLI command ${JSON.stringify(invocation.command)}.`, | ||
| invocation, | ||
| stdout: execaError.stdout, | ||
| stderr: execaError.stderr, | ||
| cause: error | ||
| }); | ||
| } | ||
| if (execaError.signal) { | ||
| return new VercelCliError({ | ||
| code: "VERCEL_CLI_SIGNALED", | ||
| message: `Vercel CLI command ${JSON.stringify(invocation.command)} exited due to signal ${execaError.signal}.`, | ||
| invocation, | ||
| stdout: execaError.stdout, | ||
| stderr: execaError.stderr, | ||
| cause: error | ||
| }); | ||
| } | ||
| if (typeof execaError.exitCode === "number") { | ||
| return new VercelCliError({ | ||
| code: "VERCEL_CLI_ERRORED", | ||
| message: execaError.shortMessage ?? execaError.message ?? `Vercel CLI command ${JSON.stringify(invocation.command)} exited with code ${execaError.exitCode}.`, | ||
| invocation, | ||
| stdout: execaError.stdout, | ||
| stderr: execaError.stderr, | ||
| exitCode: execaError.exitCode, | ||
| cause: error | ||
| }); | ||
| } | ||
| } | ||
| return new VercelCliError({ | ||
| code: "VERCEL_CLI_EXEC_FAILED", | ||
| message: `Could not execute Vercel CLI command ${JSON.stringify(invocation.command)}.`, | ||
| invocation, | ||
| cause: error | ||
| }); | ||
| } | ||
| // Annotate the CommonJS export names for ESM import in node: | ||
| 0 && (module.exports = { | ||
| VercelCliError, | ||
| assertValidCwd, | ||
| getCliNotFoundMessage, | ||
| toVercelCliError | ||
| }); | ||
| //# sourceMappingURL=errors.js.map |
| { | ||
| "version": 3, | ||
| "sources": ["../src/errors.ts"], | ||
| "sourcesContent": ["import { stat } from 'node:fs/promises';\nimport type { ResolutionDiagnostics } from './diagnostics';\nimport type { VercelCliErrorCode, VercelCliInvocation } from './types';\n\n/**\n * Error returned when CLI resolution or execution fails.\n *\n * `code` is always set. The remaining fields are populated when the failure\n * happened after a CLI invocation was resolved or started.\n */\nexport class VercelCliError extends Error {\n /**\n * Stable machine-readable error code.\n */\n code: VercelCliErrorCode;\n\n /**\n * Resolved CLI command and arguments, when available.\n */\n invocation?: VercelCliInvocation;\n\n /**\n * Captured standard output from the failed process, when available.\n */\n stdout?: string;\n\n /**\n * Captured standard error from the failed process, when available.\n */\n stderr?: string;\n\n /**\n * Process exit code for non-zero exits, when available.\n */\n exitCode?: number;\n\n constructor(options: {\n code: VercelCliErrorCode;\n message: string;\n invocation?: VercelCliInvocation;\n stdout?: string;\n stderr?: string;\n exitCode?: number;\n cause?: unknown;\n }) {\n super(options.message);\n this.name = 'VercelCliError';\n this.code = options.code;\n this.invocation = options.invocation;\n this.stdout = options.stdout;\n this.stderr = options.stderr;\n this.exitCode = options.exitCode;\n if (options.cause !== undefined) {\n (this as Error & { cause?: unknown }).cause = options.cause;\n }\n }\n}\n\n/**\n * Builds a not-found error message with diagnostics from local bin resolution.\n */\nexport function getCliNotFoundMessage(\n diagnostics: ResolutionDiagnostics\n): string {\n const details: string[] = [];\n const { localBinSearch } = diagnostics;\n\n if (localBinSearch.stopReason === 'project-root-marker') {\n details.push(\n `Local bin lookup stopped at ${JSON.stringify(localBinSearch.stoppedAt)} (${JSON.stringify(localBinSearch.markerPath)}).`\n );\n } else if (localBinSearch.stopReason === 'filesystem-root') {\n details.push(\n `No project root marker was found from ${JSON.stringify(localBinSearch.searchRoot)}; local bin lookup reached the filesystem root.`\n );\n }\n\n for (const skippedNodeModules of localBinSearch.skippedNodeModules) {\n details.push(\n `Skipped ${JSON.stringify(skippedNodeModules.directory)}: ${skippedNodeModules.reason}.`\n );\n }\n\n for (const skippedLocalBin of diagnostics.skippedLocalBins) {\n details.push(\n `Skipped ${JSON.stringify(skippedLocalBin.candidate)}: ${skippedLocalBin.reason}.`\n );\n }\n\n if (details.length === 0) {\n return 'Unable to find a usable Vercel CLI installation.';\n }\n\n return ['Unable to find a usable Vercel CLI installation.', ...details].join(\n '\\n'\n );\n}\n\n/**\n * Verifies that the resolved working directory exists and is a directory.\n */\nexport async function assertValidCwd(cwd: string) {\n try {\n if (!(await stat(cwd)).isDirectory()) {\n throw new Error('not a directory');\n }\n } catch {\n throw new VercelCliError({\n code: 'VERCEL_CLI_INVALID_CWD',\n message: `Working directory ${JSON.stringify(cwd)} does not exist or is not a directory.`,\n });\n }\n}\n\n/**\n * Converts errors from `execa` into stable `VercelCliError` instances.\n */\nexport function toVercelCliError(\n invocation: VercelCliInvocation,\n error: unknown\n): VercelCliError {\n if (typeof error === 'object' && error !== null) {\n const execaError = error as {\n code?: string;\n exitCode?: number;\n timedOut?: boolean;\n isCanceled?: boolean;\n signal?: string | null;\n stdout?: string;\n stderr?: string;\n shortMessage?: string;\n message?: string;\n };\n\n if (execaError.code === 'ENOENT') {\n return new VercelCliError({\n code: 'VERCEL_CLI_NOT_FOUND',\n message: `Unable to find Vercel CLI command ${JSON.stringify(invocation.command)}.`,\n invocation,\n cause: error,\n });\n }\n\n if (execaError.code === 'EACCES' || execaError.code === 'EPERM') {\n return new VercelCliError({\n code: 'VERCEL_CLI_PERMISSION_DENIED',\n message: `Permission denied while executing Vercel CLI command ${JSON.stringify(invocation.command)}.`,\n invocation,\n cause: error,\n });\n }\n\n if (execaError.timedOut) {\n return new VercelCliError({\n code: 'VERCEL_CLI_TIMED_OUT',\n message: `Timed out while executing Vercel CLI command ${JSON.stringify(invocation.command)}.`,\n invocation,\n stdout: execaError.stdout,\n stderr: execaError.stderr,\n cause: error,\n });\n }\n\n if (execaError.isCanceled) {\n return new VercelCliError({\n code: 'VERCEL_CLI_CANCELED',\n message: `Canceled while executing Vercel CLI command ${JSON.stringify(invocation.command)}.`,\n invocation,\n stdout: execaError.stdout,\n stderr: execaError.stderr,\n cause: error,\n });\n }\n\n if (execaError.signal) {\n return new VercelCliError({\n code: 'VERCEL_CLI_SIGNALED',\n message: `Vercel CLI command ${JSON.stringify(invocation.command)} exited due to signal ${execaError.signal}.`,\n invocation,\n stdout: execaError.stdout,\n stderr: execaError.stderr,\n cause: error,\n });\n }\n\n if (typeof execaError.exitCode === 'number') {\n return new VercelCliError({\n code: 'VERCEL_CLI_ERRORED',\n message:\n execaError.shortMessage ??\n execaError.message ??\n `Vercel CLI command ${JSON.stringify(invocation.command)} exited with code ${execaError.exitCode}.`,\n invocation,\n stdout: execaError.stdout,\n stderr: execaError.stderr,\n exitCode: execaError.exitCode,\n cause: error,\n });\n }\n }\n\n return new VercelCliError({\n code: 'VERCEL_CLI_EXEC_FAILED',\n message: `Could not execute Vercel CLI command ${JSON.stringify(invocation.command)}.`,\n invocation,\n cause: error,\n });\n}\n"], | ||
| "mappings": "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", | ||
| "names": [] | ||
| } |
| /** | ||
| * Converts any thrown value into a message suitable for diagnostics. | ||
| */ | ||
| export declare function getErrorMessage(error: unknown): string; | ||
| /** | ||
| * Returns whether a filesystem error means the requested path is absent. | ||
| */ | ||
| export declare function isMissingPathError(error: unknown): boolean; |
| "use strict"; | ||
| var __defProp = Object.defineProperty; | ||
| var __getOwnPropDesc = Object.getOwnPropertyDescriptor; | ||
| var __getOwnPropNames = Object.getOwnPropertyNames; | ||
| var __hasOwnProp = Object.prototype.hasOwnProperty; | ||
| var __export = (target, all) => { | ||
| for (var name in all) | ||
| __defProp(target, name, { get: all[name], enumerable: true }); | ||
| }; | ||
| var __copyProps = (to, from, except, desc) => { | ||
| if (from && typeof from === "object" || typeof from === "function") { | ||
| for (let key of __getOwnPropNames(from)) | ||
| if (!__hasOwnProp.call(to, key) && key !== except) | ||
| __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); | ||
| } | ||
| return to; | ||
| }; | ||
| var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); | ||
| var errutils_exports = {}; | ||
| __export(errutils_exports, { | ||
| getErrorMessage: () => getErrorMessage, | ||
| isMissingPathError: () => isMissingPathError | ||
| }); | ||
| module.exports = __toCommonJS(errutils_exports); | ||
| function getErrorMessage(error) { | ||
| if (error instanceof Error) { | ||
| return error.message; | ||
| } | ||
| return String(error); | ||
| } | ||
| function isMissingPathError(error) { | ||
| return typeof error === "object" && error !== null && "code" in error && (error.code === "ENOENT" || error.code === "ENOTDIR"); | ||
| } | ||
| // Annotate the CommonJS export names for ESM import in node: | ||
| 0 && (module.exports = { | ||
| getErrorMessage, | ||
| isMissingPathError | ||
| }); | ||
| //# sourceMappingURL=errutils.js.map |
| { | ||
| "version": 3, | ||
| "sources": ["../src/errutils.ts"], | ||
| "sourcesContent": ["/**\n * Converts any thrown value into a message suitable for diagnostics.\n */\nexport function getErrorMessage(error: unknown): string {\n if (error instanceof Error) {\n return error.message;\n }\n\n return String(error);\n}\n\n/**\n * Returns whether a filesystem error means the requested path is absent.\n */\nexport function isMissingPathError(error: unknown): boolean {\n return (\n typeof error === 'object' &&\n error !== null &&\n 'code' in error &&\n (error.code === 'ENOENT' || error.code === 'ENOTDIR')\n );\n}\n"], | ||
| "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGO,SAAS,gBAAgB,OAAwB;AACtD,MAAI,iBAAiB,OAAO;AAC1B,WAAO,MAAM;AAAA,EACf;AAEA,SAAO,OAAO,KAAK;AACrB;AAKO,SAAS,mBAAmB,OAAyB;AAC1D,SACE,OAAO,UAAU,YACjB,UAAU,QACV,UAAU,UACT,MAAM,SAAS,YAAY,MAAM,SAAS;AAE/C;", | ||
| "names": [] | ||
| } |
| import type { ExecVercelCliOptions, ExecVercelCliResult } from './types'; | ||
| /** | ||
| * Resolves and executes the Vercel CLI with the provided arguments. | ||
| * | ||
| * The execution environment is adjusted so local `node_modules/.bin` | ||
| * directories and the current Node executable remain available even when a | ||
| * caller passes a sanitized `PATH`. | ||
| */ | ||
| export declare function execVercelCli(args: string[], options?: ExecVercelCliOptions): Promise<ExecVercelCliResult>; |
+114
| "use strict"; | ||
| var __create = Object.create; | ||
| var __defProp = Object.defineProperty; | ||
| var __getOwnPropDesc = Object.getOwnPropertyDescriptor; | ||
| var __getOwnPropNames = Object.getOwnPropertyNames; | ||
| var __getProtoOf = Object.getPrototypeOf; | ||
| var __hasOwnProp = Object.prototype.hasOwnProperty; | ||
| var __export = (target, all) => { | ||
| for (var name in all) | ||
| __defProp(target, name, { get: all[name], enumerable: true }); | ||
| }; | ||
| var __copyProps = (to, from, except, desc) => { | ||
| if (from && typeof from === "object" || typeof from === "function") { | ||
| for (let key of __getOwnPropNames(from)) | ||
| if (!__hasOwnProp.call(to, key) && key !== except) | ||
| __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); | ||
| } | ||
| return to; | ||
| }; | ||
| var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( | ||
| // If the importer is in node compatibility mode or this is not an ESM | ||
| // file that has been converted to a CommonJS file using a Babel- | ||
| // compatible transform (i.e. "__esModule" has not been set), then set | ||
| // "default" to the CommonJS "module.exports" for node compatibility. | ||
| isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, | ||
| mod | ||
| )); | ||
| var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); | ||
| var exec_exports = {}; | ||
| __export(exec_exports, { | ||
| execVercelCli: () => execVercelCli | ||
| }); | ||
| module.exports = __toCommonJS(exec_exports); | ||
| var import_node_path = __toESM(require("node:path")); | ||
| var import_execa = __toESM(require("execa")); | ||
| var import_envpath = require("./envpath"); | ||
| var import_errors = require("./errors"); | ||
| var import_lookup = require("./lookup"); | ||
| async function execVercelCli(args, options = {}) { | ||
| const cwd = import_node_path.default.resolve(options.cwd ?? process.cwd()); | ||
| await (0, import_errors.assertValidCwd)(cwd); | ||
| const env = mergeExecEnv(options.env); | ||
| const pathValue = (0, import_envpath.getEnvPath)(env); | ||
| try { | ||
| return await execResolvedVercelCli(args, options, cwd, env, pathValue); | ||
| } catch (error) { | ||
| if (error instanceof import_errors.VercelCliError && error.code === "VERCEL_CLI_NOT_FOUND") { | ||
| (0, import_lookup.clearCachedCliInvocation)(cwd, pathValue); | ||
| return await execResolvedVercelCli(args, options, cwd, env, pathValue); | ||
| } | ||
| throw error; | ||
| } | ||
| } | ||
| async function execResolvedVercelCli(args, options, cwd, env, pathValue) { | ||
| const invocation = await resolveInvocationOrThrow(cwd, pathValue); | ||
| try { | ||
| const execaOptions = { | ||
| input: options.input, | ||
| stdio: options.stdio, | ||
| stdin: options.stdin, | ||
| stdout: options.stdout, | ||
| stderr: options.stderr, | ||
| timeout: options.timeout, | ||
| cwd, | ||
| env: await prependLocalBinsToEnvPath(cwd, env), | ||
| windowsHide: true | ||
| }; | ||
| if (options.signal) { | ||
| execaOptions.signal = options.signal; | ||
| } | ||
| const { stdout, stderr } = await (0, import_execa.default)( | ||
| invocation.command, | ||
| [...invocation.commandArgs, ...args], | ||
| execaOptions | ||
| ); | ||
| return { stdout, stderr, invocation }; | ||
| } catch (error) { | ||
| throw (0, import_errors.toVercelCliError)(invocation, error); | ||
| } | ||
| } | ||
| async function resolveInvocationOrThrow(cwd, pathValue) { | ||
| const resolution = await (0, import_lookup.resolveCachedCliInvocation)(cwd, pathValue); | ||
| if (!resolution.found) { | ||
| throw new import_errors.VercelCliError({ | ||
| code: "VERCEL_CLI_NOT_FOUND", | ||
| message: (0, import_errors.getCliNotFoundMessage)(resolution.diagnostics) | ||
| }); | ||
| } | ||
| return (0, import_lookup.toVercelCliInvocation)(resolution); | ||
| } | ||
| function mergeExecEnv(env) { | ||
| if (!env) { | ||
| return process.env; | ||
| } | ||
| return { ...process.env, ...env }; | ||
| } | ||
| async function prependLocalBinsToEnvPath(cwd, env = process.env) { | ||
| const localPath = await prependLocalBinsToPath(cwd, (0, import_envpath.getEnvPath)(env)); | ||
| return (0, import_envpath.setEnvPath)( | ||
| env, | ||
| (0, import_envpath.prependPathEntries)(localPath, [import_node_path.default.dirname(process.execPath)]) | ||
| ); | ||
| } | ||
| async function prependLocalBinsToPath(cwd, pathValue = "") { | ||
| return (0, import_envpath.prependPathEntries)( | ||
| pathValue, | ||
| (await (0, import_lookup.getLocalBinSearch)(cwd)).directories | ||
| ); | ||
| } | ||
| // Annotate the CommonJS export names for ESM import in node: | ||
| 0 && (module.exports = { | ||
| execVercelCli | ||
| }); | ||
| //# sourceMappingURL=exec.js.map |
| { | ||
| "version": 3, | ||
| "sources": ["../src/exec.ts"], | ||
| "sourcesContent": ["import path from 'node:path';\nimport execa from 'execa';\nimport { getEnvPath, prependPathEntries, setEnvPath } from './envpath';\nimport {\n assertValidCwd,\n getCliNotFoundMessage,\n toVercelCliError,\n VercelCliError,\n} from './errors';\nimport {\n clearCachedCliInvocation,\n getLocalBinSearch,\n resolveCachedCliInvocation,\n toVercelCliInvocation,\n} from './lookup';\nimport type {\n ExecVercelCliOptions,\n ExecVercelCliResult,\n VercelCliInvocation,\n} from './types';\n\n/**\n * Execa option subset extended for runtime options missing from its v5 types.\n */\ntype ExecaOptions = execa.Options & {\n signal?: AbortSignal;\n windowsHide?: boolean;\n};\n\n/**\n * Resolves and executes the Vercel CLI with the provided arguments.\n *\n * The execution environment is adjusted so local `node_modules/.bin`\n * directories and the current Node executable remain available even when a\n * caller passes a sanitized `PATH`.\n */\nexport async function execVercelCli(\n args: string[],\n options: ExecVercelCliOptions = {}\n): Promise<ExecVercelCliResult> {\n const cwd = path.resolve(options.cwd ?? process.cwd());\n await assertValidCwd(cwd);\n const env = mergeExecEnv(options.env);\n const pathValue = getEnvPath(env);\n\n try {\n return await execResolvedVercelCli(args, options, cwd, env, pathValue);\n } catch (error) {\n if (\n error instanceof VercelCliError &&\n error.code === 'VERCEL_CLI_NOT_FOUND'\n ) {\n clearCachedCliInvocation(cwd, pathValue);\n return await execResolvedVercelCli(args, options, cwd, env, pathValue);\n }\n\n throw error;\n }\n}\n\n/**\n * Resolves one CLI invocation and executes it once.\n */\nasync function execResolvedVercelCli(\n args: string[],\n options: ExecVercelCliOptions,\n cwd: string,\n env: NodeJS.ProcessEnv,\n pathValue: string\n): Promise<ExecVercelCliResult> {\n const invocation = await resolveInvocationOrThrow(cwd, pathValue);\n\n try {\n const execaOptions: ExecaOptions = {\n input: options.input,\n stdio: options.stdio,\n stdin: options.stdin,\n stdout: options.stdout,\n stderr: options.stderr,\n timeout: options.timeout,\n cwd,\n env: await prependLocalBinsToEnvPath(cwd, env),\n windowsHide: true,\n };\n\n if (options.signal) {\n execaOptions.signal = options.signal;\n }\n\n const { stdout, stderr } = await execa(\n invocation.command,\n [...invocation.commandArgs, ...args],\n execaOptions\n );\n\n return { stdout, stderr, invocation };\n } catch (error) {\n throw toVercelCliError(invocation, error);\n }\n}\n\n/**\n * Resolves the cached CLI invocation or throws with resolution diagnostics.\n */\nasync function resolveInvocationOrThrow(\n cwd: string,\n pathValue: string\n): Promise<VercelCliInvocation> {\n const resolution = await resolveCachedCliInvocation(cwd, pathValue);\n\n if (!resolution.found) {\n throw new VercelCliError({\n code: 'VERCEL_CLI_NOT_FOUND',\n message: getCliNotFoundMessage(resolution.diagnostics),\n });\n }\n\n return toVercelCliInvocation(resolution);\n}\n\n/**\n * Merges a caller-provided environment over the current process environment.\n */\nfunction mergeExecEnv(env?: NodeJS.ProcessEnv): NodeJS.ProcessEnv {\n if (!env) {\n return process.env;\n }\n\n return { ...process.env, ...env };\n}\n\n/**\n * Adds trusted local bins and the current Node executable directory to PATH.\n */\nasync function prependLocalBinsToEnvPath(\n cwd: string,\n env: NodeJS.ProcessEnv = process.env\n): Promise<NodeJS.ProcessEnv> {\n const localPath = await prependLocalBinsToPath(cwd, getEnvPath(env));\n\n return setEnvPath(\n env,\n prependPathEntries(localPath, [path.dirname(process.execPath)])\n );\n}\n\n/**\n * Prepends trusted local bin directories to a PATH value.\n */\nasync function prependLocalBinsToPath(\n cwd: string,\n pathValue = ''\n): Promise<string> {\n return prependPathEntries(\n pathValue,\n (await getLocalBinSearch(cwd)).directories\n );\n}\n"], | ||
| "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,uBAAiB;AACjB,mBAAkB;AAClB,qBAA2D;AAC3D,oBAKO;AACP,oBAKO;AAsBP,eAAsB,cACpB,MACA,UAAgC,CAAC,GACH;AAC9B,QAAM,MAAM,iBAAAA,QAAK,QAAQ,QAAQ,OAAO,QAAQ,IAAI,CAAC;AACrD,YAAM,8BAAe,GAAG;AACxB,QAAM,MAAM,aAAa,QAAQ,GAAG;AACpC,QAAM,gBAAY,2BAAW,GAAG;AAEhC,MAAI;AACF,WAAO,MAAM,sBAAsB,MAAM,SAAS,KAAK,KAAK,SAAS;AAAA,EACvE,SAAS,OAAO;AACd,QACE,iBAAiB,gCACjB,MAAM,SAAS,wBACf;AACA,kDAAyB,KAAK,SAAS;AACvC,aAAO,MAAM,sBAAsB,MAAM,SAAS,KAAK,KAAK,SAAS;AAAA,IACvE;AAEA,UAAM;AAAA,EACR;AACF;AAKA,eAAe,sBACb,MACA,SACA,KACA,KACA,WAC8B;AAC9B,QAAM,aAAa,MAAM,yBAAyB,KAAK,SAAS;AAEhE,MAAI;AACF,UAAM,eAA6B;AAAA,MACjC,OAAO,QAAQ;AAAA,MACf,OAAO,QAAQ;AAAA,MACf,OAAO,QAAQ;AAAA,MACf,QAAQ,QAAQ;AAAA,MAChB,QAAQ,QAAQ;AAAA,MAChB,SAAS,QAAQ;AAAA,MACjB;AAAA,MACA,KAAK,MAAM,0BAA0B,KAAK,GAAG;AAAA,MAC7C,aAAa;AAAA,IACf;AAEA,QAAI,QAAQ,QAAQ;AAClB,mBAAa,SAAS,QAAQ;AAAA,IAChC;AAEA,UAAM,EAAE,QAAQ,OAAO,IAAI,UAAM,aAAAC;AAAA,MAC/B,WAAW;AAAA,MACX,CAAC,GAAG,WAAW,aAAa,GAAG,IAAI;AAAA,MACnC;AAAA,IACF;AAEA,WAAO,EAAE,QAAQ,QAAQ,WAAW;AAAA,EACtC,SAAS,OAAO;AACd,cAAM,gCAAiB,YAAY,KAAK;AAAA,EAC1C;AACF;AAKA,eAAe,yBACb,KACA,WAC8B;AAC9B,QAAM,aAAa,UAAM,0CAA2B,KAAK,SAAS;AAElE,MAAI,CAAC,WAAW,OAAO;AACrB,UAAM,IAAI,6BAAe;AAAA,MACvB,MAAM;AAAA,MACN,aAAS,qCAAsB,WAAW,WAAW;AAAA,IACvD,CAAC;AAAA,EACH;AAEA,aAAO,qCAAsB,UAAU;AACzC;AAKA,SAAS,aAAa,KAA4C;AAChE,MAAI,CAAC,KAAK;AACR,WAAO,QAAQ;AAAA,EACjB;AAEA,SAAO,EAAE,GAAG,QAAQ,KAAK,GAAG,IAAI;AAClC;AAKA,eAAe,0BACb,KACA,MAAyB,QAAQ,KACL;AAC5B,QAAM,YAAY,MAAM,uBAAuB,SAAK,2BAAW,GAAG,CAAC;AAEnE,aAAO;AAAA,IACL;AAAA,QACA,mCAAmB,WAAW,CAAC,iBAAAD,QAAK,QAAQ,QAAQ,QAAQ,CAAC,CAAC;AAAA,EAChE;AACF;AAKA,eAAe,uBACb,KACA,YAAY,IACK;AACjB,aAAO;AAAA,IACL;AAAA,KACC,UAAM,iCAAkB,GAAG,GAAG;AAAA,EACjC;AACF;", | ||
| "names": ["path", "execa"] | ||
| } |
| import type { Stats } from 'node:fs'; | ||
| /** | ||
| * Result of reading filesystem metadata for a path that may not exist. | ||
| */ | ||
| type MaybeStatsResult = { | ||
| stats: Stats; | ||
| } | { | ||
| missing: true; | ||
| } | { | ||
| reason: string; | ||
| }; | ||
| /** | ||
| * Resolves a path through symlinks, falling back to the original path on miss. | ||
| */ | ||
| export declare function getCanonicalPath(filePath: string): Promise<string>; | ||
| /** | ||
| * Returns the inclusive directory chain from `parent` to `child`. | ||
| */ | ||
| export declare function getDirectoriesBetween(parent: string, child: string): string[]; | ||
| /** | ||
| * Reads stat metadata while distinguishing absent paths from inspection errors. | ||
| */ | ||
| export declare function statIfExists(filePath: string): Promise<MaybeStatsResult>; | ||
| /** | ||
| * Returns whether a resolved executable should be invoked through Node. | ||
| */ | ||
| export declare function isNodeScript(filePath: string): boolean; | ||
| /** | ||
| * Returns whether `child` is equal to or nested below `parent`. | ||
| */ | ||
| export declare function isSubpath(parent: string, child: string): boolean; | ||
| /** | ||
| * Strips Windows executable extensions before matching package bin names. | ||
| */ | ||
| export declare function getCommandBase(command: string): string; | ||
| export {}; |
| "use strict"; | ||
| var __create = Object.create; | ||
| var __defProp = Object.defineProperty; | ||
| var __getOwnPropDesc = Object.getOwnPropertyDescriptor; | ||
| var __getOwnPropNames = Object.getOwnPropertyNames; | ||
| var __getProtoOf = Object.getPrototypeOf; | ||
| var __hasOwnProp = Object.prototype.hasOwnProperty; | ||
| var __export = (target, all) => { | ||
| for (var name in all) | ||
| __defProp(target, name, { get: all[name], enumerable: true }); | ||
| }; | ||
| var __copyProps = (to, from, except, desc) => { | ||
| if (from && typeof from === "object" || typeof from === "function") { | ||
| for (let key of __getOwnPropNames(from)) | ||
| if (!__hasOwnProp.call(to, key) && key !== except) | ||
| __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); | ||
| } | ||
| return to; | ||
| }; | ||
| var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( | ||
| // If the importer is in node compatibility mode or this is not an ESM | ||
| // file that has been converted to a CommonJS file using a Babel- | ||
| // compatible transform (i.e. "__esModule" has not been set), then set | ||
| // "default" to the CommonJS "module.exports" for node compatibility. | ||
| isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, | ||
| mod | ||
| )); | ||
| var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); | ||
| var fsutils_exports = {}; | ||
| __export(fsutils_exports, { | ||
| getCanonicalPath: () => getCanonicalPath, | ||
| getCommandBase: () => getCommandBase, | ||
| getDirectoriesBetween: () => getDirectoriesBetween, | ||
| isNodeScript: () => isNodeScript, | ||
| isSubpath: () => isSubpath, | ||
| statIfExists: () => statIfExists | ||
| }); | ||
| module.exports = __toCommonJS(fsutils_exports); | ||
| var import_promises = require("node:fs/promises"); | ||
| var import_node_path = __toESM(require("node:path")); | ||
| var import_errutils = require("./errutils"); | ||
| async function getCanonicalPath(filePath) { | ||
| try { | ||
| return await (0, import_promises.realpath)(filePath); | ||
| } catch { | ||
| return filePath; | ||
| } | ||
| } | ||
| function getDirectoriesBetween(parent, child) { | ||
| const directories = []; | ||
| let current = import_node_path.default.resolve(child); | ||
| const resolvedParent = import_node_path.default.resolve(parent); | ||
| while (true) { | ||
| directories.push(current); | ||
| if (current === resolvedParent) { | ||
| return directories.reverse(); | ||
| } | ||
| const next = import_node_path.default.dirname(current); | ||
| if (next === current) { | ||
| return []; | ||
| } | ||
| current = next; | ||
| } | ||
| } | ||
| async function statIfExists(filePath) { | ||
| try { | ||
| return { stats: await (0, import_promises.stat)(filePath) }; | ||
| } catch (error) { | ||
| if ((0, import_errutils.isMissingPathError)(error)) { | ||
| return { missing: true }; | ||
| } | ||
| return { reason: `could not inspect: ${(0, import_errutils.getErrorMessage)(error)}` }; | ||
| } | ||
| } | ||
| function isNodeScript(filePath) { | ||
| return [".js", ".cjs", ".mjs"].includes(import_node_path.default.extname(filePath)); | ||
| } | ||
| function isSubpath(parent, child) { | ||
| const relativePath = import_node_path.default.relative(parent, child); | ||
| return relativePath === "" || relativePath !== "" && !relativePath.startsWith("..") && !import_node_path.default.isAbsolute(relativePath); | ||
| } | ||
| function getCommandBase(command) { | ||
| const extension = import_node_path.default.extname(command).toLowerCase(); | ||
| if (process.platform === "win32" && [".cmd", ".exe"].includes(extension)) { | ||
| return import_node_path.default.basename(command, extension); | ||
| } | ||
| return import_node_path.default.basename(command); | ||
| } | ||
| // Annotate the CommonJS export names for ESM import in node: | ||
| 0 && (module.exports = { | ||
| getCanonicalPath, | ||
| getCommandBase, | ||
| getDirectoriesBetween, | ||
| isNodeScript, | ||
| isSubpath, | ||
| statIfExists | ||
| }); | ||
| //# sourceMappingURL=fsutils.js.map |
| { | ||
| "version": 3, | ||
| "sources": ["../src/fsutils.ts"], | ||
| "sourcesContent": ["import type { Stats } from 'node:fs';\nimport { realpath, stat } from 'node:fs/promises';\nimport path from 'node:path';\nimport { getErrorMessage, isMissingPathError } from './errutils';\n\n/**\n * Result of reading filesystem metadata for a path that may not exist.\n */\ntype MaybeStatsResult =\n | { stats: Stats }\n | { missing: true }\n | { reason: string };\n\n/**\n * Resolves a path through symlinks, falling back to the original path on miss.\n */\nexport async function getCanonicalPath(filePath: string): Promise<string> {\n try {\n return await realpath(filePath);\n } catch {\n return filePath;\n }\n}\n\n/**\n * Returns the inclusive directory chain from `parent` to `child`.\n */\nexport function getDirectoriesBetween(parent: string, child: string): string[] {\n const directories = [];\n let current = path.resolve(child);\n const resolvedParent = path.resolve(parent);\n\n while (true) {\n directories.push(current);\n\n if (current === resolvedParent) {\n return directories.reverse();\n }\n\n const next = path.dirname(current);\n if (next === current) {\n return [];\n }\n\n current = next;\n }\n}\n\n/**\n * Reads stat metadata while distinguishing absent paths from inspection errors.\n */\nexport async function statIfExists(\n filePath: string\n): Promise<MaybeStatsResult> {\n try {\n return { stats: await stat(filePath) };\n } catch (error) {\n if (isMissingPathError(error)) {\n return { missing: true };\n }\n\n return { reason: `could not inspect: ${getErrorMessage(error)}` };\n }\n}\n\n/**\n * Returns whether a resolved executable should be invoked through Node.\n */\nexport function isNodeScript(filePath: string): boolean {\n return ['.js', '.cjs', '.mjs'].includes(path.extname(filePath));\n}\n\n/**\n * Returns whether `child` is equal to or nested below `parent`.\n */\nexport function isSubpath(parent: string, child: string): boolean {\n const relativePath = path.relative(parent, child);\n\n return (\n relativePath === '' ||\n (relativePath !== '' &&\n !relativePath.startsWith('..') &&\n !path.isAbsolute(relativePath))\n );\n}\n\n/**\n * Strips Windows executable extensions before matching package bin names.\n */\nexport function getCommandBase(command: string): string {\n const extension = path.extname(command).toLowerCase();\n\n if (process.platform === 'win32' && ['.cmd', '.exe'].includes(extension)) {\n return path.basename(command, extension);\n }\n\n return path.basename(command);\n}\n"], | ||
| "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA,sBAA+B;AAC/B,uBAAiB;AACjB,sBAAoD;AAapD,eAAsB,iBAAiB,UAAmC;AACxE,MAAI;AACF,WAAO,UAAM,0BAAS,QAAQ;AAAA,EAChC,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAKO,SAAS,sBAAsB,QAAgB,OAAyB;AAC7E,QAAM,cAAc,CAAC;AACrB,MAAI,UAAU,iBAAAA,QAAK,QAAQ,KAAK;AAChC,QAAM,iBAAiB,iBAAAA,QAAK,QAAQ,MAAM;AAE1C,SAAO,MAAM;AACX,gBAAY,KAAK,OAAO;AAExB,QAAI,YAAY,gBAAgB;AAC9B,aAAO,YAAY,QAAQ;AAAA,IAC7B;AAEA,UAAM,OAAO,iBAAAA,QAAK,QAAQ,OAAO;AACjC,QAAI,SAAS,SAAS;AACpB,aAAO,CAAC;AAAA,IACV;AAEA,cAAU;AAAA,EACZ;AACF;AAKA,eAAsB,aACpB,UAC2B;AAC3B,MAAI;AACF,WAAO,EAAE,OAAO,UAAM,sBAAK,QAAQ,EAAE;AAAA,EACvC,SAAS,OAAO;AACd,YAAI,oCAAmB,KAAK,GAAG;AAC7B,aAAO,EAAE,SAAS,KAAK;AAAA,IACzB;AAEA,WAAO,EAAE,QAAQ,0BAAsB,iCAAgB,KAAK,CAAC,GAAG;AAAA,EAClE;AACF;AAKO,SAAS,aAAa,UAA2B;AACtD,SAAO,CAAC,OAAO,QAAQ,MAAM,EAAE,SAAS,iBAAAA,QAAK,QAAQ,QAAQ,CAAC;AAChE;AAKO,SAAS,UAAU,QAAgB,OAAwB;AAChE,QAAM,eAAe,iBAAAA,QAAK,SAAS,QAAQ,KAAK;AAEhD,SACE,iBAAiB,MAChB,iBAAiB,MAChB,CAAC,aAAa,WAAW,IAAI,KAC7B,CAAC,iBAAAA,QAAK,WAAW,YAAY;AAEnC;AAKO,SAAS,eAAe,SAAyB;AACtD,QAAM,YAAY,iBAAAA,QAAK,QAAQ,OAAO,EAAE,YAAY;AAEpD,MAAI,QAAQ,aAAa,WAAW,CAAC,QAAQ,MAAM,EAAE,SAAS,SAAS,GAAG;AACxE,WAAO,iBAAAA,QAAK,SAAS,SAAS,SAAS;AAAA,EACzC;AAEA,SAAO,iBAAAA,QAAK,SAAS,OAAO;AAC9B;", | ||
| "names": ["path"] | ||
| } |
| import type { LocalBinSearchDiagnostics, ResolutionDiagnostics } from './diagnostics'; | ||
| import type { FindVercelCliOptions, VercelCliInvocation } from './types'; | ||
| /** | ||
| * Successful CLI lookup result with diagnostics preserved for callers upstream. | ||
| */ | ||
| interface ResolvedVercelCliInvocation extends VercelCliInvocation { | ||
| found: true; | ||
| diagnostics: ResolutionDiagnostics; | ||
| } | ||
| /** | ||
| * Trusted local bin directories and the diagnostics collected while finding them. | ||
| */ | ||
| interface LocalBinSearch { | ||
| directories: string[]; | ||
| diagnostics: LocalBinSearchDiagnostics; | ||
| } | ||
| /** | ||
| * Resolves the Vercel CLI from the nearest `node_modules/.bin` directories | ||
| * first, then falls back to the provided `PATH`. | ||
| * | ||
| * Returns `null` when no usable CLI executable can be found. | ||
| */ | ||
| export declare function findVercelCli(options?: FindVercelCliOptions): Promise<VercelCliInvocation | null>; | ||
| /** | ||
| * Resolves and caches the full CLI resolution, including miss diagnostics. | ||
| */ | ||
| export declare function resolveCachedCliInvocation(cwd: string, pathValue: string): Promise<ResolvedVercelCliInvocation | { | ||
| found: false; | ||
| diagnostics: ResolutionDiagnostics; | ||
| }>; | ||
| /** | ||
| * Removes internal resolution diagnostics from a successful CLI lookup result. | ||
| */ | ||
| export declare function toVercelCliInvocation(resolution: ResolvedVercelCliInvocation): VercelCliInvocation; | ||
| /** | ||
| * Clears cached positive and negative CLI resolutions. | ||
| * | ||
| * Call this after installing or removing the CLI in a long-lived process that | ||
| * needs to re-resolve the executable from disk. | ||
| */ | ||
| export declare function clearVercelCliLookupCache(): void; | ||
| /** | ||
| * Clears one cached CLI resolution for retry after a stale executable failed. | ||
| */ | ||
| export declare function clearCachedCliInvocation(cwd: string, pathValue: string): void; | ||
| /** | ||
| * Builds the trusted local `.bin` directories to prepend before scanning PATH. | ||
| * Unsafe ancestor `node_modules` directories are rejected at this discovery | ||
| * phase and kept as diagnostics for not-found errors. | ||
| */ | ||
| export declare function getLocalBinSearch(cwd: string): Promise<LocalBinSearch>; | ||
| export {}; |
+472
| "use strict"; | ||
| var __create = Object.create; | ||
| var __defProp = Object.defineProperty; | ||
| var __getOwnPropDesc = Object.getOwnPropertyDescriptor; | ||
| var __getOwnPropNames = Object.getOwnPropertyNames; | ||
| var __getProtoOf = Object.getPrototypeOf; | ||
| var __hasOwnProp = Object.prototype.hasOwnProperty; | ||
| var __export = (target, all) => { | ||
| for (var name in all) | ||
| __defProp(target, name, { get: all[name], enumerable: true }); | ||
| }; | ||
| var __copyProps = (to, from, except, desc) => { | ||
| if (from && typeof from === "object" || typeof from === "function") { | ||
| for (let key of __getOwnPropNames(from)) | ||
| if (!__hasOwnProp.call(to, key) && key !== except) | ||
| __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); | ||
| } | ||
| return to; | ||
| }; | ||
| var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( | ||
| // If the importer is in node compatibility mode or this is not an ESM | ||
| // file that has been converted to a CommonJS file using a Babel- | ||
| // compatible transform (i.e. "__esModule" has not been set), then set | ||
| // "default" to the CommonJS "module.exports" for node compatibility. | ||
| isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, | ||
| mod | ||
| )); | ||
| var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); | ||
| var lookup_exports = {}; | ||
| __export(lookup_exports, { | ||
| clearCachedCliInvocation: () => clearCachedCliInvocation, | ||
| clearVercelCliLookupCache: () => clearVercelCliLookupCache, | ||
| findVercelCli: () => findVercelCli, | ||
| getLocalBinSearch: () => getLocalBinSearch, | ||
| resolveCachedCliInvocation: () => resolveCachedCliInvocation, | ||
| toVercelCliInvocation: () => toVercelCliInvocation | ||
| }); | ||
| module.exports = __toCommonJS(lookup_exports); | ||
| var import_promises = require("node:fs/promises"); | ||
| var import_node_path = __toESM(require("node:path")); | ||
| var import_envpath = require("./envpath"); | ||
| var import_errutils = require("./errutils"); | ||
| var import_fsutils = require("./fsutils"); | ||
| var import_safety = require("./safety"); | ||
| const cliInvocationCache = /* @__PURE__ */ new Map(); | ||
| async function findVercelCli(options = {}) { | ||
| const cwd = import_node_path.default.resolve(options.cwd ?? process.cwd()); | ||
| const pathValue = options.path ?? (0, import_envpath.getEnvPath)(process.env); | ||
| const resolution = await resolveCachedCliInvocation(cwd, pathValue); | ||
| return resolution.found ? toVercelCliInvocation(resolution) : null; | ||
| } | ||
| function resolveCachedCliInvocation(cwd, pathValue) { | ||
| const cacheKey = getCliInvocationCacheKey(cwd, pathValue); | ||
| if (cliInvocationCache.has(cacheKey)) { | ||
| return cliInvocationCache.get(cacheKey); | ||
| } | ||
| const resolution = resolveCliInvocation(cwd, pathValue).catch((error) => { | ||
| cliInvocationCache.delete(cacheKey); | ||
| throw error; | ||
| }); | ||
| cliInvocationCache.set(cacheKey, resolution); | ||
| return resolution; | ||
| } | ||
| function toVercelCliInvocation(resolution) { | ||
| return { | ||
| command: resolution.command, | ||
| commandArgs: resolution.commandArgs, | ||
| source: resolution.source | ||
| }; | ||
| } | ||
| function clearVercelCliLookupCache() { | ||
| cliInvocationCache.clear(); | ||
| } | ||
| function clearCachedCliInvocation(cwd, pathValue) { | ||
| cliInvocationCache.delete(getCliInvocationCacheKey(cwd, pathValue)); | ||
| } | ||
| async function resolveCliInvocation(cwd, pathValue) { | ||
| const localBinSearch = await getLocalBinSearch(cwd); | ||
| const diagnostics = { | ||
| localBinSearch: localBinSearch.diagnostics, | ||
| skippedLocalBins: [] | ||
| }; | ||
| const resolvedPath = (0, import_envpath.prependPathEntries)( | ||
| pathValue, | ||
| localBinSearch.directories | ||
| ); | ||
| for (const command of getVercelCommandNames()) { | ||
| const resolvedCommand = await findCommandInPath( | ||
| command, | ||
| resolvedPath, | ||
| cwd, | ||
| localBinSearch, | ||
| diagnostics | ||
| ); | ||
| if (!resolvedCommand) { | ||
| continue; | ||
| } | ||
| if ((0, import_fsutils.isNodeScript)(resolvedCommand.realPath)) { | ||
| return { | ||
| found: true, | ||
| command: process.execPath, | ||
| commandArgs: [resolvedCommand.realPath], | ||
| source: resolvedCommand.source, | ||
| diagnostics | ||
| }; | ||
| } | ||
| return { | ||
| found: true, | ||
| command: resolvedCommand.realPath, | ||
| commandArgs: [], | ||
| source: resolvedCommand.source, | ||
| diagnostics | ||
| }; | ||
| } | ||
| return { found: false, diagnostics }; | ||
| } | ||
| async function findCommandInPath(command, pathValue, cwd, localBinSearch, diagnostics) { | ||
| for (const directory of (0, import_envpath.splitPath)(pathValue)) { | ||
| const candidate = getPathCommandCandidate(directory, command, cwd); | ||
| try { | ||
| const canAccess = await canAccessCommandCandidate( | ||
| candidate, | ||
| localBinSearch, | ||
| diagnostics | ||
| ); | ||
| if (canAccess) { | ||
| const resolvedCommand = await resolveCommandCandidate( | ||
| command, | ||
| candidate, | ||
| localBinSearch, | ||
| diagnostics | ||
| ); | ||
| if (resolvedCommand) { | ||
| return resolvedCommand; | ||
| } | ||
| } | ||
| } catch { | ||
| } | ||
| } | ||
| return null; | ||
| } | ||
| function getPathCommandCandidate(directory, command, cwd) { | ||
| const candidateDirectory = import_node_path.default.isAbsolute(directory) ? directory : import_node_path.default.resolve(cwd, directory); | ||
| return import_node_path.default.join(candidateDirectory, command); | ||
| } | ||
| async function canAccessCommandCandidate(candidate, localBinSearch, diagnostics) { | ||
| try { | ||
| await (0, import_promises.access)( | ||
| candidate, | ||
| process.platform === "win32" ? import_promises.constants.F_OK : import_promises.constants.F_OK | import_promises.constants.X_OK | ||
| ); | ||
| return true; | ||
| } catch (error) { | ||
| if (!(0, import_errutils.isMissingPathError)(error)) { | ||
| await recordInaccessibleLocalBinCandidate( | ||
| candidate, | ||
| error, | ||
| localBinSearch, | ||
| diagnostics | ||
| ); | ||
| } | ||
| return false; | ||
| } | ||
| } | ||
| async function recordInaccessibleLocalBinCandidate(candidate, error, localBinSearch, diagnostics) { | ||
| const localBinCandidate = await classifyPathLocalBinCandidate( | ||
| candidate, | ||
| localBinSearch.directories | ||
| ); | ||
| if (!localBinCandidate) { | ||
| return; | ||
| } | ||
| recordSkippedLocalBin( | ||
| diagnostics, | ||
| candidate, | ||
| "reason" in localBinCandidate ? localBinCandidate.reason : `local bin is not accessible: ${(0, import_errutils.getErrorMessage)(error)}` | ||
| ); | ||
| } | ||
| async function resolveCommandCandidate(command, candidate, localBinSearch, diagnostics) { | ||
| if (!(await (0, import_promises.stat)(candidate)).isFile()) { | ||
| return null; | ||
| } | ||
| const realPath = await (0, import_promises.realpath)(candidate); | ||
| const localBinCandidate = await classifyPathLocalBinCandidate( | ||
| candidate, | ||
| localBinSearch.directories | ||
| ); | ||
| if (!localBinCandidate) { | ||
| return { realPath, source: "path" }; | ||
| } | ||
| if ("reason" in localBinCandidate) { | ||
| recordSkippedLocalBin(diagnostics, candidate, localBinCandidate.reason); | ||
| return null; | ||
| } | ||
| const localPackageBinResult = await getLocalVercelPackageBin( | ||
| command, | ||
| localBinCandidate.directory | ||
| ); | ||
| if ("reason" in localPackageBinResult) { | ||
| recordSkippedLocalBin(diagnostics, candidate, localPackageBinResult.reason); | ||
| return null; | ||
| } | ||
| return { realPath: localPackageBinResult.binPath, source: "local-bin" }; | ||
| } | ||
| function recordSkippedLocalBin(diagnostics, candidate, reason) { | ||
| diagnostics.skippedLocalBins.push({ candidate, reason }); | ||
| } | ||
| function getVercelCommandNames() { | ||
| const commandBases = ["vercel"]; | ||
| if (process.platform !== "win32") { | ||
| return commandBases; | ||
| } | ||
| const extensions = [".cmd", ".exe", ""]; | ||
| return commandBases.flatMap( | ||
| (command) => extensions.map((extension) => `${command}${extension}`) | ||
| ); | ||
| } | ||
| async function getLocalBinSearch(cwd) { | ||
| const searchRoot = await (0, import_fsutils.getCanonicalPath)(import_node_path.default.resolve(cwd)); | ||
| const ancestorSearch = await getAncestorDirectorySearch(searchRoot); | ||
| const skippedNodeModules = []; | ||
| const directories = []; | ||
| for (const directory of ancestorSearch.directories) { | ||
| const nodeModulesDirectory = import_node_path.default.join(directory, "node_modules"); | ||
| const parentDirectories = ancestorSearch.stopReason === "project-root-marker" ? (0, import_fsutils.getDirectoriesBetween)(ancestorSearch.stoppedAt, directory) : (0, import_fsutils.getDirectoriesBetween)(directory, searchRoot); | ||
| const skippedReason = await (0, import_safety.getSkippedNodeModulesReason)( | ||
| nodeModulesDirectory, | ||
| parentDirectories | ||
| ); | ||
| if (skippedReason) { | ||
| skippedNodeModules.push({ | ||
| directory: nodeModulesDirectory, | ||
| reason: skippedReason | ||
| }); | ||
| continue; | ||
| } | ||
| directories.push(import_node_path.default.join(nodeModulesDirectory, ".bin")); | ||
| } | ||
| return { | ||
| directories, | ||
| diagnostics: { | ||
| searchRoot, | ||
| stoppedAt: ancestorSearch.stoppedAt, | ||
| stopReason: ancestorSearch.stopReason, | ||
| markerPath: ancestorSearch.markerPath, | ||
| skippedNodeModules | ||
| } | ||
| }; | ||
| } | ||
| async function getAncestorDirectorySearch(cwd) { | ||
| const directories = []; | ||
| let current = import_node_path.default.resolve(cwd); | ||
| while (true) { | ||
| directories.push(current); | ||
| const marker = await getProjectRootMarker(current); | ||
| if (marker) { | ||
| return { | ||
| directories, | ||
| stoppedAt: current, | ||
| stopReason: "project-root-marker", | ||
| markerPath: marker.path | ||
| }; | ||
| } | ||
| const parent = import_node_path.default.dirname(current); | ||
| if (parent === current) { | ||
| return { | ||
| directories, | ||
| stoppedAt: current, | ||
| stopReason: "filesystem-root" | ||
| }; | ||
| } | ||
| current = parent; | ||
| } | ||
| } | ||
| async function getProjectRootMarker(directory) { | ||
| const gitPath = import_node_path.default.join(directory, ".git"); | ||
| try { | ||
| await (0, import_promises.stat)(gitPath); | ||
| return { path: gitPath }; | ||
| } catch { | ||
| } | ||
| return null; | ||
| } | ||
| async function getLocalBinDirectory(filePath, localBinDirectories) { | ||
| const resolvedFilePath = import_node_path.default.resolve(filePath); | ||
| let canonicalFilePath = resolvedFilePath; | ||
| try { | ||
| canonicalFilePath = import_node_path.default.join( | ||
| await (0, import_promises.realpath)(import_node_path.default.dirname(resolvedFilePath)), | ||
| import_node_path.default.basename(resolvedFilePath) | ||
| ); | ||
| } catch { | ||
| } | ||
| for (let localBinDirectory of localBinDirectories) { | ||
| try { | ||
| localBinDirectory = await (0, import_promises.realpath)(localBinDirectory); | ||
| } catch { | ||
| } | ||
| if (canonicalFilePath.startsWith(`${localBinDirectory}${import_node_path.default.sep}`)) { | ||
| return localBinDirectory; | ||
| } | ||
| } | ||
| return null; | ||
| } | ||
| async function getNodeModulesBinDirectory(filePath) { | ||
| const candidateDirectory = import_node_path.default.resolve(import_node_path.default.dirname(filePath)); | ||
| const directories = [candidateDirectory]; | ||
| try { | ||
| const canonicalDirectory = await (0, import_promises.realpath)(candidateDirectory); | ||
| if (!directories.includes(canonicalDirectory)) { | ||
| directories.push(canonicalDirectory); | ||
| } | ||
| } catch { | ||
| } | ||
| for (const directory of directories) { | ||
| if (import_node_path.default.basename(directory) === ".bin" && import_node_path.default.basename(import_node_path.default.dirname(directory)) === "node_modules") { | ||
| return directory; | ||
| } | ||
| } | ||
| return null; | ||
| } | ||
| async function classifyPathLocalBinCandidate(filePath, localBinDirectories) { | ||
| const localBinDirectory = await getLocalBinDirectory( | ||
| filePath, | ||
| localBinDirectories | ||
| ); | ||
| if (localBinDirectory) { | ||
| return { directory: localBinDirectory }; | ||
| } | ||
| const nodeModulesBinDirectory = await getNodeModulesBinDirectory(filePath); | ||
| if (!nodeModulesBinDirectory) { | ||
| return null; | ||
| } | ||
| const nodeModulesDirectory = import_node_path.default.dirname(nodeModulesBinDirectory); | ||
| const skippedReason = await (0, import_safety.getSkippedNodeModulesReason)(nodeModulesDirectory); | ||
| if (skippedReason) { | ||
| return { reason: `local node_modules is ${skippedReason}` }; | ||
| } | ||
| return { reason: "local bin is outside project lookup boundary" }; | ||
| } | ||
| async function getLocalVercelPackageBin(command, localBinDirectory) { | ||
| const commandBase = (0, import_fsutils.getCommandBase)(command); | ||
| const nodeModulesDirectory = import_node_path.default.dirname(localBinDirectory); | ||
| if (commandBase !== "vercel" || import_node_path.default.basename(nodeModulesDirectory) !== "node_modules") { | ||
| return { reason: "not a local vercel bin" }; | ||
| } | ||
| try { | ||
| const localPackage = await getLocalVercelPackage(nodeModulesDirectory); | ||
| if ("reason" in localPackage) { | ||
| return localPackage; | ||
| } | ||
| const packageJsonResult = await readLocalVercelPackageJson( | ||
| localPackage.realPackageDirectory | ||
| ); | ||
| if ("reason" in packageJsonResult) { | ||
| return packageJsonResult; | ||
| } | ||
| localPackage.packageJson = packageJsonResult.packageJson; | ||
| return await getDeclaredLocalVercelPackageBin(localPackage, commandBase); | ||
| } catch (error) { | ||
| return { | ||
| reason: `could not validate local vercel package: ${(0, import_errutils.getErrorMessage)(error)}` | ||
| }; | ||
| } | ||
| } | ||
| async function getLocalVercelPackage(nodeModulesDirectory) { | ||
| const packageDirectory = import_node_path.default.join(nodeModulesDirectory, "vercel"); | ||
| const realNodeModulesDirectory = await (0, import_promises.realpath)(nodeModulesDirectory); | ||
| const realPackageDirectory = await (0, import_promises.realpath)(packageDirectory); | ||
| if (!(0, import_fsutils.isSubpath)(realNodeModulesDirectory, realPackageDirectory)) { | ||
| return { | ||
| reason: "local vercel package resolves outside local node_modules" | ||
| }; | ||
| } | ||
| const unsafePackageDirectoryReason = await (0, import_safety.getUnsafePackageDirectoryReason)( | ||
| realNodeModulesDirectory, | ||
| realPackageDirectory | ||
| ); | ||
| if (unsafePackageDirectoryReason) { | ||
| return { | ||
| reason: `local vercel package is unsafe: ${unsafePackageDirectoryReason}` | ||
| }; | ||
| } | ||
| return { | ||
| realNodeModulesDirectory, | ||
| realPackageDirectory, | ||
| packageJson: {} | ||
| }; | ||
| } | ||
| async function readLocalVercelPackageJson(realPackageDirectory) { | ||
| const packageJsonPath = import_node_path.default.join(realPackageDirectory, "package.json"); | ||
| const realPackageJsonPath = await (0, import_promises.realpath)(packageJsonPath); | ||
| if (!(0, import_fsutils.isSubpath)(realPackageDirectory, realPackageJsonPath)) { | ||
| return { reason: "local vercel package.json resolves outside package" }; | ||
| } | ||
| const unsafePackageJsonReason = await (0, import_safety.getUnsafePackageFileReason)( | ||
| realPackageDirectory, | ||
| realPackageJsonPath | ||
| ); | ||
| if (unsafePackageJsonReason) { | ||
| return { | ||
| reason: `local vercel package.json is unsafe: ${unsafePackageJsonReason}` | ||
| }; | ||
| } | ||
| const packageJson = JSON.parse( | ||
| await (0, import_promises.readFile)(realPackageJsonPath, "utf8") | ||
| ); | ||
| if (packageJson.name !== "vercel") { | ||
| return { | ||
| reason: 'local vercel package.json does not have name "vercel"' | ||
| }; | ||
| } | ||
| return { packageJson }; | ||
| } | ||
| async function getDeclaredLocalVercelPackageBin(localPackage, commandBase) { | ||
| const { packageJson, realNodeModulesDirectory, realPackageDirectory } = localPackage; | ||
| const binTarget = getPackageBinTarget(packageJson, commandBase); | ||
| if (!binTarget) { | ||
| return { reason: "local vercel package does not declare bin.vercel" }; | ||
| } | ||
| const declaredBinPath = import_node_path.default.resolve(realPackageDirectory, binTarget); | ||
| const realDeclaredBinPath = await (0, import_promises.realpath)(declaredBinPath); | ||
| if (!(0, import_fsutils.isSubpath)(realPackageDirectory, realDeclaredBinPath)) { | ||
| return { reason: "local vercel package bin resolves outside package" }; | ||
| } | ||
| const unsafePackageBinReason = await (0, import_safety.getUnsafePackageBinReason)( | ||
| realNodeModulesDirectory, | ||
| realPackageDirectory, | ||
| realDeclaredBinPath | ||
| ); | ||
| if (unsafePackageBinReason) { | ||
| return { | ||
| reason: `local vercel package bin is unsafe: ${unsafePackageBinReason}` | ||
| }; | ||
| } | ||
| if (process.platform !== "win32" && !(0, import_fsutils.isNodeScript)(realDeclaredBinPath)) { | ||
| try { | ||
| await (0, import_promises.access)(realDeclaredBinPath, import_promises.constants.F_OK | import_promises.constants.X_OK); | ||
| } catch (error) { | ||
| return { | ||
| reason: `local vercel package bin is not executable: ${(0, import_errutils.getErrorMessage)(error)}` | ||
| }; | ||
| } | ||
| } | ||
| return { binPath: realDeclaredBinPath }; | ||
| } | ||
| function getPackageBinTarget(packageJson, command) { | ||
| const bin = packageJson.bin; | ||
| if (typeof bin === "string") { | ||
| return command === "vercel" ? bin : null; | ||
| } | ||
| if (bin && typeof bin === "object") { | ||
| const target = bin[command]; | ||
| if (typeof target === "string") { | ||
| return target; | ||
| } | ||
| } | ||
| return null; | ||
| } | ||
| function getCliInvocationCacheKey(cwd, pathValue) { | ||
| return `${cwd}\0${pathValue}`; | ||
| } | ||
| // Annotate the CommonJS export names for ESM import in node: | ||
| 0 && (module.exports = { | ||
| clearCachedCliInvocation, | ||
| clearVercelCliLookupCache, | ||
| findVercelCli, | ||
| getLocalBinSearch, | ||
| resolveCachedCliInvocation, | ||
| toVercelCliInvocation | ||
| }); | ||
| //# sourceMappingURL=lookup.js.map |
| { | ||
| "version": 3, | ||
| "sources": ["../src/lookup.ts"], | ||
| "sourcesContent": ["import { access, constants, readFile, realpath, stat } from 'node:fs/promises';\nimport path from 'node:path';\nimport type {\n LocalBinSearchDiagnostics,\n ResolutionDiagnostics,\n SkippedNodeModules,\n} from './diagnostics';\nimport { getEnvPath, prependPathEntries, splitPath } from './envpath';\nimport { getErrorMessage, isMissingPathError } from './errutils';\nimport {\n getCanonicalPath,\n getCommandBase,\n getDirectoriesBetween,\n isNodeScript,\n isSubpath,\n} from './fsutils';\nimport {\n getSkippedNodeModulesReason,\n getUnsafePackageBinReason,\n getUnsafePackageDirectoryReason,\n getUnsafePackageFileReason,\n} from './safety';\nimport type { FindVercelCliOptions, VercelCliInvocation } from './types';\n\n/**\n * Resolved executable path and source before conversion to invocation args.\n */\ninterface ResolvedCommand {\n realPath: string;\n source: VercelCliInvocation['source'];\n}\n\n/**\n * Internal result of CLI resolution, including successful and missing lookups.\n */\ntype VercelCliResolution = ResolvedVercelCliInvocation | MissingVercelCli;\n\n/**\n * Successful CLI lookup result with diagnostics preserved for callers upstream.\n */\ninterface ResolvedVercelCliInvocation extends VercelCliInvocation {\n found: true;\n diagnostics: ResolutionDiagnostics;\n}\n\n/**\n * Missing CLI lookup result with diagnostics explaining skipped candidates.\n */\ninterface MissingVercelCli {\n found: false;\n diagnostics: ResolutionDiagnostics;\n}\n\n/**\n * Trusted local bin directories and the diagnostics collected while finding them.\n */\ninterface LocalBinSearch {\n directories: string[];\n diagnostics: LocalBinSearchDiagnostics;\n}\n\n/**\n * Ancestor directory walk result and the boundary that stopped traversal.\n */\ninterface AncestorDirectorySearch {\n directories: string[];\n stoppedAt: string;\n stopReason: LocalBinSearchDiagnostics['stopReason'];\n markerPath?: string;\n}\n\n/**\n * Project root marker used to stop local bin traversal.\n */\ninterface ProjectRootMarker {\n path: string;\n}\n\n/**\n * Result of validating the `vercel` package bin declaration.\n */\ntype LocalVercelPackageBinResult = { binPath: string } | { reason: string };\n\n/**\n * Verified local package metadata needed to resolve the declared bin.\n */\ninterface LocalVercelPackage {\n realNodeModulesDirectory: string;\n realPackageDirectory: string;\n packageJson: { name?: unknown; bin?: unknown };\n}\n\n/**\n * Classification for a concrete PATH hit that may be a local bin candidate.\n */\ntype PathLocalBinCandidate = { directory: string } | { reason: string } | null;\n\n// Cache misses too so repeated calls do not keep rescanning PATH in long-lived\n// processes. Callers can clear the cache to force re-resolution after installs.\nconst cliInvocationCache = new Map<string, Promise<VercelCliResolution>>();\n\n/**\n * Resolves the Vercel CLI from the nearest `node_modules/.bin` directories\n * first, then falls back to the provided `PATH`.\n *\n * Returns `null` when no usable CLI executable can be found.\n */\nexport async function findVercelCli(\n options: FindVercelCliOptions = {}\n): Promise<VercelCliInvocation | null> {\n const cwd = path.resolve(options.cwd ?? process.cwd());\n const pathValue = options.path ?? getEnvPath(process.env);\n const resolution = await resolveCachedCliInvocation(cwd, pathValue);\n\n return resolution.found ? toVercelCliInvocation(resolution) : null;\n}\n\n/**\n * Resolves and caches the full CLI resolution, including miss diagnostics.\n */\nexport function resolveCachedCliInvocation(\n cwd: string,\n pathValue: string\n): Promise<\n | ResolvedVercelCliInvocation\n | {\n found: false;\n diagnostics: ResolutionDiagnostics;\n }\n> {\n const cacheKey = getCliInvocationCacheKey(cwd, pathValue);\n\n if (cliInvocationCache.has(cacheKey)) {\n return cliInvocationCache.get(cacheKey)!;\n }\n\n const resolution = resolveCliInvocation(cwd, pathValue).catch(error => {\n cliInvocationCache.delete(cacheKey);\n throw error;\n });\n\n cliInvocationCache.set(cacheKey, resolution);\n return resolution;\n}\n\n/**\n * Removes internal resolution diagnostics from a successful CLI lookup result.\n */\nexport function toVercelCliInvocation(\n resolution: ResolvedVercelCliInvocation\n): VercelCliInvocation {\n return {\n command: resolution.command,\n commandArgs: resolution.commandArgs,\n source: resolution.source,\n };\n}\n\n/**\n * Clears cached positive and negative CLI resolutions.\n *\n * Call this after installing or removing the CLI in a long-lived process that\n * needs to re-resolve the executable from disk.\n */\nexport function clearVercelCliLookupCache() {\n cliInvocationCache.clear();\n}\n\n/**\n * Clears one cached CLI resolution for retry after a stale executable failed.\n */\nexport function clearCachedCliInvocation(cwd: string, pathValue: string) {\n cliInvocationCache.delete(getCliInvocationCacheKey(cwd, pathValue));\n}\n\n/**\n * Resolves the CLI invocation from local bins first, then the provided PATH.\n */\nasync function resolveCliInvocation(\n cwd: string,\n pathValue: string\n): Promise<VercelCliResolution> {\n const localBinSearch = await getLocalBinSearch(cwd);\n const diagnostics: ResolutionDiagnostics = {\n localBinSearch: localBinSearch.diagnostics,\n skippedLocalBins: [],\n };\n const resolvedPath = prependPathEntries(\n pathValue,\n localBinSearch.directories\n );\n\n for (const command of getVercelCommandNames()) {\n const resolvedCommand = await findCommandInPath(\n command,\n resolvedPath,\n cwd,\n localBinSearch,\n diagnostics\n );\n if (!resolvedCommand) {\n continue;\n }\n\n if (isNodeScript(resolvedCommand.realPath)) {\n return {\n found: true,\n command: process.execPath,\n commandArgs: [resolvedCommand.realPath],\n source: resolvedCommand.source,\n diagnostics,\n };\n }\n\n return {\n found: true,\n command: resolvedCommand.realPath,\n commandArgs: [],\n source: resolvedCommand.source,\n diagnostics,\n };\n }\n\n return { found: false, diagnostics };\n}\n\n/**\n * Resolves the first usable command from PATH, validating local bins specially.\n */\nasync function findCommandInPath(\n command: string,\n pathValue: string,\n cwd: string,\n localBinSearch: LocalBinSearch,\n diagnostics: ResolutionDiagnostics\n): Promise<ResolvedCommand | null> {\n for (const directory of splitPath(pathValue)) {\n const candidate = getPathCommandCandidate(directory, command, cwd);\n\n try {\n const canAccess = await canAccessCommandCandidate(\n candidate,\n localBinSearch,\n diagnostics\n );\n\n if (canAccess) {\n const resolvedCommand = await resolveCommandCandidate(\n command,\n candidate,\n localBinSearch,\n diagnostics\n );\n\n if (resolvedCommand) {\n return resolvedCommand;\n }\n }\n } catch {\n // The candidate can change between access, stat, and realpath. Treat it\n // like an unusable PATH entry and keep searching.\n }\n }\n\n return null;\n}\n\n/**\n * Builds an absolute candidate path for one PATH entry and command name.\n */\nfunction getPathCommandCandidate(\n directory: string,\n command: string,\n cwd: string\n): string {\n const candidateDirectory = path.isAbsolute(directory)\n ? directory\n : path.resolve(cwd, directory);\n\n return path.join(candidateDirectory, command);\n}\n\n/**\n * PATH probing treats absent candidates as normal. Permission failures are only\n * useful when they explain why a local project bin was rejected.\n */\nasync function canAccessCommandCandidate(\n candidate: string,\n localBinSearch: LocalBinSearch,\n diagnostics: ResolutionDiagnostics\n): Promise<boolean> {\n try {\n await access(\n candidate,\n process.platform === 'win32'\n ? constants.F_OK\n : constants.F_OK | constants.X_OK\n );\n return true;\n } catch (error) {\n if (!isMissingPathError(error)) {\n await recordInaccessibleLocalBinCandidate(\n candidate,\n error,\n localBinSearch,\n diagnostics\n );\n }\n\n return false;\n }\n}\n\n/**\n * Preserve local-bin access failures as diagnostics. Global PATH entries keep\n * the usual shell lookup behavior and are ignored when they cannot be used.\n */\nasync function recordInaccessibleLocalBinCandidate(\n candidate: string,\n error: unknown,\n localBinSearch: LocalBinSearch,\n diagnostics: ResolutionDiagnostics\n) {\n const localBinCandidate = await classifyPathLocalBinCandidate(\n candidate,\n localBinSearch.directories\n );\n\n if (!localBinCandidate) {\n return;\n }\n\n recordSkippedLocalBin(\n diagnostics,\n candidate,\n 'reason' in localBinCandidate\n ? localBinCandidate.reason\n : `local bin is not accessible: ${getErrorMessage(error)}`\n );\n}\n\n/**\n * Global candidates can be returned directly. Local bins must resolve through\n * the installed `vercel` package so a spoofed shim cannot be invoked.\n */\nasync function resolveCommandCandidate(\n command: string,\n candidate: string,\n localBinSearch: LocalBinSearch,\n diagnostics: ResolutionDiagnostics\n): Promise<ResolvedCommand | null> {\n if (!(await stat(candidate)).isFile()) {\n return null;\n }\n\n const realPath = await realpath(candidate);\n const localBinCandidate = await classifyPathLocalBinCandidate(\n candidate,\n localBinSearch.directories\n );\n\n if (!localBinCandidate) {\n return { realPath, source: 'path' };\n }\n\n if ('reason' in localBinCandidate) {\n recordSkippedLocalBin(diagnostics, candidate, localBinCandidate.reason);\n return null;\n }\n\n const localPackageBinResult = await getLocalVercelPackageBin(\n command,\n localBinCandidate.directory\n );\n\n if ('reason' in localPackageBinResult) {\n recordSkippedLocalBin(diagnostics, candidate, localPackageBinResult.reason);\n return null;\n }\n\n return { realPath: localPackageBinResult.binPath, source: 'local-bin' };\n}\n\n/**\n * Adds a rejected local bin candidate to lookup diagnostics.\n */\nfunction recordSkippedLocalBin(\n diagnostics: ResolutionDiagnostics,\n candidate: string,\n reason: string\n) {\n diagnostics.skippedLocalBins.push({ candidate, reason });\n}\n\n/**\n * Returns platform-specific executable names for the canonical Vercel command.\n */\nfunction getVercelCommandNames(): string[] {\n // Intentionally resolve only the canonical `vercel` binary. `vc` is a\n // convenience alias for interactive use, but callers should not depend on it\n // being present in every installation layout.\n const commandBases = ['vercel'];\n\n if (process.platform !== 'win32') {\n return commandBases;\n }\n\n const extensions = ['.cmd', '.exe', ''];\n return commandBases.flatMap(command =>\n extensions.map(extension => `${command}${extension}`)\n );\n}\n\n/**\n * Builds the trusted local `.bin` directories to prepend before scanning PATH.\n * Unsafe ancestor `node_modules` directories are rejected at this discovery\n * phase and kept as diagnostics for not-found errors.\n */\nexport async function getLocalBinSearch(cwd: string): Promise<LocalBinSearch> {\n const searchRoot = await getCanonicalPath(path.resolve(cwd));\n const ancestorSearch = await getAncestorDirectorySearch(searchRoot);\n const skippedNodeModules: SkippedNodeModules[] = [];\n const directories: string[] = [];\n\n for (const directory of ancestorSearch.directories) {\n const nodeModulesDirectory = path.join(directory, 'node_modules');\n const parentDirectories =\n ancestorSearch.stopReason === 'project-root-marker'\n ? getDirectoriesBetween(ancestorSearch.stoppedAt, directory)\n : getDirectoriesBetween(directory, searchRoot);\n const skippedReason = await getSkippedNodeModulesReason(\n nodeModulesDirectory,\n parentDirectories\n );\n\n if (skippedReason) {\n skippedNodeModules.push({\n directory: nodeModulesDirectory,\n reason: skippedReason,\n });\n continue;\n }\n\n directories.push(path.join(nodeModulesDirectory, '.bin'));\n }\n\n return {\n directories,\n diagnostics: {\n searchRoot,\n stoppedAt: ancestorSearch.stoppedAt,\n stopReason: ancestorSearch.stopReason,\n markerPath: ancestorSearch.markerPath,\n skippedNodeModules,\n },\n };\n}\n\n/**\n * Walks ancestor directories until a project marker or filesystem root is hit.\n */\nasync function getAncestorDirectorySearch(\n cwd: string\n): Promise<AncestorDirectorySearch> {\n const directories = [];\n let current = path.resolve(cwd);\n\n while (true) {\n directories.push(current);\n\n const marker = await getProjectRootMarker(current);\n\n if (marker) {\n return {\n directories,\n stoppedAt: current,\n stopReason: 'project-root-marker',\n markerPath: marker.path,\n };\n }\n\n const parent = path.dirname(current);\n if (parent === current) {\n return {\n directories,\n stoppedAt: current,\n stopReason: 'filesystem-root',\n };\n }\n current = parent;\n }\n}\n\n/**\n * Returns the project root marker used to stop local bin traversal.\n */\nasync function getProjectRootMarker(\n directory: string\n): Promise<ProjectRootMarker | null> {\n const gitPath = path.join(directory, '.git');\n\n try {\n await stat(gitPath);\n return { path: gitPath };\n } catch {}\n\n return null;\n}\n\n/**\n * Returns the trusted local bin directory that contains `filePath`, if any.\n */\nasync function getLocalBinDirectory(\n filePath: string,\n localBinDirectories: string[]\n): Promise<string | null> {\n const resolvedFilePath = path.resolve(filePath);\n let canonicalFilePath = resolvedFilePath;\n\n try {\n canonicalFilePath = path.join(\n await realpath(path.dirname(resolvedFilePath)),\n path.basename(resolvedFilePath)\n );\n } catch {}\n\n for (let localBinDirectory of localBinDirectories) {\n try {\n localBinDirectory = await realpath(localBinDirectory);\n } catch {}\n\n if (canonicalFilePath.startsWith(`${localBinDirectory}${path.sep}`)) {\n return localBinDirectory;\n }\n }\n\n return null;\n}\n\n/**\n * Detects whether `filePath` is located inside a `node_modules/.bin` directory.\n */\nasync function getNodeModulesBinDirectory(\n filePath: string\n): Promise<string | null> {\n const candidateDirectory = path.resolve(path.dirname(filePath));\n const directories = [candidateDirectory];\n\n try {\n const canonicalDirectory = await realpath(candidateDirectory);\n\n if (!directories.includes(canonicalDirectory)) {\n directories.push(canonicalDirectory);\n }\n } catch {}\n\n for (const directory of directories) {\n if (\n path.basename(directory) === '.bin' &&\n path.basename(path.dirname(directory)) === 'node_modules'\n ) {\n return directory;\n }\n }\n\n return null;\n}\n\n/**\n * Classifies a concrete PATH hit after command lookup. This catches local\n * `node_modules/.bin` entries that arrived from the user's PATH instead of the\n * trusted local-bin discovery phase above.\n */\nasync function classifyPathLocalBinCandidate(\n filePath: string,\n localBinDirectories: string[]\n): Promise<PathLocalBinCandidate> {\n const localBinDirectory = await getLocalBinDirectory(\n filePath,\n localBinDirectories\n );\n\n if (localBinDirectory) {\n return { directory: localBinDirectory };\n }\n\n const nodeModulesBinDirectory = await getNodeModulesBinDirectory(filePath);\n\n if (!nodeModulesBinDirectory) {\n return null;\n }\n\n const nodeModulesDirectory = path.dirname(nodeModulesBinDirectory);\n const skippedReason = await getSkippedNodeModulesReason(nodeModulesDirectory);\n\n if (skippedReason) {\n return { reason: `local node_modules is ${skippedReason}` };\n }\n\n return { reason: 'local bin is outside project lookup boundary' };\n}\n\n/**\n * Validates that a local bin resolves to the installed `vercel` package bin.\n */\nasync function getLocalVercelPackageBin(\n command: string,\n localBinDirectory: string\n): Promise<LocalVercelPackageBinResult> {\n const commandBase = getCommandBase(command);\n const nodeModulesDirectory = path.dirname(localBinDirectory);\n\n if (\n commandBase !== 'vercel' ||\n path.basename(nodeModulesDirectory) !== 'node_modules'\n ) {\n return { reason: 'not a local vercel bin' };\n }\n\n try {\n const localPackage = await getLocalVercelPackage(nodeModulesDirectory);\n\n if ('reason' in localPackage) {\n return localPackage;\n }\n\n const packageJsonResult = await readLocalVercelPackageJson(\n localPackage.realPackageDirectory\n );\n\n if ('reason' in packageJsonResult) {\n return packageJsonResult;\n }\n\n localPackage.packageJson = packageJsonResult.packageJson;\n\n return await getDeclaredLocalVercelPackageBin(localPackage, commandBase);\n } catch (error) {\n return {\n reason: `could not validate local vercel package: ${getErrorMessage(error)}`,\n };\n }\n}\n\n/**\n * Resolves and validates the local `vercel` package directory.\n */\nasync function getLocalVercelPackage(\n nodeModulesDirectory: string\n): Promise<LocalVercelPackage | { reason: string }> {\n const packageDirectory = path.join(nodeModulesDirectory, 'vercel');\n const realNodeModulesDirectory = await realpath(nodeModulesDirectory);\n const realPackageDirectory = await realpath(packageDirectory);\n\n if (!isSubpath(realNodeModulesDirectory, realPackageDirectory)) {\n return {\n reason: 'local vercel package resolves outside local node_modules',\n };\n }\n\n const unsafePackageDirectoryReason = await getUnsafePackageDirectoryReason(\n realNodeModulesDirectory,\n realPackageDirectory\n );\n\n if (unsafePackageDirectoryReason) {\n return {\n reason: `local vercel package is unsafe: ${unsafePackageDirectoryReason}`,\n };\n }\n\n return {\n realNodeModulesDirectory,\n realPackageDirectory,\n packageJson: {},\n };\n}\n\n/**\n * Reads and validates the local `vercel` package metadata file.\n */\nasync function readLocalVercelPackageJson(\n realPackageDirectory: string\n): Promise<\n { packageJson: { name?: unknown; bin?: unknown } } | { reason: string }\n> {\n const packageJsonPath = path.join(realPackageDirectory, 'package.json');\n const realPackageJsonPath = await realpath(packageJsonPath);\n\n if (!isSubpath(realPackageDirectory, realPackageJsonPath)) {\n return { reason: 'local vercel package.json resolves outside package' };\n }\n\n const unsafePackageJsonReason = await getUnsafePackageFileReason(\n realPackageDirectory,\n realPackageJsonPath\n );\n\n if (unsafePackageJsonReason) {\n return {\n reason: `local vercel package.json is unsafe: ${unsafePackageJsonReason}`,\n };\n }\n\n const packageJson = JSON.parse(\n await readFile(realPackageJsonPath, 'utf8')\n ) as {\n name?: unknown;\n bin?: unknown;\n };\n\n if (packageJson.name !== 'vercel') {\n return {\n reason: 'local vercel package.json does not have name \"vercel\"',\n };\n }\n\n return { packageJson };\n}\n\n/**\n * Resolves and validates the bin declared by the local `vercel` package.\n */\nasync function getDeclaredLocalVercelPackageBin(\n localPackage: LocalVercelPackage,\n commandBase: string\n): Promise<LocalVercelPackageBinResult> {\n const { packageJson, realNodeModulesDirectory, realPackageDirectory } =\n localPackage;\n\n const binTarget = getPackageBinTarget(packageJson, commandBase);\n\n if (!binTarget) {\n return { reason: 'local vercel package does not declare bin.vercel' };\n }\n\n const declaredBinPath = path.resolve(realPackageDirectory, binTarget);\n const realDeclaredBinPath = await realpath(declaredBinPath);\n\n if (!isSubpath(realPackageDirectory, realDeclaredBinPath)) {\n return { reason: 'local vercel package bin resolves outside package' };\n }\n\n const unsafePackageBinReason = await getUnsafePackageBinReason(\n realNodeModulesDirectory,\n realPackageDirectory,\n realDeclaredBinPath\n );\n\n if (unsafePackageBinReason) {\n return {\n reason: `local vercel package bin is unsafe: ${unsafePackageBinReason}`,\n };\n }\n\n if (process.platform !== 'win32' && !isNodeScript(realDeclaredBinPath)) {\n try {\n await access(realDeclaredBinPath, constants.F_OK | constants.X_OK);\n } catch (error) {\n return {\n reason: `local vercel package bin is not executable: ${getErrorMessage(error)}`,\n };\n }\n }\n\n return { binPath: realDeclaredBinPath };\n}\n\n/**\n * Reads the declared bin target for the requested command from package data.\n */\nfunction getPackageBinTarget(\n packageJson: { bin?: unknown },\n command: string\n): string | null {\n const bin = packageJson.bin;\n\n if (typeof bin === 'string') {\n return command === 'vercel' ? bin : null;\n }\n\n if (bin && typeof bin === 'object') {\n const target = (bin as Record<string, unknown>)[command];\n\n if (typeof target === 'string') {\n return target;\n }\n }\n\n return null;\n}\n\n/**\n * Builds the cache key for a lookup rooted at `cwd` and a PATH value.\n */\nfunction getCliInvocationCacheKey(cwd: string, pathValue: string): string {\n return `${cwd}\\0${pathValue}`;\n}\n"], | ||
| "mappings": "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", | ||
| "names": ["path"] | ||
| } |
| /** | ||
| * Explains why a `node_modules` directory should be skipped, or `null` if safe. | ||
| */ | ||
| export declare function getSkippedNodeModulesReason(nodeModulesDirectory: string, parentDirectories?: string[]): Promise<string | null>; | ||
| /** | ||
| * Validates package and file paths for a declared package bin target. | ||
| */ | ||
| export declare function getUnsafePackageBinReason(nodeModulesDirectory: string, packageDirectory: string, binPath: string): Promise<string | null>; | ||
| /** | ||
| * Validates that each package directory segment is safe and under node_modules. | ||
| */ | ||
| export declare function getUnsafePackageDirectoryReason(nodeModulesDirectory: string, packageDirectory: string): Promise<string | null>; | ||
| /** | ||
| * Validates that package file ancestors and the file itself are safe. | ||
| */ | ||
| export declare function getUnsafePackageFileReason(packageDirectory: string, filePath: string): Promise<string | null>; | ||
| /** | ||
| * Reports unsafe ownership or write permissions for a directory path. | ||
| */ | ||
| export declare function getUnsafeDirectoryReason(directory: string): Promise<string | null>; | ||
| /** | ||
| * Reports unsafe ownership or write permissions from filesystem metadata. | ||
| */ | ||
| export declare function getUnsafeStatsReason(stats: { | ||
| mode: number; | ||
| uid: number; | ||
| }): string | null; |
+172
| "use strict"; | ||
| var __create = Object.create; | ||
| var __defProp = Object.defineProperty; | ||
| var __getOwnPropDesc = Object.getOwnPropertyDescriptor; | ||
| var __getOwnPropNames = Object.getOwnPropertyNames; | ||
| var __getProtoOf = Object.getPrototypeOf; | ||
| var __hasOwnProp = Object.prototype.hasOwnProperty; | ||
| var __export = (target, all) => { | ||
| for (var name in all) | ||
| __defProp(target, name, { get: all[name], enumerable: true }); | ||
| }; | ||
| var __copyProps = (to, from, except, desc) => { | ||
| if (from && typeof from === "object" || typeof from === "function") { | ||
| for (let key of __getOwnPropNames(from)) | ||
| if (!__hasOwnProp.call(to, key) && key !== except) | ||
| __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); | ||
| } | ||
| return to; | ||
| }; | ||
| var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( | ||
| // If the importer is in node compatibility mode or this is not an ESM | ||
| // file that has been converted to a CommonJS file using a Babel- | ||
| // compatible transform (i.e. "__esModule" has not been set), then set | ||
| // "default" to the CommonJS "module.exports" for node compatibility. | ||
| isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, | ||
| mod | ||
| )); | ||
| var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); | ||
| var safety_exports = {}; | ||
| __export(safety_exports, { | ||
| getSkippedNodeModulesReason: () => getSkippedNodeModulesReason, | ||
| getUnsafeDirectoryReason: () => getUnsafeDirectoryReason, | ||
| getUnsafePackageBinReason: () => getUnsafePackageBinReason, | ||
| getUnsafePackageDirectoryReason: () => getUnsafePackageDirectoryReason, | ||
| getUnsafePackageFileReason: () => getUnsafePackageFileReason, | ||
| getUnsafeStatsReason: () => getUnsafeStatsReason | ||
| }); | ||
| module.exports = __toCommonJS(safety_exports); | ||
| var import_promises = require("node:fs/promises"); | ||
| var import_node_path = __toESM(require("node:path")); | ||
| var import_errutils = require("./errutils"); | ||
| var import_fsutils = require("./fsutils"); | ||
| async function getSkippedNodeModulesReason(nodeModulesDirectory, parentDirectories) { | ||
| const parentDirectory = import_node_path.default.dirname(nodeModulesDirectory); | ||
| parentDirectories ??= [parentDirectory]; | ||
| for (const directory of parentDirectories) { | ||
| let unsafeParentReason; | ||
| try { | ||
| unsafeParentReason = await getUnsafeDirectoryReason(directory); | ||
| } catch (error) { | ||
| unsafeParentReason = `could not inspect: ${(0, import_errutils.getErrorMessage)(error)}`; | ||
| } | ||
| if (unsafeParentReason) { | ||
| return `${directory} is ${unsafeParentReason}`; | ||
| } | ||
| } | ||
| const result = await (0, import_fsutils.statIfExists)(nodeModulesDirectory); | ||
| if ("missing" in result) { | ||
| return null; | ||
| } | ||
| if ("reason" in result) { | ||
| return result.reason; | ||
| } | ||
| if (!result.stats.isDirectory()) { | ||
| return "not a directory"; | ||
| } | ||
| const unsafeNodeModulesReason = getUnsafeStatsReason(result.stats); | ||
| if (unsafeNodeModulesReason) { | ||
| return unsafeNodeModulesReason; | ||
| } | ||
| return await getSkippedLocalBinDirectoryReason( | ||
| import_node_path.default.join(nodeModulesDirectory, ".bin") | ||
| ); | ||
| } | ||
| async function getSkippedLocalBinDirectoryReason(localBinDirectory) { | ||
| const result = await (0, import_fsutils.statIfExists)(localBinDirectory); | ||
| if ("missing" in result) { | ||
| return null; | ||
| } | ||
| if ("reason" in result) { | ||
| return `${localBinDirectory} ${result.reason}`; | ||
| } | ||
| if (!result.stats.isDirectory()) { | ||
| return `${localBinDirectory} is not a directory`; | ||
| } | ||
| const unsafeLocalBinReason = getUnsafeStatsReason(result.stats); | ||
| return unsafeLocalBinReason ? `${localBinDirectory} is ${unsafeLocalBinReason}` : null; | ||
| } | ||
| async function getUnsafePackageBinReason(nodeModulesDirectory, packageDirectory, binPath) { | ||
| const unsafePackageDirectoryReason = await getUnsafePackageDirectoryReason( | ||
| nodeModulesDirectory, | ||
| packageDirectory | ||
| ); | ||
| if (unsafePackageDirectoryReason) { | ||
| return unsafePackageDirectoryReason; | ||
| } | ||
| return await getUnsafePackageFileReason(packageDirectory, binPath); | ||
| } | ||
| async function getUnsafePackageDirectoryReason(nodeModulesDirectory, packageDirectory) { | ||
| const directoriesToCheck = (0, import_fsutils.getDirectoriesBetween)( | ||
| nodeModulesDirectory, | ||
| packageDirectory | ||
| ); | ||
| if (directoriesToCheck.length === 0) { | ||
| return `${packageDirectory} resolves outside local node_modules`; | ||
| } | ||
| for (const directory of directoriesToCheck) { | ||
| const reason = await getUnsafeDirectoryReason(directory); | ||
| if (reason) { | ||
| return `${directory} is ${reason}`; | ||
| } | ||
| } | ||
| return null; | ||
| } | ||
| async function getUnsafePackageFileReason(packageDirectory, filePath) { | ||
| const directoriesToCheck = (0, import_fsutils.getDirectoriesBetween)( | ||
| packageDirectory, | ||
| import_node_path.default.dirname(filePath) | ||
| ); | ||
| if (directoriesToCheck.length === 0) { | ||
| return `${filePath} resolves outside package`; | ||
| } | ||
| for (const directory of directoriesToCheck) { | ||
| const reason2 = await getUnsafeDirectoryReason(directory); | ||
| if (reason2) { | ||
| return `${directory} is ${reason2}`; | ||
| } | ||
| } | ||
| const reason = await getUnsafeFileReason(filePath); | ||
| return reason ? `${filePath} is ${reason}` : null; | ||
| } | ||
| async function getUnsafeDirectoryReason(directory) { | ||
| const stats = await (0, import_promises.stat)(directory); | ||
| if (!stats.isDirectory()) { | ||
| return "not a directory"; | ||
| } | ||
| return getUnsafeStatsReason(stats); | ||
| } | ||
| async function getUnsafeFileReason(filePath) { | ||
| const stats = await (0, import_promises.stat)(filePath); | ||
| if (!stats.isFile()) { | ||
| return "not a file"; | ||
| } | ||
| return getUnsafeStatsReason(stats); | ||
| } | ||
| function getUnsafeStatsReason(stats) { | ||
| const getuid = process.geteuid ?? process.getuid; | ||
| if (typeof getuid !== "function") { | ||
| return null; | ||
| } | ||
| const uid = getuid(); | ||
| if ((stats.mode & 18) !== 0) { | ||
| if ((stats.mode & 2) !== 0) { | ||
| return "world-writable"; | ||
| } | ||
| return "group-writable"; | ||
| } | ||
| if (stats.uid !== uid) { | ||
| return `owned by uid ${stats.uid}, current uid is ${uid}`; | ||
| } | ||
| return null; | ||
| } | ||
| // Annotate the CommonJS export names for ESM import in node: | ||
| 0 && (module.exports = { | ||
| getSkippedNodeModulesReason, | ||
| getUnsafeDirectoryReason, | ||
| getUnsafePackageBinReason, | ||
| getUnsafePackageDirectoryReason, | ||
| getUnsafePackageFileReason, | ||
| getUnsafeStatsReason | ||
| }); | ||
| //# sourceMappingURL=safety.js.map |
| { | ||
| "version": 3, | ||
| "sources": ["../src/safety.ts"], | ||
| "sourcesContent": ["import { stat } from 'node:fs/promises';\nimport path from 'node:path';\nimport { getErrorMessage } from './errutils';\nimport { getDirectoriesBetween, statIfExists } from './fsutils';\n\n/**\n * Explains why a `node_modules` directory should be skipped, or `null` if safe.\n */\nexport async function getSkippedNodeModulesReason(\n nodeModulesDirectory: string,\n parentDirectories?: string[]\n): Promise<string | null> {\n const parentDirectory = path.dirname(nodeModulesDirectory);\n parentDirectories ??= [parentDirectory];\n\n for (const directory of parentDirectories) {\n let unsafeParentReason: string | null;\n\n try {\n unsafeParentReason = await getUnsafeDirectoryReason(directory);\n } catch (error) {\n unsafeParentReason = `could not inspect: ${getErrorMessage(error)}`;\n }\n\n if (unsafeParentReason) {\n return `${directory} is ${unsafeParentReason}`;\n }\n }\n\n const result = await statIfExists(nodeModulesDirectory);\n\n if ('missing' in result) {\n return null;\n }\n\n if ('reason' in result) {\n return result.reason;\n }\n\n if (!result.stats.isDirectory()) {\n return 'not a directory';\n }\n\n const unsafeNodeModulesReason = getUnsafeStatsReason(result.stats);\n\n if (unsafeNodeModulesReason) {\n return unsafeNodeModulesReason;\n }\n\n return await getSkippedLocalBinDirectoryReason(\n path.join(nodeModulesDirectory, '.bin')\n );\n}\n\n/**\n * Explains why a `.bin` directory should be skipped, or `null` if safe.\n */\nasync function getSkippedLocalBinDirectoryReason(\n localBinDirectory: string\n): Promise<string | null> {\n const result = await statIfExists(localBinDirectory);\n\n if ('missing' in result) {\n return null;\n }\n\n if ('reason' in result) {\n return `${localBinDirectory} ${result.reason}`;\n }\n\n if (!result.stats.isDirectory()) {\n return `${localBinDirectory} is not a directory`;\n }\n\n const unsafeLocalBinReason = getUnsafeStatsReason(result.stats);\n\n return unsafeLocalBinReason\n ? `${localBinDirectory} is ${unsafeLocalBinReason}`\n : null;\n}\n\n/**\n * Validates package and file paths for a declared package bin target.\n */\nexport async function getUnsafePackageBinReason(\n nodeModulesDirectory: string,\n packageDirectory: string,\n binPath: string\n): Promise<string | null> {\n const unsafePackageDirectoryReason = await getUnsafePackageDirectoryReason(\n nodeModulesDirectory,\n packageDirectory\n );\n\n if (unsafePackageDirectoryReason) {\n return unsafePackageDirectoryReason;\n }\n\n return await getUnsafePackageFileReason(packageDirectory, binPath);\n}\n\n/**\n * Validates that each package directory segment is safe and under node_modules.\n */\nexport async function getUnsafePackageDirectoryReason(\n nodeModulesDirectory: string,\n packageDirectory: string\n): Promise<string | null> {\n const directoriesToCheck = getDirectoriesBetween(\n nodeModulesDirectory,\n packageDirectory\n );\n\n if (directoriesToCheck.length === 0) {\n return `${packageDirectory} resolves outside local node_modules`;\n }\n\n for (const directory of directoriesToCheck) {\n const reason = await getUnsafeDirectoryReason(directory);\n\n if (reason) {\n return `${directory} is ${reason}`;\n }\n }\n\n return null;\n}\n\n/**\n * Validates that package file ancestors and the file itself are safe.\n */\nexport async function getUnsafePackageFileReason(\n packageDirectory: string,\n filePath: string\n): Promise<string | null> {\n const directoriesToCheck = getDirectoriesBetween(\n packageDirectory,\n path.dirname(filePath)\n );\n\n if (directoriesToCheck.length === 0) {\n return `${filePath} resolves outside package`;\n }\n\n for (const directory of directoriesToCheck) {\n const reason = await getUnsafeDirectoryReason(directory);\n\n if (reason) {\n return `${directory} is ${reason}`;\n }\n }\n\n const reason = await getUnsafeFileReason(filePath);\n\n return reason ? `${filePath} is ${reason}` : null;\n}\n\n/**\n * Reports unsafe ownership or write permissions for a directory path.\n */\nexport async function getUnsafeDirectoryReason(\n directory: string\n): Promise<string | null> {\n const stats = await stat(directory);\n\n if (!stats.isDirectory()) {\n return 'not a directory';\n }\n\n return getUnsafeStatsReason(stats);\n}\n\n/**\n * Reports unsafe ownership or write permissions for a file path.\n */\nasync function getUnsafeFileReason(filePath: string): Promise<string | null> {\n const stats = await stat(filePath);\n\n if (!stats.isFile()) {\n return 'not a file';\n }\n\n return getUnsafeStatsReason(stats);\n}\n\n/**\n * Reports unsafe ownership or write permissions from filesystem metadata.\n */\nexport function getUnsafeStatsReason(stats: {\n mode: number;\n uid: number;\n}): string | null {\n const getuid = process.geteuid ?? process.getuid;\n\n if (typeof getuid !== 'function') {\n return null;\n }\n\n const uid = getuid();\n\n if ((stats.mode & 0o022) !== 0) {\n if ((stats.mode & 0o002) !== 0) {\n return 'world-writable';\n }\n\n return 'group-writable';\n }\n\n if (stats.uid !== uid) {\n return `owned by uid ${stats.uid}, current uid is ${uid}`;\n }\n\n return null;\n}\n"], | ||
| "mappings": "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", | ||
| "names": ["path", "reason"] | ||
| } |
| import type execa from 'execa'; | ||
| /** | ||
| * The resolved executable and arguments needed to invoke the Vercel CLI. | ||
| */ | ||
| export interface VercelCliInvocation { | ||
| /** | ||
| * Executable command passed to the child process runner. | ||
| */ | ||
| command: string; | ||
| /** | ||
| * Arguments prepended before caller-provided CLI arguments. | ||
| */ | ||
| commandArgs: string[]; | ||
| /** | ||
| * Where the executable was resolved from. | ||
| */ | ||
| source: 'local-bin' | 'path'; | ||
| } | ||
| /** | ||
| * Options for executing the resolved Vercel CLI. | ||
| */ | ||
| export interface ExecVercelCliOptions extends Pick<execa.Options, 'cwd' | 'env' | 'input' | 'stdio' | 'stdin' | 'stdout' | 'stderr' | 'timeout'> { | ||
| /** | ||
| * Abort signal used to cancel the child process. | ||
| */ | ||
| signal?: AbortSignal; | ||
| } | ||
| /** | ||
| * Captured output and invocation details from a successful CLI execution. | ||
| */ | ||
| export interface ExecVercelCliResult { | ||
| /** | ||
| * Captured standard output when execa is configured to pipe stdout. | ||
| */ | ||
| stdout?: string; | ||
| /** | ||
| * Captured standard error when execa is configured to pipe stderr. | ||
| */ | ||
| stderr?: string; | ||
| /** | ||
| * Resolved command metadata used for the successful invocation. | ||
| */ | ||
| invocation: VercelCliInvocation; | ||
| } | ||
| /** | ||
| * Options for resolving the Vercel CLI without executing it. | ||
| */ | ||
| export interface FindVercelCliOptions { | ||
| /** | ||
| * Directory where local bin lookup starts. Defaults to `process.cwd()`. | ||
| */ | ||
| cwd?: string; | ||
| /** | ||
| * PATH value used after local bin candidates. Defaults to process PATH. | ||
| */ | ||
| path?: string; | ||
| } | ||
| /** | ||
| * Stable error codes produced by {@link VercelCliError}. | ||
| */ | ||
| export type VercelCliErrorCode = 'VERCEL_CLI_INVALID_CWD' | 'VERCEL_CLI_NOT_FOUND' | 'VERCEL_CLI_PERMISSION_DENIED' | 'VERCEL_CLI_ERRORED' | 'VERCEL_CLI_TIMED_OUT' | 'VERCEL_CLI_CANCELED' | 'VERCEL_CLI_SIGNALED' | 'VERCEL_CLI_EXEC_FAILED'; |
| "use strict"; | ||
| var __defProp = Object.defineProperty; | ||
| var __getOwnPropDesc = Object.getOwnPropertyDescriptor; | ||
| var __getOwnPropNames = Object.getOwnPropertyNames; | ||
| var __hasOwnProp = Object.prototype.hasOwnProperty; | ||
| var __copyProps = (to, from, except, desc) => { | ||
| if (from && typeof from === "object" || typeof from === "function") { | ||
| for (let key of __getOwnPropNames(from)) | ||
| if (!__hasOwnProp.call(to, key) && key !== except) | ||
| __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); | ||
| } | ||
| return to; | ||
| }; | ||
| var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); | ||
| var types_exports = {}; | ||
| module.exports = __toCommonJS(types_exports); | ||
| //# sourceMappingURL=types.js.map |
| { | ||
| "version": 3, | ||
| "sources": ["../src/types.ts"], | ||
| "sourcesContent": ["import type execa from 'execa';\n\n/**\n * The resolved executable and arguments needed to invoke the Vercel CLI.\n */\nexport interface VercelCliInvocation {\n /**\n * Executable command passed to the child process runner.\n */\n command: string;\n\n /**\n * Arguments prepended before caller-provided CLI arguments.\n */\n commandArgs: string[];\n\n /**\n * Where the executable was resolved from.\n */\n source: 'local-bin' | 'path';\n}\n\n/**\n * Options for executing the resolved Vercel CLI.\n */\nexport interface ExecVercelCliOptions\n extends Pick<\n execa.Options,\n | 'cwd'\n | 'env'\n | 'input'\n | 'stdio'\n | 'stdin'\n | 'stdout'\n | 'stderr'\n | 'timeout'\n > {\n /**\n * Abort signal used to cancel the child process.\n */\n signal?: AbortSignal;\n}\n\n/**\n * Captured output and invocation details from a successful CLI execution.\n */\nexport interface ExecVercelCliResult {\n /**\n * Captured standard output when execa is configured to pipe stdout.\n */\n stdout?: string;\n\n /**\n * Captured standard error when execa is configured to pipe stderr.\n */\n stderr?: string;\n\n /**\n * Resolved command metadata used for the successful invocation.\n */\n invocation: VercelCliInvocation;\n}\n\n/**\n * Options for resolving the Vercel CLI without executing it.\n */\nexport interface FindVercelCliOptions {\n /**\n * Directory where local bin lookup starts. Defaults to `process.cwd()`.\n */\n cwd?: string;\n\n /**\n * PATH value used after local bin candidates. Defaults to process PATH.\n */\n path?: string;\n}\n\n/**\n * Stable error codes produced by {@link VercelCliError}.\n */\nexport type VercelCliErrorCode =\n | 'VERCEL_CLI_INVALID_CWD'\n | 'VERCEL_CLI_NOT_FOUND'\n | 'VERCEL_CLI_PERMISSION_DENIED'\n | 'VERCEL_CLI_ERRORED'\n | 'VERCEL_CLI_TIMED_OUT'\n | 'VERCEL_CLI_CANCELED'\n | 'VERCEL_CLI_SIGNALED'\n | 'VERCEL_CLI_EXEC_FAILED';\n"], | ||
| "mappings": ";;;;;;;;;;;;;;AAAA;AAAA;", | ||
| "names": [] | ||
| } |
+4
-93
@@ -1,93 +0,4 @@ | ||
| import execa from 'execa'; | ||
| /** | ||
| * The resolved executable and arguments needed to invoke the Vercel CLI. | ||
| */ | ||
| export interface VercelCliInvocation { | ||
| command: string; | ||
| commandArgs: string[]; | ||
| source: 'local-bin' | 'path'; | ||
| } | ||
| /** | ||
| * Options for executing the resolved Vercel CLI. | ||
| */ | ||
| export interface ExecVercelCliOptions extends Pick<execa.Options, 'cwd' | 'env' | 'input' | 'stdio' | 'stdin' | 'stdout' | 'stderr' | 'timeout'> { | ||
| signal?: AbortSignal; | ||
| } | ||
| /** | ||
| * Captured output and invocation details from a successful CLI execution. | ||
| */ | ||
| export interface ExecVercelCliResult { | ||
| stdout?: string; | ||
| stderr?: string; | ||
| invocation: VercelCliInvocation; | ||
| } | ||
| /** | ||
| * Options for resolving the Vercel CLI without executing it. | ||
| */ | ||
| export interface FindVercelCliOptions { | ||
| cwd?: string; | ||
| path?: string; | ||
| } | ||
| /** | ||
| * Stable error codes produced by {@link VercelCliError}. | ||
| */ | ||
| export type VercelCliErrorCode = 'VERCEL_CLI_INVALID_CWD' | 'VERCEL_CLI_NOT_FOUND' | 'VERCEL_CLI_PERMISSION_DENIED' | 'VERCEL_CLI_ERRORED' | 'VERCEL_CLI_TIMED_OUT' | 'VERCEL_CLI_CANCELED' | 'VERCEL_CLI_SIGNALED' | 'VERCEL_CLI_EXEC_FAILED'; | ||
| /** | ||
| * Error returned when CLI resolution or execution fails. | ||
| * | ||
| * `code` is always set. The remaining fields are populated when the failure | ||
| * happened after a CLI invocation was resolved or started. | ||
| */ | ||
| export declare class VercelCliError extends Error { | ||
| /** | ||
| * Stable machine-readable error code. | ||
| */ | ||
| code: VercelCliErrorCode; | ||
| /** | ||
| * Resolved CLI command and arguments, when available. | ||
| */ | ||
| invocation?: VercelCliInvocation; | ||
| /** | ||
| * Captured standard output from the failed process, when available. | ||
| */ | ||
| stdout?: string; | ||
| /** | ||
| * Captured standard error from the failed process, when available. | ||
| */ | ||
| stderr?: string; | ||
| /** | ||
| * Process exit code for non-zero exits, when available. | ||
| */ | ||
| exitCode?: number; | ||
| constructor(options: { | ||
| code: VercelCliErrorCode; | ||
| message: string; | ||
| invocation?: VercelCliInvocation; | ||
| stdout?: string; | ||
| stderr?: string; | ||
| exitCode?: number; | ||
| cause?: unknown; | ||
| }); | ||
| } | ||
| /** | ||
| * Resolves the Vercel CLI from the nearest `node_modules/.bin` directories | ||
| * first, then falls back to the provided `PATH`. | ||
| * | ||
| * Returns `null` when no usable CLI executable can be found. | ||
| */ | ||
| export declare function findVercelCli(options?: FindVercelCliOptions): VercelCliInvocation | null; | ||
| /** | ||
| * Clears cached positive and negative CLI resolutions. | ||
| * | ||
| * Call this after installing or removing the CLI in a long-lived process that | ||
| * needs to re-resolve the executable from disk. | ||
| */ | ||
| export declare function clearVercelCliCache(): void; | ||
| /** | ||
| * Resolves and executes the Vercel CLI with the provided arguments. | ||
| * | ||
| * The execution environment is adjusted so local `node_modules/.bin` | ||
| * directories and the current Node executable remain available even when a | ||
| * caller passes a sanitized `PATH`. | ||
| */ | ||
| export declare function execVercelCli(args: string[], options?: ExecVercelCliOptions): Promise<ExecVercelCliResult>; | ||
| export { VercelCliError } from './errors'; | ||
| export { execVercelCli } from './exec'; | ||
| export { clearVercelCliLookupCache, findVercelCli } from './lookup'; | ||
| export type { ExecVercelCliOptions, ExecVercelCliResult, FindVercelCliOptions, VercelCliErrorCode, VercelCliInvocation, } from './types'; |
+8
-337
| "use strict"; | ||
| var __create = Object.create; | ||
| var __defProp = Object.defineProperty; | ||
| var __getOwnPropDesc = Object.getOwnPropertyDescriptor; | ||
| var __getOwnPropNames = Object.getOwnPropertyNames; | ||
| var __getProtoOf = Object.getPrototypeOf; | ||
| var __hasOwnProp = Object.prototype.hasOwnProperty; | ||
@@ -20,345 +18,18 @@ var __export = (target, all) => { | ||
| }; | ||
| var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( | ||
| // If the importer is in node compatibility mode or this is not an ESM | ||
| // file that has been converted to a CommonJS file using a Babel- | ||
| // compatible transform (i.e. "__esModule" has not been set), then set | ||
| // "default" to the CommonJS "module.exports" for node compatibility. | ||
| isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, | ||
| mod | ||
| )); | ||
| var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); | ||
| var src_exports = {}; | ||
| __export(src_exports, { | ||
| VercelCliError: () => VercelCliError, | ||
| clearVercelCliCache: () => clearVercelCliCache, | ||
| execVercelCli: () => execVercelCli, | ||
| findVercelCli: () => findVercelCli | ||
| VercelCliError: () => import_errors.VercelCliError, | ||
| clearVercelCliLookupCache: () => import_lookup.clearVercelCliLookupCache, | ||
| execVercelCli: () => import_exec.execVercelCli, | ||
| findVercelCli: () => import_lookup.findVercelCli | ||
| }); | ||
| module.exports = __toCommonJS(src_exports); | ||
| var import_node_fs = require("node:fs"); | ||
| var import_node_path = __toESM(require("node:path")); | ||
| var import_execa = __toESM(require("execa")); | ||
| class VercelCliError extends Error { | ||
| constructor(options) { | ||
| super(options.message); | ||
| this.name = "VercelCliError"; | ||
| this.code = options.code; | ||
| this.invocation = options.invocation; | ||
| this.stdout = options.stdout; | ||
| this.stderr = options.stderr; | ||
| this.exitCode = options.exitCode; | ||
| if (options.cause !== void 0) { | ||
| this.cause = options.cause; | ||
| } | ||
| } | ||
| } | ||
| function findVercelCli(options = {}) { | ||
| const cwd = import_node_path.default.resolve(options.cwd ?? process.cwd()); | ||
| const pathValue = options.path ?? getEnvPath(process.env); | ||
| const cacheKey = getCliInvocationCacheKey(cwd, pathValue); | ||
| if (cliInvocationCache.has(cacheKey)) { | ||
| return cliInvocationCache.get(cacheKey) ?? null; | ||
| } | ||
| const invocation = resolveCliInvocation(cwd, pathValue); | ||
| cliInvocationCache.set(cacheKey, invocation); | ||
| return invocation; | ||
| } | ||
| function clearVercelCliCache() { | ||
| cliInvocationCache.clear(); | ||
| } | ||
| async function execVercelCli(args, options = {}) { | ||
| const cwd = import_node_path.default.resolve(options.cwd ?? process.cwd()); | ||
| assertValidCwd(cwd); | ||
| const env = mergeExecEnv(options.env); | ||
| const pathValue = getEnvPath(env); | ||
| const cacheKey = getCliInvocationCacheKey(cwd, pathValue); | ||
| for (let attempt = 0; attempt < 2; attempt++) { | ||
| const invocation = findVercelCli({ cwd, path: pathValue }); | ||
| if (!invocation) { | ||
| throw new VercelCliError({ | ||
| code: "VERCEL_CLI_NOT_FOUND", | ||
| message: "Unable to find a usable Vercel CLI installation." | ||
| }); | ||
| } | ||
| try { | ||
| const execaOptions = { | ||
| input: options.input, | ||
| stdio: options.stdio, | ||
| stdin: options.stdin, | ||
| stdout: options.stdout, | ||
| stderr: options.stderr, | ||
| timeout: options.timeout, | ||
| cwd, | ||
| env: prependLocalBinsToEnvPath(cwd, env), | ||
| windowsHide: true | ||
| }; | ||
| if (options.signal) { | ||
| execaOptions.signal = options.signal; | ||
| } | ||
| const { stdout, stderr } = await (0, import_execa.default)( | ||
| invocation.command, | ||
| [...invocation.commandArgs, ...args], | ||
| execaOptions | ||
| ); | ||
| return { stdout, stderr, invocation }; | ||
| } catch (error) { | ||
| const wrappedError = toVercelCliError(invocation, error); | ||
| if (wrappedError.code === "VERCEL_CLI_NOT_FOUND" && attempt === 0) { | ||
| cliInvocationCache.delete(cacheKey); | ||
| continue; | ||
| } | ||
| throw wrappedError; | ||
| } | ||
| } | ||
| throw new VercelCliError({ | ||
| code: "VERCEL_CLI_NOT_FOUND", | ||
| message: "Unable to find a usable Vercel CLI installation." | ||
| }); | ||
| } | ||
| const cliInvocationCache = /* @__PURE__ */ new Map(); | ||
| function getVercelCommandNames() { | ||
| const commandBases = ["vercel"]; | ||
| if (process.platform !== "win32") { | ||
| return commandBases; | ||
| } | ||
| const extensions = [".cmd", ".exe", ""]; | ||
| return commandBases.flatMap( | ||
| (command) => extensions.map((extension) => `${command}${extension}`) | ||
| ); | ||
| } | ||
| function getAncestorDirectories(cwd) { | ||
| const directories = []; | ||
| let current = import_node_path.default.resolve(cwd); | ||
| while (true) { | ||
| directories.push(current); | ||
| const parent = import_node_path.default.dirname(current); | ||
| if (parent === current) { | ||
| return directories; | ||
| } | ||
| current = parent; | ||
| } | ||
| } | ||
| function getCanonicalPath(filePath) { | ||
| try { | ||
| return (0, import_node_fs.realpathSync)(filePath); | ||
| } catch { | ||
| return filePath; | ||
| } | ||
| } | ||
| function getLocalBinDirectories(cwd) { | ||
| const searchRoot = getCanonicalPath(import_node_path.default.resolve(cwd)); | ||
| return getAncestorDirectories(searchRoot).map( | ||
| (directory) => import_node_path.default.join(directory, "node_modules", ".bin") | ||
| ); | ||
| } | ||
| function isNodeScript(filePath) { | ||
| return [".js", ".cjs", ".mjs"].includes(import_node_path.default.extname(filePath)); | ||
| } | ||
| function splitPath(pathValue) { | ||
| return pathValue.split(import_node_path.default.delimiter).filter(Boolean); | ||
| } | ||
| function getEnvPath(env = process.env) { | ||
| if (process.platform !== "win32") { | ||
| return env.PATH ?? ""; | ||
| } | ||
| const pathKeys = Object.keys(env).filter((key) => key.toLowerCase() === "path"); | ||
| for (let index = pathKeys.length - 1; index >= 0; index--) { | ||
| const value = env[pathKeys[index]]; | ||
| if (value !== void 0) { | ||
| return value; | ||
| } | ||
| } | ||
| return ""; | ||
| } | ||
| function setEnvPath(env = process.env, pathValue) { | ||
| if (process.platform !== "win32") { | ||
| return { | ||
| ...env, | ||
| PATH: pathValue | ||
| }; | ||
| } | ||
| const normalizedEnv = { ...env }; | ||
| for (const key of Object.keys(normalizedEnv)) { | ||
| if (key !== "PATH" && key.toLowerCase() === "path") { | ||
| delete normalizedEnv[key]; | ||
| } | ||
| } | ||
| normalizedEnv.PATH = pathValue; | ||
| return normalizedEnv; | ||
| } | ||
| function mergeExecEnv(env) { | ||
| if (!env) { | ||
| return process.env; | ||
| } | ||
| return { ...process.env, ...env }; | ||
| } | ||
| function findCommandInPath(command, pathValue, cwd) { | ||
| for (const directory of splitPath(pathValue)) { | ||
| const candidateDirectory = import_node_path.default.isAbsolute(directory) ? directory : import_node_path.default.resolve(cwd, directory); | ||
| const candidate = import_node_path.default.join(candidateDirectory, command); | ||
| try { | ||
| (0, import_node_fs.accessSync)( | ||
| candidate, | ||
| process.platform === "win32" ? import_node_fs.constants.F_OK : import_node_fs.constants.F_OK | import_node_fs.constants.X_OK | ||
| ); | ||
| if (!(0, import_node_fs.statSync)(candidate).isFile()) { | ||
| continue; | ||
| } | ||
| return { path: candidate, realPath: (0, import_node_fs.realpathSync)(candidate) }; | ||
| } catch { | ||
| } | ||
| } | ||
| return null; | ||
| } | ||
| function getCliInvocationCacheKey(cwd, pathValue) { | ||
| return `${cwd}\0${pathValue}`; | ||
| } | ||
| function isLocalBinPath(cwd, filePath) { | ||
| const resolvedFilePath = import_node_path.default.resolve(filePath); | ||
| let canonicalFilePath = resolvedFilePath; | ||
| try { | ||
| canonicalFilePath = import_node_path.default.join( | ||
| (0, import_node_fs.realpathSync)(import_node_path.default.dirname(resolvedFilePath)), | ||
| import_node_path.default.basename(resolvedFilePath) | ||
| ); | ||
| } catch { | ||
| } | ||
| return getLocalBinDirectories(cwd).some((localBinDirectory) => { | ||
| try { | ||
| localBinDirectory = (0, import_node_fs.realpathSync)(localBinDirectory); | ||
| } catch { | ||
| } | ||
| return canonicalFilePath.startsWith(`${localBinDirectory}${import_node_path.default.sep}`); | ||
| }); | ||
| } | ||
| function prependLocalBinsToPath(cwd, pathValue = "") { | ||
| return prependPathEntries(pathValue, getLocalBinDirectories(cwd)); | ||
| } | ||
| function prependPathEntries(pathValue, directories) { | ||
| const pathParts = pathValue.split(import_node_path.default.delimiter).filter(Boolean); | ||
| const prepended = []; | ||
| for (const directory of directories) { | ||
| if (!pathParts.includes(directory) && !prepended.includes(directory)) { | ||
| prepended.push(directory); | ||
| } | ||
| } | ||
| if (prepended.length === 0) { | ||
| return pathValue; | ||
| } | ||
| return pathValue === "" || pathValue === import_node_path.default.delimiter ? `${prepended.join(import_node_path.default.delimiter)}${pathValue}` : [...prepended, pathValue].join(import_node_path.default.delimiter); | ||
| } | ||
| function prependLocalBinsToEnvPath(cwd, env = process.env) { | ||
| const localPath = prependLocalBinsToPath(cwd, getEnvPath(env)); | ||
| return setEnvPath( | ||
| env, | ||
| prependPathEntries(localPath, [import_node_path.default.dirname(process.execPath)]) | ||
| ); | ||
| } | ||
| function resolveCliInvocation(cwd, pathValue) { | ||
| const resolvedPath = prependLocalBinsToPath(cwd, pathValue); | ||
| for (const command of getVercelCommandNames()) { | ||
| const resolvedCommand = findCommandInPath(command, resolvedPath, cwd); | ||
| if (!resolvedCommand) { | ||
| continue; | ||
| } | ||
| const source = isLocalBinPath(cwd, resolvedCommand.path) ? "local-bin" : "path"; | ||
| if (isNodeScript(resolvedCommand.realPath)) { | ||
| return { | ||
| command: process.execPath, | ||
| commandArgs: [resolvedCommand.realPath], | ||
| source | ||
| }; | ||
| } | ||
| return { | ||
| command: resolvedCommand.realPath, | ||
| commandArgs: [], | ||
| source | ||
| }; | ||
| } | ||
| return null; | ||
| } | ||
| function assertValidCwd(cwd) { | ||
| try { | ||
| if (!(0, import_node_fs.statSync)(cwd).isDirectory()) { | ||
| throw new Error("not a directory"); | ||
| } | ||
| } catch { | ||
| throw new VercelCliError({ | ||
| code: "VERCEL_CLI_INVALID_CWD", | ||
| message: `Working directory ${JSON.stringify(cwd)} does not exist or is not a directory.` | ||
| }); | ||
| } | ||
| } | ||
| function toVercelCliError(invocation, error) { | ||
| if (typeof error === "object" && error !== null) { | ||
| const execaError = error; | ||
| if (execaError.code === "ENOENT") { | ||
| return new VercelCliError({ | ||
| code: "VERCEL_CLI_NOT_FOUND", | ||
| message: `Unable to find Vercel CLI command ${JSON.stringify(invocation.command)}.`, | ||
| invocation, | ||
| cause: error | ||
| }); | ||
| } | ||
| if (execaError.code === "EACCES" || execaError.code === "EPERM") { | ||
| return new VercelCliError({ | ||
| code: "VERCEL_CLI_PERMISSION_DENIED", | ||
| message: `Permission denied while executing Vercel CLI command ${JSON.stringify(invocation.command)}.`, | ||
| invocation, | ||
| cause: error | ||
| }); | ||
| } | ||
| if (execaError.timedOut) { | ||
| return new VercelCliError({ | ||
| code: "VERCEL_CLI_TIMED_OUT", | ||
| message: `Timed out while executing Vercel CLI command ${JSON.stringify(invocation.command)}.`, | ||
| invocation, | ||
| stdout: execaError.stdout, | ||
| stderr: execaError.stderr, | ||
| cause: error | ||
| }); | ||
| } | ||
| if (execaError.isCanceled) { | ||
| return new VercelCliError({ | ||
| code: "VERCEL_CLI_CANCELED", | ||
| message: `Canceled while executing Vercel CLI command ${JSON.stringify(invocation.command)}.`, | ||
| invocation, | ||
| stdout: execaError.stdout, | ||
| stderr: execaError.stderr, | ||
| cause: error | ||
| }); | ||
| } | ||
| if (execaError.signal) { | ||
| return new VercelCliError({ | ||
| code: "VERCEL_CLI_SIGNALED", | ||
| message: `Vercel CLI command ${JSON.stringify(invocation.command)} exited due to signal ${execaError.signal}.`, | ||
| invocation, | ||
| stdout: execaError.stdout, | ||
| stderr: execaError.stderr, | ||
| cause: error | ||
| }); | ||
| } | ||
| if (typeof execaError.exitCode === "number") { | ||
| return new VercelCliError({ | ||
| code: "VERCEL_CLI_ERRORED", | ||
| message: execaError.shortMessage ?? execaError.message ?? `Vercel CLI command ${JSON.stringify(invocation.command)} exited with code ${execaError.exitCode}.`, | ||
| invocation, | ||
| stdout: execaError.stdout, | ||
| stderr: execaError.stderr, | ||
| exitCode: execaError.exitCode, | ||
| cause: error | ||
| }); | ||
| } | ||
| } | ||
| return new VercelCliError({ | ||
| code: "VERCEL_CLI_EXEC_FAILED", | ||
| message: `Could not execute Vercel CLI command ${JSON.stringify(invocation.command)}.`, | ||
| invocation, | ||
| cause: error | ||
| }); | ||
| } | ||
| var import_errors = require("./errors"); | ||
| var import_exec = require("./exec"); | ||
| var import_lookup = require("./lookup"); | ||
| // Annotate the CommonJS export names for ESM import in node: | ||
| 0 && (module.exports = { | ||
| VercelCliError, | ||
| clearVercelCliCache, | ||
| clearVercelCliLookupCache, | ||
| execVercelCli, | ||
@@ -365,0 +36,0 @@ findVercelCli |
| { | ||
| "version": 3, | ||
| "sources": ["../src/index.ts"], | ||
| "sourcesContent": ["import { accessSync, constants, realpathSync, statSync } from 'node:fs';\nimport path from 'node:path';\nimport execa from 'execa';\n\n/**\n * The resolved executable and arguments needed to invoke the Vercel CLI.\n */\nexport interface VercelCliInvocation {\n command: string;\n commandArgs: string[];\n source: 'local-bin' | 'path';\n}\n\n/**\n * Options for executing the resolved Vercel CLI.\n */\nexport interface ExecVercelCliOptions\n extends Pick<\n execa.Options,\n | 'cwd'\n | 'env'\n | 'input'\n | 'stdio'\n | 'stdin'\n | 'stdout'\n | 'stderr'\n | 'timeout'\n > {\n signal?: AbortSignal;\n}\n\n/**\n * Captured output and invocation details from a successful CLI execution.\n */\nexport interface ExecVercelCliResult {\n stdout?: string;\n stderr?: string;\n invocation: VercelCliInvocation;\n}\n\n/**\n * Options for resolving the Vercel CLI without executing it.\n */\nexport interface FindVercelCliOptions {\n cwd?: string;\n path?: string;\n}\n\n/**\n * Stable error codes produced by {@link VercelCliError}.\n */\nexport type VercelCliErrorCode =\n | 'VERCEL_CLI_INVALID_CWD'\n | 'VERCEL_CLI_NOT_FOUND'\n | 'VERCEL_CLI_PERMISSION_DENIED'\n | 'VERCEL_CLI_ERRORED'\n | 'VERCEL_CLI_TIMED_OUT'\n | 'VERCEL_CLI_CANCELED'\n | 'VERCEL_CLI_SIGNALED'\n | 'VERCEL_CLI_EXEC_FAILED';\n\n/**\n * Error returned when CLI resolution or execution fails.\n *\n * `code` is always set. The remaining fields are populated when the failure\n * happened after a CLI invocation was resolved or started.\n */\nexport class VercelCliError extends Error {\n /**\n * Stable machine-readable error code.\n */\n code: VercelCliErrorCode;\n\n /**\n * Resolved CLI command and arguments, when available.\n */\n invocation?: VercelCliInvocation;\n\n /**\n * Captured standard output from the failed process, when available.\n */\n stdout?: string;\n\n /**\n * Captured standard error from the failed process, when available.\n */\n stderr?: string;\n\n /**\n * Process exit code for non-zero exits, when available.\n */\n exitCode?: number;\n\n constructor(options: {\n code: VercelCliErrorCode;\n message: string;\n invocation?: VercelCliInvocation;\n stdout?: string;\n stderr?: string;\n exitCode?: number;\n cause?: unknown;\n }) {\n super(options.message);\n this.name = 'VercelCliError';\n this.code = options.code;\n this.invocation = options.invocation;\n this.stdout = options.stdout;\n this.stderr = options.stderr;\n this.exitCode = options.exitCode;\n if (options.cause !== undefined) {\n (this as Error & { cause?: unknown }).cause = options.cause;\n }\n }\n}\n\n/**\n * Resolves the Vercel CLI from the nearest `node_modules/.bin` directories\n * first, then falls back to the provided `PATH`.\n *\n * Returns `null` when no usable CLI executable can be found.\n */\nexport function findVercelCli(\n options: FindVercelCliOptions = {}\n): VercelCliInvocation | null {\n const cwd = path.resolve(options.cwd ?? process.cwd());\n const pathValue = options.path ?? getEnvPath(process.env);\n const cacheKey = getCliInvocationCacheKey(cwd, pathValue);\n\n if (cliInvocationCache.has(cacheKey)) {\n return cliInvocationCache.get(cacheKey) ?? null;\n }\n\n const invocation = resolveCliInvocation(cwd, pathValue);\n\n cliInvocationCache.set(cacheKey, invocation);\n return invocation;\n}\n\n/**\n * Clears cached positive and negative CLI resolutions.\n *\n * Call this after installing or removing the CLI in a long-lived process that\n * needs to re-resolve the executable from disk.\n */\nexport function clearVercelCliCache() {\n cliInvocationCache.clear();\n}\n\n/**\n * Resolves and executes the Vercel CLI with the provided arguments.\n *\n * The execution environment is adjusted so local `node_modules/.bin`\n * directories and the current Node executable remain available even when a\n * caller passes a sanitized `PATH`.\n */\nexport async function execVercelCli(\n args: string[],\n options: ExecVercelCliOptions = {}\n): Promise<ExecVercelCliResult> {\n const cwd = path.resolve(options.cwd ?? process.cwd());\n assertValidCwd(cwd);\n const env = mergeExecEnv(options.env);\n const pathValue = getEnvPath(env);\n const cacheKey = getCliInvocationCacheKey(cwd, pathValue);\n\n for (let attempt = 0; attempt < 2; attempt++) {\n const invocation = findVercelCli({ cwd, path: pathValue });\n if (!invocation) {\n throw new VercelCliError({\n code: 'VERCEL_CLI_NOT_FOUND',\n message: 'Unable to find a usable Vercel CLI installation.',\n });\n }\n\n try {\n const execaOptions: ExecaOptions = {\n input: options.input,\n stdio: options.stdio,\n stdin: options.stdin,\n stdout: options.stdout,\n stderr: options.stderr,\n timeout: options.timeout,\n cwd,\n env: prependLocalBinsToEnvPath(cwd, env),\n windowsHide: true,\n };\n\n if (options.signal) {\n execaOptions.signal = options.signal;\n }\n\n const { stdout, stderr } = await execa(\n invocation.command,\n [...invocation.commandArgs, ...args],\n execaOptions\n );\n\n return { stdout, stderr, invocation };\n } catch (error) {\n const wrappedError = toVercelCliError(invocation, error);\n if (wrappedError.code === 'VERCEL_CLI_NOT_FOUND' && attempt === 0) {\n cliInvocationCache.delete(cacheKey);\n continue;\n }\n\n throw wrappedError;\n }\n }\n\n throw new VercelCliError({\n code: 'VERCEL_CLI_NOT_FOUND',\n message: 'Unable to find a usable Vercel CLI installation.',\n });\n}\n\ninterface ResolvedCommand {\n path: string;\n realPath: string;\n}\n\ntype ExecaOptions = execa.Options & {\n signal?: AbortSignal;\n windowsHide?: boolean;\n};\n\n// Cache misses too so repeated calls do not keep rescanning PATH in long-lived\n// processes. Callers can clear the cache to force re-resolution after installs.\nconst cliInvocationCache = new Map<string, VercelCliInvocation | null>();\n\nfunction getVercelCommandNames(): string[] {\n // Intentionally resolve only the canonical `vercel` binary. `vc` is a\n // convenience alias for interactive use, but callers should not depend on it\n // being present in every installation layout.\n const commandBases = ['vercel'];\n\n if (process.platform !== 'win32') {\n return commandBases;\n }\n\n const extensions = ['.cmd', '.exe', ''];\n return commandBases.flatMap(command =>\n extensions.map(extension => `${command}${extension}`)\n );\n}\n\nfunction getAncestorDirectories(cwd: string): string[] {\n const directories = [];\n let current = path.resolve(cwd);\n\n while (true) {\n directories.push(current);\n const parent = path.dirname(current);\n if (parent === current) {\n return directories;\n }\n current = parent;\n }\n}\n\nfunction getCanonicalPath(filePath: string): string {\n try {\n return realpathSync(filePath);\n } catch {\n return filePath;\n }\n}\n\nfunction getLocalBinDirectories(cwd: string): string[] {\n const searchRoot = getCanonicalPath(path.resolve(cwd));\n\n return getAncestorDirectories(searchRoot).map(directory =>\n path.join(directory, 'node_modules', '.bin')\n );\n}\n\nfunction isNodeScript(filePath: string): boolean {\n return ['.js', '.cjs', '.mjs'].includes(path.extname(filePath));\n}\n\nfunction splitPath(pathValue: string): string[] {\n return pathValue.split(path.delimiter).filter(Boolean);\n}\n\nfunction getEnvPath(env: NodeJS.ProcessEnv = process.env): string {\n if (process.platform !== 'win32') {\n return env.PATH ?? '';\n }\n\n const pathKeys = Object.keys(env).filter(key => key.toLowerCase() === 'path');\n\n for (let index = pathKeys.length - 1; index >= 0; index--) {\n const value = env[pathKeys[index]];\n if (value !== undefined) {\n return value;\n }\n }\n\n return '';\n}\n\nfunction setEnvPath(\n env: NodeJS.ProcessEnv = process.env,\n pathValue: string\n): NodeJS.ProcessEnv {\n if (process.platform !== 'win32') {\n return {\n ...env,\n PATH: pathValue,\n };\n }\n\n const normalizedEnv = { ...env };\n\n for (const key of Object.keys(normalizedEnv)) {\n if (key !== 'PATH' && key.toLowerCase() === 'path') {\n delete normalizedEnv[key];\n }\n }\n\n normalizedEnv.PATH = pathValue;\n return normalizedEnv;\n}\n\nfunction mergeExecEnv(env?: NodeJS.ProcessEnv): NodeJS.ProcessEnv {\n if (!env) {\n return process.env;\n }\n\n return { ...process.env, ...env };\n}\n\nfunction findCommandInPath(\n command: string,\n pathValue: string,\n cwd: string\n): ResolvedCommand | null {\n for (const directory of splitPath(pathValue)) {\n const candidateDirectory = path.isAbsolute(directory)\n ? directory\n : path.resolve(cwd, directory);\n const candidate = path.join(candidateDirectory, command);\n try {\n accessSync(\n candidate,\n process.platform === 'win32'\n ? constants.F_OK\n : constants.F_OK | constants.X_OK\n );\n\n if (!statSync(candidate).isFile()) {\n continue;\n }\n\n return { path: candidate, realPath: realpathSync(candidate) };\n } catch {}\n }\n\n return null;\n}\n\nfunction getCliInvocationCacheKey(cwd: string, pathValue: string): string {\n return `${cwd}\\0${pathValue}`;\n}\n\nfunction isLocalBinPath(cwd: string, filePath: string): boolean {\n const resolvedFilePath = path.resolve(filePath);\n let canonicalFilePath = resolvedFilePath;\n\n try {\n canonicalFilePath = path.join(\n realpathSync(path.dirname(resolvedFilePath)),\n path.basename(resolvedFilePath)\n );\n } catch {}\n\n return getLocalBinDirectories(cwd).some(localBinDirectory => {\n try {\n localBinDirectory = realpathSync(localBinDirectory);\n } catch {}\n return canonicalFilePath.startsWith(`${localBinDirectory}${path.sep}`);\n });\n}\n\nfunction prependLocalBinsToPath(cwd: string, pathValue = ''): string {\n return prependPathEntries(pathValue, getLocalBinDirectories(cwd));\n}\n\nfunction prependPathEntries(pathValue: string, directories: string[]): string {\n const pathParts = pathValue.split(path.delimiter).filter(Boolean);\n const prepended: string[] = [];\n\n for (const directory of directories) {\n if (!pathParts.includes(directory) && !prepended.includes(directory)) {\n prepended.push(directory);\n }\n }\n\n if (prepended.length === 0) {\n return pathValue;\n }\n\n return pathValue === '' || pathValue === path.delimiter\n ? `${prepended.join(path.delimiter)}${pathValue}`\n : [...prepended, pathValue].join(path.delimiter);\n}\n\nfunction prependLocalBinsToEnvPath(\n cwd: string,\n env: NodeJS.ProcessEnv = process.env\n): NodeJS.ProcessEnv {\n const localPath = prependLocalBinsToPath(cwd, getEnvPath(env));\n\n return setEnvPath(\n env,\n prependPathEntries(localPath, [path.dirname(process.execPath)])\n );\n}\n\nfunction resolveCliInvocation(\n cwd: string,\n pathValue: string\n): VercelCliInvocation | null {\n const resolvedPath = prependLocalBinsToPath(cwd, pathValue);\n\n for (const command of getVercelCommandNames()) {\n const resolvedCommand = findCommandInPath(command, resolvedPath, cwd);\n if (!resolvedCommand) {\n continue;\n }\n\n const source = isLocalBinPath(cwd, resolvedCommand.path)\n ? 'local-bin'\n : 'path';\n\n if (isNodeScript(resolvedCommand.realPath)) {\n return {\n command: process.execPath,\n commandArgs: [resolvedCommand.realPath],\n source,\n };\n }\n\n return {\n command: resolvedCommand.realPath,\n commandArgs: [],\n source,\n };\n }\n\n return null;\n}\n\nfunction assertValidCwd(cwd: string) {\n try {\n if (!statSync(cwd).isDirectory()) {\n throw new Error('not a directory');\n }\n } catch {\n throw new VercelCliError({\n code: 'VERCEL_CLI_INVALID_CWD',\n message: `Working directory ${JSON.stringify(cwd)} does not exist or is not a directory.`,\n });\n }\n}\n\nfunction toVercelCliError(\n invocation: VercelCliInvocation,\n error: unknown\n): VercelCliError {\n if (typeof error === 'object' && error !== null) {\n const execaError = error as {\n code?: string;\n exitCode?: number;\n timedOut?: boolean;\n isCanceled?: boolean;\n signal?: string | null;\n stdout?: string;\n stderr?: string;\n shortMessage?: string;\n message?: string;\n };\n\n if (execaError.code === 'ENOENT') {\n return new VercelCliError({\n code: 'VERCEL_CLI_NOT_FOUND',\n message: `Unable to find Vercel CLI command ${JSON.stringify(invocation.command)}.`,\n invocation,\n cause: error,\n });\n }\n\n if (execaError.code === 'EACCES' || execaError.code === 'EPERM') {\n return new VercelCliError({\n code: 'VERCEL_CLI_PERMISSION_DENIED',\n message: `Permission denied while executing Vercel CLI command ${JSON.stringify(invocation.command)}.`,\n invocation,\n cause: error,\n });\n }\n\n if (execaError.timedOut) {\n return new VercelCliError({\n code: 'VERCEL_CLI_TIMED_OUT',\n message: `Timed out while executing Vercel CLI command ${JSON.stringify(invocation.command)}.`,\n invocation,\n stdout: execaError.stdout,\n stderr: execaError.stderr,\n cause: error,\n });\n }\n\n if (execaError.isCanceled) {\n return new VercelCliError({\n code: 'VERCEL_CLI_CANCELED',\n message: `Canceled while executing Vercel CLI command ${JSON.stringify(invocation.command)}.`,\n invocation,\n stdout: execaError.stdout,\n stderr: execaError.stderr,\n cause: error,\n });\n }\n\n if (execaError.signal) {\n return new VercelCliError({\n code: 'VERCEL_CLI_SIGNALED',\n message: `Vercel CLI command ${JSON.stringify(invocation.command)} exited due to signal ${execaError.signal}.`,\n invocation,\n stdout: execaError.stdout,\n stderr: execaError.stderr,\n cause: error,\n });\n }\n\n if (typeof execaError.exitCode === 'number') {\n return new VercelCliError({\n code: 'VERCEL_CLI_ERRORED',\n message:\n execaError.shortMessage ??\n execaError.message ??\n `Vercel CLI command ${JSON.stringify(invocation.command)} exited with code ${execaError.exitCode}.`,\n invocation,\n stdout: execaError.stdout,\n stderr: execaError.stderr,\n exitCode: execaError.exitCode,\n cause: error,\n });\n }\n }\n\n return new VercelCliError({\n code: 'VERCEL_CLI_EXEC_FAILED',\n message: `Could not execute Vercel CLI command ${JSON.stringify(invocation.command)}.`,\n invocation,\n cause: error,\n });\n}\n"], | ||
| "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,qBAA8D;AAC9D,uBAAiB;AACjB,mBAAkB;AAiEX,MAAM,uBAAuB,MAAM;AAAA,EA0BxC,YAAY,SAQT;AACD,UAAM,QAAQ,OAAO;AACrB,SAAK,OAAO;AACZ,SAAK,OAAO,QAAQ;AACpB,SAAK,aAAa,QAAQ;AAC1B,SAAK,SAAS,QAAQ;AACtB,SAAK,SAAS,QAAQ;AACtB,SAAK,WAAW,QAAQ;AACxB,QAAI,QAAQ,UAAU,QAAW;AAC/B,MAAC,KAAqC,QAAQ,QAAQ;AAAA,IACxD;AAAA,EACF;AACF;AAQO,SAAS,cACd,UAAgC,CAAC,GACL;AAC5B,QAAM,MAAM,iBAAAA,QAAK,QAAQ,QAAQ,OAAO,QAAQ,IAAI,CAAC;AACrD,QAAM,YAAY,QAAQ,QAAQ,WAAW,QAAQ,GAAG;AACxD,QAAM,WAAW,yBAAyB,KAAK,SAAS;AAExD,MAAI,mBAAmB,IAAI,QAAQ,GAAG;AACpC,WAAO,mBAAmB,IAAI,QAAQ,KAAK;AAAA,EAC7C;AAEA,QAAM,aAAa,qBAAqB,KAAK,SAAS;AAEtD,qBAAmB,IAAI,UAAU,UAAU;AAC3C,SAAO;AACT;AAQO,SAAS,sBAAsB;AACpC,qBAAmB,MAAM;AAC3B;AASA,eAAsB,cACpB,MACA,UAAgC,CAAC,GACH;AAC9B,QAAM,MAAM,iBAAAA,QAAK,QAAQ,QAAQ,OAAO,QAAQ,IAAI,CAAC;AACrD,iBAAe,GAAG;AAClB,QAAM,MAAM,aAAa,QAAQ,GAAG;AACpC,QAAM,YAAY,WAAW,GAAG;AAChC,QAAM,WAAW,yBAAyB,KAAK,SAAS;AAExD,WAAS,UAAU,GAAG,UAAU,GAAG,WAAW;AAC5C,UAAM,aAAa,cAAc,EAAE,KAAK,MAAM,UAAU,CAAC;AACzD,QAAI,CAAC,YAAY;AACf,YAAM,IAAI,eAAe;AAAA,QACvB,MAAM;AAAA,QACN,SAAS;AAAA,MACX,CAAC;AAAA,IACH;AAEA,QAAI;AACF,YAAM,eAA6B;AAAA,QACjC,OAAO,QAAQ;AAAA,QACf,OAAO,QAAQ;AAAA,QACf,OAAO,QAAQ;AAAA,QACf,QAAQ,QAAQ;AAAA,QAChB,QAAQ,QAAQ;AAAA,QAChB,SAAS,QAAQ;AAAA,QACjB;AAAA,QACA,KAAK,0BAA0B,KAAK,GAAG;AAAA,QACvC,aAAa;AAAA,MACf;AAEA,UAAI,QAAQ,QAAQ;AAClB,qBAAa,SAAS,QAAQ;AAAA,MAChC;AAEA,YAAM,EAAE,QAAQ,OAAO,IAAI,UAAM,aAAAC;AAAA,QAC/B,WAAW;AAAA,QACX,CAAC,GAAG,WAAW,aAAa,GAAG,IAAI;AAAA,QACnC;AAAA,MACF;AAEA,aAAO,EAAE,QAAQ,QAAQ,WAAW;AAAA,IACtC,SAAS,OAAO;AACd,YAAM,eAAe,iBAAiB,YAAY,KAAK;AACvD,UAAI,aAAa,SAAS,0BAA0B,YAAY,GAAG;AACjE,2BAAmB,OAAO,QAAQ;AAClC;AAAA,MACF;AAEA,YAAM;AAAA,IACR;AAAA,EACF;AAEA,QAAM,IAAI,eAAe;AAAA,IACvB,MAAM;AAAA,IACN,SAAS;AAAA,EACX,CAAC;AACH;AAcA,MAAM,qBAAqB,oBAAI,IAAwC;AAEvE,SAAS,wBAAkC;AAIzC,QAAM,eAAe,CAAC,QAAQ;AAE9B,MAAI,QAAQ,aAAa,SAAS;AAChC,WAAO;AAAA,EACT;AAEA,QAAM,aAAa,CAAC,QAAQ,QAAQ,EAAE;AACtC,SAAO,aAAa;AAAA,IAAQ,aAC1B,WAAW,IAAI,eAAa,GAAG,OAAO,GAAG,SAAS,EAAE;AAAA,EACtD;AACF;AAEA,SAAS,uBAAuB,KAAuB;AACrD,QAAM,cAAc,CAAC;AACrB,MAAI,UAAU,iBAAAD,QAAK,QAAQ,GAAG;AAE9B,SAAO,MAAM;AACX,gBAAY,KAAK,OAAO;AACxB,UAAM,SAAS,iBAAAA,QAAK,QAAQ,OAAO;AACnC,QAAI,WAAW,SAAS;AACtB,aAAO;AAAA,IACT;AACA,cAAU;AAAA,EACZ;AACF;AAEA,SAAS,iBAAiB,UAA0B;AAClD,MAAI;AACF,eAAO,6BAAa,QAAQ;AAAA,EAC9B,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,SAAS,uBAAuB,KAAuB;AACrD,QAAM,aAAa,iBAAiB,iBAAAA,QAAK,QAAQ,GAAG,CAAC;AAErD,SAAO,uBAAuB,UAAU,EAAE;AAAA,IAAI,eAC5C,iBAAAA,QAAK,KAAK,WAAW,gBAAgB,MAAM;AAAA,EAC7C;AACF;AAEA,SAAS,aAAa,UAA2B;AAC/C,SAAO,CAAC,OAAO,QAAQ,MAAM,EAAE,SAAS,iBAAAA,QAAK,QAAQ,QAAQ,CAAC;AAChE;AAEA,SAAS,UAAU,WAA6B;AAC9C,SAAO,UAAU,MAAM,iBAAAA,QAAK,SAAS,EAAE,OAAO,OAAO;AACvD;AAEA,SAAS,WAAW,MAAyB,QAAQ,KAAa;AAChE,MAAI,QAAQ,aAAa,SAAS;AAChC,WAAO,IAAI,QAAQ;AAAA,EACrB;AAEA,QAAM,WAAW,OAAO,KAAK,GAAG,EAAE,OAAO,SAAO,IAAI,YAAY,MAAM,MAAM;AAE5E,WAAS,QAAQ,SAAS,SAAS,GAAG,SAAS,GAAG,SAAS;AACzD,UAAM,QAAQ,IAAI,SAAS,KAAK,CAAC;AACjC,QAAI,UAAU,QAAW;AACvB,aAAO;AAAA,IACT;AAAA,EACF;AAEA,SAAO;AACT;AAEA,SAAS,WACP,MAAyB,QAAQ,KACjC,WACmB;AACnB,MAAI,QAAQ,aAAa,SAAS;AAChC,WAAO;AAAA,MACL,GAAG;AAAA,MACH,MAAM;AAAA,IACR;AAAA,EACF;AAEA,QAAM,gBAAgB,EAAE,GAAG,IAAI;AAE/B,aAAW,OAAO,OAAO,KAAK,aAAa,GAAG;AAC5C,QAAI,QAAQ,UAAU,IAAI,YAAY,MAAM,QAAQ;AAClD,aAAO,cAAc,GAAG;AAAA,IAC1B;AAAA,EACF;AAEA,gBAAc,OAAO;AACrB,SAAO;AACT;AAEA,SAAS,aAAa,KAA4C;AAChE,MAAI,CAAC,KAAK;AACR,WAAO,QAAQ;AAAA,EACjB;AAEA,SAAO,EAAE,GAAG,QAAQ,KAAK,GAAG,IAAI;AAClC;AAEA,SAAS,kBACP,SACA,WACA,KACwB;AACxB,aAAW,aAAa,UAAU,SAAS,GAAG;AAC5C,UAAM,qBAAqB,iBAAAA,QAAK,WAAW,SAAS,IAChD,YACA,iBAAAA,QAAK,QAAQ,KAAK,SAAS;AAC/B,UAAM,YAAY,iBAAAA,QAAK,KAAK,oBAAoB,OAAO;AACvD,QAAI;AACF;AAAA,QACE;AAAA,QACA,QAAQ,aAAa,UACjB,yBAAU,OACV,yBAAU,OAAO,yBAAU;AAAA,MACjC;AAEA,UAAI,KAAC,yBAAS,SAAS,EAAE,OAAO,GAAG;AACjC;AAAA,MACF;AAEA,aAAO,EAAE,MAAM,WAAW,cAAU,6BAAa,SAAS,EAAE;AAAA,IAC9D,QAAQ;AAAA,IAAC;AAAA,EACX;AAEA,SAAO;AACT;AAEA,SAAS,yBAAyB,KAAa,WAA2B;AACxE,SAAO,GAAG,GAAG,KAAK,SAAS;AAC7B;AAEA,SAAS,eAAe,KAAa,UAA2B;AAC9D,QAAM,mBAAmB,iBAAAA,QAAK,QAAQ,QAAQ;AAC9C,MAAI,oBAAoB;AAExB,MAAI;AACF,wBAAoB,iBAAAA,QAAK;AAAA,UACvB,6BAAa,iBAAAA,QAAK,QAAQ,gBAAgB,CAAC;AAAA,MAC3C,iBAAAA,QAAK,SAAS,gBAAgB;AAAA,IAChC;AAAA,EACF,QAAQ;AAAA,EAAC;AAET,SAAO,uBAAuB,GAAG,EAAE,KAAK,uBAAqB;AAC3D,QAAI;AACF,8BAAoB,6BAAa,iBAAiB;AAAA,IACpD,QAAQ;AAAA,IAAC;AACT,WAAO,kBAAkB,WAAW,GAAG,iBAAiB,GAAG,iBAAAA,QAAK,GAAG,EAAE;AAAA,EACvE,CAAC;AACH;AAEA,SAAS,uBAAuB,KAAa,YAAY,IAAY;AACnE,SAAO,mBAAmB,WAAW,uBAAuB,GAAG,CAAC;AAClE;AAEA,SAAS,mBAAmB,WAAmB,aAA+B;AAC5E,QAAM,YAAY,UAAU,MAAM,iBAAAA,QAAK,SAAS,EAAE,OAAO,OAAO;AAChE,QAAM,YAAsB,CAAC;AAE7B,aAAW,aAAa,aAAa;AACnC,QAAI,CAAC,UAAU,SAAS,SAAS,KAAK,CAAC,UAAU,SAAS,SAAS,GAAG;AACpE,gBAAU,KAAK,SAAS;AAAA,IAC1B;AAAA,EACF;AAEA,MAAI,UAAU,WAAW,GAAG;AAC1B,WAAO;AAAA,EACT;AAEA,SAAO,cAAc,MAAM,cAAc,iBAAAA,QAAK,YAC1C,GAAG,UAAU,KAAK,iBAAAA,QAAK,SAAS,CAAC,GAAG,SAAS,KAC7C,CAAC,GAAG,WAAW,SAAS,EAAE,KAAK,iBAAAA,QAAK,SAAS;AACnD;AAEA,SAAS,0BACP,KACA,MAAyB,QAAQ,KACd;AACnB,QAAM,YAAY,uBAAuB,KAAK,WAAW,GAAG,CAAC;AAE7D,SAAO;AAAA,IACL;AAAA,IACA,mBAAmB,WAAW,CAAC,iBAAAA,QAAK,QAAQ,QAAQ,QAAQ,CAAC,CAAC;AAAA,EAChE;AACF;AAEA,SAAS,qBACP,KACA,WAC4B;AAC5B,QAAM,eAAe,uBAAuB,KAAK,SAAS;AAE1D,aAAW,WAAW,sBAAsB,GAAG;AAC7C,UAAM,kBAAkB,kBAAkB,SAAS,cAAc,GAAG;AACpE,QAAI,CAAC,iBAAiB;AACpB;AAAA,IACF;AAEA,UAAM,SAAS,eAAe,KAAK,gBAAgB,IAAI,IACnD,cACA;AAEJ,QAAI,aAAa,gBAAgB,QAAQ,GAAG;AAC1C,aAAO;AAAA,QACL,SAAS,QAAQ;AAAA,QACjB,aAAa,CAAC,gBAAgB,QAAQ;AAAA,QACtC;AAAA,MACF;AAAA,IACF;AAEA,WAAO;AAAA,MACL,SAAS,gBAAgB;AAAA,MACzB,aAAa,CAAC;AAAA,MACd;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AAEA,SAAS,eAAe,KAAa;AACnC,MAAI;AACF,QAAI,KAAC,yBAAS,GAAG,EAAE,YAAY,GAAG;AAChC,YAAM,IAAI,MAAM,iBAAiB;AAAA,IACnC;AAAA,EACF,QAAQ;AACN,UAAM,IAAI,eAAe;AAAA,MACvB,MAAM;AAAA,MACN,SAAS,qBAAqB,KAAK,UAAU,GAAG,CAAC;AAAA,IACnD,CAAC;AAAA,EACH;AACF;AAEA,SAAS,iBACP,YACA,OACgB;AAChB,MAAI,OAAO,UAAU,YAAY,UAAU,MAAM;AAC/C,UAAM,aAAa;AAYnB,QAAI,WAAW,SAAS,UAAU;AAChC,aAAO,IAAI,eAAe;AAAA,QACxB,MAAM;AAAA,QACN,SAAS,qCAAqC,KAAK,UAAU,WAAW,OAAO,CAAC;AAAA,QAChF;AAAA,QACA,OAAO;AAAA,MACT,CAAC;AAAA,IACH;AAEA,QAAI,WAAW,SAAS,YAAY,WAAW,SAAS,SAAS;AAC/D,aAAO,IAAI,eAAe;AAAA,QACxB,MAAM;AAAA,QACN,SAAS,wDAAwD,KAAK,UAAU,WAAW,OAAO,CAAC;AAAA,QACnG;AAAA,QACA,OAAO;AAAA,MACT,CAAC;AAAA,IACH;AAEA,QAAI,WAAW,UAAU;AACvB,aAAO,IAAI,eAAe;AAAA,QACxB,MAAM;AAAA,QACN,SAAS,gDAAgD,KAAK,UAAU,WAAW,OAAO,CAAC;AAAA,QAC3F;AAAA,QACA,QAAQ,WAAW;AAAA,QACnB,QAAQ,WAAW;AAAA,QACnB,OAAO;AAAA,MACT,CAAC;AAAA,IACH;AAEA,QAAI,WAAW,YAAY;AACzB,aAAO,IAAI,eAAe;AAAA,QACxB,MAAM;AAAA,QACN,SAAS,+CAA+C,KAAK,UAAU,WAAW,OAAO,CAAC;AAAA,QAC1F;AAAA,QACA,QAAQ,WAAW;AAAA,QACnB,QAAQ,WAAW;AAAA,QACnB,OAAO;AAAA,MACT,CAAC;AAAA,IACH;AAEA,QAAI,WAAW,QAAQ;AACrB,aAAO,IAAI,eAAe;AAAA,QACxB,MAAM;AAAA,QACN,SAAS,sBAAsB,KAAK,UAAU,WAAW,OAAO,CAAC,yBAAyB,WAAW,MAAM;AAAA,QAC3G;AAAA,QACA,QAAQ,WAAW;AAAA,QACnB,QAAQ,WAAW;AAAA,QACnB,OAAO;AAAA,MACT,CAAC;AAAA,IACH;AAEA,QAAI,OAAO,WAAW,aAAa,UAAU;AAC3C,aAAO,IAAI,eAAe;AAAA,QACxB,MAAM;AAAA,QACN,SACE,WAAW,gBACX,WAAW,WACX,sBAAsB,KAAK,UAAU,WAAW,OAAO,CAAC,qBAAqB,WAAW,QAAQ;AAAA,QAClG;AAAA,QACA,QAAQ,WAAW;AAAA,QACnB,QAAQ,WAAW;AAAA,QACnB,UAAU,WAAW;AAAA,QACrB,OAAO;AAAA,MACT,CAAC;AAAA,IACH;AAAA,EACF;AAEA,SAAO,IAAI,eAAe;AAAA,IACxB,MAAM;AAAA,IACN,SAAS,wCAAwC,KAAK,UAAU,WAAW,OAAO,CAAC;AAAA,IACnF;AAAA,IACA,OAAO;AAAA,EACT,CAAC;AACH;", | ||
| "names": ["path", "execa"] | ||
| "sourcesContent": ["export { VercelCliError } from './errors';\nexport { execVercelCli } from './exec';\nexport { clearVercelCliLookupCache, findVercelCli } from './lookup';\nexport type {\n ExecVercelCliOptions,\n ExecVercelCliResult,\n FindVercelCliOptions,\n VercelCliErrorCode,\n VercelCliInvocation,\n} from './types';\n"], | ||
| "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,oBAA+B;AAC/B,kBAA8B;AAC9B,oBAAyD;", | ||
| "names": [] | ||
| } |
+1
-1
@@ -15,3 +15,3 @@ { | ||
| }, | ||
| "version": "0.1.1", | ||
| "version": "1.0.0", | ||
| "repository": { | ||
@@ -18,0 +18,0 @@ "directory": "packages/cli-exec", |
+4
-2
@@ -9,4 +9,6 @@ # `@vercel/cli-exec` | ||
| Resolves the Vercel CLI executable without running it. | ||
| Asynchronously resolves the Vercel CLI executable without running it. | ||
| Returns a `Promise<VercelCliInvocation | null>`. | ||
| - Prefers the nearest `node_modules/.bin/vercel` | ||
@@ -27,3 +29,3 @@ - Falls back to the provided `PATH` | ||
| ### `clearVercelCliCache()` | ||
| ### `clearVercelCliLookupCache()` | ||
@@ -30,0 +32,0 @@ Clears cached CLI lookups. Use this when a long-lived process needs to pick up |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
133923
158.83%33
450%1509
228.76%0
-100%55
3.77%1
Infinity%