@sanity/cli-core 1.2.0 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/SanityCommand.js +3 -3
- package/dist/SanityCommand.js.map +1 -1
- package/dist/{index.d.ts → _exports/index.d.ts} +68 -38
- package/dist/_exports/index.js +39 -0
- package/dist/_exports/index.js.map +1 -0
- package/dist/config/findProjectRoot.js +3 -1
- package/dist/config/findProjectRoot.js.map +1 -1
- package/dist/config/findProjectRootSync.js +3 -1
- package/dist/config/findProjectRootSync.js.map +1 -1
- package/dist/config/studio/readStudioConfig.js +3 -1
- package/dist/config/studio/readStudioConfig.js.map +1 -1
- package/dist/exitCodes.js +17 -0
- package/dist/exitCodes.js.map +1 -0
- package/dist/services/cliTokenCache.js +25 -0
- package/dist/services/cliTokenCache.js.map +1 -0
- package/dist/services/cliUserConfig.js +88 -47
- package/dist/services/cliUserConfig.js.map +1 -1
- package/dist/services/getCliToken.js +12 -7
- package/dist/services/getCliToken.js.map +1 -1
- package/dist/telemetry/getCliTelemetry.js.map +1 -0
- package/dist/telemetry/readNDJSON.js.map +1 -0
- package/dist/util/environment/getStudioEnvironmentVariables.js +3 -1
- package/dist/util/environment/getStudioEnvironmentVariables.js.map +1 -1
- package/dist/util/readJsonFileSync.js +26 -0
- package/dist/util/readJsonFileSync.js.map +1 -0
- package/dist/util/resolveLocalPackage.js +6 -2
- package/dist/util/resolveLocalPackage.js.map +1 -1
- package/dist/util/writeJsonFileSync.js +19 -0
- package/dist/util/writeJsonFileSync.js.map +1 -0
- package/package.json +23 -23
- package/dist/index.js +0 -39
- package/dist/index.js.map +0 -1
- package/dist/util/getCliTelemetry.js.map +0 -1
- package/dist/util/getUserConfig.js +0 -15
- package/dist/util/getUserConfig.js.map +0 -1
- package/dist/util/readNDJSON.js.map +0 -1
- package/dist/util/writeJsonFile.js +0 -19
- package/dist/util/writeJsonFile.js.map +0 -1
- /package/dist/{util → telemetry}/getCliTelemetry.js +0 -0
- /package/dist/{util → telemetry}/readNDJSON.js +0 -0
package/dist/SanityCommand.js
CHANGED
|
@@ -5,8 +5,9 @@ import { findProjectRoot } from './config/findProjectRoot.js';
|
|
|
5
5
|
import { subdebug } from './debug.js';
|
|
6
6
|
import { NonInteractiveError } from './errors/NonInteractiveError.js';
|
|
7
7
|
import { ProjectRootNotFoundError } from './errors/ProjectRootNotFoundError.js';
|
|
8
|
+
import { exitCodes } from './exitCodes.js';
|
|
8
9
|
import { getGlobalCliClient, getProjectCliClient } from './services/apiClient.js';
|
|
9
|
-
import { getCliTelemetry, reportCliTraceError } from './
|
|
10
|
+
import { getCliTelemetry, reportCliTraceError } from './telemetry/getCliTelemetry.js';
|
|
10
11
|
import { isInteractive } from './util/isInteractive.js';
|
|
11
12
|
const debug = subdebug('sanityCommand');
|
|
12
13
|
export class SanityCommand extends Command {
|
|
@@ -55,9 +56,8 @@ export class SanityCommand extends Command {
|
|
|
55
56
|
// ExitPromptError is thrown by `@inquirer/prompts` when the user cancels a prompt
|
|
56
57
|
// The `message === 'SIGINT'` check matches oclif's own convention (see handle.js in @oclif/core)
|
|
57
58
|
if (err.name === 'ExitPromptError' || err.message === 'SIGINT') {
|
|
58
|
-
// 130 is the standard exit code for script termination by Ctrl+C
|
|
59
59
|
this.logToStderr(styleText('yellow', '\u{203A}') + ' Aborted by user');
|
|
60
|
-
return this.exit(
|
|
60
|
+
return this.exit(exitCodes.SIGINT);
|
|
61
61
|
}
|
|
62
62
|
// In other cases, we _do_ want to report the error
|
|
63
63
|
reportCliTraceError(err);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/SanityCommand.ts"],"sourcesContent":["import {styleText} from 'node:util'\n\nimport {Command, Interfaces} from '@oclif/core'\nimport {type CommandError} from '@oclif/core/interfaces'\n\nimport {getCliConfig} from './config/cli/getCliConfig.js'\nimport {type CliConfig} from './config/cli/types/cliConfig.js'\nimport {findProjectRoot} from './config/findProjectRoot.js'\nimport {type ProjectRootResult} from './config/util/recursivelyResolveProjectRoot.js'\nimport {subdebug} from './debug.js'\nimport {NonInteractiveError} from './errors/NonInteractiveError.js'\nimport {ProjectRootNotFoundError} from './errors/ProjectRootNotFoundError.js'\nimport {\n getGlobalCliClient,\n getProjectCliClient,\n type GlobalCliClientOptions,\n type ProjectCliClientOptions,\n} from './services/apiClient.js'\nimport {type CLITelemetryStore} from './telemetry/types.js'\nimport {type Output} from './types.js'\nimport {getCliTelemetry, reportCliTraceError} from './util/getCliTelemetry.js'\nimport {isInteractive} from './util/isInteractive.js'\n\ntype Flags<T extends typeof Command> = Interfaces.InferredFlags<\n (typeof SanityCommand)['baseFlags'] & T['flags']\n>\n\ntype Args<T extends typeof Command> = Interfaces.InferredArgs<T['args']>\n\nconst debug = subdebug('sanityCommand')\n\nexport abstract class SanityCommand<T extends typeof Command> extends Command {\n protected args!: Args<T>\n protected flags!: Flags<T>\n\n /**\n * Get the global API client.\n *\n * @param args - The global API client options.\n * @returns The global API client.\n *\n * @deprecated use `getGlobalCliClient` function directly instead.\n */\n protected getGlobalApiClient = (args: GlobalCliClientOptions) => getGlobalCliClient(args)\n\n /**\n * Get the project API client.\n *\n * @param args - The project API client options.\n * @returns The project API client.\n *\n * @deprecated use `getProjectCliClient` function directly instead.\n */\n protected getProjectApiClient = (args: ProjectCliClientOptions) => getProjectCliClient(args)\n\n /**\n * Helper for outputting to the console.\n *\n * @example\n * ```ts\n * this.output.log('Hello')\n * this.output.warn('Warning')\n * this.output.error('Error')\n * ```\n */\n protected output: Output = {\n error: this.error.bind(this),\n log: this.log.bind(this),\n warn: this.warn.bind(this),\n }\n\n /**\n * The telemetry store.\n *\n * @returns The telemetry store.\n */\n protected telemetry!: CLITelemetryStore\n\n /**\n * Report real command errors to the CLI command trace.\n * User aborts (SIGINT, ExitPromptError) are not reported — the trace is left\n * incomplete, which accurately represents that the command was interrupted.\n */\n protected override async catch(err: CommandError): Promise<void> {\n // ExitPromptError is thrown by `@inquirer/prompts` when the user cancels a prompt\n // The `message === 'SIGINT'` check matches oclif's own convention (see handle.js in @oclif/core)\n if (err.name === 'ExitPromptError' || err.message === 'SIGINT') {\n // 130 is the standard exit code for script termination by Ctrl+C\n this.logToStderr(styleText('yellow', '\\u{203A}') + ' Aborted by user')\n return this.exit(130)\n }\n\n // In other cases, we _do_ want to report the error\n reportCliTraceError(err)\n return super.catch(err)\n }\n\n /**\n * Get the CLI config.\n *\n * @returns The CLI config.\n */\n protected async getCliConfig(): Promise<CliConfig> {\n const root = await this.getProjectRoot()\n\n debug(`Using project root`, root)\n return getCliConfig(root.directory)\n }\n\n /**\n * Get the project ID from passed flags or (if not provided) the CLI config.\n *\n * Optionally accepts a `fallback` function that is called when no project ID\n * can be determined from flags or config. This allows commands to provide\n * interactive project selection while keeping the prompt logic in the CLI package.\n *\n * If the fallback throws a `NonInteractiveError` (e.g. because the terminal is\n * not interactive), it falls through to the standard error with suggestions.\n *\n * Optionally accepts a `deprecatedFlagName` for commands that have a deprecated\n * flag (e.g. `--project`) that should be checked after `--project-id` but before\n * the CLI config.\n *\n * @returns The project ID.\n */\n protected async getProjectId(options?: {\n deprecatedFlagName?: string\n fallback?: () => Promise<string>\n }): Promise<string> {\n const hasProjectFlag = this.ctor.flags != null && 'project-id' in this.ctor.flags\n\n // Check --project-id flag first\n if (hasProjectFlag) {\n const flagProjectId =\n 'project-id' in this.flags && typeof this.flags['project-id'] === 'string'\n ? this.flags['project-id']\n : undefined\n\n if (flagProjectId) return flagProjectId\n }\n\n // Check deprecated flag (e.g. --project) before CLI config\n if (options?.deprecatedFlagName) {\n const deprecatedValue =\n options.deprecatedFlagName in this.flags &&\n typeof this.flags[options.deprecatedFlagName] === 'string'\n ? (this.flags[options.deprecatedFlagName] as string)\n : undefined\n\n if (deprecatedValue) return deprecatedValue\n }\n\n // Fall back to CLI config\n try {\n const config = await this.getCliConfig()\n const configProjectId = config.api?.projectId\n if (configProjectId) return configProjectId\n } catch (err) {\n if (!(err instanceof ProjectRootNotFoundError)) throw err\n // No project root — fall through to fallback/error\n }\n\n // Offer interactive selection if a fallback was provided\n if (options?.fallback) {\n try {\n return await options.fallback()\n } catch (err) {\n if (!(err instanceof NonInteractiveError)) throw err\n // Non-interactive: throw with actionable suggestions\n throw new ProjectRootNotFoundError('Unable to determine project ID', {\n cause: err,\n suggestions: [\n ...(hasProjectFlag ? ['Providing a project ID: --project-id <project-id>'] : []),\n 'Running this command from within a Sanity project directory',\n 'Running in an interactive terminal to get a project selection prompt',\n ],\n })\n }\n }\n\n throw new ProjectRootNotFoundError('Unable to determine project ID', {\n suggestions: [\n ...(hasProjectFlag ? ['Providing a project ID: --project-id <project-id>'] : []),\n 'Running this command from within a Sanity project directory',\n ],\n })\n }\n\n /**\n * Get the project's root directory by resolving the config\n *\n * @returns The project root result.\n */\n protected getProjectRoot(): Promise<ProjectRootResult> {\n return findProjectRoot(process.cwd())\n }\n\n public async init(): Promise<void> {\n const {args, flags} = await this.parse({\n args: this.ctor.args,\n baseFlags: (super.ctor as typeof SanityCommand).baseFlags,\n enableJsonFlag: this.ctor.enableJsonFlag,\n flags: this.ctor.flags,\n strict: this.ctor.strict,\n })\n\n this.args = args as Args<T>\n this.flags = flags as Flags<T>\n this.telemetry = getCliTelemetry()\n\n await super.init()\n }\n\n /**\n * Check if the command is running in unattended mode.\n *\n * This means the command should not ask for user input, instead using defaults where\n * possible, and if that does not make sense (eg there's missing information), then we\n * should error out (remember to exit with a non-zero code).\n *\n * Most commands should take an explicit `--yes` flag to enable unattended mode, but\n * some commands may also be run in unattended mode if `process.stdin` is not a TTY\n * (eg when running in a CI environment).\n */\n protected isUnattended(): boolean {\n return this.flags.yes || !this.resolveIsInteractive()\n }\n\n /**\n * Resolver for checking if the terminal is interactive. Override in tests to provide mock values.\n *\n * @returns Whether the terminal is interactive.\n */\n protected resolveIsInteractive(): boolean {\n return isInteractive()\n }\n\n /**\n * Get the CLI config, returning an empty config if no project root is found.\n *\n * Use this instead of `getCliConfig()` in commands that can operate without a\n * project directory (e.g. when `--project-id` and `--dataset` flags are provided).\n *\n * @returns The CLI config, or an empty config object if no project root is found.\n */\n protected async tryGetCliConfig(): Promise<CliConfig> {\n try {\n return await this.getCliConfig()\n } catch (err) {\n if (!(err instanceof ProjectRootNotFoundError)) throw err\n return {}\n }\n }\n}\n"],"names":["styleText","Command","getCliConfig","findProjectRoot","subdebug","NonInteractiveError","ProjectRootNotFoundError","getGlobalCliClient","getProjectCliClient","getCliTelemetry","reportCliTraceError","isInteractive","debug","SanityCommand","args","flags","getGlobalApiClient","getProjectApiClient","output","error","bind","log","warn","telemetry","catch","err","name","message","logToStderr","exit","root","getProjectRoot","directory","getProjectId","options","hasProjectFlag","ctor","flagProjectId","undefined","deprecatedFlagName","deprecatedValue","config","configProjectId","api","projectId","fallback","cause","suggestions","process","cwd","init","parse","baseFlags","enableJsonFlag","strict","isUnattended","yes","resolveIsInteractive","tryGetCliConfig"],"mappings":"AAAA,SAAQA,SAAS,QAAO,YAAW;AAEnC,SAAQC,OAAO,QAAmB,cAAa;AAG/C,SAAQC,YAAY,QAAO,+BAA8B;AAEzD,SAAQC,eAAe,QAAO,8BAA6B;AAE3D,SAAQC,QAAQ,QAAO,aAAY;AACnC,SAAQC,mBAAmB,QAAO,kCAAiC;AACnE,SAAQC,wBAAwB,QAAO,uCAAsC;AAC7E,SACEC,kBAAkB,EAClBC,mBAAmB,QAGd,0BAAyB;AAGhC,SAAQC,eAAe,EAAEC,mBAAmB,QAAO,4BAA2B;AAC9E,SAAQC,aAAa,QAAO,0BAAyB;AAQrD,MAAMC,QAAQR,SAAS;AAEvB,OAAO,MAAeS,sBAAgDZ;IAC1Da,KAAc;IACdC,MAAgB;IAE1B;;;;;;;GAOC,GACD,AAAUC,qBAAqB,CAACF,OAAiCP,mBAAmBO,MAAK;IAEzF;;;;;;;GAOC,GACD,AAAUG,sBAAsB,CAACH,OAAkCN,oBAAoBM,MAAK;IAE5F;;;;;;;;;GASC,GACD,AAAUI,SAAiB;QACzBC,OAAO,IAAI,CAACA,KAAK,CAACC,IAAI,CAAC,IAAI;QAC3BC,KAAK,IAAI,CAACA,GAAG,CAACD,IAAI,CAAC,IAAI;QACvBE,MAAM,IAAI,CAACA,IAAI,CAACF,IAAI,CAAC,IAAI;IAC3B,EAAC;IAED;;;;GAIC,GACD,AAAUG,UAA6B;IAEvC;;;;GAIC,GACD,MAAyBC,MAAMC,GAAiB,EAAiB;QAC/D,kFAAkF;QAClF,iGAAiG;QACjG,IAAIA,IAAIC,IAAI,KAAK,qBAAqBD,IAAIE,OAAO,KAAK,UAAU;YAC9D,iEAAiE;YACjE,IAAI,CAACC,WAAW,CAAC5B,UAAU,UAAU,cAAc;YACnD,OAAO,IAAI,CAAC6B,IAAI,CAAC;QACnB;QAEA,mDAAmD;QACnDnB,oBAAoBe;QACpB,OAAO,KAAK,CAACD,MAAMC;IACrB;IAEA;;;;GAIC,GACD,MAAgBvB,eAAmC;QACjD,MAAM4B,OAAO,MAAM,IAAI,CAACC,cAAc;QAEtCnB,MAAM,CAAC,kBAAkB,CAAC,EAAEkB;QAC5B,OAAO5B,aAAa4B,KAAKE,SAAS;IACpC;IAEA;;;;;;;;;;;;;;;GAeC,GACD,MAAgBC,aAAaC,OAG5B,EAAmB;QAClB,MAAMC,iBAAiB,IAAI,CAACC,IAAI,CAACrB,KAAK,IAAI,QAAQ,gBAAgB,IAAI,CAACqB,IAAI,CAACrB,KAAK;QAEjF,gCAAgC;QAChC,IAAIoB,gBAAgB;YAClB,MAAME,gBACJ,gBAAgB,IAAI,CAACtB,KAAK,IAAI,OAAO,IAAI,CAACA,KAAK,CAAC,aAAa,KAAK,WAC9D,IAAI,CAACA,KAAK,CAAC,aAAa,GACxBuB;YAEN,IAAID,eAAe,OAAOA;QAC5B;QAEA,2DAA2D;QAC3D,IAAIH,SAASK,oBAAoB;YAC/B,MAAMC,kBACJN,QAAQK,kBAAkB,IAAI,IAAI,CAACxB,KAAK,IACxC,OAAO,IAAI,CAACA,KAAK,CAACmB,QAAQK,kBAAkB,CAAC,KAAK,WAC7C,IAAI,CAACxB,KAAK,CAACmB,QAAQK,kBAAkB,CAAC,GACvCD;YAEN,IAAIE,iBAAiB,OAAOA;QAC9B;QAEA,0BAA0B;QAC1B,IAAI;YACF,MAAMC,SAAS,MAAM,IAAI,CAACvC,YAAY;YACtC,MAAMwC,kBAAkBD,OAAOE,GAAG,EAAEC;YACpC,IAAIF,iBAAiB,OAAOA;QAC9B,EAAE,OAAOjB,KAAK;YACZ,IAAI,CAAEA,CAAAA,eAAenB,wBAAuB,GAAI,MAAMmB;QACtD,mDAAmD;QACrD;QAEA,yDAAyD;QACzD,IAAIS,SAASW,UAAU;YACrB,IAAI;gBACF,OAAO,MAAMX,QAAQW,QAAQ;YAC/B,EAAE,OAAOpB,KAAK;gBACZ,IAAI,CAAEA,CAAAA,eAAepB,mBAAkB,GAAI,MAAMoB;gBACjD,qDAAqD;gBACrD,MAAM,IAAInB,yBAAyB,kCAAkC;oBACnEwC,OAAOrB;oBACPsB,aAAa;2BACPZ,iBAAiB;4BAAC;yBAAoD,GAAG,EAAE;wBAC/E;wBACA;qBACD;gBACH;YACF;QACF;QAEA,MAAM,IAAI7B,yBAAyB,kCAAkC;YACnEyC,aAAa;mBACPZ,iBAAiB;oBAAC;iBAAoD,GAAG,EAAE;gBAC/E;aACD;QACH;IACF;IAEA;;;;GAIC,GACD,AAAUJ,iBAA6C;QACrD,OAAO5B,gBAAgB6C,QAAQC,GAAG;IACpC;IAEA,MAAaC,OAAsB;QACjC,MAAM,EAACpC,IAAI,EAAEC,KAAK,EAAC,GAAG,MAAM,IAAI,CAACoC,KAAK,CAAC;YACrCrC,MAAM,IAAI,CAACsB,IAAI,CAACtB,IAAI;YACpBsC,WAAW,AAAC,KAAK,CAAChB,KAA8BgB,SAAS;YACzDC,gBAAgB,IAAI,CAACjB,IAAI,CAACiB,cAAc;YACxCtC,OAAO,IAAI,CAACqB,IAAI,CAACrB,KAAK;YACtBuC,QAAQ,IAAI,CAAClB,IAAI,CAACkB,MAAM;QAC1B;QAEA,IAAI,CAACxC,IAAI,GAAGA;QACZ,IAAI,CAACC,KAAK,GAAGA;QACb,IAAI,CAACQ,SAAS,GAAGd;QAEjB,MAAM,KAAK,CAACyC;IACd;IAEA;;;;;;;;;;GAUC,GACD,AAAUK,eAAwB;QAChC,OAAO,IAAI,CAACxC,KAAK,CAACyC,GAAG,IAAI,CAAC,IAAI,CAACC,oBAAoB;IACrD;IAEA;;;;GAIC,GACD,AAAUA,uBAAgC;QACxC,OAAO9C;IACT;IAEA;;;;;;;GAOC,GACD,MAAgB+C,kBAAsC;QACpD,IAAI;YACF,OAAO,MAAM,IAAI,CAACxD,YAAY;QAChC,EAAE,OAAOuB,KAAK;YACZ,IAAI,CAAEA,CAAAA,eAAenB,wBAAuB,GAAI,MAAMmB;YACtD,OAAO,CAAC;QACV;IACF;AACF"}
|
|
1
|
+
{"version":3,"sources":["../src/SanityCommand.ts"],"sourcesContent":["import {styleText} from 'node:util'\n\nimport {Command, Interfaces} from '@oclif/core'\nimport {type CommandError} from '@oclif/core/interfaces'\n\nimport {getCliConfig} from './config/cli/getCliConfig.js'\nimport {type CliConfig} from './config/cli/types/cliConfig.js'\nimport {findProjectRoot} from './config/findProjectRoot.js'\nimport {type ProjectRootResult} from './config/util/recursivelyResolveProjectRoot.js'\nimport {subdebug} from './debug.js'\nimport {NonInteractiveError} from './errors/NonInteractiveError.js'\nimport {ProjectRootNotFoundError} from './errors/ProjectRootNotFoundError.js'\nimport {exitCodes} from './exitCodes.js'\nimport {\n getGlobalCliClient,\n getProjectCliClient,\n type GlobalCliClientOptions,\n type ProjectCliClientOptions,\n} from './services/apiClient.js'\nimport {getCliTelemetry, reportCliTraceError} from './telemetry/getCliTelemetry.js'\nimport {type CLITelemetryStore} from './telemetry/types.js'\nimport {type Output} from './types.js'\nimport {isInteractive} from './util/isInteractive.js'\n\ntype Flags<T extends typeof Command> = Interfaces.InferredFlags<\n (typeof SanityCommand)['baseFlags'] & T['flags']\n>\n\ntype Args<T extends typeof Command> = Interfaces.InferredArgs<T['args']>\n\nconst debug = subdebug('sanityCommand')\n\nexport abstract class SanityCommand<T extends typeof Command> extends Command {\n protected args!: Args<T>\n protected flags!: Flags<T>\n\n /**\n * Get the global API client.\n *\n * @param args - The global API client options.\n * @returns The global API client.\n *\n * @deprecated use `getGlobalCliClient` function directly instead.\n */\n protected getGlobalApiClient = (args: GlobalCliClientOptions) => getGlobalCliClient(args)\n\n /**\n * Get the project API client.\n *\n * @param args - The project API client options.\n * @returns The project API client.\n *\n * @deprecated use `getProjectCliClient` function directly instead.\n */\n protected getProjectApiClient = (args: ProjectCliClientOptions) => getProjectCliClient(args)\n\n /**\n * Helper for outputting to the console.\n *\n * @example\n * ```ts\n * this.output.log('Hello')\n * this.output.warn('Warning')\n * this.output.error('Error')\n * ```\n */\n protected output: Output = {\n error: this.error.bind(this),\n log: this.log.bind(this),\n warn: this.warn.bind(this),\n }\n\n /**\n * The telemetry store.\n *\n * @returns The telemetry store.\n */\n protected telemetry!: CLITelemetryStore\n\n /**\n * Report real command errors to the CLI command trace.\n * User aborts (SIGINT, ExitPromptError) are not reported — the trace is left\n * incomplete, which accurately represents that the command was interrupted.\n */\n protected override async catch(err: CommandError): Promise<void> {\n // ExitPromptError is thrown by `@inquirer/prompts` when the user cancels a prompt\n // The `message === 'SIGINT'` check matches oclif's own convention (see handle.js in @oclif/core)\n if (err.name === 'ExitPromptError' || err.message === 'SIGINT') {\n this.logToStderr(styleText('yellow', '\\u{203A}') + ' Aborted by user')\n return this.exit(exitCodes.SIGINT)\n }\n\n // In other cases, we _do_ want to report the error\n reportCliTraceError(err)\n return super.catch(err)\n }\n\n /**\n * Get the CLI config.\n *\n * @returns The CLI config.\n */\n protected async getCliConfig(): Promise<CliConfig> {\n const root = await this.getProjectRoot()\n\n debug(`Using project root`, root)\n return getCliConfig(root.directory)\n }\n\n /**\n * Get the project ID from passed flags or (if not provided) the CLI config.\n *\n * Optionally accepts a `fallback` function that is called when no project ID\n * can be determined from flags or config. This allows commands to provide\n * interactive project selection while keeping the prompt logic in the CLI package.\n *\n * If the fallback throws a `NonInteractiveError` (e.g. because the terminal is\n * not interactive), it falls through to the standard error with suggestions.\n *\n * Optionally accepts a `deprecatedFlagName` for commands that have a deprecated\n * flag (e.g. `--project`) that should be checked after `--project-id` but before\n * the CLI config.\n *\n * @returns The project ID.\n */\n protected async getProjectId(options?: {\n deprecatedFlagName?: string\n fallback?: () => Promise<string>\n }): Promise<string> {\n const hasProjectFlag = this.ctor.flags != null && 'project-id' in this.ctor.flags\n\n // Check --project-id flag first\n if (hasProjectFlag) {\n const flagProjectId =\n 'project-id' in this.flags && typeof this.flags['project-id'] === 'string'\n ? this.flags['project-id']\n : undefined\n\n if (flagProjectId) return flagProjectId\n }\n\n // Check deprecated flag (e.g. --project) before CLI config\n if (options?.deprecatedFlagName) {\n const deprecatedValue =\n options.deprecatedFlagName in this.flags &&\n typeof this.flags[options.deprecatedFlagName] === 'string'\n ? (this.flags[options.deprecatedFlagName] as string)\n : undefined\n\n if (deprecatedValue) return deprecatedValue\n }\n\n // Fall back to CLI config\n try {\n const config = await this.getCliConfig()\n const configProjectId = config.api?.projectId\n if (configProjectId) return configProjectId\n } catch (err) {\n if (!(err instanceof ProjectRootNotFoundError)) throw err\n // No project root — fall through to fallback/error\n }\n\n // Offer interactive selection if a fallback was provided\n if (options?.fallback) {\n try {\n return await options.fallback()\n } catch (err) {\n if (!(err instanceof NonInteractiveError)) throw err\n // Non-interactive: throw with actionable suggestions\n throw new ProjectRootNotFoundError('Unable to determine project ID', {\n cause: err,\n suggestions: [\n ...(hasProjectFlag ? ['Providing a project ID: --project-id <project-id>'] : []),\n 'Running this command from within a Sanity project directory',\n 'Running in an interactive terminal to get a project selection prompt',\n ],\n })\n }\n }\n\n throw new ProjectRootNotFoundError('Unable to determine project ID', {\n suggestions: [\n ...(hasProjectFlag ? ['Providing a project ID: --project-id <project-id>'] : []),\n 'Running this command from within a Sanity project directory',\n ],\n })\n }\n\n /**\n * Get the project's root directory by resolving the config\n *\n * @returns The project root result.\n */\n protected getProjectRoot(): Promise<ProjectRootResult> {\n return findProjectRoot(process.cwd())\n }\n\n public async init(): Promise<void> {\n const {args, flags} = await this.parse({\n args: this.ctor.args,\n baseFlags: (super.ctor as typeof SanityCommand).baseFlags,\n enableJsonFlag: this.ctor.enableJsonFlag,\n flags: this.ctor.flags,\n strict: this.ctor.strict,\n })\n\n this.args = args as Args<T>\n this.flags = flags as Flags<T>\n this.telemetry = getCliTelemetry()\n\n await super.init()\n }\n\n /**\n * Check if the command is running in unattended mode.\n *\n * This means the command should not ask for user input, instead using defaults where\n * possible, and if that does not make sense (eg there's missing information), then we\n * should error out (remember to exit with a non-zero code).\n *\n * Most commands should take an explicit `--yes` flag to enable unattended mode, but\n * some commands may also be run in unattended mode if `process.stdin` is not a TTY\n * (eg when running in a CI environment).\n */\n protected isUnattended(): boolean {\n return this.flags.yes || !this.resolveIsInteractive()\n }\n\n /**\n * Resolver for checking if the terminal is interactive. Override in tests to provide mock values.\n *\n * @returns Whether the terminal is interactive.\n */\n protected resolveIsInteractive(): boolean {\n return isInteractive()\n }\n\n /**\n * Get the CLI config, returning an empty config if no project root is found.\n *\n * Use this instead of `getCliConfig()` in commands that can operate without a\n * project directory (e.g. when `--project-id` and `--dataset` flags are provided).\n *\n * @returns The CLI config, or an empty config object if no project root is found.\n */\n protected async tryGetCliConfig(): Promise<CliConfig> {\n try {\n return await this.getCliConfig()\n } catch (err) {\n if (!(err instanceof ProjectRootNotFoundError)) throw err\n return {}\n }\n }\n}\n"],"names":["styleText","Command","getCliConfig","findProjectRoot","subdebug","NonInteractiveError","ProjectRootNotFoundError","exitCodes","getGlobalCliClient","getProjectCliClient","getCliTelemetry","reportCliTraceError","isInteractive","debug","SanityCommand","args","flags","getGlobalApiClient","getProjectApiClient","output","error","bind","log","warn","telemetry","catch","err","name","message","logToStderr","exit","SIGINT","root","getProjectRoot","directory","getProjectId","options","hasProjectFlag","ctor","flagProjectId","undefined","deprecatedFlagName","deprecatedValue","config","configProjectId","api","projectId","fallback","cause","suggestions","process","cwd","init","parse","baseFlags","enableJsonFlag","strict","isUnattended","yes","resolveIsInteractive","tryGetCliConfig"],"mappings":"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"}
|
|
@@ -3,7 +3,6 @@ import { CLIError } from "@oclif/core/errors";
|
|
|
3
3
|
import { Command } from "@oclif/core";
|
|
4
4
|
import { CommandError } from "@oclif/core/interfaces";
|
|
5
5
|
import { ConfigEnv } from "vite";
|
|
6
|
-
import ConfigStore from "configstore";
|
|
7
6
|
import { ConsentStatus } from "@sanity/telemetry";
|
|
8
7
|
import debugIt from "debug";
|
|
9
8
|
import { InlineConfig } from "vite";
|
|
@@ -28,6 +27,16 @@ declare type Args<T extends typeof Command> = Interfaces.InferredArgs<
|
|
|
28
27
|
*/
|
|
29
28
|
export declare function clearCliTelemetry(): void;
|
|
30
29
|
|
|
30
|
+
/**
|
|
31
|
+
* Clear the in-process token cache so the next `getCliToken()` call
|
|
32
|
+
* re-reads from disk or the environment.
|
|
33
|
+
*
|
|
34
|
+
* Called automatically by `setCliUserConfig('authToken', ...)`.
|
|
35
|
+
*
|
|
36
|
+
* @internal
|
|
37
|
+
*/
|
|
38
|
+
export declare function clearCliTokenCache(): void;
|
|
39
|
+
|
|
31
40
|
/**
|
|
32
41
|
* @public
|
|
33
42
|
* Symbol used to store CLI telemetry state on globalThis.
|
|
@@ -163,38 +172,23 @@ export declare interface CliConfig {
|
|
|
163
172
|
export declare type CLITelemetryStore =
|
|
164
173
|
TelemetryLogger<TelemetryUserProperties>;
|
|
165
174
|
|
|
175
|
+
export declare function colorizeJson(input: unknown): string;
|
|
176
|
+
|
|
166
177
|
/**
|
|
167
|
-
*
|
|
178
|
+
* A raw key-value store for CLI user configuration.
|
|
179
|
+
* Unlike the typed `getCliUserConfig`/`setCliUserConfig`, this operates on
|
|
180
|
+
* arbitrary keys without schema validation.
|
|
168
181
|
*
|
|
169
|
-
* @
|
|
182
|
+
* @public
|
|
170
183
|
*/
|
|
171
|
-
declare
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
value: z.ZodObject<
|
|
180
|
-
{
|
|
181
|
-
status: z.ZodEnum<{
|
|
182
|
-
undetermined: "undetermined";
|
|
183
|
-
unset: "unset";
|
|
184
|
-
granted: "granted";
|
|
185
|
-
denied: "denied";
|
|
186
|
-
}>;
|
|
187
|
-
type: z.ZodString;
|
|
188
|
-
},
|
|
189
|
-
z.core.$loose
|
|
190
|
-
>;
|
|
191
|
-
},
|
|
192
|
-
z.core.$strip
|
|
193
|
-
>
|
|
194
|
-
>;
|
|
195
|
-
};
|
|
196
|
-
|
|
197
|
-
export declare function colorizeJson(input: unknown): string;
|
|
184
|
+
export declare interface ConfigStore {
|
|
185
|
+
/** Remove a key from the config file. */
|
|
186
|
+
delete: (key: string) => void;
|
|
187
|
+
/** Read a value by key. Returns `undefined` if the key does not exist. */
|
|
188
|
+
get: (key: string) => unknown;
|
|
189
|
+
/** Write a value by key, merging it into the existing config. */
|
|
190
|
+
set: (key: string, value: unknown) => void;
|
|
191
|
+
}
|
|
198
192
|
|
|
199
193
|
export declare type ConsentInformation =
|
|
200
194
|
| {
|
|
@@ -263,6 +257,28 @@ export { debug_2 as debug };
|
|
|
263
257
|
*/
|
|
264
258
|
export declare function doImport(source: string): Promise<any>;
|
|
265
259
|
|
|
260
|
+
/**
|
|
261
|
+
* Standard exit codes for CLI commands.
|
|
262
|
+
*
|
|
263
|
+
* - 0, 1, 2 align with oclif defaults and Unix convention.
|
|
264
|
+
* - 3 is application-defined (oclif does not use it).
|
|
265
|
+
* - 130 follows the Unix convention of 128 + signal number (SIGINT = 2).
|
|
266
|
+
*
|
|
267
|
+
* @see CLAUDE.md "Exit Code Convention" for usage guidance and examples.
|
|
268
|
+
*/
|
|
269
|
+
export declare const exitCodes: {
|
|
270
|
+
/** Something went wrong that is not the user's fault (API errors, network, missing config, etc.). */
|
|
271
|
+
readonly RUNTIME_ERROR: 1;
|
|
272
|
+
/** The user interrupted via Ctrl+C (128 + SIGINT). Handled by SanityCommand.catch(). */
|
|
273
|
+
readonly SIGINT: 130;
|
|
274
|
+
/** Command completed normally. */
|
|
275
|
+
readonly SUCCESS: 0;
|
|
276
|
+
/** The user provided invalid input (bad args, unknown flags, validation failures). */
|
|
277
|
+
readonly USAGE_ERROR: 2;
|
|
278
|
+
/** The user declined a confirmation or chose not to proceed. */
|
|
279
|
+
readonly USER_ABORT: 3;
|
|
280
|
+
};
|
|
281
|
+
|
|
266
282
|
/**
|
|
267
283
|
* Finds the path for a given set of files.
|
|
268
284
|
*
|
|
@@ -371,9 +387,7 @@ export declare function getCliToken(): Promise<string | undefined>;
|
|
|
371
387
|
* @returns The value of the given property
|
|
372
388
|
* @internal
|
|
373
389
|
*/
|
|
374
|
-
export declare function getCliUserConfig
|
|
375
|
-
prop: P,
|
|
376
|
-
): Promise<CliUserConfig[P]>;
|
|
390
|
+
export declare function getCliUserConfig(prop: "authToken"): string | undefined;
|
|
377
391
|
|
|
378
392
|
/**
|
|
379
393
|
* Create a "global" (unscoped) Sanity API client.
|
|
@@ -487,7 +501,23 @@ export declare function getTelemetryBaseInfo(): Promise<TelemetryBaseInfo>;
|
|
|
487
501
|
*/
|
|
488
502
|
export declare function getTimer(): TimeMeasurer;
|
|
489
503
|
|
|
490
|
-
|
|
504
|
+
/**
|
|
505
|
+
* Get a key-value store backed by the CLI user configuration file
|
|
506
|
+
* (`~/.config/sanity/config.json`).
|
|
507
|
+
*
|
|
508
|
+
* Each call to `get`, `set`, or `delete` performs a full synchronous
|
|
509
|
+
* read-modify-write cycle. This is intentional: sync I/O prevents
|
|
510
|
+
* intra-process race conditions that occurred with the previous async
|
|
511
|
+
* (configstore-backed) implementation.
|
|
512
|
+
*
|
|
513
|
+
* Note: there is no file-level locking, so concurrent writes from
|
|
514
|
+
* separate CLI processes could still conflict. In practice this is
|
|
515
|
+
* unlikely since CLI config writes are rare and user-initiated.
|
|
516
|
+
*
|
|
517
|
+
* @returns A {@link ConfigStore} for the CLI config file
|
|
518
|
+
* @public
|
|
519
|
+
*/
|
|
520
|
+
export declare function getUserConfig(): ConfigStore;
|
|
491
521
|
|
|
492
522
|
/**
|
|
493
523
|
* @public
|
|
@@ -1176,10 +1206,10 @@ export declare function setCliTelemetry(
|
|
|
1176
1206
|
* @param value - The value to set
|
|
1177
1207
|
* @internal
|
|
1178
1208
|
*/
|
|
1179
|
-
export declare function setCliUserConfig
|
|
1180
|
-
prop:
|
|
1181
|
-
value:
|
|
1182
|
-
):
|
|
1209
|
+
export declare function setCliUserConfig(
|
|
1210
|
+
prop: "authToken",
|
|
1211
|
+
value: string | undefined,
|
|
1212
|
+
): void;
|
|
1183
1213
|
|
|
1184
1214
|
/**
|
|
1185
1215
|
* Executes a worker file in a Sanity Studio browser context.
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
export * from '../config/cli/getCliConfig.js';
|
|
2
|
+
export * from '../config/cli/getCliConfigSync.js';
|
|
3
|
+
export * from '../config/findProjectRoot.js';
|
|
4
|
+
export * from '../config/findProjectRootSync.js';
|
|
5
|
+
export * from '../config/studio/getStudioConfig.js';
|
|
6
|
+
export * from '../config/studio/getStudioWorkspaces.js';
|
|
7
|
+
export * from '../config/studio/isStudioConfig.js';
|
|
8
|
+
export * from '../config/util/findConfigsPaths.js';
|
|
9
|
+
export * from '../config/util/findStudioConfigPath.js';
|
|
10
|
+
export * from '../debug.js';
|
|
11
|
+
export * from '../errors/NonInteractiveError.js';
|
|
12
|
+
export * from '../errors/NotFoundError.js';
|
|
13
|
+
export * from '../errors/ProjectRootNotFoundError.js';
|
|
14
|
+
export * from '../exitCodes.js';
|
|
15
|
+
export * from '../loaders/studio/studioWorkerTask.js';
|
|
16
|
+
export * from '../loaders/tsx/tsxWorkerTask.js';
|
|
17
|
+
export * from '../SanityCommand.js';
|
|
18
|
+
export * from '../services/apiClient.js';
|
|
19
|
+
export * from '../services/cliUserConfig.js';
|
|
20
|
+
export * from '../services/getCliToken.js';
|
|
21
|
+
export { clearCliTelemetry, CLI_TELEMETRY_SYMBOL, getCliTelemetry, setCliTelemetry } from '../telemetry/getCliTelemetry.js';
|
|
22
|
+
export { getTelemetryBaseInfo } from '../telemetry/getTelemetryBaseInfo.js';
|
|
23
|
+
export { doImport } from '../util/doImport.js';
|
|
24
|
+
export * from '../util/environment/mockBrowserEnvironment.js';
|
|
25
|
+
export * from '../util/getSanityEnvVar.js';
|
|
26
|
+
export * from '../util/getSanityUrl.js';
|
|
27
|
+
export * from '../util/importModule.js';
|
|
28
|
+
export * from '../util/isCi.js';
|
|
29
|
+
export * from '../util/isInteractive.js';
|
|
30
|
+
export * from '../util/isStaging.js';
|
|
31
|
+
export * from '../util/normalizePath.js';
|
|
32
|
+
export * from '../util/promisifyWorker.js';
|
|
33
|
+
export * from '../util/readPackageJson.js';
|
|
34
|
+
export * from '../util/resolveLocalPackage.js';
|
|
35
|
+
export * from '../util/safeStructuredClone.js';
|
|
36
|
+
export * from '../ux/colorizeJson.js';
|
|
37
|
+
export * from '../ux/timer.js';
|
|
38
|
+
|
|
39
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/_exports/index.ts"],"sourcesContent":["export * from '../config/cli/getCliConfig.js'\nexport * from '../config/cli/getCliConfigSync.js'\nexport {type CliConfig} from '../config/cli/types/cliConfig.js'\nexport {type UserViteConfig} from '../config/cli/types/userViteConfig.js'\nexport * from '../config/findProjectRoot.js'\nexport * from '../config/findProjectRootSync.js'\nexport * from '../config/studio/getStudioConfig.js'\nexport * from '../config/studio/getStudioWorkspaces.js'\nexport * from '../config/studio/isStudioConfig.js'\nexport * from '../config/util/findConfigsPaths.js'\nexport * from '../config/util/findStudioConfigPath.js'\nexport {type ProjectRootResult} from '../config/util/recursivelyResolveProjectRoot.js'\nexport * from '../debug.js'\nexport * from '../errors/NonInteractiveError.js'\nexport * from '../errors/NotFoundError.js'\nexport * from '../errors/ProjectRootNotFoundError.js'\nexport * from '../exitCodes.js'\nexport * from '../loaders/studio/studioWorkerTask.js'\nexport * from '../loaders/tsx/tsxWorkerTask.js'\nexport * from '../SanityCommand.js'\nexport * from '../services/apiClient.js'\nexport * from '../services/cliUserConfig.js'\nexport * from '../services/getCliToken.js'\nexport {\n clearCliTelemetry,\n CLI_TELEMETRY_SYMBOL,\n getCliTelemetry,\n setCliTelemetry,\n} from '../telemetry/getCliTelemetry.js'\nexport {getTelemetryBaseInfo} from '../telemetry/getTelemetryBaseInfo.js'\nexport {\n type CLITelemetryStore,\n type ConsentInformation,\n type TelemetryUserProperties,\n} from '../telemetry/types.js'\nexport {type Output, type SanityOrgUser} from '../types.js'\nexport {doImport} from '../util/doImport.js'\nexport * from '../util/environment/mockBrowserEnvironment.js'\nexport * from '../util/getSanityEnvVar.js'\nexport * from '../util/getSanityUrl.js'\nexport * from '../util/importModule.js'\nexport * from '../util/isCi.js'\nexport * from '../util/isInteractive.js'\nexport * from '../util/isStaging.js'\nexport * from '../util/normalizePath.js'\nexport * from '../util/promisifyWorker.js'\nexport * from '../util/readPackageJson.js'\nexport * from '../util/resolveLocalPackage.js'\nexport * from '../util/safeStructuredClone.js'\nexport * from '../ux/colorizeJson.js'\nexport * from '../ux/timer.js'\n"],"names":["clearCliTelemetry","CLI_TELEMETRY_SYMBOL","getCliTelemetry","setCliTelemetry","getTelemetryBaseInfo","doImport"],"mappings":"AAAA,cAAc,gCAA+B;AAC7C,cAAc,oCAAmC;AAGjD,cAAc,+BAA8B;AAC5C,cAAc,mCAAkC;AAChD,cAAc,sCAAqC;AACnD,cAAc,0CAAyC;AACvD,cAAc,qCAAoC;AAClD,cAAc,qCAAoC;AAClD,cAAc,yCAAwC;AAEtD,cAAc,cAAa;AAC3B,cAAc,mCAAkC;AAChD,cAAc,6BAA4B;AAC1C,cAAc,wCAAuC;AACrD,cAAc,kBAAiB;AAC/B,cAAc,wCAAuC;AACrD,cAAc,kCAAiC;AAC/C,cAAc,sBAAqB;AACnC,cAAc,2BAA0B;AACxC,cAAc,+BAA8B;AAC5C,cAAc,6BAA4B;AAC1C,SACEA,iBAAiB,EACjBC,oBAAoB,EACpBC,eAAe,EACfC,eAAe,QACV,kCAAiC;AACxC,SAAQC,oBAAoB,QAAO,uCAAsC;AAOzE,SAAQC,QAAQ,QAAO,sBAAqB;AAC5C,cAAc,gDAA+C;AAC7D,cAAc,6BAA4B;AAC1C,cAAc,0BAAyB;AACvC,cAAc,0BAAyB;AACvC,cAAc,kBAAiB;AAC/B,cAAc,2BAA0B;AACxC,cAAc,uBAAsB;AACpC,cAAc,2BAA0B;AACxC,cAAc,6BAA4B;AAC1C,cAAc,6BAA4B;AAC1C,cAAc,iCAAgC;AAC9C,cAAc,iCAAgC;AAC9C,cAAc,wBAAuB;AACrC,cAAc,iBAAgB"}
|
|
@@ -32,7 +32,9 @@ import { recursivelyResolveProjectRoot } from './util/recursivelyResolveProjectR
|
|
|
32
32
|
throw err;
|
|
33
33
|
}
|
|
34
34
|
const message = err instanceof Error ? err.message : `${err}`;
|
|
35
|
-
throw new Error(`Error occurred trying to resolve project root:\n${message}
|
|
35
|
+
throw new Error(`Error occurred trying to resolve project root:\n${message}`, {
|
|
36
|
+
cause: err
|
|
37
|
+
});
|
|
36
38
|
}
|
|
37
39
|
}
|
|
38
40
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/config/findProjectRoot.ts"],"sourcesContent":["import {ProjectRootNotFoundError} from '../errors/ProjectRootNotFoundError.js'\nimport {findAppConfigPath} from './util/findAppConfigPath.js'\nimport {tryFindStudioConfigPath} from './util/findStudioConfigPath.js'\nimport {\n type ProjectRootResult,\n recursivelyResolveProjectRoot,\n} from './util/recursivelyResolveProjectRoot.js'\n\n/**\n * Resolve project root directory and type.\n *\n * Project root is:\n * - `studio` - A pre-blueprints Sanity studio root (containing `sanity.config.(ts|js)`)\n * - `app` - A Sanity app root (containing `sanity.cli.(ts|js)`)\n *\n * If a Sanity Studio v2/v1 root is found (containing `sanity.json` with `root: true`),\n * an error is thrown, as v2/v1 is no longer supported.\n *\n * @internal\n */\nexport async function findProjectRoot(cwd: string): Promise<ProjectRootResult> {\n try {\n // First try to find a studio project root, looks for `sanity.config.(ts|js)`\n const studioProjectRoot = await resolveProjectRootForStudio(cwd)\n if (studioProjectRoot) {\n return studioProjectRoot\n }\n\n // Second try to find a app project root, looks for `sanity.cli.(ts|js)`\n const appProjectRoot = await resolveProjectRootForApp(cwd)\n if (appProjectRoot) {\n return appProjectRoot\n }\n\n // If nothing is found throw a specific error\n throw new ProjectRootNotFoundError('No project root found')\n } catch (err: unknown) {\n if (err instanceof ProjectRootNotFoundError) {\n throw err\n }\n const message = err instanceof Error ? err.message : `${err}`\n throw new Error(`Error occurred trying to resolve project root:\\n${message}
|
|
1
|
+
{"version":3,"sources":["../../src/config/findProjectRoot.ts"],"sourcesContent":["import {ProjectRootNotFoundError} from '../errors/ProjectRootNotFoundError.js'\nimport {findAppConfigPath} from './util/findAppConfigPath.js'\nimport {tryFindStudioConfigPath} from './util/findStudioConfigPath.js'\nimport {\n type ProjectRootResult,\n recursivelyResolveProjectRoot,\n} from './util/recursivelyResolveProjectRoot.js'\n\n/**\n * Resolve project root directory and type.\n *\n * Project root is:\n * - `studio` - A pre-blueprints Sanity studio root (containing `sanity.config.(ts|js)`)\n * - `app` - A Sanity app root (containing `sanity.cli.(ts|js)`)\n *\n * If a Sanity Studio v2/v1 root is found (containing `sanity.json` with `root: true`),\n * an error is thrown, as v2/v1 is no longer supported.\n *\n * @internal\n */\nexport async function findProjectRoot(cwd: string): Promise<ProjectRootResult> {\n try {\n // First try to find a studio project root, looks for `sanity.config.(ts|js)`\n const studioProjectRoot = await resolveProjectRootForStudio(cwd)\n if (studioProjectRoot) {\n return studioProjectRoot\n }\n\n // Second try to find a app project root, looks for `sanity.cli.(ts|js)`\n const appProjectRoot = await resolveProjectRootForApp(cwd)\n if (appProjectRoot) {\n return appProjectRoot\n }\n\n // If nothing is found throw a specific error\n throw new ProjectRootNotFoundError('No project root found')\n } catch (err: unknown) {\n if (err instanceof ProjectRootNotFoundError) {\n throw err\n }\n const message = err instanceof Error ? err.message : `${err}`\n throw new Error(`Error occurred trying to resolve project root:\\n${message}`, {cause: err})\n }\n}\n\n/**\n * Recursively searches for a project configuration file in the given directory and its parents.\n * Throws if Sanity v2 studio root is found.\n *\n * @param basePath - The base path to start searching from\n * @param iterations - Current iteration count, passed internally to prevent infinite recursion.\n * @returns A promise that resolves to an object if config is found, false otherwise\n * @internal\n */\nasync function resolveProjectRootForStudio(\n basePath: string,\n iterations = 0,\n): Promise<false | ProjectRootResult> {\n return recursivelyResolveProjectRoot(basePath, tryFindStudioConfigPath, 'studio', iterations)\n}\n\n/**\n * Recursively searches for a app project configuration file in the given directory and its parents.\n *\n * @param basePath - The base path to start searching from\n * @param iterations - Current iteration count, passed internally to prevent infinite recursion.\n * @returns A promise that resolves to an object if config is found, false otherwise\n * @internal\n */\nasync function resolveProjectRootForApp(\n basePath: string,\n iterations = 0,\n): Promise<false | ProjectRootResult> {\n return recursivelyResolveProjectRoot(basePath, findAppConfigPath, 'app', iterations)\n}\n"],"names":["ProjectRootNotFoundError","findAppConfigPath","tryFindStudioConfigPath","recursivelyResolveProjectRoot","findProjectRoot","cwd","studioProjectRoot","resolveProjectRootForStudio","appProjectRoot","resolveProjectRootForApp","err","message","Error","cause","basePath","iterations"],"mappings":"AAAA,SAAQA,wBAAwB,QAAO,wCAAuC;AAC9E,SAAQC,iBAAiB,QAAO,8BAA6B;AAC7D,SAAQC,uBAAuB,QAAO,iCAAgC;AACtE,SAEEC,6BAA6B,QACxB,0CAAyC;AAEhD;;;;;;;;;;;CAWC,GACD,OAAO,eAAeC,gBAAgBC,GAAW;IAC/C,IAAI;QACF,6EAA6E;QAC7E,MAAMC,oBAAoB,MAAMC,4BAA4BF;QAC5D,IAAIC,mBAAmB;YACrB,OAAOA;QACT;QAEA,wEAAwE;QACxE,MAAME,iBAAiB,MAAMC,yBAAyBJ;QACtD,IAAIG,gBAAgB;YAClB,OAAOA;QACT;QAEA,6CAA6C;QAC7C,MAAM,IAAIR,yBAAyB;IACrC,EAAE,OAAOU,KAAc;QACrB,IAAIA,eAAeV,0BAA0B;YAC3C,MAAMU;QACR;QACA,MAAMC,UAAUD,eAAeE,QAAQF,IAAIC,OAAO,GAAG,GAAGD,KAAK;QAC7D,MAAM,IAAIE,MAAM,CAAC,gDAAgD,EAAED,SAAS,EAAE;YAACE,OAAOH;QAAG;IAC3F;AACF;AAEA;;;;;;;;CAQC,GACD,eAAeH,4BACbO,QAAgB,EAChBC,aAAa,CAAC;IAEd,OAAOZ,8BAA8BW,UAAUZ,yBAAyB,UAAUa;AACpF;AAEA;;;;;;;CAOC,GACD,eAAeN,yBACbK,QAAgB,EAChBC,aAAa,CAAC;IAEd,OAAOZ,8BAA8BW,UAAUb,mBAAmB,OAAOc;AAC3E"}
|
|
@@ -58,7 +58,9 @@ import { findAppConfigPathSync, findStudioConfigPathSync } from './util/configPa
|
|
|
58
58
|
throw err;
|
|
59
59
|
}
|
|
60
60
|
const message = err instanceof Error ? err.message : `${err}`;
|
|
61
|
-
throw new Error(`Error occurred trying to resolve project root:\n${message}
|
|
61
|
+
throw new Error(`Error occurred trying to resolve project root:\n${message}`, {
|
|
62
|
+
cause: err
|
|
63
|
+
});
|
|
62
64
|
}
|
|
63
65
|
}
|
|
64
66
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/config/findProjectRootSync.ts"],"sourcesContent":["import {dirname, resolve} from 'node:path'\n\nimport {ProjectRootNotFoundError} from '../errors/ProjectRootNotFoundError.js'\nimport {findAppConfigPathSync, findStudioConfigPathSync} from './util/configPathsSync.js'\nimport {ProjectRootResult} from './util/recursivelyResolveProjectRoot.js'\n\n/**\n * Generic recursive search function for project configuration files (synchronous version).\n *\n * @param basePath - The base path to start searching from\n * @param findConfigFn - Function that looks for config files in a given directory\n * @param projectType - The type of project ('app' | 'studio')\n * @param iterations - Current iteration count, passed internally to prevent infinite recursion\n * @returns An object if config is found, false otherwise\n * @internal\n */\nfunction recursivelyResolveProjectRootSync(\n basePath: string,\n findConfigFn: (path: string) => string | undefined,\n projectType: 'app' | 'studio',\n iterations = 0,\n): false | ProjectRootResult {\n const configPath = findConfigFn(basePath)\n\n if (configPath) {\n return {\n directory: dirname(configPath),\n path: configPath,\n type: projectType,\n }\n }\n\n const parentDir = resolve(basePath, '..')\n if (parentDir === basePath || iterations > 50) {\n // Reached root (or max depth), give up\n return false\n }\n\n return recursivelyResolveProjectRootSync(parentDir, findConfigFn, projectType, iterations + 1)\n}\n\n/**\n * Resolve project root directory and type synchronously.\n *\n * Project root is:\n * - `studio` - A pre-blueprints Sanity studio root (containing `sanity.config.(ts|js)`)\n * - `app` - A Sanity app root (containing `sanity.cli.(ts|js)`)\n *\n * If a Sanity Studio v2/v1 root is found (containing `sanity.json` with `root: true`),\n * an error is thrown, as v2/v1 is no longer supported.\n *\n * @param cwd - Current working directory to start searching from\n * @returns Project root result\n * @internal\n */\nexport function findProjectRootSync(cwd: string): ProjectRootResult {\n try {\n // First try to find a studio project root, looks for `sanity.config.(ts|js)`\n const studioProjectRoot = resolveProjectRootForStudioSync(cwd)\n if (studioProjectRoot) {\n return studioProjectRoot\n }\n\n // Second try to find a app project root, looks for `sanity.cli.(ts|js)`\n const appProjectRoot = resolveProjectRootForAppSync(cwd)\n if (appProjectRoot) {\n return appProjectRoot\n }\n\n // If nothing is found throw a specific error\n throw new ProjectRootNotFoundError(`No project root found in ${cwd}`)\n } catch (err: unknown) {\n if (err instanceof ProjectRootNotFoundError) {\n throw err\n }\n const message = err instanceof Error ? err.message : `${err}`\n throw new Error(`Error occurred trying to resolve project root:\\n${message}
|
|
1
|
+
{"version":3,"sources":["../../src/config/findProjectRootSync.ts"],"sourcesContent":["import {dirname, resolve} from 'node:path'\n\nimport {ProjectRootNotFoundError} from '../errors/ProjectRootNotFoundError.js'\nimport {findAppConfigPathSync, findStudioConfigPathSync} from './util/configPathsSync.js'\nimport {ProjectRootResult} from './util/recursivelyResolveProjectRoot.js'\n\n/**\n * Generic recursive search function for project configuration files (synchronous version).\n *\n * @param basePath - The base path to start searching from\n * @param findConfigFn - Function that looks for config files in a given directory\n * @param projectType - The type of project ('app' | 'studio')\n * @param iterations - Current iteration count, passed internally to prevent infinite recursion\n * @returns An object if config is found, false otherwise\n * @internal\n */\nfunction recursivelyResolveProjectRootSync(\n basePath: string,\n findConfigFn: (path: string) => string | undefined,\n projectType: 'app' | 'studio',\n iterations = 0,\n): false | ProjectRootResult {\n const configPath = findConfigFn(basePath)\n\n if (configPath) {\n return {\n directory: dirname(configPath),\n path: configPath,\n type: projectType,\n }\n }\n\n const parentDir = resolve(basePath, '..')\n if (parentDir === basePath || iterations > 50) {\n // Reached root (or max depth), give up\n return false\n }\n\n return recursivelyResolveProjectRootSync(parentDir, findConfigFn, projectType, iterations + 1)\n}\n\n/**\n * Resolve project root directory and type synchronously.\n *\n * Project root is:\n * - `studio` - A pre-blueprints Sanity studio root (containing `sanity.config.(ts|js)`)\n * - `app` - A Sanity app root (containing `sanity.cli.(ts|js)`)\n *\n * If a Sanity Studio v2/v1 root is found (containing `sanity.json` with `root: true`),\n * an error is thrown, as v2/v1 is no longer supported.\n *\n * @param cwd - Current working directory to start searching from\n * @returns Project root result\n * @internal\n */\nexport function findProjectRootSync(cwd: string): ProjectRootResult {\n try {\n // First try to find a studio project root, looks for `sanity.config.(ts|js)`\n const studioProjectRoot = resolveProjectRootForStudioSync(cwd)\n if (studioProjectRoot) {\n return studioProjectRoot\n }\n\n // Second try to find a app project root, looks for `sanity.cli.(ts|js)`\n const appProjectRoot = resolveProjectRootForAppSync(cwd)\n if (appProjectRoot) {\n return appProjectRoot\n }\n\n // If nothing is found throw a specific error\n throw new ProjectRootNotFoundError(`No project root found in ${cwd}`)\n } catch (err: unknown) {\n if (err instanceof ProjectRootNotFoundError) {\n throw err\n }\n const message = err instanceof Error ? err.message : `${err}`\n throw new Error(`Error occurred trying to resolve project root:\\n${message}`, {cause: err})\n }\n}\n\n/**\n * Recursively searches for a project configuration file in the given directory and its parents.\n * Throws if Sanity v2 studio root is found.\n *\n * @param basePath - The base path to start searching from\n * @param iterations - Current iteration count, passed internally to prevent infinite recursion.\n * @returns An object if config is found, false otherwise\n * @internal\n */\nfunction resolveProjectRootForStudioSync(\n basePath: string,\n iterations = 0,\n): false | ProjectRootResult {\n return recursivelyResolveProjectRootSync(basePath, findStudioConfigPathSync, 'studio', iterations)\n}\n\n/**\n * Recursively searches for a app project configuration file in the given directory and its parents.\n *\n * @param basePath - The base path to start searching from\n * @param iterations - Current iteration count, passed internally to prevent infinite recursion.\n * @returns An object if config is found, false otherwise\n * @internal\n */\nfunction resolveProjectRootForAppSync(basePath: string, iterations = 0): false | ProjectRootResult {\n return recursivelyResolveProjectRootSync(basePath, findAppConfigPathSync, 'app', iterations)\n}\n"],"names":["dirname","resolve","ProjectRootNotFoundError","findAppConfigPathSync","findStudioConfigPathSync","recursivelyResolveProjectRootSync","basePath","findConfigFn","projectType","iterations","configPath","directory","path","type","parentDir","findProjectRootSync","cwd","studioProjectRoot","resolveProjectRootForStudioSync","appProjectRoot","resolveProjectRootForAppSync","err","message","Error","cause"],"mappings":"AAAA,SAAQA,OAAO,EAAEC,OAAO,QAAO,YAAW;AAE1C,SAAQC,wBAAwB,QAAO,wCAAuC;AAC9E,SAAQC,qBAAqB,EAAEC,wBAAwB,QAAO,4BAA2B;AAGzF;;;;;;;;;CASC,GACD,SAASC,kCACPC,QAAgB,EAChBC,YAAkD,EAClDC,WAA6B,EAC7BC,aAAa,CAAC;IAEd,MAAMC,aAAaH,aAAaD;IAEhC,IAAII,YAAY;QACd,OAAO;YACLC,WAAWX,QAAQU;YACnBE,MAAMF;YACNG,MAAML;QACR;IACF;IAEA,MAAMM,YAAYb,QAAQK,UAAU;IACpC,IAAIQ,cAAcR,YAAYG,aAAa,IAAI;QAC7C,uCAAuC;QACvC,OAAO;IACT;IAEA,OAAOJ,kCAAkCS,WAAWP,cAAcC,aAAaC,aAAa;AAC9F;AAEA;;;;;;;;;;;;;CAaC,GACD,OAAO,SAASM,oBAAoBC,GAAW;IAC7C,IAAI;QACF,6EAA6E;QAC7E,MAAMC,oBAAoBC,gCAAgCF;QAC1D,IAAIC,mBAAmB;YACrB,OAAOA;QACT;QAEA,wEAAwE;QACxE,MAAME,iBAAiBC,6BAA6BJ;QACpD,IAAIG,gBAAgB;YAClB,OAAOA;QACT;QAEA,6CAA6C;QAC7C,MAAM,IAAIjB,yBAAyB,CAAC,yBAAyB,EAAEc,KAAK;IACtE,EAAE,OAAOK,KAAc;QACrB,IAAIA,eAAenB,0BAA0B;YAC3C,MAAMmB;QACR;QACA,MAAMC,UAAUD,eAAeE,QAAQF,IAAIC,OAAO,GAAG,GAAGD,KAAK;QAC7D,MAAM,IAAIE,MAAM,CAAC,gDAAgD,EAAED,SAAS,EAAE;YAACE,OAAOH;QAAG;IAC3F;AACF;AAEA;;;;;;;;CAQC,GACD,SAASH,gCACPZ,QAAgB,EAChBG,aAAa,CAAC;IAEd,OAAOJ,kCAAkCC,UAAUF,0BAA0B,UAAUK;AACzF;AAEA;;;;;;;CAOC,GACD,SAASW,6BAA6Bd,QAAgB,EAAEG,aAAa,CAAC;IACpE,OAAOJ,kCAAkCC,UAAUH,uBAAuB,OAAOM;AACnF"}
|
|
@@ -49,7 +49,9 @@ export async function readStudioConfig(configPath, options) {
|
|
|
49
49
|
return options.resolvePlugins ? resolvedConfigSchema.parse(result) : rawConfigSchema.parse(result);
|
|
50
50
|
} catch (err) {
|
|
51
51
|
if (err instanceof z.ZodError) {
|
|
52
|
-
throw new Error(`Invalid studio config at ${configPath}:\n${formatZodIssues(err.issues)}
|
|
52
|
+
throw new Error(`Invalid studio config at ${configPath}:\n${formatZodIssues(err.issues)}`, {
|
|
53
|
+
cause: err
|
|
54
|
+
});
|
|
53
55
|
}
|
|
54
56
|
throw err;
|
|
55
57
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/config/studio/readStudioConfig.ts"],"sourcesContent":["import {dirname} from 'node:path'\n\nimport {z} from 'zod'\n\nimport {studioWorkerTask} from '../../loaders/studio/studioWorkerTask.js'\n\nconst schemaSchema = z.looseObject({\n name: z.string().optional(),\n types: z.array(z.looseObject({})),\n})\n\nconst sourceSchema = z.looseObject({\n dataset: z.string(),\n projectId: z.string(),\n schema: z.looseObject({_original: schemaSchema}),\n})\n\n// Raw workspace schema (resolvePlugins: false) - unstable_sources not yet populated\nconst rawWorkspaceSchema = z.looseObject({\n ...sourceSchema.shape,\n basePath: z.string().optional(),\n name: z.string().optional(),\n plugins: z.array(z.unknown()).optional(),\n schema: schemaSchema.optional(),\n title: z.string().optional(),\n unstable_sources: z.array(sourceSchema).optional(),\n})\n\n// Resolved config schema (resolvePlugins: true) - all fields required\nconst resolvedWorkspaceSchema = z.looseObject({\n ...sourceSchema.shape,\n basePath: z.string(),\n name: z.string(),\n plugins: z.array(z.unknown()).optional(),\n title: z.string(),\n unstable_sources: z.array(sourceSchema),\n})\n\nconst rawConfigSchema = z.union([z.array(rawWorkspaceSchema), rawWorkspaceSchema])\nconst resolvedConfigSchema = z.array(resolvedWorkspaceSchema)\n\nexport type RawStudioConfig = z.infer<typeof rawConfigSchema>\nexport type ResolvedStudioConfig = z.infer<typeof resolvedConfigSchema>\n\nexport interface ReadStudioConfigOptions {\n /**\n * Whether or not to resolve the plugins defined in the config.\n *\n * In some cases, you need this in order to have the full picture of what the studio\n * would \"see\". As an example, plugins can define schema types that are not explicitly\n * defined in the users' schema types. In order to get the full picture, you need to\n * resolve the plugins, which is an asyncronous operation.\n *\n * In other cases, it might be enough to only do a shallow pass. As an example, if you\n * only need to know about the defined workspace, or the user-defined schema types,\n * this can be set to `false` - which should resolve faster (and potentially \"safer\")\n * in terms of not triggering all kinds of browser behavior that may or may not be\n * loaded as the plugins are resolved.\n */\n resolvePlugins: boolean\n}\n\nexport async function readStudioConfig(\n configPath: string,\n options: {resolvePlugins: true},\n): Promise<ResolvedStudioConfig>\n\nexport async function readStudioConfig(\n configPath: string,\n options: {resolvePlugins: false},\n): Promise<RawStudioConfig>\n\nexport async function readStudioConfig(\n configPath: string,\n options: ReadStudioConfigOptions,\n): Promise<RawStudioConfig | ResolvedStudioConfig> {\n const result = await studioWorkerTask(new URL('readStudioConfig.worker.js', import.meta.url), {\n name: 'studioConfig',\n studioRootPath: dirname(configPath),\n workerData: {configPath, resolvePlugins: options.resolvePlugins},\n })\n\n try {\n return options.resolvePlugins\n ? resolvedConfigSchema.parse(result)\n : rawConfigSchema.parse(result)\n } catch (err) {\n if (err instanceof z.ZodError) {\n throw new Error(`Invalid studio config at ${configPath}:\\n${formatZodIssues(err.issues)}
|
|
1
|
+
{"version":3,"sources":["../../../src/config/studio/readStudioConfig.ts"],"sourcesContent":["import {dirname} from 'node:path'\n\nimport {z} from 'zod'\n\nimport {studioWorkerTask} from '../../loaders/studio/studioWorkerTask.js'\n\nconst schemaSchema = z.looseObject({\n name: z.string().optional(),\n types: z.array(z.looseObject({})),\n})\n\nconst sourceSchema = z.looseObject({\n dataset: z.string(),\n projectId: z.string(),\n schema: z.looseObject({_original: schemaSchema}),\n})\n\n// Raw workspace schema (resolvePlugins: false) - unstable_sources not yet populated\nconst rawWorkspaceSchema = z.looseObject({\n ...sourceSchema.shape,\n basePath: z.string().optional(),\n name: z.string().optional(),\n plugins: z.array(z.unknown()).optional(),\n schema: schemaSchema.optional(),\n title: z.string().optional(),\n unstable_sources: z.array(sourceSchema).optional(),\n})\n\n// Resolved config schema (resolvePlugins: true) - all fields required\nconst resolvedWorkspaceSchema = z.looseObject({\n ...sourceSchema.shape,\n basePath: z.string(),\n name: z.string(),\n plugins: z.array(z.unknown()).optional(),\n title: z.string(),\n unstable_sources: z.array(sourceSchema),\n})\n\nconst rawConfigSchema = z.union([z.array(rawWorkspaceSchema), rawWorkspaceSchema])\nconst resolvedConfigSchema = z.array(resolvedWorkspaceSchema)\n\nexport type RawStudioConfig = z.infer<typeof rawConfigSchema>\nexport type ResolvedStudioConfig = z.infer<typeof resolvedConfigSchema>\n\nexport interface ReadStudioConfigOptions {\n /**\n * Whether or not to resolve the plugins defined in the config.\n *\n * In some cases, you need this in order to have the full picture of what the studio\n * would \"see\". As an example, plugins can define schema types that are not explicitly\n * defined in the users' schema types. In order to get the full picture, you need to\n * resolve the plugins, which is an asyncronous operation.\n *\n * In other cases, it might be enough to only do a shallow pass. As an example, if you\n * only need to know about the defined workspace, or the user-defined schema types,\n * this can be set to `false` - which should resolve faster (and potentially \"safer\")\n * in terms of not triggering all kinds of browser behavior that may or may not be\n * loaded as the plugins are resolved.\n */\n resolvePlugins: boolean\n}\n\nexport async function readStudioConfig(\n configPath: string,\n options: {resolvePlugins: true},\n): Promise<ResolvedStudioConfig>\n\nexport async function readStudioConfig(\n configPath: string,\n options: {resolvePlugins: false},\n): Promise<RawStudioConfig>\n\nexport async function readStudioConfig(\n configPath: string,\n options: ReadStudioConfigOptions,\n): Promise<RawStudioConfig | ResolvedStudioConfig> {\n const result = await studioWorkerTask(new URL('readStudioConfig.worker.js', import.meta.url), {\n name: 'studioConfig',\n studioRootPath: dirname(configPath),\n workerData: {configPath, resolvePlugins: options.resolvePlugins},\n })\n\n try {\n return options.resolvePlugins\n ? resolvedConfigSchema.parse(result)\n : rawConfigSchema.parse(result)\n } catch (err) {\n if (err instanceof z.ZodError) {\n throw new Error(`Invalid studio config at ${configPath}:\\n${formatZodIssues(err.issues)}`, {\n cause: err,\n })\n }\n\n throw err\n }\n}\n\n/**\n * Recursively extracts leaf-level messages from Zod issues, including\n * those nested inside union errors. Note that `prettifyError` from Zod\n * only gives a high-level summary for union errors, so this function is\n * needed to get the full details of all validation issues in a readable format.\n *\n * @internal exported for testing only\n */\nexport function formatZodIssues(issues: z.core.$ZodIssue[], indent = 2): string {\n const lines: string[] = []\n const prefix = ' '.repeat(indent)\n\n for (const issue of issues) {\n if (issue.code === 'invalid_union' && 'errors' in issue && Array.isArray(issue.errors)) {\n for (const [i, unionIssues] of issue.errors.entries()) {\n lines.push(`${prefix}Union option ${i + 1}:`, formatZodIssues(unionIssues, indent + 2))\n }\n } else {\n const path = issue.path.length > 0 ? ` at \"${issue.path.join('.')}\"` : ''\n lines.push(`${prefix}- ${issue.message}${path}`)\n }\n }\n\n return lines.join('\\n')\n}\n"],"names":["dirname","z","studioWorkerTask","schemaSchema","looseObject","name","string","optional","types","array","sourceSchema","dataset","projectId","schema","_original","rawWorkspaceSchema","shape","basePath","plugins","unknown","title","unstable_sources","resolvedWorkspaceSchema","rawConfigSchema","union","resolvedConfigSchema","readStudioConfig","configPath","options","result","URL","url","studioRootPath","workerData","resolvePlugins","parse","err","ZodError","Error","formatZodIssues","issues","cause","indent","lines","prefix","repeat","issue","code","Array","isArray","errors","i","unionIssues","entries","push","path","length","join","message"],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Standard exit codes for CLI commands.
|
|
3
|
+
*
|
|
4
|
+
* - 0, 1, 2 align with oclif defaults and Unix convention.
|
|
5
|
+
* - 3 is application-defined (oclif does not use it).
|
|
6
|
+
* - 130 follows the Unix convention of 128 + signal number (SIGINT = 2).
|
|
7
|
+
*
|
|
8
|
+
* @see CLAUDE.md "Exit Code Convention" for usage guidance and examples.
|
|
9
|
+
*/ export const exitCodes = {
|
|
10
|
+
/** Something went wrong that is not the user's fault (API errors, network, missing config, etc.). */ RUNTIME_ERROR: 1,
|
|
11
|
+
/** The user interrupted via Ctrl+C (128 + SIGINT). Handled by SanityCommand.catch(). */ SIGINT: 130,
|
|
12
|
+
/** Command completed normally. */ SUCCESS: 0,
|
|
13
|
+
/** The user provided invalid input (bad args, unknown flags, validation failures). */ USAGE_ERROR: 2,
|
|
14
|
+
/** The user declined a confirmation or chose not to proceed. */ USER_ABORT: 3
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
//# sourceMappingURL=exitCodes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/exitCodes.ts"],"sourcesContent":["/**\n * Standard exit codes for CLI commands.\n *\n * - 0, 1, 2 align with oclif defaults and Unix convention.\n * - 3 is application-defined (oclif does not use it).\n * - 130 follows the Unix convention of 128 + signal number (SIGINT = 2).\n *\n * @see CLAUDE.md \"Exit Code Convention\" for usage guidance and examples.\n */\nexport const exitCodes = {\n /** Something went wrong that is not the user's fault (API errors, network, missing config, etc.). */\n RUNTIME_ERROR: 1,\n /** The user interrupted via Ctrl+C (128 + SIGINT). Handled by SanityCommand.catch(). */\n SIGINT: 130,\n /** Command completed normally. */\n SUCCESS: 0,\n /** The user provided invalid input (bad args, unknown flags, validation failures). */\n USAGE_ERROR: 2,\n /** The user declined a confirmation or chose not to proceed. */\n USER_ABORT: 3,\n} as const\n"],"names":["exitCodes","RUNTIME_ERROR","SIGINT","SUCCESS","USAGE_ERROR","USER_ABORT"],"mappings":"AAAA;;;;;;;;CAQC,GACD,OAAO,MAAMA,YAAY;IACvB,mGAAmG,GACnGC,eAAe;IACf,sFAAsF,GACtFC,QAAQ;IACR,gCAAgC,GAChCC,SAAS;IACT,oFAAoF,GACpFC,aAAa;IACb,8DAA8D,GAC9DC,YAAY;AACd,EAAU"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Module-level cache for the CLI auth token, shared between
|
|
3
|
+
* `getCliToken` (reads/writes) and `setCliUserConfig` (invalidates).
|
|
4
|
+
*
|
|
5
|
+
* Extracted into its own module to avoid a circular dependency
|
|
6
|
+
* between `cliUserConfig.ts` and `getCliToken.ts`.
|
|
7
|
+
*/ let cachedToken;
|
|
8
|
+
export function getCachedToken() {
|
|
9
|
+
return cachedToken;
|
|
10
|
+
}
|
|
11
|
+
export function setCachedToken(token) {
|
|
12
|
+
cachedToken = token;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Clear the in-process token cache so the next `getCliToken()` call
|
|
16
|
+
* re-reads from disk or the environment.
|
|
17
|
+
*
|
|
18
|
+
* Called automatically by `setCliUserConfig('authToken', ...)`.
|
|
19
|
+
*
|
|
20
|
+
* @internal
|
|
21
|
+
*/ export function clearCliTokenCache() {
|
|
22
|
+
cachedToken = undefined;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
//# sourceMappingURL=cliTokenCache.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/services/cliTokenCache.ts"],"sourcesContent":["/**\n * Module-level cache for the CLI auth token, shared between\n * `getCliToken` (reads/writes) and `setCliUserConfig` (invalidates).\n *\n * Extracted into its own module to avoid a circular dependency\n * between `cliUserConfig.ts` and `getCliToken.ts`.\n */\nlet cachedToken: string | undefined\n\nexport function getCachedToken(): string | undefined {\n return cachedToken\n}\n\nexport function setCachedToken(token: string | undefined): void {\n cachedToken = token\n}\n\n/**\n * Clear the in-process token cache so the next `getCliToken()` call\n * re-reads from disk or the environment.\n *\n * Called automatically by `setCliUserConfig('authToken', ...)`.\n *\n * @internal\n */\nexport function clearCliTokenCache(): void {\n cachedToken = undefined\n}\n"],"names":["cachedToken","getCachedToken","setCachedToken","token","clearCliTokenCache","undefined"],"mappings":"AAAA;;;;;;CAMC,GACD,IAAIA;AAEJ,OAAO,SAASC;IACd,OAAOD;AACT;AAEA,OAAO,SAASE,eAAeC,KAAyB;IACtDH,cAAcG;AAChB;AAEA;;;;;;;CAOC,GACD,OAAO,SAASC;IACdJ,cAAcK;AAChB"}
|
|
@@ -1,24 +1,13 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { mkdirSync } from 'node:fs';
|
|
2
2
|
import { homedir } from 'node:os';
|
|
3
3
|
import { dirname, join as joinPath } from 'node:path';
|
|
4
4
|
import { z } from 'zod';
|
|
5
5
|
import { debug } from '../debug.js';
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
6
|
+
import { readJsonFileSync } from '../util/readJsonFileSync.js';
|
|
7
|
+
import { writeJsonFileSync } from '../util/writeJsonFileSync.js';
|
|
8
|
+
import { clearCliTokenCache } from './cliTokenCache.js';
|
|
8
9
|
const cliUserConfigSchema = {
|
|
9
|
-
authToken: z.string().optional()
|
|
10
|
-
telemetryConsent: z.object({
|
|
11
|
-
updatedAt: z.number().optional(),
|
|
12
|
-
value: z.object({
|
|
13
|
-
status: z.enum([
|
|
14
|
-
'undetermined',
|
|
15
|
-
'unset',
|
|
16
|
-
'granted',
|
|
17
|
-
'denied'
|
|
18
|
-
]),
|
|
19
|
-
type: z.string()
|
|
20
|
-
}).passthrough()
|
|
21
|
-
}).optional()
|
|
10
|
+
authToken: z.string().optional()
|
|
22
11
|
};
|
|
23
12
|
/**
|
|
24
13
|
* Set the config value for the given property.
|
|
@@ -27,27 +16,35 @@ const cliUserConfigSchema = {
|
|
|
27
16
|
* @param prop - The property to set the value for
|
|
28
17
|
* @param value - The value to set
|
|
29
18
|
* @internal
|
|
30
|
-
*/ export
|
|
31
|
-
const config =
|
|
32
|
-
const
|
|
33
|
-
if (!
|
|
34
|
-
|
|
35
|
-
}
|
|
36
|
-
const { error, success } = valueSchema.safeParse(value);
|
|
37
|
-
if (!success) {
|
|
38
|
-
const message = error.issues.map(({ message, path })=>`[${path.join('.')}] ${message}`).join('\n');
|
|
19
|
+
*/ export function setCliUserConfig(prop, value) {
|
|
20
|
+
const config = readConfig();
|
|
21
|
+
const result = cliUserConfigSchema[prop].safeParse(value);
|
|
22
|
+
if (!result.success) {
|
|
23
|
+
const message = result.error.issues.map(({ message, path })=>`[${path.join('.')}] ${message}`).join('\n');
|
|
39
24
|
throw new Error(`Invalid value for config property "${prop}": ${message}`);
|
|
40
25
|
}
|
|
41
26
|
const configPath = getCliUserConfigPath();
|
|
42
|
-
|
|
27
|
+
mkdirSync(dirname(configPath), {
|
|
43
28
|
recursive: true
|
|
44
29
|
});
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
30
|
+
// When value is undefined, explicitly delete the key rather than relying
|
|
31
|
+
// on JSON.stringify silently dropping undefined values.
|
|
32
|
+
if (value === undefined) {
|
|
33
|
+
const { [prop]: _, ...rest } = config;
|
|
34
|
+
writeJsonFileSync(configPath, rest, {
|
|
35
|
+
pretty: true
|
|
36
|
+
});
|
|
37
|
+
} else {
|
|
38
|
+
writeJsonFileSync(configPath, {
|
|
39
|
+
...config,
|
|
40
|
+
[prop]: value
|
|
41
|
+
}, {
|
|
42
|
+
pretty: true
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
// Invalidate the in-process token cache so subsequent getCliToken() calls
|
|
46
|
+
// pick up the new value from disk.
|
|
47
|
+
clearCliTokenCache();
|
|
51
48
|
}
|
|
52
49
|
/**
|
|
53
50
|
* Get the config value for the given property
|
|
@@ -55,36 +52,80 @@ const cliUserConfigSchema = {
|
|
|
55
52
|
* @param prop - The property to get the value for
|
|
56
53
|
* @returns The value of the given property
|
|
57
54
|
* @internal
|
|
58
|
-
*/ export
|
|
59
|
-
const config =
|
|
60
|
-
const
|
|
61
|
-
if (!
|
|
62
|
-
throw new Error(`No schema defined for config property "${prop}"`);
|
|
63
|
-
}
|
|
64
|
-
const { success } = valueSchema.safeParse(config[prop]);
|
|
65
|
-
if (!success) {
|
|
55
|
+
*/ export function getCliUserConfig(prop) {
|
|
56
|
+
const config = readConfig();
|
|
57
|
+
const result = cliUserConfigSchema[prop].safeParse(config[prop]);
|
|
58
|
+
if (!result.success) {
|
|
66
59
|
debug('Ignoring invalid stored value for "%s", returning undefined', prop);
|
|
67
60
|
return undefined;
|
|
68
61
|
}
|
|
69
|
-
return
|
|
62
|
+
return result.data;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Get a key-value store backed by the CLI user configuration file
|
|
66
|
+
* (`~/.config/sanity/config.json`).
|
|
67
|
+
*
|
|
68
|
+
* Each call to `get`, `set`, or `delete` performs a full synchronous
|
|
69
|
+
* read-modify-write cycle. This is intentional: sync I/O prevents
|
|
70
|
+
* intra-process race conditions that occurred with the previous async
|
|
71
|
+
* (configstore-backed) implementation.
|
|
72
|
+
*
|
|
73
|
+
* Note: there is no file-level locking, so concurrent writes from
|
|
74
|
+
* separate CLI processes could still conflict. In practice this is
|
|
75
|
+
* unlikely since CLI config writes are rare and user-initiated.
|
|
76
|
+
*
|
|
77
|
+
* @returns A {@link ConfigStore} for the CLI config file
|
|
78
|
+
* @public
|
|
79
|
+
*/ export function getUserConfig() {
|
|
80
|
+
return {
|
|
81
|
+
get (key) {
|
|
82
|
+
const config = readConfig();
|
|
83
|
+
return config[key];
|
|
84
|
+
},
|
|
85
|
+
set (key, value) {
|
|
86
|
+
const config = readConfig();
|
|
87
|
+
const configPath = getCliUserConfigPath();
|
|
88
|
+
mkdirSync(dirname(configPath), {
|
|
89
|
+
recursive: true
|
|
90
|
+
});
|
|
91
|
+
writeJsonFileSync(configPath, {
|
|
92
|
+
...config,
|
|
93
|
+
[key]: value
|
|
94
|
+
}, {
|
|
95
|
+
pretty: true
|
|
96
|
+
});
|
|
97
|
+
if (key === 'authToken') clearCliTokenCache();
|
|
98
|
+
},
|
|
99
|
+
// No mkdirSync needed: if readConfig() succeeded the directory already exists.
|
|
100
|
+
delete (key) {
|
|
101
|
+
const config = readConfig();
|
|
102
|
+
if (!(key in config)) return;
|
|
103
|
+
const { [key]: _, ...rest } = config;
|
|
104
|
+
writeJsonFileSync(getCliUserConfigPath(), rest, {
|
|
105
|
+
pretty: true
|
|
106
|
+
});
|
|
107
|
+
if (key === 'authToken') clearCliTokenCache();
|
|
108
|
+
}
|
|
109
|
+
};
|
|
70
110
|
}
|
|
71
111
|
/**
|
|
72
|
-
* Read the whole configuration from file system. If the file does not exist
|
|
73
|
-
*
|
|
112
|
+
* Read the whole configuration from file system. If the file does not exist,
|
|
113
|
+
* is corrupt, or otherwise unreadable, an empty object is returned. This is
|
|
114
|
+
* intentional: the config only holds recoverable data (auth tokens, telemetry
|
|
115
|
+
* consent) so silently resetting is preferable to blocking the user.
|
|
74
116
|
*
|
|
75
117
|
* @returns The whole CLI configuration.
|
|
76
118
|
* @internal
|
|
77
|
-
*/
|
|
78
|
-
const defaultConfig = {};
|
|
119
|
+
*/ function readConfig() {
|
|
79
120
|
try {
|
|
80
|
-
const config =
|
|
121
|
+
const config = readJsonFileSync(getCliUserConfigPath());
|
|
81
122
|
if (!config || typeof config !== 'object' || Array.isArray(config)) {
|
|
82
123
|
throw new Error('Invalid config file - expected an object');
|
|
83
124
|
}
|
|
84
125
|
return config;
|
|
85
126
|
} catch (err) {
|
|
86
127
|
debug('Failed to read CLI config file: %s', err instanceof Error ? err.message : `${err}`);
|
|
87
|
-
return
|
|
128
|
+
return {};
|
|
88
129
|
}
|
|
89
130
|
}
|
|
90
131
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/services/cliUserConfig.ts"],"sourcesContent":["import {
|
|
1
|
+
{"version":3,"sources":["../../src/services/cliUserConfig.ts"],"sourcesContent":["import {mkdirSync} from 'node:fs'\nimport {homedir} from 'node:os'\nimport {dirname, join as joinPath} from 'node:path'\n\nimport {z} from 'zod'\n\nimport {debug} from '../debug.js'\nimport {readJsonFileSync} from '../util/readJsonFileSync.js'\nimport {writeJsonFileSync} from '../util/writeJsonFileSync.js'\nimport {clearCliTokenCache} from './cliTokenCache.js'\n\nconst cliUserConfigSchema = {\n authToken: z.string().optional(),\n}\n\n/**\n * Set the config value for the given property.\n * Validates that the passed value adheres to the defined CLI config schema.\n *\n * @param prop - The property to set the value for\n * @param value - The value to set\n * @internal\n */\nexport function setCliUserConfig(prop: 'authToken', value: string | undefined): void {\n const config = readConfig()\n const result = cliUserConfigSchema[prop].safeParse(value)\n if (!result.success) {\n const message = result.error.issues\n .map(({message, path}) => `[${path.join('.')}] ${message}`)\n .join('\\n')\n\n throw new Error(`Invalid value for config property \"${prop}\": ${message}`)\n }\n\n const configPath = getCliUserConfigPath()\n mkdirSync(dirname(configPath), {recursive: true})\n\n // When value is undefined, explicitly delete the key rather than relying\n // on JSON.stringify silently dropping undefined values.\n if (value === undefined) {\n const {[prop]: _, ...rest} = config\n writeJsonFileSync(configPath, rest, {pretty: true})\n } else {\n writeJsonFileSync(configPath, {...config, [prop]: value}, {pretty: true})\n }\n\n // Invalidate the in-process token cache so subsequent getCliToken() calls\n // pick up the new value from disk.\n clearCliTokenCache()\n}\n\n/**\n * Get the config value for the given property\n *\n * @param prop - The property to get the value for\n * @returns The value of the given property\n * @internal\n */\nexport function getCliUserConfig(prop: 'authToken'): string | undefined {\n const config = readConfig()\n const result = cliUserConfigSchema[prop].safeParse(config[prop])\n if (!result.success) {\n debug('Ignoring invalid stored value for \"%s\", returning undefined', prop)\n return undefined\n }\n\n return result.data\n}\n\n/**\n * A raw key-value store for CLI user configuration.\n * Unlike the typed `getCliUserConfig`/`setCliUserConfig`, this operates on\n * arbitrary keys without schema validation.\n *\n * @public\n */\nexport interface ConfigStore {\n /** Remove a key from the config file. */\n delete: (key: string) => void\n /** Read a value by key. Returns `undefined` if the key does not exist. */\n get: (key: string) => unknown\n /** Write a value by key, merging it into the existing config. */\n set: (key: string, value: unknown) => void\n}\n\n/**\n * Get a key-value store backed by the CLI user configuration file\n * (`~/.config/sanity/config.json`).\n *\n * Each call to `get`, `set`, or `delete` performs a full synchronous\n * read-modify-write cycle. This is intentional: sync I/O prevents\n * intra-process race conditions that occurred with the previous async\n * (configstore-backed) implementation.\n *\n * Note: there is no file-level locking, so concurrent writes from\n * separate CLI processes could still conflict. In practice this is\n * unlikely since CLI config writes are rare and user-initiated.\n *\n * @returns A {@link ConfigStore} for the CLI config file\n * @public\n */\nexport function getUserConfig(): ConfigStore {\n return {\n get(key: string): unknown {\n const config = readConfig()\n return config[key]\n },\n\n set(key: string, value: unknown): void {\n const config = readConfig()\n const configPath = getCliUserConfigPath()\n mkdirSync(dirname(configPath), {recursive: true})\n writeJsonFileSync(configPath, {...config, [key]: value}, {pretty: true})\n if (key === 'authToken') clearCliTokenCache()\n },\n\n // No mkdirSync needed: if readConfig() succeeded the directory already exists.\n delete(key: string): void {\n const config = readConfig()\n if (!(key in config)) return\n const {[key]: _, ...rest} = config\n writeJsonFileSync(getCliUserConfigPath(), rest, {pretty: true})\n if (key === 'authToken') clearCliTokenCache()\n },\n }\n}\n\n/**\n * Read the whole configuration from file system. If the file does not exist,\n * is corrupt, or otherwise unreadable, an empty object is returned. This is\n * intentional: the config only holds recoverable data (auth tokens, telemetry\n * consent) so silently resetting is preferable to blocking the user.\n *\n * @returns The whole CLI configuration.\n * @internal\n */\nfunction readConfig(): Record<string, unknown> {\n try {\n const config = readJsonFileSync(getCliUserConfigPath())\n if (!config || typeof config !== 'object' || Array.isArray(config)) {\n throw new Error('Invalid config file - expected an object')\n }\n return config\n } catch (err: unknown) {\n debug('Failed to read CLI config file: %s', err instanceof Error ? err.message : `${err}`)\n return {}\n }\n}\n\n/**\n * Get the file system location for the CLI user configuration file.\n * Takes into account the active environment (staging vs production).\n * The file is located in the user's home directory under the `.config` directory.\n *\n * @returns The path to the CLI configuration file.\n * @internal\n */\nfunction getCliUserConfigPath() {\n const sanityEnvSuffix = process.env.SANITY_INTERNAL_ENV === 'staging' ? '-staging' : ''\n const cliConfigPath =\n process.env.SANITY_CLI_CONFIG_PATH ||\n joinPath(homedir(), '.config', `sanity${sanityEnvSuffix}`, 'config.json')\n\n return cliConfigPath\n}\n"],"names":["mkdirSync","homedir","dirname","join","joinPath","z","debug","readJsonFileSync","writeJsonFileSync","clearCliTokenCache","cliUserConfigSchema","authToken","string","optional","setCliUserConfig","prop","value","config","readConfig","result","safeParse","success","message","error","issues","map","path","Error","configPath","getCliUserConfigPath","recursive","undefined","_","rest","pretty","getCliUserConfig","data","getUserConfig","get","key","set","delete","Array","isArray","err","sanityEnvSuffix","process","env","SANITY_INTERNAL_ENV","cliConfigPath","SANITY_CLI_CONFIG_PATH"],"mappings":"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"}
|
|
@@ -1,21 +1,26 @@
|
|
|
1
|
+
import { getCachedToken, setCachedToken } from './cliTokenCache.js';
|
|
1
2
|
import { getCliUserConfig } from './cliUserConfig.js';
|
|
2
|
-
|
|
3
|
+
// Re-export so existing consumers don't break
|
|
4
|
+
export { clearCliTokenCache } from './cliTokenCache.js';
|
|
3
5
|
/**
|
|
4
6
|
* Get the CLI authentication token from the environment or the config file
|
|
5
7
|
*
|
|
6
8
|
* @returns A promise that resolves to a CLI token, or undefined if no token is found
|
|
7
9
|
* @internal
|
|
8
10
|
*/ export async function getCliToken() {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
+
const cached = getCachedToken();
|
|
12
|
+
if (cached !== undefined) {
|
|
13
|
+
return cached;
|
|
11
14
|
}
|
|
12
15
|
const token = process.env.SANITY_AUTH_TOKEN;
|
|
13
16
|
if (token) {
|
|
14
|
-
|
|
15
|
-
|
|
17
|
+
const trimmed = token.trim();
|
|
18
|
+
setCachedToken(trimmed);
|
|
19
|
+
return trimmed;
|
|
16
20
|
}
|
|
17
|
-
|
|
18
|
-
|
|
21
|
+
const configToken = getCliUserConfig('authToken');
|
|
22
|
+
setCachedToken(configToken);
|
|
23
|
+
return configToken;
|
|
19
24
|
}
|
|
20
25
|
|
|
21
26
|
//# sourceMappingURL=getCliToken.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/services/getCliToken.ts"],"sourcesContent":["import {getCliUserConfig} from './cliUserConfig.js'\n\
|
|
1
|
+
{"version":3,"sources":["../../src/services/getCliToken.ts"],"sourcesContent":["import {getCachedToken, setCachedToken} from './cliTokenCache.js'\nimport {getCliUserConfig} from './cliUserConfig.js'\n\n// Re-export so existing consumers don't break\nexport {clearCliTokenCache} from './cliTokenCache.js'\n\n/**\n * Get the CLI authentication token from the environment or the config file\n *\n * @returns A promise that resolves to a CLI token, or undefined if no token is found\n * @internal\n */\nexport async function getCliToken(): Promise<string | undefined> {\n const cached = getCachedToken()\n if (cached !== undefined) {\n return cached\n }\n\n const token = process.env.SANITY_AUTH_TOKEN\n if (token) {\n const trimmed = token.trim()\n setCachedToken(trimmed)\n return trimmed\n }\n\n const configToken = getCliUserConfig('authToken')\n setCachedToken(configToken)\n return configToken\n}\n"],"names":["getCachedToken","setCachedToken","getCliUserConfig","clearCliTokenCache","getCliToken","cached","undefined","token","process","env","SANITY_AUTH_TOKEN","trimmed","trim","configToken"],"mappings":"AAAA,SAAQA,cAAc,EAAEC,cAAc,QAAO,qBAAoB;AACjE,SAAQC,gBAAgB,QAAO,qBAAoB;AAEnD,8CAA8C;AAC9C,SAAQC,kBAAkB,QAAO,qBAAoB;AAErD;;;;;CAKC,GACD,OAAO,eAAeC;IACpB,MAAMC,SAASL;IACf,IAAIK,WAAWC,WAAW;QACxB,OAAOD;IACT;IAEA,MAAME,QAAQC,QAAQC,GAAG,CAACC,iBAAiB;IAC3C,IAAIH,OAAO;QACT,MAAMI,UAAUJ,MAAMK,IAAI;QAC1BX,eAAeU;QACf,OAAOA;IACT;IAEA,MAAME,cAAcX,iBAAiB;IACrCD,eAAeY;IACf,OAAOA;AACT"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/telemetry/getCliTelemetry.ts"],"sourcesContent":["import {ux} from '@oclif/core'\nimport {noopLogger} from '@sanity/telemetry'\n\nimport {type CLITelemetryStore} from './types.js'\n\n/**\n * @public\n * Symbol used to store CLI telemetry state on globalThis.\n * Use the accessor functions instead of accessing this directly.\n */\nexport const CLI_TELEMETRY_SYMBOL = Symbol.for('sanity.cli.telemetry')\n\ntype TraceErrorReporter = (error: Error) => void\n\ninterface CliTelemetryState {\n logger: CLITelemetryStore\n\n reportTraceError?: TraceErrorReporter\n}\n\ntype GlobalWithTelemetry = typeof globalThis & {\n [CLI_TELEMETRY_SYMBOL]?: CliTelemetryState\n}\n\nfunction getState(): CliTelemetryState | undefined {\n return (globalThis as GlobalWithTelemetry)[CLI_TELEMETRY_SYMBOL]\n}\n\n/**\n * @public\n */\nexport function getCliTelemetry(): CLITelemetryStore {\n const state = getState()\n // This should never happen, but if it does, we return a noop logger to avoid errors.\n if (!state) {\n ux.warn('CLI telemetry not initialized, returning noop logger')\n return noopLogger\n }\n\n return state.logger\n}\n\n/**\n * Sets the global CLI telemetry state.\n * @internal\n */\nexport function setCliTelemetry(\n telemetry: CLITelemetryStore,\n options?: {reportTraceError?: TraceErrorReporter},\n): void {\n ;(globalThis as GlobalWithTelemetry)[CLI_TELEMETRY_SYMBOL] = {\n logger: telemetry,\n reportTraceError: options?.reportTraceError,\n }\n}\n\n/**\n * Reports an error to the CLI command trace. Called from SanityCommand.catch()\n * for real command errors (not user aborts).\n * @internal\n */\nexport function reportCliTraceError(error: Error): void {\n getState()?.reportTraceError?.(error)\n}\n\n/**\n * Clears the global CLI telemetry store.\n * @internal\n */\nexport function clearCliTelemetry(): void {\n const global = globalThis as GlobalWithTelemetry\n delete global[CLI_TELEMETRY_SYMBOL]\n}\n"],"names":["ux","noopLogger","CLI_TELEMETRY_SYMBOL","Symbol","for","getState","globalThis","getCliTelemetry","state","warn","logger","setCliTelemetry","telemetry","options","reportTraceError","reportCliTraceError","error","clearCliTelemetry","global"],"mappings":"AAAA,SAAQA,EAAE,QAAO,cAAa;AAC9B,SAAQC,UAAU,QAAO,oBAAmB;AAI5C;;;;CAIC,GACD,OAAO,MAAMC,uBAAuBC,OAAOC,GAAG,CAAC,wBAAuB;AActE,SAASC;IACP,OAAO,AAACC,UAAkC,CAACJ,qBAAqB;AAClE;AAEA;;CAEC,GACD,OAAO,SAASK;IACd,MAAMC,QAAQH;IACd,qFAAqF;IACrF,IAAI,CAACG,OAAO;QACVR,GAAGS,IAAI,CAAC;QACR,OAAOR;IACT;IAEA,OAAOO,MAAME,MAAM;AACrB;AAEA;;;CAGC,GACD,OAAO,SAASC,gBACdC,SAA4B,EAC5BC,OAAiD;;IAE/CP,UAAkC,CAACJ,qBAAqB,GAAG;QAC3DQ,QAAQE;QACRE,kBAAkBD,SAASC;IAC7B;AACF;AAEA;;;;CAIC,GACD,OAAO,SAASC,oBAAoBC,KAAY;IAC9CX,YAAYS,mBAAmBE;AACjC;AAEA;;;CAGC,GACD,OAAO,SAASC;IACd,MAAMC,SAASZ;IACf,OAAOY,MAAM,CAAChB,qBAAqB;AACrC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/telemetry/readNDJSON.ts"],"sourcesContent":["import {readFile} from 'node:fs/promises'\n\n/**\n * Reads and parses an NDJSON (newline-delimited JSON) file containing telemetry events.\n *\n * @param filePath - Path to the NDJSON file\n * @returns Promise resolving to array of parsed telemetry events\n * @throws Error if file cannot be read or contains invalid JSON\n *\n * @internal\n */\nexport async function readNDJSON<T>(filePath: string): Promise<T[]> {\n const content = await readFile(filePath, 'utf8')\n\n if (!content.trim()) {\n return []\n }\n\n return content\n .trim()\n .split('\\n')\n .filter(Boolean)\n .map((line) => JSON.parse(line) as T)\n}\n"],"names":["readFile","readNDJSON","filePath","content","trim","split","filter","Boolean","map","line","JSON","parse"],"mappings":"AAAA,SAAQA,QAAQ,QAAO,mBAAkB;AAEzC;;;;;;;;CAQC,GACD,OAAO,eAAeC,WAAcC,QAAgB;IAClD,MAAMC,UAAU,MAAMH,SAASE,UAAU;IAEzC,IAAI,CAACC,QAAQC,IAAI,IAAI;QACnB,OAAO,EAAE;IACX;IAEA,OAAOD,QACJC,IAAI,GACJC,KAAK,CAAC,MACNC,MAAM,CAACC,SACPC,GAAG,CAAC,CAACC,OAASC,KAAKC,KAAK,CAACF;AAC9B"}
|
|
@@ -27,7 +27,9 @@ import { doImport } from '../doImport.js';
|
|
|
27
27
|
return getEnvVars(rootPath);
|
|
28
28
|
} catch (err) {
|
|
29
29
|
const message = err instanceof Error ? err.message : String(err);
|
|
30
|
-
throw new Error(`Failed to import getStudioEnvironmentVariables from sanity/cli module: ${message}
|
|
30
|
+
throw new Error(`Failed to import getStudioEnvironmentVariables from sanity/cli module: ${message}`, {
|
|
31
|
+
cause: err
|
|
32
|
+
});
|
|
31
33
|
}
|
|
32
34
|
}
|
|
33
35
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/util/environment/getStudioEnvironmentVariables.ts"],"sourcesContent":["import {resolve} from 'node:path'\nimport {pathToFileURL} from 'node:url'\n\nimport {moduleResolve} from 'import-meta-resolve'\n\nimport {doImport} from '../doImport.js'\n\n/**\n * Loads the `getStudioEnvironmentVariables` function from the studio's\n * installed `sanity` package and returns the environment variables.\n *\n * This is used to ensure we're using the same version of environment variable\n * logic as the studio itself.\n *\n * @param rootPath - The root path of the Sanity Studio project\n * @returns Object containing studio environment variables\n * @internal\n */\nexport async function getStudioEnvironmentVariables(\n rootPath: string,\n): Promise<Record<string, string>> {\n // Create a fake config URL - doesn't have to be correct, just need the root path\n const fakeConfigUrl = pathToFileURL(resolve(rootPath, 'sanity.config.mjs'))\n\n // Load `getStudioEnvironmentVariables` from the `sanity/cli` module installed\n // relative to where the studio is located, instead of resolving from where this CLI is\n // running, in order to ensure we're using the same version as the studio would.\n const sanityCliUrl = moduleResolve('sanity/cli', fakeConfigUrl)\n try {\n const {getStudioEnvironmentVariables: getEnvVars} = await doImport(sanityCliUrl.href)\n if (typeof getEnvVars !== 'function') {\n throw new TypeError(\n 'Expected `getStudioEnvironmentVariables` from `sanity/cli` to be a function',\n )\n }\n return getEnvVars(rootPath)\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err)\n throw new Error(\n `Failed to import getStudioEnvironmentVariables from sanity/cli module: ${message}`,\n )\n }\n}\n"],"names":["resolve","pathToFileURL","moduleResolve","doImport","getStudioEnvironmentVariables","rootPath","fakeConfigUrl","sanityCliUrl","getEnvVars","href","TypeError","err","message","Error","String"],"mappings":"AAAA,SAAQA,OAAO,QAAO,YAAW;AACjC,SAAQC,aAAa,QAAO,WAAU;AAEtC,SAAQC,aAAa,QAAO,sBAAqB;AAEjD,SAAQC,QAAQ,QAAO,iBAAgB;AAEvC;;;;;;;;;;CAUC,GACD,OAAO,eAAeC,8BACpBC,QAAgB;IAEhB,iFAAiF;IACjF,MAAMC,gBAAgBL,cAAcD,QAAQK,UAAU;IAEtD,8EAA8E;IAC9E,uFAAuF;IACvF,gFAAgF;IAChF,MAAME,eAAeL,cAAc,cAAcI;IACjD,IAAI;QACF,MAAM,EAACF,+BAA+BI,UAAU,EAAC,GAAG,MAAML,SAASI,aAAaE,IAAI;QACpF,IAAI,OAAOD,eAAe,YAAY;YACpC,MAAM,IAAIE,UACR;QAEJ;QACA,OAAOF,WAAWH;IACpB,EAAE,OAAOM,KAAK;QACZ,MAAMC,UAAUD,eAAeE,QAAQF,IAAIC,OAAO,GAAGE,OAAOH;QAC5D,MAAM,IAAIE,MACR,CAAC,uEAAuE,EAAED,SAAS;
|
|
1
|
+
{"version":3,"sources":["../../../src/util/environment/getStudioEnvironmentVariables.ts"],"sourcesContent":["import {resolve} from 'node:path'\nimport {pathToFileURL} from 'node:url'\n\nimport {moduleResolve} from 'import-meta-resolve'\n\nimport {doImport} from '../doImport.js'\n\n/**\n * Loads the `getStudioEnvironmentVariables` function from the studio's\n * installed `sanity` package and returns the environment variables.\n *\n * This is used to ensure we're using the same version of environment variable\n * logic as the studio itself.\n *\n * @param rootPath - The root path of the Sanity Studio project\n * @returns Object containing studio environment variables\n * @internal\n */\nexport async function getStudioEnvironmentVariables(\n rootPath: string,\n): Promise<Record<string, string>> {\n // Create a fake config URL - doesn't have to be correct, just need the root path\n const fakeConfigUrl = pathToFileURL(resolve(rootPath, 'sanity.config.mjs'))\n\n // Load `getStudioEnvironmentVariables` from the `sanity/cli` module installed\n // relative to where the studio is located, instead of resolving from where this CLI is\n // running, in order to ensure we're using the same version as the studio would.\n const sanityCliUrl = moduleResolve('sanity/cli', fakeConfigUrl)\n try {\n const {getStudioEnvironmentVariables: getEnvVars} = await doImport(sanityCliUrl.href)\n if (typeof getEnvVars !== 'function') {\n throw new TypeError(\n 'Expected `getStudioEnvironmentVariables` from `sanity/cli` to be a function',\n )\n }\n return getEnvVars(rootPath)\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err)\n throw new Error(\n `Failed to import getStudioEnvironmentVariables from sanity/cli module: ${message}`,\n {cause: err},\n )\n }\n}\n"],"names":["resolve","pathToFileURL","moduleResolve","doImport","getStudioEnvironmentVariables","rootPath","fakeConfigUrl","sanityCliUrl","getEnvVars","href","TypeError","err","message","Error","String","cause"],"mappings":"AAAA,SAAQA,OAAO,QAAO,YAAW;AACjC,SAAQC,aAAa,QAAO,WAAU;AAEtC,SAAQC,aAAa,QAAO,sBAAqB;AAEjD,SAAQC,QAAQ,QAAO,iBAAgB;AAEvC;;;;;;;;;;CAUC,GACD,OAAO,eAAeC,8BACpBC,QAAgB;IAEhB,iFAAiF;IACjF,MAAMC,gBAAgBL,cAAcD,QAAQK,UAAU;IAEtD,8EAA8E;IAC9E,uFAAuF;IACvF,gFAAgF;IAChF,MAAME,eAAeL,cAAc,cAAcI;IACjD,IAAI;QACF,MAAM,EAACF,+BAA+BI,UAAU,EAAC,GAAG,MAAML,SAASI,aAAaE,IAAI;QACpF,IAAI,OAAOD,eAAe,YAAY;YACpC,MAAM,IAAIE,UACR;QAEJ;QACA,OAAOF,WAAWH;IACpB,EAAE,OAAOM,KAAK;QACZ,MAAMC,UAAUD,eAAeE,QAAQF,IAAIC,OAAO,GAAGE,OAAOH;QAC5D,MAAM,IAAIE,MACR,CAAC,uEAAuE,EAAED,SAAS,EACnF;YAACG,OAAOJ;QAAG;IAEf;AACF"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { readFileSync } from 'node:fs';
|
|
2
|
+
/**
|
|
3
|
+
* Read the file at the given path synchronously and parse it as JSON.
|
|
4
|
+
*
|
|
5
|
+
* @param filePath - Path to JSON file to read
|
|
6
|
+
* @returns The parsed file
|
|
7
|
+
* @internal
|
|
8
|
+
*/ export function readJsonFileSync(filePath) {
|
|
9
|
+
let content;
|
|
10
|
+
try {
|
|
11
|
+
content = readFileSync(filePath, 'utf8');
|
|
12
|
+
} catch (err) {
|
|
13
|
+
throw new Error(`Failed to read "${filePath}"`, {
|
|
14
|
+
cause: err
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
try {
|
|
18
|
+
return JSON.parse(content);
|
|
19
|
+
} catch (err) {
|
|
20
|
+
throw new Error(`Failed to parse "${filePath}" as JSON`, {
|
|
21
|
+
cause: err
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
//# sourceMappingURL=readJsonFileSync.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/util/readJsonFileSync.ts"],"sourcesContent":["import {readFileSync} from 'node:fs'\n\ntype JSONValue = boolean | JSONArray | JSONObject | number | string | null\n\ntype JSONObject = {[key: string]: JSONValue}\n\ntype JSONArray = Array<JSONValue>\n\n/**\n * Read the file at the given path synchronously and parse it as JSON.\n *\n * @param filePath - Path to JSON file to read\n * @returns The parsed file\n * @internal\n */\nexport function readJsonFileSync(filePath: string): JSONValue {\n let content: string\n try {\n content = readFileSync(filePath, 'utf8')\n } catch (err: unknown) {\n throw new Error(`Failed to read \"${filePath}\"`, {cause: err})\n }\n\n try {\n return JSON.parse(content)\n } catch (err: unknown) {\n throw new Error(`Failed to parse \"${filePath}\" as JSON`, {cause: err})\n }\n}\n"],"names":["readFileSync","readJsonFileSync","filePath","content","err","Error","cause","JSON","parse"],"mappings":"AAAA,SAAQA,YAAY,QAAO,UAAS;AAQpC;;;;;;CAMC,GACD,OAAO,SAASC,iBAAiBC,QAAgB;IAC/C,IAAIC;IACJ,IAAI;QACFA,UAAUH,aAAaE,UAAU;IACnC,EAAE,OAAOE,KAAc;QACrB,MAAM,IAAIC,MAAM,CAAC,gBAAgB,EAAEH,SAAS,CAAC,CAAC,EAAE;YAACI,OAAOF;QAAG;IAC7D;IAEA,IAAI;QACF,OAAOG,KAAKC,KAAK,CAACL;IACpB,EAAE,OAAOC,KAAc;QACrB,MAAM,IAAIC,MAAM,CAAC,iBAAiB,EAAEH,SAAS,SAAS,CAAC,EAAE;YAACI,OAAOF;QAAG;IACtE;AACF"}
|
|
@@ -45,7 +45,9 @@ import { doImport } from './doImport.js';
|
|
|
45
45
|
try {
|
|
46
46
|
return moduleResolve(packageName, fakeCliConfigUrl);
|
|
47
47
|
} catch (error) {
|
|
48
|
-
throw new Error(`Failed to resolve package "${packageName}" from "${workDir}": ${error instanceof Error ? error.message : String(error)}
|
|
48
|
+
throw new Error(`Failed to resolve package "${packageName}" from "${workDir}": ${error instanceof Error ? error.message : String(error)}`, {
|
|
49
|
+
cause: error
|
|
50
|
+
});
|
|
49
51
|
}
|
|
50
52
|
}
|
|
51
53
|
/**
|
|
@@ -71,7 +73,9 @@ import { doImport } from './doImport.js';
|
|
|
71
73
|
const module = await doImport(packageUrl.href);
|
|
72
74
|
return module;
|
|
73
75
|
} catch (error) {
|
|
74
|
-
throw new Error(`Failed to resolve package "${packageName}" from "${parentUrl.href}": ${error instanceof Error ? error.message : String(error)}
|
|
76
|
+
throw new Error(`Failed to resolve package "${packageName}" from "${parentUrl.href}": ${error instanceof Error ? error.message : String(error)}`, {
|
|
77
|
+
cause: error
|
|
78
|
+
});
|
|
75
79
|
}
|
|
76
80
|
}
|
|
77
81
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/util/resolveLocalPackage.ts"],"sourcesContent":["import {resolve} from 'node:path'\nimport {pathToFileURL} from 'node:url'\n\nimport {moduleResolve} from 'import-meta-resolve'\n\nimport {doImport} from './doImport.js'\n\n/**\n * Resolves and imports a package from the local project's node_modules,\n * relative to the given working directory. This avoids circular dependencies\n * and ensures the correct version of the package is used.\n *\n * @param packageName - The name of the package to resolve (e.g., 'sanity')\n * @param workDir - The working directory to resolve the package from\n * @returns The imported module\n * @throws If the package cannot be resolved or imported\n *\n * @example\n * ```ts\n * const {createSchema} = await resolveLocalPackage('sanity', workDir)\n * ```\n *\n * @internal\n */\nexport async function resolveLocalPackage<T = unknown>(\n packageName: string,\n workDir: string,\n): Promise<T> {\n const packageUrl = resolveLocalPackagePath(packageName, workDir)\n const module = await doImport(packageUrl.href)\n return module as T\n}\n\n/**\n * Resolves the URL of a package from the local project's node_modules,\n * relative to the given working directory, without importing it.\n *\n * @param packageName - The name of the package to resolve (e.g., 'sanity')\n * @param workDir - The working directory to resolve the package from\n * @returns The resolved URL of the package entry point\n * @throws If the package cannot be resolved\n *\n * @example\n * ```ts\n * // Resolve a transitive dependency via its parent package:\n * const sanityUrl = resolveLocalPackagePath('sanity', workDir)\n * const uiUrl = resolveLocalPackagePathFrom('@sanity/ui', sanityUrl)\n * ```\n *\n * @internal\n */\nexport function resolveLocalPackagePath(packageName: string, workDir: string): URL {\n const fakeCliConfigUrl = pathToFileURL(resolve(workDir, 'sanity.cli.mjs'))\n\n try {\n return moduleResolve(packageName, fakeCliConfigUrl)\n } catch (error) {\n throw new Error(\n `Failed to resolve package \"${packageName}\" from \"${workDir}\": ${error instanceof Error ? error.message : String(error)}`,\n )\n }\n}\n\n/**\n * Resolves and imports a package relative to another resolved module URL.\n * Useful for resolving transitive dependencies that may not be directly\n * accessible from the project root (e.g., in pnpm strict mode).\n *\n * @param packageName - The name of the package to resolve\n * @param parentUrl - The URL of the parent module to resolve from\n * @returns The imported module\n * @throws If the package cannot be resolved or imported\n *\n * @example\n * ```ts\n * const sanityUrl = resolveLocalPackagePath('sanity', workDir)\n * const ui = await resolveLocalPackageFrom<typeof import('@sanity/ui')>('@sanity/ui', sanityUrl)\n * ```\n *\n * @internal\n */\nexport async function resolveLocalPackageFrom<T = unknown>(\n packageName: string,\n parentUrl: URL,\n): Promise<T> {\n try {\n const packageUrl = moduleResolve(packageName, parentUrl)\n const module = await doImport(packageUrl.href)\n return module as T\n } catch (error) {\n throw new Error(\n `Failed to resolve package \"${packageName}\" from \"${parentUrl.href}\": ${error instanceof Error ? error.message : String(error)}`,\n )\n }\n}\n"],"names":["resolve","pathToFileURL","moduleResolve","doImport","resolveLocalPackage","packageName","workDir","packageUrl","resolveLocalPackagePath","module","href","fakeCliConfigUrl","error","Error","message","String","resolveLocalPackageFrom","parentUrl"],"mappings":"AAAA,SAAQA,OAAO,QAAO,YAAW;AACjC,SAAQC,aAAa,QAAO,WAAU;AAEtC,SAAQC,aAAa,QAAO,sBAAqB;AAEjD,SAAQC,QAAQ,QAAO,gBAAe;AAEtC;;;;;;;;;;;;;;;;CAgBC,GACD,OAAO,eAAeC,oBACpBC,WAAmB,EACnBC,OAAe;IAEf,MAAMC,aAAaC,wBAAwBH,aAAaC;IACxD,MAAMG,SAAS,MAAMN,SAASI,WAAWG,IAAI;IAC7C,OAAOD;AACT;AAEA;;;;;;;;;;;;;;;;;CAiBC,GACD,OAAO,SAASD,wBAAwBH,WAAmB,EAAEC,OAAe;IAC1E,MAAMK,mBAAmBV,cAAcD,QAAQM,SAAS;IAExD,IAAI;QACF,OAAOJ,cAAcG,aAAaM;IACpC,EAAE,OAAOC,OAAO;QACd,MAAM,IAAIC,MACR,CAAC,2BAA2B,EAAER,YAAY,QAAQ,EAAEC,QAAQ,GAAG,EAAEM,iBAAiBC,QAAQD,MAAME,OAAO,GAAGC,OAAOH,QAAQ;
|
|
1
|
+
{"version":3,"sources":["../../src/util/resolveLocalPackage.ts"],"sourcesContent":["import {resolve} from 'node:path'\nimport {pathToFileURL} from 'node:url'\n\nimport {moduleResolve} from 'import-meta-resolve'\n\nimport {doImport} from './doImport.js'\n\n/**\n * Resolves and imports a package from the local project's node_modules,\n * relative to the given working directory. This avoids circular dependencies\n * and ensures the correct version of the package is used.\n *\n * @param packageName - The name of the package to resolve (e.g., 'sanity')\n * @param workDir - The working directory to resolve the package from\n * @returns The imported module\n * @throws If the package cannot be resolved or imported\n *\n * @example\n * ```ts\n * const {createSchema} = await resolveLocalPackage('sanity', workDir)\n * ```\n *\n * @internal\n */\nexport async function resolveLocalPackage<T = unknown>(\n packageName: string,\n workDir: string,\n): Promise<T> {\n const packageUrl = resolveLocalPackagePath(packageName, workDir)\n const module = await doImport(packageUrl.href)\n return module as T\n}\n\n/**\n * Resolves the URL of a package from the local project's node_modules,\n * relative to the given working directory, without importing it.\n *\n * @param packageName - The name of the package to resolve (e.g., 'sanity')\n * @param workDir - The working directory to resolve the package from\n * @returns The resolved URL of the package entry point\n * @throws If the package cannot be resolved\n *\n * @example\n * ```ts\n * // Resolve a transitive dependency via its parent package:\n * const sanityUrl = resolveLocalPackagePath('sanity', workDir)\n * const uiUrl = resolveLocalPackagePathFrom('@sanity/ui', sanityUrl)\n * ```\n *\n * @internal\n */\nexport function resolveLocalPackagePath(packageName: string, workDir: string): URL {\n const fakeCliConfigUrl = pathToFileURL(resolve(workDir, 'sanity.cli.mjs'))\n\n try {\n return moduleResolve(packageName, fakeCliConfigUrl)\n } catch (error) {\n throw new Error(\n `Failed to resolve package \"${packageName}\" from \"${workDir}\": ${error instanceof Error ? error.message : String(error)}`,\n {cause: error},\n )\n }\n}\n\n/**\n * Resolves and imports a package relative to another resolved module URL.\n * Useful for resolving transitive dependencies that may not be directly\n * accessible from the project root (e.g., in pnpm strict mode).\n *\n * @param packageName - The name of the package to resolve\n * @param parentUrl - The URL of the parent module to resolve from\n * @returns The imported module\n * @throws If the package cannot be resolved or imported\n *\n * @example\n * ```ts\n * const sanityUrl = resolveLocalPackagePath('sanity', workDir)\n * const ui = await resolveLocalPackageFrom<typeof import('@sanity/ui')>('@sanity/ui', sanityUrl)\n * ```\n *\n * @internal\n */\nexport async function resolveLocalPackageFrom<T = unknown>(\n packageName: string,\n parentUrl: URL,\n): Promise<T> {\n try {\n const packageUrl = moduleResolve(packageName, parentUrl)\n const module = await doImport(packageUrl.href)\n return module as T\n } catch (error) {\n throw new Error(\n `Failed to resolve package \"${packageName}\" from \"${parentUrl.href}\": ${error instanceof Error ? error.message : String(error)}`,\n {cause: error},\n )\n }\n}\n"],"names":["resolve","pathToFileURL","moduleResolve","doImport","resolveLocalPackage","packageName","workDir","packageUrl","resolveLocalPackagePath","module","href","fakeCliConfigUrl","error","Error","message","String","cause","resolveLocalPackageFrom","parentUrl"],"mappings":"AAAA,SAAQA,OAAO,QAAO,YAAW;AACjC,SAAQC,aAAa,QAAO,WAAU;AAEtC,SAAQC,aAAa,QAAO,sBAAqB;AAEjD,SAAQC,QAAQ,QAAO,gBAAe;AAEtC;;;;;;;;;;;;;;;;CAgBC,GACD,OAAO,eAAeC,oBACpBC,WAAmB,EACnBC,OAAe;IAEf,MAAMC,aAAaC,wBAAwBH,aAAaC;IACxD,MAAMG,SAAS,MAAMN,SAASI,WAAWG,IAAI;IAC7C,OAAOD;AACT;AAEA;;;;;;;;;;;;;;;;;CAiBC,GACD,OAAO,SAASD,wBAAwBH,WAAmB,EAAEC,OAAe;IAC1E,MAAMK,mBAAmBV,cAAcD,QAAQM,SAAS;IAExD,IAAI;QACF,OAAOJ,cAAcG,aAAaM;IACpC,EAAE,OAAOC,OAAO;QACd,MAAM,IAAIC,MACR,CAAC,2BAA2B,EAAER,YAAY,QAAQ,EAAEC,QAAQ,GAAG,EAAEM,iBAAiBC,QAAQD,MAAME,OAAO,GAAGC,OAAOH,QAAQ,EACzH;YAACI,OAAOJ;QAAK;IAEjB;AACF;AAEA;;;;;;;;;;;;;;;;;CAiBC,GACD,OAAO,eAAeK,wBACpBZ,WAAmB,EACnBa,SAAc;IAEd,IAAI;QACF,MAAMX,aAAaL,cAAcG,aAAaa;QAC9C,MAAMT,SAAS,MAAMN,SAASI,WAAWG,IAAI;QAC7C,OAAOD;IACT,EAAE,OAAOG,OAAO;QACd,MAAM,IAAIC,MACR,CAAC,2BAA2B,EAAER,YAAY,QAAQ,EAAEa,UAAUR,IAAI,CAAC,GAAG,EAAEE,iBAAiBC,QAAQD,MAAME,OAAO,GAAGC,OAAOH,QAAQ,EAChI;YAACI,OAAOJ;QAAK;IAEjB;AACF"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { writeFileSync } from 'node:fs';
|
|
2
|
+
/**
|
|
3
|
+
* Serialize the given `data` as JSON and write it synchronously to the given path.
|
|
4
|
+
*
|
|
5
|
+
* @param filePath - Path to JSON file to write
|
|
6
|
+
* @internal
|
|
7
|
+
*/ export function writeJsonFileSync(filePath, data, options = {}) {
|
|
8
|
+
const { pretty = false } = options;
|
|
9
|
+
try {
|
|
10
|
+
const stringified = pretty ? JSON.stringify(data, null, 2) : JSON.stringify(data);
|
|
11
|
+
writeFileSync(filePath, `${stringified}\n`, 'utf8');
|
|
12
|
+
} catch (err) {
|
|
13
|
+
throw new Error(`Failed to write "${filePath}"`, {
|
|
14
|
+
cause: err
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
//# sourceMappingURL=writeJsonFileSync.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/util/writeJsonFileSync.ts"],"sourcesContent":["import {writeFileSync} from 'node:fs'\n\n/**\n * Serialize the given `data` as JSON and write it synchronously to the given path.\n *\n * @param filePath - Path to JSON file to write\n * @internal\n */\nexport function writeJsonFileSync(\n filePath: string,\n data: unknown,\n options: {pretty?: boolean} = {},\n): void {\n const {pretty = false} = options\n try {\n const stringified = pretty ? JSON.stringify(data, null, 2) : JSON.stringify(data)\n writeFileSync(filePath, `${stringified}\\n`, 'utf8')\n } catch (err: unknown) {\n throw new Error(`Failed to write \"${filePath}\"`, {cause: err})\n }\n}\n"],"names":["writeFileSync","writeJsonFileSync","filePath","data","options","pretty","stringified","JSON","stringify","err","Error","cause"],"mappings":"AAAA,SAAQA,aAAa,QAAO,UAAS;AAErC;;;;;CAKC,GACD,OAAO,SAASC,kBACdC,QAAgB,EAChBC,IAAa,EACbC,UAA8B,CAAC,CAAC;IAEhC,MAAM,EAACC,SAAS,KAAK,EAAC,GAAGD;IACzB,IAAI;QACF,MAAME,cAAcD,SAASE,KAAKC,SAAS,CAACL,MAAM,MAAM,KAAKI,KAAKC,SAAS,CAACL;QAC5EH,cAAcE,UAAU,GAAGI,YAAY,EAAE,CAAC,EAAE;IAC9C,EAAE,OAAOG,KAAc;QACrB,MAAM,IAAIC,MAAM,CAAC,iBAAiB,EAAER,SAAS,CAAC,CAAC,EAAE;YAACS,OAAOF;QAAG;IAC9D;AACF"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sanity/cli-core",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"description": "Sanity CLI core package",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cli",
|
|
@@ -21,16 +21,17 @@
|
|
|
21
21
|
"directory": "packages/@sanity/cli-core"
|
|
22
22
|
},
|
|
23
23
|
"files": [
|
|
24
|
-
"./dist"
|
|
24
|
+
"./dist",
|
|
25
|
+
"!./dist/**/__tests__"
|
|
25
26
|
],
|
|
26
27
|
"type": "module",
|
|
27
28
|
"sideEffects": false,
|
|
28
|
-
"main": "./dist/index.js",
|
|
29
|
-
"types": "dist/index.d.ts",
|
|
29
|
+
"main": "./dist/_exports/index.js",
|
|
30
|
+
"types": "dist/_exports/index.d.ts",
|
|
30
31
|
"exports": {
|
|
31
32
|
".": {
|
|
32
|
-
"source": "./src/index.ts",
|
|
33
|
-
"default": "./dist/index.js"
|
|
33
|
+
"source": "./src/_exports/index.ts",
|
|
34
|
+
"default": "./dist/_exports/index.js"
|
|
34
35
|
},
|
|
35
36
|
"./ux": {
|
|
36
37
|
"source": "./src/_exports/ux.ts",
|
|
@@ -51,17 +52,16 @@
|
|
|
51
52
|
},
|
|
52
53
|
"dependencies": {
|
|
53
54
|
"@inquirer/prompts": "^8.3.0",
|
|
54
|
-
"@oclif/core": "^4.
|
|
55
|
+
"@oclif/core": "^4.10.2",
|
|
55
56
|
"@rexxars/jiti": "^2.6.2",
|
|
56
|
-
"@sanity/client": "^7.
|
|
57
|
+
"@sanity/client": "^7.20.0",
|
|
57
58
|
"babel-plugin-react-compiler": "^1.0.0",
|
|
58
59
|
"boxen": "^8.0.1",
|
|
59
|
-
"configstore": "^7.0.0",
|
|
60
60
|
"debug": "^4.4.3",
|
|
61
61
|
"get-it": "^8.7.0",
|
|
62
|
-
"get-tsconfig": "^4.13.
|
|
62
|
+
"get-tsconfig": "^4.13.7",
|
|
63
63
|
"import-meta-resolve": "^4.2.0",
|
|
64
|
-
"jsdom": "^
|
|
64
|
+
"jsdom": "^29.0.1",
|
|
65
65
|
"json-lexer": "^1.2.0",
|
|
66
66
|
"log-symbols": "^7.0.1",
|
|
67
67
|
"ora": "^9.0.0",
|
|
@@ -74,30 +74,30 @@
|
|
|
74
74
|
},
|
|
75
75
|
"devDependencies": {
|
|
76
76
|
"@eslint/compat": "^2.0.3",
|
|
77
|
-
"@sanity/pkg-utils": "^10.4.
|
|
78
|
-
"@sanity/telemetry": "^0.
|
|
77
|
+
"@sanity/pkg-utils": "^10.4.13",
|
|
78
|
+
"@sanity/telemetry": "^0.9.0",
|
|
79
79
|
"@swc/cli": "^0.8.0",
|
|
80
|
-
"@swc/core": "^1.15.
|
|
81
|
-
"@types/debug": "^4.1.
|
|
82
|
-
"@types/jsdom": "^28.0.
|
|
80
|
+
"@swc/core": "^1.15.21",
|
|
81
|
+
"@types/debug": "^4.1.13",
|
|
82
|
+
"@types/jsdom": "^28.0.1",
|
|
83
83
|
"@types/node": "^20.19.37",
|
|
84
|
-
"eslint": "^
|
|
84
|
+
"eslint": "^10.1.0",
|
|
85
85
|
"publint": "^0.3.18",
|
|
86
|
-
"sanity": "^5.
|
|
86
|
+
"sanity": "^5.18.0",
|
|
87
87
|
"typescript": "^5.9.3",
|
|
88
|
-
"vitest": "^4.1.
|
|
89
|
-
"@repo/tsconfig": "3.70.0",
|
|
88
|
+
"vitest": "^4.1.2",
|
|
90
89
|
"@repo/package.config": "0.0.1",
|
|
91
|
-
"@sanity/eslint-config-cli": "1.0
|
|
90
|
+
"@sanity/eslint-config-cli": "1.1.0",
|
|
91
|
+
"@repo/tsconfig": "3.70.0"
|
|
92
92
|
},
|
|
93
93
|
"peerDependencies": {
|
|
94
|
-
"@sanity/telemetry": ">=0.
|
|
94
|
+
"@sanity/telemetry": ">=0.9.0 <0.10.0"
|
|
95
95
|
},
|
|
96
96
|
"engines": {
|
|
97
97
|
"node": ">=20.19.1 <22 || >=22.12"
|
|
98
98
|
},
|
|
99
99
|
"scripts": {
|
|
100
|
-
"build": "swc --delete-dir-on-start --strip-leading-paths --out-dir dist/ src --ignore '**/*.test.ts'",
|
|
100
|
+
"build": "swc --delete-dir-on-start --strip-leading-paths --out-dir dist/ src --ignore '**/*.test.ts' --ignore '**/__tests__/**'",
|
|
101
101
|
"build:types": "pkg-utils build --emitDeclarationOnly",
|
|
102
102
|
"check:types": "tsc --noEmit",
|
|
103
103
|
"lint": "eslint .",
|
package/dist/index.js
DELETED
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
export * from './config/cli/getCliConfig.js';
|
|
2
|
-
export * from './config/cli/getCliConfigSync.js';
|
|
3
|
-
export * from './config/findProjectRoot.js';
|
|
4
|
-
export * from './config/findProjectRootSync.js';
|
|
5
|
-
export * from './config/studio/getStudioConfig.js';
|
|
6
|
-
export * from './config/studio/getStudioWorkspaces.js';
|
|
7
|
-
export * from './config/studio/isStudioConfig.js';
|
|
8
|
-
export * from './config/util/findConfigsPaths.js';
|
|
9
|
-
export * from './config/util/findStudioConfigPath.js';
|
|
10
|
-
export * from './debug.js';
|
|
11
|
-
export * from './errors/NonInteractiveError.js';
|
|
12
|
-
export * from './errors/NotFoundError.js';
|
|
13
|
-
export * from './errors/ProjectRootNotFoundError.js';
|
|
14
|
-
export * from './loaders/studio/studioWorkerTask.js';
|
|
15
|
-
export * from './loaders/tsx/tsxWorkerTask.js';
|
|
16
|
-
export * from './SanityCommand.js';
|
|
17
|
-
export * from './services/apiClient.js';
|
|
18
|
-
export * from './services/cliUserConfig.js';
|
|
19
|
-
export * from './services/getCliToken.js';
|
|
20
|
-
export * from './telemetry/getTelemetryBaseInfo.js';
|
|
21
|
-
export { doImport } from './util/doImport.js';
|
|
22
|
-
export * from './util/environment/mockBrowserEnvironment.js';
|
|
23
|
-
export { clearCliTelemetry, CLI_TELEMETRY_SYMBOL, getCliTelemetry, setCliTelemetry } from './util/getCliTelemetry.js';
|
|
24
|
-
export * from './util/getSanityEnvVar.js';
|
|
25
|
-
export * from './util/getSanityUrl.js';
|
|
26
|
-
export * from './util/getUserConfig.js';
|
|
27
|
-
export * from './util/importModule.js';
|
|
28
|
-
export * from './util/isCi.js';
|
|
29
|
-
export * from './util/isInteractive.js';
|
|
30
|
-
export * from './util/isStaging.js';
|
|
31
|
-
export * from './util/normalizePath.js';
|
|
32
|
-
export * from './util/promisifyWorker.js';
|
|
33
|
-
export * from './util/readPackageJson.js';
|
|
34
|
-
export * from './util/resolveLocalPackage.js';
|
|
35
|
-
export * from './util/safeStructuredClone.js';
|
|
36
|
-
export * from './ux/colorizeJson.js';
|
|
37
|
-
export * from './ux/timer.js';
|
|
38
|
-
|
|
39
|
-
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["export * from './config/cli/getCliConfig.js'\nexport * from './config/cli/getCliConfigSync.js'\nexport {type CliConfig} from './config/cli/types/cliConfig.js'\nexport {type UserViteConfig} from './config/cli/types/userViteConfig.js'\nexport * from './config/findProjectRoot.js'\nexport * from './config/findProjectRootSync.js'\nexport * from './config/studio/getStudioConfig.js'\nexport * from './config/studio/getStudioWorkspaces.js'\nexport * from './config/studio/isStudioConfig.js'\nexport * from './config/util/findConfigsPaths.js'\nexport * from './config/util/findStudioConfigPath.js'\nexport {type ProjectRootResult} from './config/util/recursivelyResolveProjectRoot.js'\nexport * from './debug.js'\nexport * from './errors/NonInteractiveError.js'\nexport * from './errors/NotFoundError.js'\nexport * from './errors/ProjectRootNotFoundError.js'\nexport * from './loaders/studio/studioWorkerTask.js'\nexport * from './loaders/tsx/tsxWorkerTask.js'\nexport * from './SanityCommand.js'\nexport * from './services/apiClient.js'\nexport * from './services/cliUserConfig.js'\nexport * from './services/getCliToken.js'\nexport * from './telemetry/getTelemetryBaseInfo.js'\nexport {\n type CLITelemetryStore,\n type ConsentInformation,\n type TelemetryUserProperties,\n} from './telemetry/types.js'\nexport {type Output, type SanityOrgUser} from './types.js'\nexport {doImport} from './util/doImport.js'\nexport * from './util/environment/mockBrowserEnvironment.js'\nexport {\n clearCliTelemetry,\n CLI_TELEMETRY_SYMBOL,\n getCliTelemetry,\n setCliTelemetry,\n} from './util/getCliTelemetry.js'\nexport * from './util/getSanityEnvVar.js'\nexport * from './util/getSanityUrl.js'\nexport * from './util/getUserConfig.js'\nexport * from './util/importModule.js'\nexport * from './util/isCi.js'\nexport * from './util/isInteractive.js'\nexport * from './util/isStaging.js'\nexport * from './util/normalizePath.js'\nexport * from './util/promisifyWorker.js'\nexport * from './util/readPackageJson.js'\nexport * from './util/resolveLocalPackage.js'\nexport * from './util/safeStructuredClone.js'\nexport * from './ux/colorizeJson.js'\nexport * from './ux/timer.js'\n"],"names":["doImport","clearCliTelemetry","CLI_TELEMETRY_SYMBOL","getCliTelemetry","setCliTelemetry"],"mappings":"AAAA,cAAc,+BAA8B;AAC5C,cAAc,mCAAkC;AAGhD,cAAc,8BAA6B;AAC3C,cAAc,kCAAiC;AAC/C,cAAc,qCAAoC;AAClD,cAAc,yCAAwC;AACtD,cAAc,oCAAmC;AACjD,cAAc,oCAAmC;AACjD,cAAc,wCAAuC;AAErD,cAAc,aAAY;AAC1B,cAAc,kCAAiC;AAC/C,cAAc,4BAA2B;AACzC,cAAc,uCAAsC;AACpD,cAAc,uCAAsC;AACpD,cAAc,iCAAgC;AAC9C,cAAc,qBAAoB;AAClC,cAAc,0BAAyB;AACvC,cAAc,8BAA6B;AAC3C,cAAc,4BAA2B;AACzC,cAAc,sCAAqC;AAOnD,SAAQA,QAAQ,QAAO,qBAAoB;AAC3C,cAAc,+CAA8C;AAC5D,SACEC,iBAAiB,EACjBC,oBAAoB,EACpBC,eAAe,EACfC,eAAe,QACV,4BAA2B;AAClC,cAAc,4BAA2B;AACzC,cAAc,yBAAwB;AACtC,cAAc,0BAAyB;AACvC,cAAc,yBAAwB;AACtC,cAAc,iBAAgB;AAC9B,cAAc,0BAAyB;AACvC,cAAc,sBAAqB;AACnC,cAAc,0BAAyB;AACvC,cAAc,4BAA2B;AACzC,cAAc,4BAA2B;AACzC,cAAc,gCAA+B;AAC7C,cAAc,gCAA+B;AAC7C,cAAc,uBAAsB;AACpC,cAAc,gBAAe"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/util/getCliTelemetry.ts"],"sourcesContent":["import {ux} from '@oclif/core'\nimport {noopLogger} from '@sanity/telemetry'\n\nimport {type CLITelemetryStore} from '../telemetry/types.js'\n\n/**\n * @public\n * Symbol used to store CLI telemetry state on globalThis.\n * Use the accessor functions instead of accessing this directly.\n */\nexport const CLI_TELEMETRY_SYMBOL = Symbol.for('sanity.cli.telemetry')\n\ntype TraceErrorReporter = (error: Error) => void\n\ninterface CliTelemetryState {\n logger: CLITelemetryStore\n\n reportTraceError?: TraceErrorReporter\n}\n\ntype GlobalWithTelemetry = typeof globalThis & {\n [CLI_TELEMETRY_SYMBOL]?: CliTelemetryState\n}\n\nfunction getState(): CliTelemetryState | undefined {\n return (globalThis as GlobalWithTelemetry)[CLI_TELEMETRY_SYMBOL]\n}\n\n/**\n * @public\n */\nexport function getCliTelemetry(): CLITelemetryStore {\n const state = getState()\n // This should never happen, but if it does, we return a noop logger to avoid errors.\n if (!state) {\n ux.warn('CLI telemetry not initialized, returning noop logger')\n return noopLogger\n }\n\n return state.logger\n}\n\n/**\n * Sets the global CLI telemetry state.\n * @internal\n */\nexport function setCliTelemetry(\n telemetry: CLITelemetryStore,\n options?: {reportTraceError?: TraceErrorReporter},\n): void {\n ;(globalThis as GlobalWithTelemetry)[CLI_TELEMETRY_SYMBOL] = {\n logger: telemetry,\n reportTraceError: options?.reportTraceError,\n }\n}\n\n/**\n * Reports an error to the CLI command trace. Called from SanityCommand.catch()\n * for real command errors (not user aborts).\n * @internal\n */\nexport function reportCliTraceError(error: Error): void {\n getState()?.reportTraceError?.(error)\n}\n\n/**\n * Clears the global CLI telemetry store.\n * @internal\n */\nexport function clearCliTelemetry(): void {\n const global = globalThis as GlobalWithTelemetry\n delete global[CLI_TELEMETRY_SYMBOL]\n}\n"],"names":["ux","noopLogger","CLI_TELEMETRY_SYMBOL","Symbol","for","getState","globalThis","getCliTelemetry","state","warn","logger","setCliTelemetry","telemetry","options","reportTraceError","reportCliTraceError","error","clearCliTelemetry","global"],"mappings":"AAAA,SAAQA,EAAE,QAAO,cAAa;AAC9B,SAAQC,UAAU,QAAO,oBAAmB;AAI5C;;;;CAIC,GACD,OAAO,MAAMC,uBAAuBC,OAAOC,GAAG,CAAC,wBAAuB;AActE,SAASC;IACP,OAAO,AAACC,UAAkC,CAACJ,qBAAqB;AAClE;AAEA;;CAEC,GACD,OAAO,SAASK;IACd,MAAMC,QAAQH;IACd,qFAAqF;IACrF,IAAI,CAACG,OAAO;QACVR,GAAGS,IAAI,CAAC;QACR,OAAOR;IACT;IAEA,OAAOO,MAAME,MAAM;AACrB;AAEA;;;CAGC,GACD,OAAO,SAASC,gBACdC,SAA4B,EAC5BC,OAAiD;;IAE/CP,UAAkC,CAACJ,qBAAqB,GAAG;QAC3DQ,QAAQE;QACRE,kBAAkBD,SAASC;IAC7B;AACF;AAEA;;;;CAIC,GACD,OAAO,SAASC,oBAAoBC,KAAY;IAC9CX,YAAYS,mBAAmBE;AACjC;AAEA;;;CAGC,GACD,OAAO,SAASC;IACd,MAAMC,SAASZ;IACf,OAAOY,MAAM,CAAChB,qBAAqB;AACrC"}
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import ConfigStore from 'configstore';
|
|
2
|
-
const sanityEnv = (process.env.SANITY_INTERNAL_ENV || '').toLowerCase();
|
|
3
|
-
const configName = sanityEnv && sanityEnv !== 'production' ? `sanity-${sanityEnv}` : 'sanity';
|
|
4
|
-
const defaults = {};
|
|
5
|
-
let config;
|
|
6
|
-
export const getUserConfig = ()=>{
|
|
7
|
-
if (!config) {
|
|
8
|
-
config = new ConfigStore(configName, defaults, {
|
|
9
|
-
globalConfigPath: true
|
|
10
|
-
});
|
|
11
|
-
}
|
|
12
|
-
return config;
|
|
13
|
-
};
|
|
14
|
-
|
|
15
|
-
//# sourceMappingURL=getUserConfig.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/util/getUserConfig.ts"],"sourcesContent":["import ConfigStore from 'configstore'\n\nconst sanityEnv = (process.env.SANITY_INTERNAL_ENV || '').toLowerCase()\nconst configName = sanityEnv && sanityEnv !== 'production' ? `sanity-${sanityEnv}` : 'sanity'\nconst defaults = {}\nlet config: ConfigStore\n\nexport const getUserConfig = (): ConfigStore => {\n if (!config) {\n config = new ConfigStore(configName, defaults, {globalConfigPath: true})\n }\n\n return config\n}\n"],"names":["ConfigStore","sanityEnv","process","env","SANITY_INTERNAL_ENV","toLowerCase","configName","defaults","config","getUserConfig","globalConfigPath"],"mappings":"AAAA,OAAOA,iBAAiB,cAAa;AAErC,MAAMC,YAAY,AAACC,CAAAA,QAAQC,GAAG,CAACC,mBAAmB,IAAI,EAAC,EAAGC,WAAW;AACrE,MAAMC,aAAaL,aAAaA,cAAc,eAAe,CAAC,OAAO,EAAEA,WAAW,GAAG;AACrF,MAAMM,WAAW,CAAC;AAClB,IAAIC;AAEJ,OAAO,MAAMC,gBAAgB;IAC3B,IAAI,CAACD,QAAQ;QACXA,SAAS,IAAIR,YAAYM,YAAYC,UAAU;YAACG,kBAAkB;QAAI;IACxE;IAEA,OAAOF;AACT,EAAC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/util/readNDJSON.ts"],"sourcesContent":["import {readFile} from 'node:fs/promises'\n\n/**\n * Reads and parses an NDJSON (newline-delimited JSON) file containing telemetry events.\n *\n * @param filePath - Path to the NDJSON file\n * @returns Promise resolving to array of parsed telemetry events\n * @throws Error if file cannot be read or contains invalid JSON\n *\n * @internal\n */\nexport async function readNDJSON<T>(filePath: string): Promise<T[]> {\n const content = await readFile(filePath, 'utf8')\n\n if (!content.trim()) {\n return []\n }\n\n return content\n .trim()\n .split('\\n')\n .filter(Boolean)\n .map((line) => JSON.parse(line) as T)\n}\n"],"names":["readFile","readNDJSON","filePath","content","trim","split","filter","Boolean","map","line","JSON","parse"],"mappings":"AAAA,SAAQA,QAAQ,QAAO,mBAAkB;AAEzC;;;;;;;;CAQC,GACD,OAAO,eAAeC,WAAcC,QAAgB;IAClD,MAAMC,UAAU,MAAMH,SAASE,UAAU;IAEzC,IAAI,CAACC,QAAQC,IAAI,IAAI;QACnB,OAAO,EAAE;IACX;IAEA,OAAOD,QACJC,IAAI,GACJC,KAAK,CAAC,MACNC,MAAM,CAACC,SACPC,GAAG,CAAC,CAACC,OAASC,KAAKC,KAAK,CAACF;AAC9B"}
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import { writeFile } from 'node:fs/promises';
|
|
2
|
-
/**
|
|
3
|
-
* Serialize the given `data` as JSON and write it to the given path.
|
|
4
|
-
*
|
|
5
|
-
* @param filePath - Path to JSON file to read
|
|
6
|
-
* @internal
|
|
7
|
-
*/ export async function writeJsonFile(filePath, data, options = {}) {
|
|
8
|
-
const { pretty = false } = options;
|
|
9
|
-
try {
|
|
10
|
-
const stringified = pretty ? JSON.stringify(data, null, 2) : JSON.stringify(data);
|
|
11
|
-
await writeFile(filePath, stringified, 'utf8');
|
|
12
|
-
} catch (err) {
|
|
13
|
-
throw new Error(`Failed to write "${filePath}"`, {
|
|
14
|
-
cause: err
|
|
15
|
-
});
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
//# sourceMappingURL=writeJsonFile.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/util/writeJsonFile.ts"],"sourcesContent":["import {writeFile} from 'node:fs/promises'\n\n/**\n * Serialize the given `data` as JSON and write it to the given path.\n *\n * @param filePath - Path to JSON file to read\n * @internal\n */\nexport async function writeJsonFile(\n filePath: string,\n data: unknown,\n options: {pretty?: boolean} = {},\n): Promise<void> {\n const {pretty = false} = options\n try {\n const stringified = pretty ? JSON.stringify(data, null, 2) : JSON.stringify(data)\n await writeFile(filePath, stringified, 'utf8')\n } catch (err: unknown) {\n throw new Error(`Failed to write \"${filePath}\"`, {cause: err})\n }\n}\n"],"names":["writeFile","writeJsonFile","filePath","data","options","pretty","stringified","JSON","stringify","err","Error","cause"],"mappings":"AAAA,SAAQA,SAAS,QAAO,mBAAkB;AAE1C;;;;;CAKC,GACD,OAAO,eAAeC,cACpBC,QAAgB,EAChBC,IAAa,EACbC,UAA8B,CAAC,CAAC;IAEhC,MAAM,EAACC,SAAS,KAAK,EAAC,GAAGD;IACzB,IAAI;QACF,MAAME,cAAcD,SAASE,KAAKC,SAAS,CAACL,MAAM,MAAM,KAAKI,KAAKC,SAAS,CAACL;QAC5E,MAAMH,UAAUE,UAAUI,aAAa;IACzC,EAAE,OAAOG,KAAc;QACrB,MAAM,IAAIC,MAAM,CAAC,iBAAiB,EAAER,SAAS,CAAC,CAAC,EAAE;YAACS,OAAOF;QAAG;IAC9D;AACF"}
|
|
File without changes
|
|
File without changes
|