@sanity/cli-core 1.0.1 → 1.1.1
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 +18 -1
- package/dist/SanityCommand.js.map +1 -1
- package/dist/index.d.ts +64 -4
- package/dist/util/getCliTelemetry.js +22 -9
- package/dist/util/getCliTelemetry.js.map +1 -1
- package/dist/util/resolveLocalPackage.js +48 -4
- package/dist/util/resolveLocalPackage.js.map +1 -1
- package/package.json +2 -2
package/dist/SanityCommand.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { styleText } from 'node:util';
|
|
1
2
|
import { Command } from '@oclif/core';
|
|
2
3
|
import { getCliConfig } from './config/cli/getCliConfig.js';
|
|
3
4
|
import { findProjectRoot } from './config/findProjectRoot.js';
|
|
@@ -5,7 +6,7 @@ import { subdebug } from './debug.js';
|
|
|
5
6
|
import { NonInteractiveError } from './errors/NonInteractiveError.js';
|
|
6
7
|
import { ProjectRootNotFoundError } from './errors/ProjectRootNotFoundError.js';
|
|
7
8
|
import { getGlobalCliClient, getProjectCliClient } from './services/apiClient.js';
|
|
8
|
-
import { getCliTelemetry } from './util/getCliTelemetry.js';
|
|
9
|
+
import { getCliTelemetry, reportCliTraceError } from './util/getCliTelemetry.js';
|
|
9
10
|
import { isInteractive } from './util/isInteractive.js';
|
|
10
11
|
const debug = subdebug('sanityCommand');
|
|
11
12
|
export class SanityCommand extends Command {
|
|
@@ -47,6 +48,22 @@ export class SanityCommand extends Command {
|
|
|
47
48
|
* @returns The telemetry store.
|
|
48
49
|
*/ telemetry;
|
|
49
50
|
/**
|
|
51
|
+
* Report real command errors to the CLI command trace.
|
|
52
|
+
* User aborts (SIGINT, ExitPromptError) are not reported — the trace is left
|
|
53
|
+
* incomplete, which accurately represents that the command was interrupted.
|
|
54
|
+
*/ async catch(err) {
|
|
55
|
+
// ExitPromptError is thrown by `@inquirer/prompts` when the user cancels a prompt
|
|
56
|
+
// The `message === 'SIGINT'` check matches oclif's own convention (see handle.js in @oclif/core)
|
|
57
|
+
if (err.name === 'ExitPromptError' || err.message === 'SIGINT') {
|
|
58
|
+
// 130 is the standard exit code for script termination by Ctrl+C
|
|
59
|
+
this.logToStderr(styleText('yellow', '\u{203A}') + ' Aborted by user');
|
|
60
|
+
return this.exit(130);
|
|
61
|
+
}
|
|
62
|
+
// In other cases, we _do_ want to report the error
|
|
63
|
+
reportCliTraceError(err);
|
|
64
|
+
return super.catch(err);
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
50
67
|
* Get the CLI config.
|
|
51
68
|
*
|
|
52
69
|
* @returns The CLI config.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/SanityCommand.ts"],"sourcesContent":["import {Command, Interfaces} from '@oclif/core'\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} 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 * 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":["Command","getCliConfig","findProjectRoot","subdebug","NonInteractiveError","ProjectRootNotFoundError","getGlobalCliClient","getProjectCliClient","getCliTelemetry","isInteractive","debug","SanityCommand","args","flags","getGlobalApiClient","getProjectApiClient","output","error","bind","log","warn","telemetry","root","getProjectRoot","directory","getProjectId","options","hasProjectFlag","ctor","flagProjectId","undefined","deprecatedFlagName","deprecatedValue","config","configProjectId","api","projectId","err","fallback","cause","suggestions","process","cwd","init","parse","baseFlags","enableJsonFlag","strict","isUnattended","yes","resolveIsInteractive","tryGetCliConfig"],"mappings":"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"}
|
|
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":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { ClientConfig } from "@sanity/client";
|
|
2
2
|
import { CLIError } from "@oclif/core/errors";
|
|
3
3
|
import { Command } from "@oclif/core";
|
|
4
|
+
import { CommandError } from "@oclif/core/interfaces";
|
|
4
5
|
import { ConfigEnv } from "vite";
|
|
5
6
|
import ConfigStore from "configstore";
|
|
6
7
|
import { ConsentStatus } from "@sanity/telemetry";
|
|
@@ -29,8 +30,8 @@ export declare function clearCliTelemetry(): void;
|
|
|
29
30
|
|
|
30
31
|
/**
|
|
31
32
|
* @public
|
|
32
|
-
* Symbol used to store
|
|
33
|
-
* Use
|
|
33
|
+
* Symbol used to store CLI telemetry state on globalThis.
|
|
34
|
+
* Use the accessor functions instead of accessing this directly.
|
|
34
35
|
*/
|
|
35
36
|
export declare const CLI_TELEMETRY_SYMBOL: unique symbol;
|
|
36
37
|
|
|
@@ -979,6 +980,52 @@ export declare function resolveLocalPackage<T = unknown>(
|
|
|
979
980
|
workDir: string,
|
|
980
981
|
): Promise<T>;
|
|
981
982
|
|
|
983
|
+
/**
|
|
984
|
+
* Resolves and imports a package relative to another resolved module URL.
|
|
985
|
+
* Useful for resolving transitive dependencies that may not be directly
|
|
986
|
+
* accessible from the project root (e.g., in pnpm strict mode).
|
|
987
|
+
*
|
|
988
|
+
* @param packageName - The name of the package to resolve
|
|
989
|
+
* @param parentUrl - The URL of the parent module to resolve from
|
|
990
|
+
* @returns The imported module
|
|
991
|
+
* @throws If the package cannot be resolved or imported
|
|
992
|
+
*
|
|
993
|
+
* @example
|
|
994
|
+
* ```ts
|
|
995
|
+
* const sanityUrl = resolveLocalPackagePath('sanity', workDir)
|
|
996
|
+
* const ui = await resolveLocalPackageFrom<typeof import('@sanity/ui')>('@sanity/ui', sanityUrl)
|
|
997
|
+
* ```
|
|
998
|
+
*
|
|
999
|
+
* @internal
|
|
1000
|
+
*/
|
|
1001
|
+
export declare function resolveLocalPackageFrom<T = unknown>(
|
|
1002
|
+
packageName: string,
|
|
1003
|
+
parentUrl: URL,
|
|
1004
|
+
): Promise<T>;
|
|
1005
|
+
|
|
1006
|
+
/**
|
|
1007
|
+
* Resolves the URL of a package from the local project's node_modules,
|
|
1008
|
+
* relative to the given working directory, without importing it.
|
|
1009
|
+
*
|
|
1010
|
+
* @param packageName - The name of the package to resolve (e.g., 'sanity')
|
|
1011
|
+
* @param workDir - The working directory to resolve the package from
|
|
1012
|
+
* @returns The resolved URL of the package entry point
|
|
1013
|
+
* @throws If the package cannot be resolved
|
|
1014
|
+
*
|
|
1015
|
+
* @example
|
|
1016
|
+
* ```ts
|
|
1017
|
+
* // Resolve a transitive dependency via its parent package:
|
|
1018
|
+
* const sanityUrl = resolveLocalPackagePath('sanity', workDir)
|
|
1019
|
+
* const uiUrl = resolveLocalPackagePathFrom('@sanity/ui', sanityUrl)
|
|
1020
|
+
* ```
|
|
1021
|
+
*
|
|
1022
|
+
* @internal
|
|
1023
|
+
*/
|
|
1024
|
+
export declare function resolveLocalPackagePath(
|
|
1025
|
+
packageName: string,
|
|
1026
|
+
workDir: string,
|
|
1027
|
+
): URL;
|
|
1028
|
+
|
|
982
1029
|
/**
|
|
983
1030
|
* `structuredClone()`, but doesn't throw on non-clonable values - instead it drops them.
|
|
984
1031
|
*
|
|
@@ -1032,6 +1079,12 @@ export declare abstract class SanityCommand<
|
|
|
1032
1079
|
* @returns The telemetry store.
|
|
1033
1080
|
*/
|
|
1034
1081
|
protected telemetry: CLITelemetryStore;
|
|
1082
|
+
/**
|
|
1083
|
+
* Report real command errors to the CLI command trace.
|
|
1084
|
+
* User aborts (SIGINT, ExitPromptError) are not reported — the trace is left
|
|
1085
|
+
* incomplete, which accurately represents that the command was interrupted.
|
|
1086
|
+
*/
|
|
1087
|
+
protected catch(err: CommandError): Promise<void>;
|
|
1035
1088
|
/**
|
|
1036
1089
|
* Get the CLI config.
|
|
1037
1090
|
*
|
|
@@ -1104,10 +1157,15 @@ export declare type SanityOrgUser = {
|
|
|
1104
1157
|
};
|
|
1105
1158
|
|
|
1106
1159
|
/**
|
|
1107
|
-
* Sets the global CLI telemetry
|
|
1160
|
+
* Sets the global CLI telemetry state.
|
|
1108
1161
|
* @internal
|
|
1109
1162
|
*/
|
|
1110
|
-
export declare function setCliTelemetry(
|
|
1163
|
+
export declare function setCliTelemetry(
|
|
1164
|
+
telemetry: CLITelemetryStore,
|
|
1165
|
+
options?: {
|
|
1166
|
+
reportTraceError?: TraceErrorReporter;
|
|
1167
|
+
},
|
|
1168
|
+
): void;
|
|
1111
1169
|
|
|
1112
1170
|
/**
|
|
1113
1171
|
* Set the config value for the given property.
|
|
@@ -1212,6 +1270,8 @@ declare interface TimeMeasurer {
|
|
|
1212
1270
|
start: (name: string) => void;
|
|
1213
1271
|
}
|
|
1214
1272
|
|
|
1273
|
+
declare type TraceErrorReporter = (error: Error) => void;
|
|
1274
|
+
|
|
1215
1275
|
/**
|
|
1216
1276
|
* Tries to find the studio config path, returning `undefined` if not found.
|
|
1217
1277
|
*
|
|
@@ -2,26 +2,39 @@ import { ux } from '@oclif/core';
|
|
|
2
2
|
import { noopLogger } from '@sanity/telemetry';
|
|
3
3
|
/**
|
|
4
4
|
* @public
|
|
5
|
-
* Symbol used to store
|
|
6
|
-
* Use
|
|
5
|
+
* Symbol used to store CLI telemetry state on globalThis.
|
|
6
|
+
* Use the accessor functions instead of accessing this directly.
|
|
7
7
|
*/ export const CLI_TELEMETRY_SYMBOL = Symbol.for('sanity.cli.telemetry');
|
|
8
|
+
function getState() {
|
|
9
|
+
return globalThis[CLI_TELEMETRY_SYMBOL];
|
|
10
|
+
}
|
|
8
11
|
/**
|
|
9
12
|
* @public
|
|
10
13
|
*/ export function getCliTelemetry() {
|
|
11
|
-
const
|
|
14
|
+
const state = getState();
|
|
12
15
|
// This should never happen, but if it does, we return a noop logger to avoid errors.
|
|
13
|
-
if (!
|
|
16
|
+
if (!state) {
|
|
14
17
|
ux.warn('CLI telemetry not initialized, returning noop logger');
|
|
15
18
|
return noopLogger;
|
|
16
19
|
}
|
|
17
|
-
return
|
|
20
|
+
return state.logger;
|
|
18
21
|
}
|
|
19
22
|
/**
|
|
20
|
-
* Sets the global CLI telemetry
|
|
23
|
+
* Sets the global CLI telemetry state.
|
|
21
24
|
* @internal
|
|
22
|
-
*/ export function setCliTelemetry(telemetry) {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
+
*/ export function setCliTelemetry(telemetry, options) {
|
|
26
|
+
;
|
|
27
|
+
globalThis[CLI_TELEMETRY_SYMBOL] = {
|
|
28
|
+
logger: telemetry,
|
|
29
|
+
reportTraceError: options?.reportTraceError
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Reports an error to the CLI command trace. Called from SanityCommand.catch()
|
|
34
|
+
* for real command errors (not user aborts).
|
|
35
|
+
* @internal
|
|
36
|
+
*/ export function reportCliTraceError(error) {
|
|
37
|
+
getState()?.reportTraceError?.(error);
|
|
25
38
|
}
|
|
26
39
|
/**
|
|
27
40
|
* Clears the global CLI telemetry store.
|
|
@@ -1 +1 @@
|
|
|
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
|
|
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"}
|
|
@@ -19,15 +19,59 @@ import { doImport } from './doImport.js';
|
|
|
19
19
|
*
|
|
20
20
|
* @internal
|
|
21
21
|
*/ export async function resolveLocalPackage(packageName, workDir) {
|
|
22
|
-
|
|
23
|
-
|
|
22
|
+
const packageUrl = resolveLocalPackagePath(packageName, workDir);
|
|
23
|
+
const module = await doImport(packageUrl.href);
|
|
24
|
+
return module;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Resolves the URL of a package from the local project's node_modules,
|
|
28
|
+
* relative to the given working directory, without importing it.
|
|
29
|
+
*
|
|
30
|
+
* @param packageName - The name of the package to resolve (e.g., 'sanity')
|
|
31
|
+
* @param workDir - The working directory to resolve the package from
|
|
32
|
+
* @returns The resolved URL of the package entry point
|
|
33
|
+
* @throws If the package cannot be resolved
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* ```ts
|
|
37
|
+
* // Resolve a transitive dependency via its parent package:
|
|
38
|
+
* const sanityUrl = resolveLocalPackagePath('sanity', workDir)
|
|
39
|
+
* const uiUrl = resolveLocalPackagePathFrom('@sanity/ui', sanityUrl)
|
|
40
|
+
* ```
|
|
41
|
+
*
|
|
42
|
+
* @internal
|
|
43
|
+
*/ export function resolveLocalPackagePath(packageName, workDir) {
|
|
24
44
|
const fakeCliConfigUrl = pathToFileURL(resolve(workDir, 'sanity.cli.mjs'));
|
|
25
45
|
try {
|
|
26
|
-
|
|
46
|
+
return moduleResolve(packageName, fakeCliConfigUrl);
|
|
47
|
+
} catch (error) {
|
|
48
|
+
throw new Error(`Failed to resolve package "${packageName}" from "${workDir}": ${error instanceof Error ? error.message : String(error)}`);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Resolves and imports a package relative to another resolved module URL.
|
|
53
|
+
* Useful for resolving transitive dependencies that may not be directly
|
|
54
|
+
* accessible from the project root (e.g., in pnpm strict mode).
|
|
55
|
+
*
|
|
56
|
+
* @param packageName - The name of the package to resolve
|
|
57
|
+
* @param parentUrl - The URL of the parent module to resolve from
|
|
58
|
+
* @returns The imported module
|
|
59
|
+
* @throws If the package cannot be resolved or imported
|
|
60
|
+
*
|
|
61
|
+
* @example
|
|
62
|
+
* ```ts
|
|
63
|
+
* const sanityUrl = resolveLocalPackagePath('sanity', workDir)
|
|
64
|
+
* const ui = await resolveLocalPackageFrom<typeof import('@sanity/ui')>('@sanity/ui', sanityUrl)
|
|
65
|
+
* ```
|
|
66
|
+
*
|
|
67
|
+
* @internal
|
|
68
|
+
*/ export async function resolveLocalPackageFrom(packageName, parentUrl) {
|
|
69
|
+
try {
|
|
70
|
+
const packageUrl = moduleResolve(packageName, parentUrl);
|
|
27
71
|
const module = await doImport(packageUrl.href);
|
|
28
72
|
return module;
|
|
29
73
|
} catch (error) {
|
|
30
|
-
throw new Error(`Failed to resolve package "${packageName}" from "${
|
|
74
|
+
throw new Error(`Failed to resolve package "${packageName}" from "${parentUrl.href}": ${error instanceof Error ? error.message : String(error)}`);
|
|
31
75
|
}
|
|
32
76
|
}
|
|
33
77
|
|
|
@@ -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
|
|
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;IAE7H;AACF;AAEA;;;;;;;;;;;;;;;;;CAiBC,GACD,OAAO,eAAeI,wBACpBX,WAAmB,EACnBY,SAAc;IAEd,IAAI;QACF,MAAMV,aAAaL,cAAcG,aAAaY;QAC9C,MAAMR,SAAS,MAAMN,SAASI,WAAWG,IAAI;QAC7C,OAAOD;IACT,EAAE,OAAOG,OAAO;QACd,MAAM,IAAIC,MACR,CAAC,2BAA2B,EAAER,YAAY,QAAQ,EAAEY,UAAUP,IAAI,CAAC,GAAG,EAAEE,iBAAiBC,QAAQD,MAAME,OAAO,GAAGC,OAAOH,QAAQ;IAEpI;AACF"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sanity/cli-core",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.1",
|
|
4
4
|
"description": "Sanity CLI core package",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cli",
|
|
@@ -86,8 +86,8 @@
|
|
|
86
86
|
"sanity": "^5.14.1",
|
|
87
87
|
"typescript": "^5.9.3",
|
|
88
88
|
"vitest": "^4.0.18",
|
|
89
|
-
"@repo/tsconfig": "3.70.0",
|
|
90
89
|
"@repo/package.config": "0.0.1",
|
|
90
|
+
"@repo/tsconfig": "3.70.0",
|
|
91
91
|
"@sanity/eslint-config-cli": "1.0.0"
|
|
92
92
|
},
|
|
93
93
|
"peerDependencies": {
|