@sanity/cli 8.21.0 → 8.22.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/README.md +106 -47
- package/codemods/dashboard.js +111 -0
- package/dist/actions/build/buildApp.js +1 -1
- package/dist/actions/build/buildApp.js.map +1 -1
- package/dist/actions/build/buildStudio.js +1 -1
- package/dist/actions/build/buildStudio.js.map +1 -1
- package/dist/actions/codemods/dashboard.js +113 -0
- package/dist/actions/codemods/dashboard.js.map +1 -0
- package/dist/actions/codemods/index.js +2 -0
- package/dist/actions/codemods/index.js.map +1 -1
- package/dist/actions/codemods/types.js.map +1 -1
- package/dist/actions/deploy/deployApp.js +13 -6
- package/dist/actions/deploy/deployApp.js.map +1 -1
- package/dist/actions/deploy/deployChecks.js +12 -7
- package/dist/actions/deploy/deployChecks.js.map +1 -1
- package/dist/actions/deploy/deployRunner.js +14 -8
- package/dist/actions/deploy/deployRunner.js.map +1 -1
- package/dist/actions/deploy/deployStudio.js +39 -4
- package/dist/actions/deploy/deployStudio.js.map +1 -1
- package/dist/actions/deploy/resolveDeployTarget.js +7 -6
- package/dist/actions/deploy/resolveDeployTarget.js.map +1 -1
- package/dist/actions/init/project/promptForAppTemplateSetup.js +22 -0
- package/dist/actions/init/project/promptForAppTemplateSetup.js.map +1 -1
- package/dist/actions/schema/listSchemas.js +2 -3
- package/dist/actions/schema/listSchemas.js.map +1 -1
- package/dist/actions/typegen/generateResourceTypes.js +11 -8
- package/dist/actions/typegen/generateResourceTypes.js.map +1 -1
- package/dist/actions/typegen/watchResourceTypes.js +208 -0
- package/dist/actions/typegen/watchResourceTypes.js.map +1 -0
- package/dist/actions/undeploy/runUndeploy.js +14 -8
- package/dist/actions/undeploy/runUndeploy.js.map +1 -1
- package/dist/commands/codemod.js +15 -4
- package/dist/commands/codemod.js.map +1 -1
- package/dist/commands/context/get.js +3 -8
- package/dist/commands/context/get.js.map +1 -1
- package/dist/commands/context/imports/download.js +3 -8
- package/dist/commands/context/imports/download.js.map +1 -1
- package/dist/commands/context/imports/get.js +3 -8
- package/dist/commands/context/imports/get.js.map +1 -1
- package/dist/commands/context/imports/list.js +3 -8
- package/dist/commands/context/imports/list.js.map +1 -1
- package/dist/commands/context/jobs/get.js +8 -8
- package/dist/commands/context/jobs/get.js.map +1 -1
- package/dist/commands/context/list.js +2 -6
- package/dist/commands/context/list.js.map +1 -1
- package/dist/commands/deploy.js +1 -0
- package/dist/commands/deploy.js.map +1 -1
- package/dist/commands/doctor.js +2 -1
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/openapi/list.js +2 -4
- package/dist/commands/openapi/list.js.map +1 -1
- package/dist/commands/projects/create.js +3 -6
- package/dist/commands/projects/create.js.map +1 -1
- package/dist/commands/schemas/list.js +1 -3
- package/dist/commands/schemas/list.js.map +1 -1
- package/dist/commands/tokens/create.js +2 -5
- package/dist/commands/tokens/create.js.map +1 -1
- package/dist/commands/tokens/list.js +2 -6
- package/dist/commands/tokens/list.js.map +1 -1
- package/dist/commands/tokens/rotate.js +2 -5
- package/dist/commands/tokens/rotate.js.map +1 -1
- package/dist/commands/typegen/generate.js +83 -45
- package/dist/commands/typegen/generate.js.map +1 -1
- package/dist/commands/undeploy.js +1 -0
- package/dist/commands/undeploy.js.map +1 -1
- package/dist/commands/whoami.js +5 -11
- package/dist/commands/whoami.js.map +1 -1
- package/dist/exports/invokeSanityCli/index.js +26 -6
- package/dist/exports/invokeSanityCli/index.js.map +1 -1
- package/dist/generated/apiRoutes.js +11 -26
- package/dist/generated/apiRoutes.js.map +1 -1
- package/dist/telemetry/init.telemetry.js.map +1 -1
- package/oclif.manifest.json +1323 -1294
- package/package.json +6 -5
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/commands/typegen/generate.ts"],"sourcesContent":["import {stat} from 'node:fs/promises'\nimport {styleText} from 'node:util'\n\nimport {Flags} from '@oclif/core'\nimport {CLIError} from '@oclif/core/errors'\nimport {exitCodes, SanityCommand} from '@sanity/cli-core'\nimport {spinner, type SpinnerInstance} from '@sanity/cli-core/ux'\nimport {\n readConfig,\n runTypegenGenerate,\n runTypegenWatcher,\n type TypeGenConfig,\n TypegenWatchModeTrace,\n TypesGeneratedTrace,\n} from '@sanity/codegen'\nimport omit from 'lodash-es/omit.js'\nimport once from 'lodash-es/once.js'\n\nimport {formatPath} from '../../actions/typegen/formatPath.js'\nimport {\n generateResourceTypes,\n resolveResourceSchemas,\n} from '../../actions/typegen/generateResourceTypes.js'\nimport {parseTypegenConfig} from '../../actions/typegen/parseTypegenConfig.js'\nimport {\n parseTypegenResources,\n type TypegenResourcesConfig,\n} from '../../actions/typegen/parseTypegenResources.js'\nimport {createTypegenProgressRenderer} from '../../actions/typegen/renderTypegenProgress.js'\n\nconst description = `Sanity TypeGen\n\n${styleText('bold', 'Configuration:')}\nThis command can utilize configuration settings defined in a \\`sanity-typegen.json\\` file. These settings include:\n\n- \"path\": Specifies a glob pattern to locate your TypeScript or JavaScript files.\n Default: \"./src/**/*.{ts,tsx,js,jsx}\"\n\n- \"schema\": Defines the path to your Sanity schema file. This file should be generated using the \\`sanity schema extract\\` command.\n Default: \"schema.json\"\n\n- \"generates\": Indicates the path where the generated TypeScript type definitions will be saved.\n Default: \"./sanity.types.ts\"\n\nThe default configuration values listed above are used if not overridden in your \\`sanity-typegen.json\\` configuration file. To customize the behavior of the type generation, adjust these properties in the configuration file according to your project's needs.\n\n${styleText('bold', 'Note:')}\n- The \\`sanity schema extract\\` command is a prerequisite for extracting your Sanity Studio schema into a \\`schema.json\\` file, which is then used by the \\`sanity typegen generate\\` command to generate type definitions.\n- To generate types for several datasets, list them in \\`typegen.resources\\` in \\`sanity.cli.ts\\` (beta). Each resource uses its own \\`schema\\` file, or the schema bound to its dataset when \\`schema\\` is omitted.`.trim()\n\nexport class TypegenGenerateCommand extends SanityCommand<typeof TypegenGenerateCommand> {\n static override description = description\n\n static override examples = [\n {\n command: '<%= config.bin %> <%= command.id %>',\n description: `Generate TypeScript type definitions from a Sanity Studio schema extracted using the \\`sanity schema extract\\` command.`,\n },\n ]\n\n static override flags = {\n 'config-path': Flags.string({\n description:\n '[Default: sanity-typegen.json] Specifies the path to the typegen configuration file. This file should be a JSON file that contains settings for the type generation process.',\n }),\n watch: Flags.boolean({\n default: false,\n description: '[Default: false] Run the typegen in watch mode',\n }),\n }\n\n static override hiddenAliases: string[] = ['typegen:generate']\n\n public async run(): Promise<void> {\n const {flags} = await this.parse(TypegenGenerateCommand)\n\n if (flags.watch) {\n await this.runWatcher()\n return\n }\n\n await this.runSingle()\n }\n\n private async getConfig(): Promise<{\n config: TypeGenConfig\n path?: string\n resources?: TypegenResourcesConfig\n type: 'cli' | 'legacy'\n workDir: string\n }> {\n const spin = spinner({}).start('Loading config…')\n\n try {\n const {flags} = await this.parse(TypegenGenerateCommand)\n const rootDir = await this.getProjectRoot()\n const config = await this.getCliConfig()\n\n const configPath = flags['config-path']\n const workDir = rootDir.directory\n\n const legacyConfigPath = configPath || 'sanity-typegen.json'\n let hasLegacyConfig = false\n\n try {\n const file = await stat(legacyConfigPath)\n hasLegacyConfig = file.isFile()\n } catch (err) {\n if (err instanceof Error && 'code' in err && err.code === 'ENOENT' && configPath) {\n spin.fail()\n this.error(`Typegen config file not found: ${configPath}`, {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n\n if (err instanceof Error && 'code' in err && err.code !== 'ENOENT') {\n spin.fail()\n this.error(`Error when checking if typegen config file exists: ${legacyConfigPath}`, {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n }\n\n if (config?.typegen && hasLegacyConfig) {\n spin.warn(\n styleText(\n 'yellow',\n `You've specified typegen in your Sanity CLI config, but also have a typegen config.\n\n The config from the Sanity CLI config is used.\n `,\n ),\n )\n\n const resources = parseTypegenResources(config.typegen, workDir)\n return {\n config: resources?.config ?? parseTypegenConfig(config.typegen || {}),\n path: rootDir.path,\n resources,\n type: 'cli',\n workDir,\n }\n }\n\n if (hasLegacyConfig) {\n spin.warn(\n styleText(\n 'yellow',\n `The separate typegen config has been deprecated. Use \\`typegen\\` in the sanity CLI config instead.\n\n See: https://www.sanity.io/docs/help/configuring-typegen-in-sanity-cli-config`,\n ),\n )\n return {\n config: await readConfig(legacyConfigPath),\n path: legacyConfigPath,\n type: 'legacy',\n workDir,\n }\n }\n\n const resources = parseTypegenResources(config.typegen, workDir)\n spin.succeed(`Config loaded from sanity.cli.ts`)\n\n return {\n config: resources?.config ?? parseTypegenConfig(config.typegen || {}),\n path: rootDir.path,\n resources,\n type: 'cli',\n workDir,\n }\n } catch (err) {\n // The config-file checks above already reported a user-facing error via\n // `this.error()` (an oclif CLIError). Re-throw those as-is instead of\n // wrapping them a second time and failing the spinner twice.\n if (err instanceof CLIError) throw err\n spin.fail()\n this.error(`An error occurred during config loading: ${err}`, {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n }\n\n private async runSingle(): Promise<void> {\n const trace = this.telemetry.trace(TypesGeneratedTrace)\n let spin: SpinnerInstance | undefined\n\n try {\n const {\n config: typegenConfig,\n resources,\n type: typegenConfigMethod,\n workDir,\n } = await this.getConfig()\n trace.start()\n\n if (resources) {\n for (const warning of resources.warnings) {\n this.output.warn(warning)\n }\n\n const resourceSpin = spinner({})\n spin = resourceSpin\n const resolved = await resolveResourceSchemas({\n onResolved: (entry) => {\n resourceSpin.succeed(\n 'schemaPath' in entry\n ? `Using ${formatPath(entry.schemaPath)} for ${entry.key}`\n : `Fetched the schema bound to ${entry.key} (${entry.schemaVersion})`,\n )\n },\n onResolving: (resource, key) => {\n resourceSpin.start(\n resource.schema === undefined\n ? `Fetching the schema bound to ${key}…`\n : `Checking the schema file for ${key}…`,\n )\n },\n resources: resources.resources,\n workDir,\n })\n\n const results = await generateResourceTypes({\n config: typegenConfig,\n onProgress: (entry) => {\n resourceSpin.start(`Generating types for ${entry.key}…`)\n return createTypegenProgressRenderer(resourceSpin, {\n formatGeneratedCode: typegenConfig.formatGeneratedCode,\n generates: entry.resource.generates,\n schema: 'schemaPath' in entry ? entry.schemaPath : entry.key,\n })\n },\n resolved,\n workDir,\n })\n\n for (const {result} of results) {\n trace.log({\n configMethod: typegenConfigMethod,\n configOverloadClientMethods: typegenConfig.overloadClientMethods,\n ...omit(result, 'code', 'duration'),\n })\n }\n trace.complete()\n return\n }\n\n spin = spinner({}).start('Loading schema…')\n const result = await runTypegenGenerate({\n config: typegenConfig,\n onProgress: createTypegenProgressRenderer(spin, {\n formatGeneratedCode: typegenConfig.formatGeneratedCode,\n generates: typegenConfig.generates,\n schema: typegenConfig.schema,\n }),\n workDir,\n })\n\n const traceStats = omit(result, 'code', 'duration')\n\n trace.log({\n configMethod: typegenConfigMethod,\n configOverloadClientMethods: typegenConfig.overloadClientMethods,\n ...traceStats,\n })\n trace.complete()\n } catch (error) {\n if (spin?.isSpinning) {\n spin.fail()\n }\n trace.error(error instanceof Error ? error : new Error(String(error)))\n this.error(`${error instanceof Error ? error.message : 'Unknown error'}`, {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n }\n\n private async runWatcher(): Promise<void> {\n const trace = this.telemetry.trace(TypegenWatchModeTrace)\n let spin: SpinnerInstance | undefined\n\n try {\n const {config: typegenConfig, resources, workDir} = await this.getConfig()\n if (resources) {\n this.error(\n 'Watch mode does not support typegen.resources yet. Run \"sanity typegen generate\" without --watch.',\n {exit: exitCodes.USAGE_ERROR},\n )\n }\n trace.start()\n\n let resolve: () => void = () => {}\n const promise = new Promise<void>((res) => {\n resolve = res\n })\n\n const watchSpin = spinner({}).start('Loading schema…')\n spin = watchSpin\n const rendererContext = {\n formatGeneratedCode: typegenConfig.formatGeneratedCode,\n generates: typegenConfig.generates,\n schema: typegenConfig.schema,\n }\n let renderProgress = createTypegenProgressRenderer(watchSpin, rendererContext)\n\n const typegenWatcher = runTypegenWatcher({\n config: typegenConfig,\n onProgress: (event) => {\n // 'schemaLoaded' is the first event of every generation cycle; the\n // renderer accumulates per-run state, so start each cycle fresh.\n if (event.type === 'schemaLoaded') {\n renderProgress = createTypegenProgressRenderer(watchSpin, rendererContext)\n }\n renderProgress(event)\n },\n workDir,\n })\n\n const stop = once(async () => {\n process.off('SIGINT', stop)\n process.off('SIGTERM', stop)\n\n if (watchSpin.isSpinning) {\n watchSpin.stop()\n }\n\n trace.log({\n step: 'stopped',\n ...typegenWatcher.getStats(),\n })\n trace.complete()\n\n try {\n await typegenWatcher.stop()\n } catch {\n // We're shutting down; a failure to close the watcher shouldn't hang\n // the process or surface as an unhandled rejection.\n }\n resolve()\n })\n\n process.on('SIGINT', stop)\n process.on('SIGTERM', stop)\n\n await promise\n } catch (error) {\n if (spin?.isSpinning) {\n spin.fail()\n }\n trace.error(error instanceof Error ? error : new Error(String(error)))\n // Errors already reported with `this.error()` keep their own exit code.\n if (error instanceof CLIError) throw error\n this.error(`${error instanceof Error ? error.message : 'Unknown error'}`, {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n }\n}\n"],"names":["stat","styleText","Flags","CLIError","exitCodes","SanityCommand","spinner","readConfig","runTypegenGenerate","runTypegenWatcher","TypegenWatchModeTrace","TypesGeneratedTrace","omit","once","formatPath","generateResourceTypes","resolveResourceSchemas","parseTypegenConfig","parseTypegenResources","createTypegenProgressRenderer","description","trim","TypegenGenerateCommand","examples","command","flags","string","watch","boolean","default","hiddenAliases","run","parse","runWatcher","runSingle","getConfig","spin","start","rootDir","getProjectRoot","config","getCliConfig","configPath","workDir","directory","legacyConfigPath","hasLegacyConfig","file","isFile","err","Error","code","fail","error","exit","RUNTIME_ERROR","typegen","warn","resources","path","type","succeed","trace","telemetry","typegenConfig","typegenConfigMethod","warning","warnings","output","resourceSpin","resolved","onResolved","entry","schemaPath","key","schemaVersion","onResolving","resource","schema","undefined","results","onProgress","formatGeneratedCode","generates","result","log","configMethod","configOverloadClientMethods","overloadClientMethods","complete","traceStats","isSpinning","String","message","USAGE_ERROR","resolve","promise","Promise","res","watchSpin","rendererContext","renderProgress","typegenWatcher","event","stop","process","off","step","getStats","on"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../src/commands/typegen/generate.ts"],"sourcesContent":["import {stat} from 'node:fs/promises'\nimport {styleText} from 'node:util'\n\nimport {Flags} from '@oclif/core'\nimport {CLIError} from '@oclif/core/errors'\nimport {exitCodes, SanityCommand} from '@sanity/cli-core'\nimport {spinner, type SpinnerInstance} from '@sanity/cli-core/ux'\nimport {\n readConfig,\n runTypegenGenerate,\n runTypegenWatcher,\n type TypeGenConfig,\n type TypegenProgressEvent,\n TypegenWatchModeTrace,\n TypesGeneratedTrace,\n} from '@sanity/codegen'\nimport omit from 'lodash-es/omit.js'\nimport once from 'lodash-es/once.js'\n\nimport {formatPath} from '../../actions/typegen/formatPath.js'\nimport {\n generateResourceTypes,\n type ResolvedResource,\n resolveResourceSchemas,\n} from '../../actions/typegen/generateResourceTypes.js'\nimport {parseTypegenConfig} from '../../actions/typegen/parseTypegenConfig.js'\nimport {\n parseTypegenResources,\n type TypegenResourcesConfig,\n} from '../../actions/typegen/parseTypegenResources.js'\nimport {createTypegenProgressRenderer} from '../../actions/typegen/renderTypegenProgress.js'\nimport {\n type ResourceTypesWatcher,\n watchResourceTypes,\n} from '../../actions/typegen/watchResourceTypes.js'\n\nconst description = `Sanity TypeGen\n\n${styleText('bold', 'Configuration:')}\nThis command can utilize configuration settings defined in a \\`sanity-typegen.json\\` file. These settings include:\n\n- \"path\": Specifies a glob pattern to locate your TypeScript or JavaScript files.\n Default: \"./src/**/*.{ts,tsx,js,jsx}\"\n\n- \"schema\": Defines the path to your Sanity schema file. This file should be generated using the \\`sanity schema extract\\` command.\n Default: \"schema.json\"\n\n- \"generates\": Indicates the path where the generated TypeScript type definitions will be saved.\n Default: \"./sanity.types.ts\"\n\nThe default configuration values listed above are used if not overridden in your \\`sanity-typegen.json\\` configuration file. To customize the behavior of the type generation, adjust these properties in the configuration file according to your project's needs.\n\n${styleText('bold', 'Note:')}\n- The \\`sanity schema extract\\` command is a prerequisite for extracting your Sanity Studio schema into a \\`schema.json\\` file, which is then used by the \\`sanity typegen generate\\` command to generate type definitions.\n- To generate types for several datasets, list them in \\`typegen.resources\\` in \\`sanity.cli.ts\\` (beta). Each resource uses its own \\`schema\\` file, or the schema bound to its dataset when \\`schema\\` is omitted. With \\`--watch\\`, a schema bound to a dataset is fetched once, when the watcher starts. Restart it after deploying a schema.`.trim()\n\nexport class TypegenGenerateCommand extends SanityCommand<typeof TypegenGenerateCommand> {\n static override description = description\n\n static override examples = [\n {\n command: '<%= config.bin %> <%= command.id %>',\n description: `Generate TypeScript type definitions from a Sanity Studio schema extracted using the \\`sanity schema extract\\` command.`,\n },\n ]\n\n static override flags = {\n 'config-path': Flags.string({\n description:\n '[Default: sanity-typegen.json] Specifies the path to the typegen configuration file. This file should be a JSON file that contains settings for the type generation process.',\n }),\n watch: Flags.boolean({\n default: false,\n description: '[Default: false] Run the typegen in watch mode',\n }),\n }\n\n static override hiddenAliases: string[] = ['typegen:generate']\n\n public async run(): Promise<void> {\n const {flags} = await this.parse(TypegenGenerateCommand)\n\n if (flags.watch) {\n await this.runWatcher()\n return\n }\n\n await this.runSingle()\n }\n\n private async getConfig(): Promise<{\n config: TypeGenConfig\n path?: string\n resources?: TypegenResourcesConfig\n type: 'cli' | 'legacy'\n workDir: string\n }> {\n const spin = spinner({}).start('Loading config…')\n\n try {\n const {flags} = await this.parse(TypegenGenerateCommand)\n const rootDir = await this.getProjectRoot()\n const config = await this.getCliConfig()\n\n const configPath = flags['config-path']\n const workDir = rootDir.directory\n\n const legacyConfigPath = configPath || 'sanity-typegen.json'\n let hasLegacyConfig = false\n\n try {\n const file = await stat(legacyConfigPath)\n hasLegacyConfig = file.isFile()\n } catch (err) {\n if (err instanceof Error && 'code' in err && err.code === 'ENOENT' && configPath) {\n spin.fail()\n this.error(`Typegen config file not found: ${configPath}`, {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n\n if (err instanceof Error && 'code' in err && err.code !== 'ENOENT') {\n spin.fail()\n this.error(`Error when checking if typegen config file exists: ${legacyConfigPath}`, {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n }\n\n if (config?.typegen && hasLegacyConfig) {\n spin.warn(\n styleText(\n 'yellow',\n `You've specified typegen in your Sanity CLI config, but also have a typegen config.\n\n The config from the Sanity CLI config is used.\n `,\n ),\n )\n\n const resources = parseTypegenResources(config.typegen, workDir)\n return {\n config: resources?.config ?? parseTypegenConfig(config.typegen || {}),\n path: rootDir.path,\n resources,\n type: 'cli',\n workDir,\n }\n }\n\n if (hasLegacyConfig) {\n spin.warn(\n styleText(\n 'yellow',\n `The separate typegen config has been deprecated. Use \\`typegen\\` in the sanity CLI config instead.\n\n See: https://www.sanity.io/docs/help/configuring-typegen-in-sanity-cli-config`,\n ),\n )\n return {\n config: await readConfig(legacyConfigPath),\n path: legacyConfigPath,\n type: 'legacy',\n workDir,\n }\n }\n\n const resources = parseTypegenResources(config.typegen, workDir)\n spin.succeed(`Config loaded from sanity.cli.ts`)\n\n return {\n config: resources?.config ?? parseTypegenConfig(config.typegen || {}),\n path: rootDir.path,\n resources,\n type: 'cli',\n workDir,\n }\n } catch (err) {\n // The config-file checks above already reported a user-facing error via\n // `this.error()` (an oclif CLIError). Re-throw those as-is instead of\n // wrapping them a second time and failing the spinner twice.\n if (err instanceof CLIError) throw err\n spin.fail()\n this.error(`An error occurred during config loading: ${err}`, {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n }\n\n /**\n * Prints the resources' configuration warnings, then locates every resource's schema, reporting\n * each one on the spinner.\n */\n private async resolveResources(\n resources: TypegenResourcesConfig,\n spin: SpinnerInstance,\n workDir: string,\n {checkSchemaFiles}: {checkSchemaFiles: boolean},\n ): Promise<ResolvedResource[]> {\n for (const warning of resources.warnings) {\n this.output.warn(warning)\n }\n\n return resolveResourceSchemas({\n checkSchemaFiles,\n onResolved: (entry) => {\n spin.succeed(\n 'schemaPath' in entry\n ? `Using ${formatPath(entry.schemaPath)} for ${entry.key}`\n : `Fetched the schema bound to ${entry.key} (${entry.schemaVersion})`,\n )\n },\n onResolving: (resource, key) => {\n spin.start(\n resource.schema === undefined\n ? `Fetching the schema bound to ${key}…`\n : `Checking the schema file for ${key}…`,\n )\n },\n resources: resources.resources,\n workDir,\n })\n }\n\n private async runSingle(): Promise<void> {\n const trace = this.telemetry.trace(TypesGeneratedTrace)\n let spin: SpinnerInstance | undefined\n\n try {\n const {\n config: typegenConfig,\n resources,\n type: typegenConfigMethod,\n workDir,\n } = await this.getConfig()\n trace.start()\n\n if (resources) {\n const resourceSpin = spinner({})\n spin = resourceSpin\n const resolved = await this.resolveResources(resources, resourceSpin, workDir, {\n checkSchemaFiles: true,\n })\n\n const results = await generateResourceTypes({\n config: typegenConfig,\n onProgress: createResourceProgressHandler(resourceSpin, typegenConfig),\n resolved,\n workDir,\n })\n\n for (const {result} of results) {\n trace.log({\n configMethod: typegenConfigMethod,\n configOverloadClientMethods: typegenConfig.overloadClientMethods,\n ...omit(result, 'code', 'duration'),\n })\n }\n trace.complete()\n return\n }\n\n spin = spinner({}).start('Loading schema…')\n const result = await runTypegenGenerate({\n config: typegenConfig,\n onProgress: createTypegenProgressRenderer(spin, {\n formatGeneratedCode: typegenConfig.formatGeneratedCode,\n generates: typegenConfig.generates,\n schema: typegenConfig.schema,\n }),\n workDir,\n })\n\n const traceStats = omit(result, 'code', 'duration')\n\n trace.log({\n configMethod: typegenConfigMethod,\n configOverloadClientMethods: typegenConfig.overloadClientMethods,\n ...traceStats,\n })\n trace.complete()\n } catch (error) {\n if (spin?.isSpinning) {\n spin.fail()\n }\n trace.error(error instanceof Error ? error : new Error(String(error)))\n this.error(`${error instanceof Error ? error.message : 'Unknown error'}`, {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n }\n\n private async runWatcher(): Promise<void> {\n const trace = this.telemetry.trace(TypegenWatchModeTrace)\n let spin: SpinnerInstance | undefined\n\n try {\n const {config: typegenConfig, resources, workDir} = await this.getConfig()\n trace.start()\n\n let resolve: () => void = () => {}\n const promise = new Promise<void>((res) => {\n resolve = res\n })\n\n const watchSpin = spinner({})\n spin = watchSpin\n const typegenWatcher = resources\n ? await this.startResourceWatcher(typegenConfig, resources, watchSpin, workDir)\n : this.startSchemaWatcher(typegenConfig, watchSpin, workDir)\n\n const stop = once(async () => {\n process.off('SIGINT', stop)\n process.off('SIGTERM', stop)\n\n if (watchSpin.isSpinning) {\n watchSpin.stop()\n }\n\n trace.log({\n step: 'stopped',\n ...typegenWatcher.getStats(),\n })\n trace.complete()\n\n try {\n await typegenWatcher.stop()\n } catch {\n // We're shutting down; a failure to close the watcher shouldn't hang\n // the process or surface as an unhandled rejection.\n }\n resolve()\n })\n\n process.on('SIGINT', stop)\n process.on('SIGTERM', stop)\n\n await promise\n } catch (error) {\n if (spin?.isSpinning) {\n spin.fail()\n }\n trace.error(error instanceof Error ? error : new Error(String(error)))\n // Errors already reported with `this.error()` keep their own exit code.\n if (error instanceof CLIError) throw error\n this.error(`${error instanceof Error ? error.message : 'Unknown error'}`, {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n }\n\n /**\n * Locates every resource's schema once, then generates on each query or local schema change.\n * A schema bound to a dataset is fetched only here, so a schema deployed while the watcher runs\n * is used after a restart.\n */\n private async startResourceWatcher(\n config: TypeGenConfig,\n resources: TypegenResourcesConfig,\n spin: SpinnerInstance,\n workDir: string,\n ): Promise<ResourceTypesWatcher> {\n // A missing local schema file fails that resource's generation until the file appears,\n // instead of ending the watcher.\n const resolved = await this.resolveResources(resources, spin, workDir, {\n checkSchemaFiles: false,\n })\n\n return watchResourceTypes({\n config,\n onChange: (event, relativePath) => {\n this.output.log(`[${new Date().toLocaleTimeString()}] ${event}: ${relativePath}`)\n },\n onError: (error) => {\n spin.fail(error instanceof Error ? error.message : String(error))\n },\n onProgress: createResourceProgressHandler(spin, config),\n resolved,\n workDir,\n })\n }\n\n private startSchemaWatcher(\n config: TypeGenConfig,\n spin: SpinnerInstance,\n workDir: string,\n ): ReturnType<typeof runTypegenWatcher> {\n spin.start('Loading schema…')\n const rendererContext = {\n formatGeneratedCode: config.formatGeneratedCode,\n generates: config.generates,\n schema: config.schema,\n }\n let renderProgress = createTypegenProgressRenderer(spin, rendererContext)\n\n return runTypegenWatcher({\n config,\n onProgress: (event) => {\n // 'schemaLoaded' is the first event of every generation cycle; the\n // renderer accumulates per-run state, so start each cycle fresh.\n if (event.type === 'schemaLoaded') {\n renderProgress = createTypegenProgressRenderer(spin, rendererContext)\n }\n renderProgress(event)\n },\n workDir,\n })\n }\n}\n\n/**\n * Returns the progress handler for one resource's generation, which starts with a line naming\n * the resource. The renderer keeps per-run state, so each generation gets a new one.\n */\nfunction createResourceProgressHandler(\n spin: SpinnerInstance,\n config: TypeGenConfig,\n): (entry: ResolvedResource) => (event: TypegenProgressEvent) => void {\n return (entry) => {\n spin.start(`Generating types for ${entry.key}…`)\n return createTypegenProgressRenderer(spin, {\n formatGeneratedCode: config.formatGeneratedCode,\n generates: entry.resource.generates,\n schema: 'schemaPath' in entry ? entry.schemaPath : entry.key,\n })\n }\n}\n"],"names":["stat","styleText","Flags","CLIError","exitCodes","SanityCommand","spinner","readConfig","runTypegenGenerate","runTypegenWatcher","TypegenWatchModeTrace","TypesGeneratedTrace","omit","once","formatPath","generateResourceTypes","resolveResourceSchemas","parseTypegenConfig","parseTypegenResources","createTypegenProgressRenderer","watchResourceTypes","description","trim","TypegenGenerateCommand","examples","command","flags","string","watch","boolean","default","hiddenAliases","run","parse","runWatcher","runSingle","getConfig","spin","start","rootDir","getProjectRoot","config","getCliConfig","configPath","workDir","directory","legacyConfigPath","hasLegacyConfig","file","isFile","err","Error","code","fail","error","exit","RUNTIME_ERROR","typegen","warn","resources","path","type","succeed","resolveResources","checkSchemaFiles","warning","warnings","output","onResolved","entry","schemaPath","key","schemaVersion","onResolving","resource","schema","undefined","trace","telemetry","typegenConfig","typegenConfigMethod","resourceSpin","resolved","results","onProgress","createResourceProgressHandler","result","log","configMethod","configOverloadClientMethods","overloadClientMethods","complete","formatGeneratedCode","generates","traceStats","isSpinning","String","message","resolve","promise","Promise","res","watchSpin","typegenWatcher","startResourceWatcher","startSchemaWatcher","stop","process","off","step","getStats","on","onChange","event","relativePath","Date","toLocaleTimeString","onError","rendererContext","renderProgress"],"mappings":"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"}
|
|
@@ -13,6 +13,7 @@ export class UndeployCommand extends SanityCommand {
|
|
|
13
13
|
})
|
|
14
14
|
};
|
|
15
15
|
static description = 'Removes the deployed Sanity Studio/App from Sanity hosting';
|
|
16
|
+
static enableJsonFlag = true;
|
|
16
17
|
static examples = [
|
|
17
18
|
{
|
|
18
19
|
command: '<%= config.bin %> <%= command.id %>',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/commands/undeploy.ts"],"sourcesContent":["import {Args, Flags} from '@oclif/core'\nimport {type CliConfig, exitCodes, SanityCommand} from '@sanity/cli-core'\nimport {type UndeployAdapter} from '@sanity/cli-core/undeploy'\nimport {getWorkbench, resolveWorkbenchConfig} from '@sanity/workbench-cli/deploy'\nimport {createWorkbenchUndeployAdapter} from '@sanity/workbench-cli/undeploy'\n\nimport {\n createAppUndeployAdapter,\n createStudioUndeployAdapter,\n} from '../actions/undeploy/adapters.js'\nimport {runUndeploy} from '../actions/undeploy/runUndeploy.js'\nimport {getAppId} from '../util/appId.js'\nimport {determineIsApp} from '../util/determineIsApp.js'\n\nexport class UndeployCommand extends SanityCommand<typeof UndeployCommand> {\n static override args = {\n appId: Args.string({\n description:\n 'ID of the application to undeploy. Overrides `deployment.appId` in sanity.cli.ts',\n }),\n }\n\n static override description = 'Removes the deployed Sanity Studio/App from Sanity hosting'\n\n static override examples = [\n {\n command: '<%= config.bin %> <%= command.id %>',\n description: 'Undeploy the studio or application after confirming',\n },\n {\n command: '<%= config.bin %> <%= command.id %> abc123',\n description: 'Undeploy the studio or application with the given ID',\n },\n {\n command: '<%= config.bin %> <%= command.id %> --dry-run',\n description: 'Report what would be undeployed without deleting anything',\n },\n {\n command: '<%= config.bin %> <%= command.id %> --json --yes',\n description: 'Undeploy without prompting and report the result as JSON',\n },\n ]\n\n static override flags = {\n 'dry-run': Flags.boolean({\n default: false,\n description: 'Report what would be undeployed without deleting anything',\n }),\n json: Flags.boolean({\n char: 'j',\n default: false,\n description: 'Output the result as JSON',\n }),\n yes: Flags.boolean({\n char: 'y',\n default: false,\n description:\n 'Unattended mode, answers \"yes\" to any \"yes/no\" prompt and otherwise uses defaults',\n }),\n }\n\n public async run(): Promise<void> {\n const {args, flags} = await this.parse(UndeployCommand)\n\n const projectConfig = await this.getCliConfig()\n const isApp = determineIsApp(projectConfig)\n if (args.appId) this.warnIfOverridingConfig(args.appId, projectConfig, isApp)\n // An explicit ID stands in for `deployment.appId`, which every adapter\n // already prefers over `studioHost` and the deprecated `app.id`.\n const cliConfig = args.appId\n ? {...projectConfig, deployment: {...projectConfig.deployment, appId: args.appId}}\n : projectConfig\n\n // Workbench apps and configs deploy through Brett, so they undeploy through\n // it too; plain projects keep the user-applications backend.\n const workbench = getWorkbench(cliConfig)\n const config = resolveWorkbenchConfig(cliConfig)\n if (args.appId && config) {\n this.error('An app ID cannot be used to undeploy a config. Run without the argument.', {\n exit: exitCodes.USAGE_ERROR,\n })\n }\n\n const adapter: UndeployAdapter =\n workbench || config\n ? createWorkbenchUndeployAdapter({\n appId: getAppId(cliConfig),\n config: config ?? undefined,\n organizationId: cliConfig.app?.organizationId,\n type: isApp ? 'coreApp' : 'studio',\n workbench: workbench ?? undefined,\n })\n : isApp\n ? createAppUndeployAdapter(cliConfig)\n : createStudioUndeployAdapter(cliConfig)\n\n await runUndeploy({flags, isUnattended: this.isUnattended(), output: this.output}, adapter)\n }\n\n private warnIfOverridingConfig(appId: string, cliConfig: CliConfig, isApp: boolean): void {\n const configuredAppId = getAppId(cliConfig)\n if (configuredAppId) {\n if (configuredAppId !== appId) {\n this.output.warn(\n `Using app ID \"${appId}\" instead of \"${configuredAppId}\" configured in sanity.cli.ts`,\n )\n }\n return\n }\n\n if (!isApp && cliConfig.studioHost) {\n this.output.warn(\n `Using app ID \"${appId}\" instead of studio host \"${cliConfig.studioHost}\" configured in sanity.cli.ts`,\n )\n }\n }\n}\n"],"names":["Args","Flags","exitCodes","SanityCommand","getWorkbench","resolveWorkbenchConfig","createWorkbenchUndeployAdapter","createAppUndeployAdapter","createStudioUndeployAdapter","runUndeploy","getAppId","determineIsApp","UndeployCommand","args","appId","string","description","examples","command","flags","boolean","default","json","char","yes","run","parse","projectConfig","getCliConfig","isApp","warnIfOverridingConfig","cliConfig","deployment","workbench","config","error","exit","USAGE_ERROR","adapter","undefined","organizationId","app","type","isUnattended","output","configuredAppId","warn","studioHost"],"mappings":"AAAA,SAAQA,IAAI,EAAEC,KAAK,QAAO,cAAa;AACvC,SAAwBC,SAAS,EAAEC,aAAa,QAAO,mBAAkB;AAEzE,SAAQC,YAAY,EAAEC,sBAAsB,QAAO,+BAA8B;AACjF,SAAQC,8BAA8B,QAAO,iCAAgC;AAE7E,SACEC,wBAAwB,EACxBC,2BAA2B,QACtB,kCAAiC;AACxC,SAAQC,WAAW,QAAO,qCAAoC;AAC9D,SAAQC,QAAQ,QAAO,mBAAkB;AACzC,SAAQC,cAAc,QAAO,4BAA2B;AAExD,OAAO,MAAMC,wBAAwBT;IACnC,OAAgBU,OAAO;QACrBC,OAAOd,KAAKe,MAAM,CAAC;YACjBC,aACE;QACJ;IACF,EAAC;IAED,OAAgBA,cAAc,6DAA4D;IAE1F,OAAgBC,WAAW;QACzB;YACEC,SAAS;
|
|
1
|
+
{"version":3,"sources":["../../src/commands/undeploy.ts"],"sourcesContent":["import {Args, Flags} from '@oclif/core'\nimport {type CliConfig, exitCodes, SanityCommand} from '@sanity/cli-core'\nimport {type UndeployAdapter} from '@sanity/cli-core/undeploy'\nimport {getWorkbench, resolveWorkbenchConfig} from '@sanity/workbench-cli/deploy'\nimport {createWorkbenchUndeployAdapter} from '@sanity/workbench-cli/undeploy'\n\nimport {\n createAppUndeployAdapter,\n createStudioUndeployAdapter,\n} from '../actions/undeploy/adapters.js'\nimport {runUndeploy} from '../actions/undeploy/runUndeploy.js'\nimport {getAppId} from '../util/appId.js'\nimport {determineIsApp} from '../util/determineIsApp.js'\n\nexport class UndeployCommand extends SanityCommand<typeof UndeployCommand> {\n static override args = {\n appId: Args.string({\n description:\n 'ID of the application to undeploy. Overrides `deployment.appId` in sanity.cli.ts',\n }),\n }\n\n static override description = 'Removes the deployed Sanity Studio/App from Sanity hosting'\n\n static override enableJsonFlag = true\n\n static override examples = [\n {\n command: '<%= config.bin %> <%= command.id %>',\n description: 'Undeploy the studio or application after confirming',\n },\n {\n command: '<%= config.bin %> <%= command.id %> abc123',\n description: 'Undeploy the studio or application with the given ID',\n },\n {\n command: '<%= config.bin %> <%= command.id %> --dry-run',\n description: 'Report what would be undeployed without deleting anything',\n },\n {\n command: '<%= config.bin %> <%= command.id %> --json --yes',\n description: 'Undeploy without prompting and report the result as JSON',\n },\n ]\n\n static override flags = {\n 'dry-run': Flags.boolean({\n default: false,\n description: 'Report what would be undeployed without deleting anything',\n }),\n json: Flags.boolean({\n char: 'j',\n default: false,\n description: 'Output the result as JSON',\n }),\n yes: Flags.boolean({\n char: 'y',\n default: false,\n description:\n 'Unattended mode, answers \"yes\" to any \"yes/no\" prompt and otherwise uses defaults',\n }),\n }\n\n public async run(): Promise<void> {\n const {args, flags} = await this.parse(UndeployCommand)\n\n const projectConfig = await this.getCliConfig()\n const isApp = determineIsApp(projectConfig)\n if (args.appId) this.warnIfOverridingConfig(args.appId, projectConfig, isApp)\n // An explicit ID stands in for `deployment.appId`, which every adapter\n // already prefers over `studioHost` and the deprecated `app.id`.\n const cliConfig = args.appId\n ? {...projectConfig, deployment: {...projectConfig.deployment, appId: args.appId}}\n : projectConfig\n\n // Workbench apps and configs deploy through Brett, so they undeploy through\n // it too; plain projects keep the user-applications backend.\n const workbench = getWorkbench(cliConfig)\n const config = resolveWorkbenchConfig(cliConfig)\n if (args.appId && config) {\n this.error('An app ID cannot be used to undeploy a config. Run without the argument.', {\n exit: exitCodes.USAGE_ERROR,\n })\n }\n\n const adapter: UndeployAdapter =\n workbench || config\n ? createWorkbenchUndeployAdapter({\n appId: getAppId(cliConfig),\n config: config ?? undefined,\n organizationId: cliConfig.app?.organizationId,\n type: isApp ? 'coreApp' : 'studio',\n workbench: workbench ?? undefined,\n })\n : isApp\n ? createAppUndeployAdapter(cliConfig)\n : createStudioUndeployAdapter(cliConfig)\n\n await runUndeploy({flags, isUnattended: this.isUnattended(), output: this.output}, adapter)\n }\n\n private warnIfOverridingConfig(appId: string, cliConfig: CliConfig, isApp: boolean): void {\n const configuredAppId = getAppId(cliConfig)\n if (configuredAppId) {\n if (configuredAppId !== appId) {\n this.output.warn(\n `Using app ID \"${appId}\" instead of \"${configuredAppId}\" configured in sanity.cli.ts`,\n )\n }\n return\n }\n\n if (!isApp && cliConfig.studioHost) {\n this.output.warn(\n `Using app ID \"${appId}\" instead of studio host \"${cliConfig.studioHost}\" configured in sanity.cli.ts`,\n )\n }\n }\n}\n"],"names":["Args","Flags","exitCodes","SanityCommand","getWorkbench","resolveWorkbenchConfig","createWorkbenchUndeployAdapter","createAppUndeployAdapter","createStudioUndeployAdapter","runUndeploy","getAppId","determineIsApp","UndeployCommand","args","appId","string","description","enableJsonFlag","examples","command","flags","boolean","default","json","char","yes","run","parse","projectConfig","getCliConfig","isApp","warnIfOverridingConfig","cliConfig","deployment","workbench","config","error","exit","USAGE_ERROR","adapter","undefined","organizationId","app","type","isUnattended","output","configuredAppId","warn","studioHost"],"mappings":"AAAA,SAAQA,IAAI,EAAEC,KAAK,QAAO,cAAa;AACvC,SAAwBC,SAAS,EAAEC,aAAa,QAAO,mBAAkB;AAEzE,SAAQC,YAAY,EAAEC,sBAAsB,QAAO,+BAA8B;AACjF,SAAQC,8BAA8B,QAAO,iCAAgC;AAE7E,SACEC,wBAAwB,EACxBC,2BAA2B,QACtB,kCAAiC;AACxC,SAAQC,WAAW,QAAO,qCAAoC;AAC9D,SAAQC,QAAQ,QAAO,mBAAkB;AACzC,SAAQC,cAAc,QAAO,4BAA2B;AAExD,OAAO,MAAMC,wBAAwBT;IACnC,OAAgBU,OAAO;QACrBC,OAAOd,KAAKe,MAAM,CAAC;YACjBC,aACE;QACJ;IACF,EAAC;IAED,OAAgBA,cAAc,6DAA4D;IAE1F,OAAgBC,iBAAiB,KAAI;IAErC,OAAgBC,WAAW;QACzB;YACEC,SAAS;YACTH,aAAa;QACf;QACA;YACEG,SAAS;YACTH,aAAa;QACf;QACA;YACEG,SAAS;YACTH,aAAa;QACf;QACA;YACEG,SAAS;YACTH,aAAa;QACf;KACD,CAAA;IAED,OAAgBI,QAAQ;QACtB,WAAWnB,MAAMoB,OAAO,CAAC;YACvBC,SAAS;YACTN,aAAa;QACf;QACAO,MAAMtB,MAAMoB,OAAO,CAAC;YAClBG,MAAM;YACNF,SAAS;YACTN,aAAa;QACf;QACAS,KAAKxB,MAAMoB,OAAO,CAAC;YACjBG,MAAM;YACNF,SAAS;YACTN,aACE;QACJ;IACF,EAAC;IAED,MAAaU,MAAqB;QAChC,MAAM,EAACb,IAAI,EAAEO,KAAK,EAAC,GAAG,MAAM,IAAI,CAACO,KAAK,CAACf;QAEvC,MAAMgB,gBAAgB,MAAM,IAAI,CAACC,YAAY;QAC7C,MAAMC,QAAQnB,eAAeiB;QAC7B,IAAIf,KAAKC,KAAK,EAAE,IAAI,CAACiB,sBAAsB,CAAClB,KAAKC,KAAK,EAAEc,eAAeE;QACvE,uEAAuE;QACvE,iEAAiE;QACjE,MAAME,YAAYnB,KAAKC,KAAK,GACxB;YAAC,GAAGc,aAAa;YAAEK,YAAY;gBAAC,GAAGL,cAAcK,UAAU;gBAAEnB,OAAOD,KAAKC,KAAK;YAAA;QAAC,IAC/Ec;QAEJ,4EAA4E;QAC5E,6DAA6D;QAC7D,MAAMM,YAAY9B,aAAa4B;QAC/B,MAAMG,SAAS9B,uBAAuB2B;QACtC,IAAInB,KAAKC,KAAK,IAAIqB,QAAQ;YACxB,IAAI,CAACC,KAAK,CAAC,4EAA4E;gBACrFC,MAAMnC,UAAUoC,WAAW;YAC7B;QACF;QAEA,MAAMC,UACJL,aAAaC,SACT7B,+BAA+B;YAC7BQ,OAAOJ,SAASsB;YAChBG,QAAQA,UAAUK;YAClBC,gBAAgBT,UAAUU,GAAG,EAAED;YAC/BE,MAAMb,QAAQ,YAAY;YAC1BI,WAAWA,aAAaM;QAC1B,KACAV,QACEvB,yBAAyByB,aACzBxB,4BAA4BwB;QAEpC,MAAMvB,YAAY;YAACW;YAAOwB,cAAc,IAAI,CAACA,YAAY;YAAIC,QAAQ,IAAI,CAACA,MAAM;QAAA,GAAGN;IACrF;IAEQR,uBAAuBjB,KAAa,EAAEkB,SAAoB,EAAEF,KAAc,EAAQ;QACxF,MAAMgB,kBAAkBpC,SAASsB;QACjC,IAAIc,iBAAiB;YACnB,IAAIA,oBAAoBhC,OAAO;gBAC7B,IAAI,CAAC+B,MAAM,CAACE,IAAI,CACd,CAAC,cAAc,EAAEjC,MAAM,cAAc,EAAEgC,gBAAgB,6BAA6B,CAAC;YAEzF;YACA;QACF;QAEA,IAAI,CAAChB,SAASE,UAAUgB,UAAU,EAAE;YAClC,IAAI,CAACH,MAAM,CAACE,IAAI,CACd,CAAC,cAAc,EAAEjC,MAAM,0BAA0B,EAAEkB,UAAUgB,UAAU,CAAC,6BAA6B,CAAC;QAE1G;IACF;AACF"}
|
package/dist/commands/whoami.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { Flags } from '@oclif/core';
|
|
2
1
|
import { exitCodes, getCliTokenInfo, SanityCommand } from '@sanity/cli-core';
|
|
3
2
|
import { isHttpError } from '@sanity/client';
|
|
4
3
|
import { getProviderName } from '../actions/auth/getProviderName.js';
|
|
@@ -7,6 +6,7 @@ import { getSamlProviderId, resolveSSOProvider } from '../actions/whoami/resolve
|
|
|
7
6
|
import { getCliUser } from '../services/user.js';
|
|
8
7
|
export class WhoamiCommand extends SanityCommand {
|
|
9
8
|
static description = 'Show the user or API token the CLI is authenticated as';
|
|
9
|
+
static enableJsonFlag = true;
|
|
10
10
|
static examples = [
|
|
11
11
|
{
|
|
12
12
|
command: '<%= config.bin %> <%= command.id %>',
|
|
@@ -17,14 +17,8 @@ export class WhoamiCommand extends SanityCommand {
|
|
|
17
17
|
description: 'Output the current user as JSON, for scripts and agents'
|
|
18
18
|
}
|
|
19
19
|
];
|
|
20
|
-
static flags = {
|
|
21
|
-
json: Flags.boolean({
|
|
22
|
-
default: false,
|
|
23
|
-
description: 'Output as JSON'
|
|
24
|
-
})
|
|
25
|
-
};
|
|
26
20
|
async run() {
|
|
27
|
-
const {
|
|
21
|
+
const { json } = this.flags;
|
|
28
22
|
const tokenInfo = await getCliTokenInfo();
|
|
29
23
|
if (!tokenInfo?.token) {
|
|
30
24
|
this.error('Not logged in. Run `sanity login` to authenticate.', {
|
|
@@ -42,8 +36,8 @@ export class WhoamiCommand extends SanityCommand {
|
|
|
42
36
|
});
|
|
43
37
|
const samlProviderId = getSamlProviderId(user.provider);
|
|
44
38
|
const sso = samlProviderId ? await resolveSSOProvider(samlProviderId) : undefined;
|
|
45
|
-
if (
|
|
46
|
-
this.
|
|
39
|
+
if (json) {
|
|
40
|
+
this.logJson({
|
|
47
41
|
email: user.email ?? null,
|
|
48
42
|
id: user.id,
|
|
49
43
|
name: user.name,
|
|
@@ -52,7 +46,7 @@ export class WhoamiCommand extends SanityCommand {
|
|
|
52
46
|
sso: sso ?? null
|
|
53
47
|
} : {},
|
|
54
48
|
tokenSource: tokenInfo.source
|
|
55
|
-
}
|
|
49
|
+
});
|
|
56
50
|
return;
|
|
57
51
|
}
|
|
58
52
|
const padTo = 8 // "Provider" is the longest key
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/commands/whoami.ts"],"sourcesContent":["import {
|
|
1
|
+
{"version":3,"sources":["../../src/commands/whoami.ts"],"sourcesContent":["import {exitCodes, getCliTokenInfo, SanityCommand} from '@sanity/cli-core'\nimport {isHttpError} from '@sanity/client'\n\nimport {getProviderName} from '../actions/auth/getProviderName.js'\nimport {formatKeyValue} from '../actions/debug/output.js'\nimport {\n getSamlProviderId,\n resolveSSOProvider,\n type SSOProviderInfo,\n} from '../actions/whoami/resolveSSOProvider.js'\nimport {getCliUser} from '../services/user.js'\n\nexport class WhoamiCommand extends SanityCommand<typeof WhoamiCommand> {\n static override description = 'Show the user or API token the CLI is authenticated as'\n\n static override enableJsonFlag = true\n\n static override examples = [\n {\n command: '<%= config.bin %> <%= command.id %>',\n description: 'Show the currently authenticated user',\n },\n {\n command: '<%= config.bin %> <%= command.id %> --json',\n description: 'Output the current user as JSON, for scripts and agents',\n },\n ]\n\n public async run(): Promise<void> {\n const {json} = this.flags\n\n const tokenInfo = await getCliTokenInfo()\n if (!tokenInfo?.token) {\n this.error('Not logged in. Run `sanity login` to authenticate.', {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n\n const user = await getCliUser().catch((err: unknown) => {\n // A stale SANITY_AUTH_TOKEN overrides a valid saved login, so \"run sanity login\" won't help\n if (tokenInfo.source === ENV_TOKEN_SOURCE && isRejectedToken(err)) {\n this.error(\n 'Authentication failed using SANITY_AUTH_TOKEN.\\nUnset it to use your saved login, or replace it with a valid token.',\n {exit: exitCodes.RUNTIME_ERROR},\n )\n }\n throw err\n })\n const samlProviderId = getSamlProviderId(user.provider)\n const sso = samlProviderId ? await resolveSSOProvider(samlProviderId) : undefined\n\n if (json) {\n this.logJson({\n email: user.email ?? null,\n id: user.id,\n name: user.name,\n provider: user.provider,\n ...(samlProviderId ? {sso: sso ?? null} : {}),\n tokenSource: tokenInfo.source,\n })\n return\n }\n\n const padTo = 8 // \"Provider\" is the longest key\n this.log(formatKeyValue('Name', user.name, {indent: 0, padTo}))\n if (user.email) {\n this.log(formatKeyValue('Email', user.email, {indent: 0, padTo}))\n }\n this.log(formatKeyValue('ID', user.id, {indent: 0, padTo}))\n this.log(\n formatKeyValue('Provider', formatProvider(user.provider, samlProviderId, sso), {\n indent: 0,\n padTo,\n }),\n )\n if (sso) {\n this.log(formatKeyValue('Org', formatOrganization(sso), {indent: 0, padTo}))\n }\n this.log(formatKeyValue('Token', tokenInfo.source, {indent: 0, padTo}))\n }\n}\n\nconst ENV_TOKEN_SOURCE = 'SANITY_AUTH_TOKEN environment variable'\n\nfunction isRejectedToken(err: unknown): boolean {\n return isHttpError(err) && (err.statusCode === 401 || err.statusCode === 403)\n}\n\nfunction formatProvider(\n provider: string,\n samlProviderId: string | undefined,\n sso: SSOProviderInfo | undefined,\n): string {\n if (provider === 'sanity-token') return 'API token'\n if (samlProviderId) return formatSamlProvider(sso)\n return getProviderName(provider)\n}\n\nfunction formatOrganization(sso: SSOProviderInfo): string {\n if (!sso.organizationSlug) return sso.organizationName\n return `${sso.organizationName} (sanity login --sso ${sso.organizationSlug})`\n}\n\nfunction formatSamlProvider(sso: SSOProviderInfo | undefined): string {\n // Provider names like \"saml\" or \"SSO\" repeat the label without adding anything\n const name = sso?.providerName.trim()\n if (!name || /^(saml|sso|saml sso)$/i.test(name)) return 'SAML SSO'\n return `SAML SSO (${name})`\n}\n"],"names":["exitCodes","getCliTokenInfo","SanityCommand","isHttpError","getProviderName","formatKeyValue","getSamlProviderId","resolveSSOProvider","getCliUser","WhoamiCommand","description","enableJsonFlag","examples","command","run","json","flags","tokenInfo","token","error","exit","RUNTIME_ERROR","user","catch","err","source","ENV_TOKEN_SOURCE","isRejectedToken","samlProviderId","provider","sso","undefined","logJson","email","id","name","tokenSource","padTo","log","indent","formatProvider","formatOrganization","statusCode","formatSamlProvider","organizationSlug","organizationName","providerName","trim","test"],"mappings":"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"}
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
* (or `help`) renders root help listing the invokable topics, and a subject
|
|
23
23
|
* (`cors --help`, `cors list --help`) renders topic or command help.
|
|
24
24
|
*/ import { fileURLToPath } from 'node:url';
|
|
25
|
-
import { Config, Parser, settings } from '@oclif/core';
|
|
25
|
+
import { Config, Flags, Parser, settings } from '@oclif/core';
|
|
26
26
|
import { getHelpFlagAdditions, normalizeArgv } from '@oclif/core/help';
|
|
27
27
|
import { exitCodes } from '@sanity/cli-core';
|
|
28
28
|
import { deny, isConditionalInvocationPolicy } from '@sanity/cli-core/commandPolicy';
|
|
@@ -74,6 +74,12 @@ import { prettyPrintError } from './prettyPrintError.js';
|
|
|
74
74
|
});
|
|
75
75
|
}
|
|
76
76
|
let cachedConfig;
|
|
77
|
+
function withoutJsonFlag(argv) {
|
|
78
|
+
// Anything after `--` belongs to the command, not to us.
|
|
79
|
+
const passThrough = argv.indexOf('--');
|
|
80
|
+
const limit = passThrough === -1 ? argv.length : passThrough;
|
|
81
|
+
return argv.filter((token, index)=>index >= limit || token !== '--json');
|
|
82
|
+
}
|
|
77
83
|
function unknownCommandResult(argv, policySet) {
|
|
78
84
|
const available = Object.entries(policySet).filter(([, policy])=>policy.kind !== 'deny').map(([id])=>id.replaceAll(':', ' ')).toSorted();
|
|
79
85
|
return {
|
|
@@ -161,7 +167,8 @@ async function invokeSanityCliInContext({ args, source }, resolvedConfig, output
|
|
|
161
167
|
// space-separated topics, accepting colon-separated ids as-is), then apply
|
|
162
168
|
// the policy. Denied and uncategorized ids fail closed, indistinguishable
|
|
163
169
|
// from commands that don't exist.
|
|
164
|
-
const [commandId = '', ...
|
|
170
|
+
const [commandId = '', ...requestedArgv] = normalizeArgv(resolvedConfig, argv);
|
|
171
|
+
const commandArgv = withoutJsonFlag(requestedArgv);
|
|
165
172
|
const policy = policySet[commandId] ?? deny;
|
|
166
173
|
const commandDefinition = policy.kind === 'deny' ? undefined : resolvedConfig.findCommand(commandId);
|
|
167
174
|
if (!commandDefinition) return unknownCommandResult(argv, policySet);
|
|
@@ -176,9 +183,13 @@ async function invokeSanityCliInContext({ args, source }, resolvedConfig, output
|
|
|
176
183
|
try {
|
|
177
184
|
const parsed = await Parser.parse(commandArgv, {
|
|
178
185
|
args: CommandClass.args,
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
186
|
+
flags: {
|
|
187
|
+
...CommandClass.enableJsonFlag ? {
|
|
188
|
+
json: Flags.boolean()
|
|
189
|
+
} : {},
|
|
190
|
+
...CommandClass.baseFlags,
|
|
191
|
+
...CommandClass.flags
|
|
192
|
+
},
|
|
182
193
|
strict: CommandClass.strict
|
|
183
194
|
});
|
|
184
195
|
invocation = {
|
|
@@ -207,8 +218,17 @@ async function invokeSanityCliInContext({ args, source }, resolvedConfig, output
|
|
|
207
218
|
output
|
|
208
219
|
};
|
|
209
220
|
}
|
|
221
|
+
let command;
|
|
222
|
+
try {
|
|
223
|
+
command = instantiateCommand(CommandClass, commandArgv, resolvedConfig);
|
|
224
|
+
} catch (err) {
|
|
225
|
+
return {
|
|
226
|
+
commandId,
|
|
227
|
+
exitCode: err.oclif?.exit ?? exitCodes.RUNTIME_ERROR,
|
|
228
|
+
output: prettyPrintError(err) || String(err)
|
|
229
|
+
};
|
|
230
|
+
}
|
|
210
231
|
try {
|
|
211
|
-
const command = instantiateCommand(CommandClass, commandArgv, resolvedConfig);
|
|
212
232
|
await command.runInExecutionContext();
|
|
213
233
|
return {
|
|
214
234
|
commandId,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/exports/invokeSanityCli/index.ts"],"sourcesContent":["/**\n * Programmatic (in-process) invocation of CLI commands, e.g. from an MCP\n * server. The invokable surface is governed by a per-source command policy\n * (see ./commandPolicies): every CLI command is explicitly allowed, denied,\n * or allowed conditionally on the parsed invocation. Commands contributed by\n * plugins are covered by the policies those plugins declare, and are denied\n * unless they declare one.\n *\n * {@link invokeSanityCli} handles arg parsing, policy enforcement, command\n * dispatch, per-invocation auth, and output capture.\n * ```ts\n * import {invokeSanityCli} from '@sanity/cli/invokeSanityCli'\n *\n * const {exitCode, output} = await invokeSanityCli({\n * args: 'cors list --project-id abc123',\n * source: 'mcp',\n * token: extra.authInfo.token,\n * })\n * ```\n *\n * Help works like the regular CLI, scoped to the source's policy: `--help`\n * (or `help`) renders root help listing the invokable topics, and a subject\n * (`cors --help`, `cors list --help`) renders topic or command help.\n */\nimport {fileURLToPath} from 'node:url'\n\nimport {Command, Config, Parser, settings} from '@oclif/core'\nimport {getHelpFlagAdditions, normalizeArgv} from '@oclif/core/help'\nimport {exitCodes} from '@sanity/cli-core'\nimport {\n type CommandPolicySet,\n deny,\n type InvocationSource,\n isConditionalInvocationPolicy,\n} from '@sanity/cli-core/commandPolicy'\nimport {runWithCliExecutionContext, type SanityEnvironment} from '@sanity/cli-core/executionContext'\nimport {type SanityCommand} from '@sanity/cli-core/SanityCommand'\nimport {type FetchFunction} from 'get-it'\nimport {parseArgsStringToArgv} from 'string-argv'\n\nimport {resolveTopicAliasInArgv} from '../../topicAliases.js'\nimport {resolveCommandPolicies} from './commandPolicies/index.js'\nimport {isHelpRequest, renderInvokableHelp} from './help.js'\nimport {prettyPrintError} from './prettyPrintError.js'\n\ntype InvokableCommand = Pick<SanityCommand<typeof Command>, 'runInExecutionContext'>\n\n/**\n * Whether a command can run in isolation, which in practice means it extends\n * `SanityCommand`: only that base class routes output, token resolution,\n * interactivity, and project discovery through the CLI execution context.\n *\n * This is a capability check, not a policy check. A plugin can declare a\n * policy for a command that still extends oclif's `Command` directly, and\n * such a command must not run here — the policy says the invocation is safe,\n * but nothing would hold it to the isolation guarantees that assessment\n * assumes.\n */\nfunction supportsIsolatedExecution(CommandClass: Command.Class): boolean {\n const prototype = CommandClass.prototype as Partial<InvokableCommand> | undefined\n return typeof prototype?.runInExecutionContext === 'function'\n}\n\n/**\n * Instantiate a policy-approved command for isolated execution.\n *\n * `runInExecutionContext()` runs the instance without oclif's static\n * `Command.run()` — the static runner re-enters `Config.load()` (filesystem\n * reads and a process-global config cache write) on every call. The manifest\n * types command classes as the abstract oclif `Command`, hence the\n * constructor cast.\n */\nfunction instantiateCommand(\n CommandClass: Command.Class,\n argv: string[],\n config: Config,\n): InvokableCommand {\n const ConcreteCommand = CommandClass as unknown as new (argv: string[], config: Config) => Command\n return new ConcreteCommand(argv, config) as unknown as InvokableCommand\n}\n\n/**\n * Load the oclif `Config` for this package, needed to resolve, load, and run\n * commands. Loading it once and reusing it across invocations avoids\n * re-reading the command manifest per call. It only reads this package's own\n * installed files — process-lifetime initialization, not per-invocation host\n * state — so it happens outside any execution context.\n *\n * `userPlugins: false` keeps this surface to the plugins this package ships\n * with. oclif otherwise loads whatever `<dataDir>/package.json` lists.\n */\nfunction loadCliCommandConfig(): Promise<Config> {\n return Config.load({root: fileURLToPath(import.meta.url), userPlugins: false})\n}\n\nlet cachedConfig: Promise<Config> | undefined\n\nfunction unknownCommandResult(argv: string[], policySet: CommandPolicySet): InvokeSanityCliResult {\n const available = Object.entries(policySet)\n .filter(([, policy]) => policy.kind !== 'deny')\n .map(([id]) => id.replaceAll(':', ' '))\n .toSorted()\n return {\n exitCode: exitCodes.USAGE_ERROR,\n output: [\n `Unknown or unsupported command: ${argv.slice(0, 2).join(' ') || '(none)'}`,\n `Available commands: ${available.join(', ')}`,\n ].join('\\n'),\n }\n}\n\n/**\n * @internal\n */\nexport interface InvokeSanityCliOptions {\n /**\n * Arguments after `sanity` (a leading `sanity` token is tolerated), either\n * as a single string — shell-style quoting is supported, but no shell is\n * ever executed — or as a pre-split argv array.\n */\n args: string | string[]\n\n /**\n * Where this invocation originates. Selects the command policy to enforce:\n * which commands are invokable and which invocations of them are permitted.\n */\n source: InvocationSource\n\n /**\n * Auth token for this invocation. Scoped to this call via the CLI execution\n * context: it never touches process env or the process-wide token cache, so\n * concurrent invocations with different tokens are fully isolated.\n */\n token: string\n\n /**\n * Optional oclif config override (mainly for tests). Defaults to this\n * package's config, loaded once and cached across invocations.\n */\n config?: Config\n\n /**\n * Optional fetch implementation for API requests made by this invocation.\n * Scoped to this call via the CLI execution context; defaults to the CLI's\n * own transport. The execution context's transport hygiene (such as\n * stripping the embedding process's lineage header) is applied on top.\n */\n fetch?: FetchFunction\n\n /**\n * Sanity deployment environment for this invocation. Scoped to this call\n * via the CLI execution context and defaults to production. The embedding\n * process's `SANITY_INTERNAL_ENV` is never consulted.\n */\n sanityEnv?: SanityEnvironment\n}\n\n/**\n * @internal\n */\nexport interface InvokeSanityCliResult {\n /** `0` on success, the command's exit code otherwise. */\n exitCode: number\n\n /** Combined stdout and stderr output, in emission order. */\n output: string\n\n /**\n * Canonical oclif command id when the invocation resolved to a command\n * exposed by the selected policy (for example, `datasets:create`).\n */\n commandId?: string\n}\n\n/**\n * Unlike a shell, string-argv keeps quotes that are glued to unquoted text:\n * `--name=\"my project\"` tokenizes with the quotes intact. Strip a matching\n * wrapping quote pair from the value side of `--flag=`-shaped tokens so the\n * common shell-style form yields the value the caller intended.\n */\nfunction stripFlagQuotes(rawToken: string): string {\n const match = /^(-{1,2}[^\\s=]+=)(['\"])([\\s\\S]*)\\2$/.exec(rawToken)\n return match ? match[1] + match[3] : rawToken\n}\n\n/**\n * Run a policy-permitted CLI command in-process and capture its result.\n *\n * Command-level failures (unknown command, bad flags, API errors) are\n * reported through `exitCode`/`output` rather than thrown, so callers can\n * relay them verbatim.\n *\n * @internal\n */\nexport async function invokeSanityCli(\n options: InvokeSanityCliOptions,\n): Promise<InvokeSanityCliResult> {\n // Always load compiled command modules. Oclif's dev-mode source resolution\n // otherwise probes tsconfigs (reading the filesystem and process.cwd) on\n // every command load, and may register ts-node process-wide.\n settings.enableAutoTranspile = false\n\n const resolvedConfig = options.config ?? (await (cachedConfig ??= loadCliCommandConfig()))\n const output: string[] = []\n const sink = (line: string) => output.push(line)\n const {fetch, sanityEnv, token} = options\n\n // Establish the isolation boundary before rendering help, loading command\n // modules, parsing, or executing. Any code reached by an external\n // invocation can therefore fail closed on context.\n return runWithCliExecutionContext({fetch, sanityEnv, stderr: sink, stdout: sink, token}, () =>\n invokeSanityCliInContext(options, resolvedConfig, output),\n )\n}\n\nasync function invokeSanityCliInContext(\n {args, source}: InvokeSanityCliOptions,\n resolvedConfig: Config,\n output: string[],\n): Promise<InvokeSanityCliResult> {\n // Combines this package's own policies with those each plugin declares for\n // the commands it contributes. Resolved once per config, not per call.\n const policySet = await resolveCommandPolicies(resolvedConfig, source)\n\n // Pre-split argv arrays are taken verbatim; only string input goes through\n // shell-style tokenization and quote normalization.\n let argv =\n typeof args === 'string'\n ? parseArgsStringToArgv(args).map((t) => stripFlagQuotes(t))\n : [...args]\n if (argv[0] === 'sanity') argv = argv.slice(1)\n argv = resolveTopicAliasInArgv(argv)\n\n // Help requests are routed through oclif's help system, scoped to the\n // source's policy: root help for a bare request, topic/command help when a\n // subject is given. Denied subjects get the standard unknown-command\n // response (identical to a truly unknown command, so hosts can't probe the\n // full CLI surface through help), and a help request never executes a\n // command.\n if (isHelpRequest(argv, resolvedConfig)) {\n try {\n // Drop a leading `help` so the rest is the subject, mirroring how\n // oclif's dispatch consumes the token before the help command sees argv\n const helpArgv = argv[0] === 'help' ? argv.slice(1) : argv\n const result = await renderInvokableHelp(resolvedConfig, helpArgv, policySet)\n if (result) return {...result, exitCode: exitCodes.SUCCESS}\n const helpFlags = getHelpFlagAdditions(resolvedConfig)\n return unknownCommandResult(\n helpArgv.filter((token) => !helpFlags.includes(token)),\n policySet,\n )\n } catch (err) {\n return {\n exitCode: exitCodes.RUNTIME_ERROR,\n output: err instanceof Error ? err.message : String(err),\n }\n }\n }\n\n // Resolve the command id the same way oclif's dispatch would (collating\n // space-separated topics, accepting colon-separated ids as-is), then apply\n // the policy. Denied and uncategorized ids fail closed, indistinguishable\n // from commands that don't exist.\n const [commandId = '', ...commandArgv] = normalizeArgv(resolvedConfig, argv)\n const policy = policySet[commandId] ?? deny\n const commandDefinition =\n policy.kind === 'deny' ? undefined : resolvedConfig.findCommand(commandId)\n if (!commandDefinition) return unknownCommandResult(argv, policySet)\n\n const CommandClass = await commandDefinition.load()\n\n // A policy can only speak to whether an invocation is safe; it cannot make\n // a command isolatable. One that isn't is treated as if it did not exist,\n // like every other fail-closed path here.\n if (!supportsIsolatedExecution(CommandClass)) return unknownCommandResult(argv, policySet)\n\n // Parse with the command's real definitions (without executing anything) so\n // conditional policies are evaluated against typed args/flags, not tokens.\n let invocation: {args: Record<string, unknown>; flags: Record<string, unknown>}\n try {\n const parsed = await Parser.parse(commandArgv, {\n args: CommandClass.args,\n baseFlags: CommandClass.baseFlags,\n enableJsonFlag: CommandClass.enableJsonFlag,\n flags: CommandClass.flags,\n strict: CommandClass.strict,\n })\n invocation = {\n args: parsed.args as Record<string, unknown>,\n flags: parsed.flags as Record<string, unknown>,\n }\n } catch (err) {\n return {\n commandId,\n exitCode: exitCodes.USAGE_ERROR,\n output: err instanceof Error ? err.message : String(err),\n }\n }\n\n if (!policy.validate(invocation)) {\n const displayId = commandId.replaceAll(':', ' ')\n let output = `This invocation of \\`${displayId}\\` is not supported here`\n\n if (isConditionalInvocationPolicy(policy)) {\n const usedDeniedFlags = policy.deniedFlags.filter(\n (name) => invocation.flags[name] !== undefined && invocation.flags[name] !== false,\n )\n if (usedDeniedFlags.length > 0) {\n output = `\\nThe ${usedDeniedFlags.map((name) => `--${name}`).join(', ')} flag is not supported here for \\`${displayId}\\``\n }\n }\n\n return {\n commandId,\n exitCode: exitCodes.USAGE_ERROR,\n output,\n }\n }\n\n try {\n const command = instantiateCommand(CommandClass, commandArgv, resolvedConfig)\n await command.runInExecutionContext()\n return {commandId, exitCode: exitCodes.SUCCESS, output: output.join('\\n')}\n } catch (err) {\n const exit = err.oclif?.exit\n\n // `this.exit(0)` throws an ExitError but is a successful outcome\n if (exit === exitCodes.SUCCESS) {\n return {commandId, exitCode: exitCodes.SUCCESS, output: output.join('\\n')}\n }\n\n const message = prettyPrintError(err) || String(err)\n if (message) output.push(message)\n return {\n commandId,\n exitCode: typeof exit === 'number' ? exit : exitCodes.RUNTIME_ERROR,\n output: output.join('\\n'),\n }\n }\n}\n"],"names":["fileURLToPath","Config","Parser","settings","getHelpFlagAdditions","normalizeArgv","exitCodes","deny","isConditionalInvocationPolicy","runWithCliExecutionContext","parseArgsStringToArgv","resolveTopicAliasInArgv","resolveCommandPolicies","isHelpRequest","renderInvokableHelp","prettyPrintError","supportsIsolatedExecution","CommandClass","prototype","runInExecutionContext","instantiateCommand","argv","config","ConcreteCommand","loadCliCommandConfig","load","root","url","userPlugins","cachedConfig","unknownCommandResult","policySet","available","Object","entries","filter","policy","kind","map","id","replaceAll","toSorted","exitCode","USAGE_ERROR","output","slice","join","stripFlagQuotes","rawToken","match","exec","invokeSanityCli","options","enableAutoTranspile","resolvedConfig","sink","line","push","fetch","sanityEnv","token","stderr","stdout","invokeSanityCliInContext","args","source","t","helpArgv","result","SUCCESS","helpFlags","includes","err","RUNTIME_ERROR","Error","message","String","commandId","commandArgv","commandDefinition","undefined","findCommand","invocation","parsed","parse","baseFlags","enableJsonFlag","flags","strict","validate","displayId","usedDeniedFlags","deniedFlags","name","length","command","exit","oclif"],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;CAuBC,GACD,SAAQA,aAAa,QAAO,WAAU;AAEtC,SAAiBC,MAAM,EAAEC,MAAM,EAAEC,QAAQ,QAAO,cAAa;AAC7D,SAAQC,oBAAoB,EAAEC,aAAa,QAAO,mBAAkB;AACpE,SAAQC,SAAS,QAAO,mBAAkB;AAC1C,SAEEC,IAAI,EAEJC,6BAA6B,QACxB,iCAAgC;AACvC,SAAQC,0BAA0B,QAA+B,oCAAmC;AAGpG,SAAQC,qBAAqB,QAAO,cAAa;AAEjD,SAAQC,uBAAuB,QAAO,wBAAuB;AAC7D,SAAQC,sBAAsB,QAAO,6BAA4B;AACjE,SAAQC,aAAa,EAAEC,mBAAmB,QAAO,YAAW;AAC5D,SAAQC,gBAAgB,QAAO,wBAAuB;AAItD;;;;;;;;;;CAUC,GACD,SAASC,0BAA0BC,YAA2B;IAC5D,MAAMC,YAAYD,aAAaC,SAAS;IACxC,OAAO,OAAOA,WAAWC,0BAA0B;AACrD;AAEA;;;;;;;;CAQC,GACD,SAASC,mBACPH,YAA2B,EAC3BI,IAAc,EACdC,MAAc;IAEd,MAAMC,kBAAkBN;IACxB,OAAO,IAAIM,gBAAgBF,MAAMC;AACnC;AAEA;;;;;;;;;CASC,GACD,SAASE;IACP,OAAOvB,OAAOwB,IAAI,CAAC;QAACC,MAAM1B,cAAc,YAAY2B,GAAG;QAAGC,aAAa;IAAK;AAC9E;AAEA,IAAIC;AAEJ,SAASC,qBAAqBT,IAAc,EAAEU,SAA2B;IACvE,MAAMC,YAAYC,OAAOC,OAAO,CAACH,WAC9BI,MAAM,CAAC,CAAC,GAAGC,OAAO,GAAKA,OAAOC,IAAI,KAAK,QACvCC,GAAG,CAAC,CAAC,CAACC,GAAG,GAAKA,GAAGC,UAAU,CAAC,KAAK,MACjCC,QAAQ;IACX,OAAO;QACLC,UAAUpC,UAAUqC,WAAW;QAC/BC,QAAQ;YACN,CAAC,gCAAgC,EAAEvB,KAAKwB,KAAK,CAAC,GAAG,GAAGC,IAAI,CAAC,QAAQ,UAAU;YAC3E,CAAC,oBAAoB,EAAEd,UAAUc,IAAI,CAAC,OAAO;SAC9C,CAACA,IAAI,CAAC;IACT;AACF;AAiEA;;;;;CAKC,GACD,SAASC,gBAAgBC,QAAgB;IACvC,MAAMC,QAAQ,sCAAsCC,IAAI,CAACF;IACzD,OAAOC,QAAQA,KAAK,CAAC,EAAE,GAAGA,KAAK,CAAC,EAAE,GAAGD;AACvC;AAEA;;;;;;;;CAQC,GACD,OAAO,eAAeG,gBACpBC,OAA+B;IAE/B,2EAA2E;IAC3E,yEAAyE;IACzE,6DAA6D;IAC7DjD,SAASkD,mBAAmB,GAAG;IAE/B,MAAMC,iBAAiBF,QAAQ9B,MAAM,IAAK,MAAOO,CAAAA,iBAAiBL,sBAAqB;IACvF,MAAMoB,SAAmB,EAAE;IAC3B,MAAMW,OAAO,CAACC,OAAiBZ,OAAOa,IAAI,CAACD;IAC3C,MAAM,EAACE,KAAK,EAAEC,SAAS,EAAEC,KAAK,EAAC,GAAGR;IAElC,0EAA0E;IAC1E,kEAAkE;IAClE,mDAAmD;IACnD,OAAO3C,2BAA2B;QAACiD;QAAOC;QAAWE,QAAQN;QAAMO,QAAQP;QAAMK;IAAK,GAAG,IACvFG,yBAAyBX,SAASE,gBAAgBV;AAEtD;AAEA,eAAemB,yBACb,EAACC,IAAI,EAAEC,MAAM,EAAyB,EACtCX,cAAsB,EACtBV,MAAgB;IAEhB,2EAA2E;IAC3E,uEAAuE;IACvE,MAAMb,YAAY,MAAMnB,uBAAuB0C,gBAAgBW;IAE/D,2EAA2E;IAC3E,oDAAoD;IACpD,IAAI5C,OACF,OAAO2C,SAAS,WACZtD,sBAAsBsD,MAAM1B,GAAG,CAAC,CAAC4B,IAAMnB,gBAAgBmB,MACvD;WAAIF;KAAK;IACf,IAAI3C,IAAI,CAAC,EAAE,KAAK,UAAUA,OAAOA,KAAKwB,KAAK,CAAC;IAC5CxB,OAAOV,wBAAwBU;IAE/B,sEAAsE;IACtE,2EAA2E;IAC3E,qEAAqE;IACrE,2EAA2E;IAC3E,sEAAsE;IACtE,WAAW;IACX,IAAIR,cAAcQ,MAAMiC,iBAAiB;QACvC,IAAI;YACF,kEAAkE;YAClE,wEAAwE;YACxE,MAAMa,WAAW9C,IAAI,CAAC,EAAE,KAAK,SAASA,KAAKwB,KAAK,CAAC,KAAKxB;YACtD,MAAM+C,SAAS,MAAMtD,oBAAoBwC,gBAAgBa,UAAUpC;YACnE,IAAIqC,QAAQ,OAAO;gBAAC,GAAGA,MAAM;gBAAE1B,UAAUpC,UAAU+D,OAAO;YAAA;YAC1D,MAAMC,YAAYlE,qBAAqBkD;YACvC,OAAOxB,qBACLqC,SAAShC,MAAM,CAAC,CAACyB,QAAU,CAACU,UAAUC,QAAQ,CAACX,SAC/C7B;QAEJ,EAAE,OAAOyC,KAAK;YACZ,OAAO;gBACL9B,UAAUpC,UAAUmE,aAAa;gBACjC7B,QAAQ4B,eAAeE,QAAQF,IAAIG,OAAO,GAAGC,OAAOJ;YACtD;QACF;IACF;IAEA,wEAAwE;IACxE,2EAA2E;IAC3E,0EAA0E;IAC1E,kCAAkC;IAClC,MAAM,CAACK,YAAY,EAAE,EAAE,GAAGC,YAAY,GAAGzE,cAAciD,gBAAgBjC;IACvE,MAAMe,SAASL,SAAS,CAAC8C,UAAU,IAAItE;IACvC,MAAMwE,oBACJ3C,OAAOC,IAAI,KAAK,SAAS2C,YAAY1B,eAAe2B,WAAW,CAACJ;IAClE,IAAI,CAACE,mBAAmB,OAAOjD,qBAAqBT,MAAMU;IAE1D,MAAMd,eAAe,MAAM8D,kBAAkBtD,IAAI;IAEjD,2EAA2E;IAC3E,0EAA0E;IAC1E,0CAA0C;IAC1C,IAAI,CAACT,0BAA0BC,eAAe,OAAOa,qBAAqBT,MAAMU;IAEhF,4EAA4E;IAC5E,2EAA2E;IAC3E,IAAImD;IACJ,IAAI;QACF,MAAMC,SAAS,MAAMjF,OAAOkF,KAAK,CAACN,aAAa;YAC7Cd,MAAM/C,aAAa+C,IAAI;YACvBqB,WAAWpE,aAAaoE,SAAS;YACjCC,gBAAgBrE,aAAaqE,cAAc;YAC3CC,OAAOtE,aAAasE,KAAK;YACzBC,QAAQvE,aAAauE,MAAM;QAC7B;QACAN,aAAa;YACXlB,MAAMmB,OAAOnB,IAAI;YACjBuB,OAAOJ,OAAOI,KAAK;QACrB;IACF,EAAE,OAAOf,KAAK;QACZ,OAAO;YACLK;YACAnC,UAAUpC,UAAUqC,WAAW;YAC/BC,QAAQ4B,eAAeE,QAAQF,IAAIG,OAAO,GAAGC,OAAOJ;QACtD;IACF;IAEA,IAAI,CAACpC,OAAOqD,QAAQ,CAACP,aAAa;QAChC,MAAMQ,YAAYb,UAAUrC,UAAU,CAAC,KAAK;QAC5C,IAAII,SAAS,CAAC,qBAAqB,EAAE8C,UAAU,wBAAwB,CAAC;QAExE,IAAIlF,8BAA8B4B,SAAS;YACzC,MAAMuD,kBAAkBvD,OAAOwD,WAAW,CAACzD,MAAM,CAC/C,CAAC0D,OAASX,WAAWK,KAAK,CAACM,KAAK,KAAKb,aAAaE,WAAWK,KAAK,CAACM,KAAK,KAAK;YAE/E,IAAIF,gBAAgBG,MAAM,GAAG,GAAG;gBAC9BlD,SAAS,CAAC,MAAM,EAAE+C,gBAAgBrD,GAAG,CAAC,CAACuD,OAAS,CAAC,EAAE,EAAEA,MAAM,EAAE/C,IAAI,CAAC,MAAM,kCAAkC,EAAE4C,UAAU,EAAE,CAAC;YAC3H;QACF;QAEA,OAAO;YACLb;YACAnC,UAAUpC,UAAUqC,WAAW;YAC/BC;QACF;IACF;IAEA,IAAI;QACF,MAAMmD,UAAU3E,mBAAmBH,cAAc6D,aAAaxB;QAC9D,MAAMyC,QAAQ5E,qBAAqB;QACnC,OAAO;YAAC0D;YAAWnC,UAAUpC,UAAU+D,OAAO;YAAEzB,QAAQA,OAAOE,IAAI,CAAC;QAAK;IAC3E,EAAE,OAAO0B,KAAK;QACZ,MAAMwB,OAAOxB,IAAIyB,KAAK,EAAED;QAExB,iEAAiE;QACjE,IAAIA,SAAS1F,UAAU+D,OAAO,EAAE;YAC9B,OAAO;gBAACQ;gBAAWnC,UAAUpC,UAAU+D,OAAO;gBAAEzB,QAAQA,OAAOE,IAAI,CAAC;YAAK;QAC3E;QAEA,MAAM6B,UAAU5D,iBAAiByD,QAAQI,OAAOJ;QAChD,IAAIG,SAAS/B,OAAOa,IAAI,CAACkB;QACzB,OAAO;YACLE;YACAnC,UAAU,OAAOsD,SAAS,WAAWA,OAAO1F,UAAUmE,aAAa;YACnE7B,QAAQA,OAAOE,IAAI,CAAC;QACtB;IACF;AACF"}
|
|
1
|
+
{"version":3,"sources":["../../../src/exports/invokeSanityCli/index.ts"],"sourcesContent":["/**\n * Programmatic (in-process) invocation of CLI commands, e.g. from an MCP\n * server. The invokable surface is governed by a per-source command policy\n * (see ./commandPolicies): every CLI command is explicitly allowed, denied,\n * or allowed conditionally on the parsed invocation. Commands contributed by\n * plugins are covered by the policies those plugins declare, and are denied\n * unless they declare one.\n *\n * {@link invokeSanityCli} handles arg parsing, policy enforcement, command\n * dispatch, per-invocation auth, and output capture.\n * ```ts\n * import {invokeSanityCli} from '@sanity/cli/invokeSanityCli'\n *\n * const {exitCode, output} = await invokeSanityCli({\n * args: 'cors list --project-id abc123',\n * source: 'mcp',\n * token: extra.authInfo.token,\n * })\n * ```\n *\n * Help works like the regular CLI, scoped to the source's policy: `--help`\n * (or `help`) renders root help listing the invokable topics, and a subject\n * (`cors --help`, `cors list --help`) renders topic or command help.\n */\nimport {fileURLToPath} from 'node:url'\n\nimport {Command, Config, Flags, Parser, settings} from '@oclif/core'\nimport {getHelpFlagAdditions, normalizeArgv} from '@oclif/core/help'\nimport {exitCodes} from '@sanity/cli-core'\nimport {\n type CommandPolicySet,\n deny,\n type InvocationSource,\n isConditionalInvocationPolicy,\n} from '@sanity/cli-core/commandPolicy'\nimport {runWithCliExecutionContext, type SanityEnvironment} from '@sanity/cli-core/executionContext'\nimport {type SanityCommand} from '@sanity/cli-core/SanityCommand'\nimport {type FetchFunction} from 'get-it'\nimport {parseArgsStringToArgv} from 'string-argv'\n\nimport {resolveTopicAliasInArgv} from '../../topicAliases.js'\nimport {resolveCommandPolicies} from './commandPolicies/index.js'\nimport {isHelpRequest, renderInvokableHelp} from './help.js'\nimport {prettyPrintError} from './prettyPrintError.js'\n\ntype InvokableCommand = Pick<SanityCommand<typeof Command>, 'runInExecutionContext'>\n\n/**\n * Whether a command can run in isolation, which in practice means it extends\n * `SanityCommand`: only that base class routes output, token resolution,\n * interactivity, and project discovery through the CLI execution context.\n *\n * This is a capability check, not a policy check. A plugin can declare a\n * policy for a command that still extends oclif's `Command` directly, and\n * such a command must not run here — the policy says the invocation is safe,\n * but nothing would hold it to the isolation guarantees that assessment\n * assumes.\n */\nfunction supportsIsolatedExecution(CommandClass: Command.Class): boolean {\n const prototype = CommandClass.prototype as Partial<InvokableCommand> | undefined\n return typeof prototype?.runInExecutionContext === 'function'\n}\n\n/**\n * Instantiate a policy-approved command for isolated execution.\n *\n * `runInExecutionContext()` runs the instance without oclif's static\n * `Command.run()` — the static runner re-enters `Config.load()` (filesystem\n * reads and a process-global config cache write) on every call. The manifest\n * types command classes as the abstract oclif `Command`, hence the\n * constructor cast.\n */\nfunction instantiateCommand(\n CommandClass: Command.Class,\n argv: string[],\n config: Config,\n): InvokableCommand {\n const ConcreteCommand = CommandClass as unknown as new (argv: string[], config: Config) => Command\n return new ConcreteCommand(argv, config) as unknown as InvokableCommand\n}\n\n/**\n * Load the oclif `Config` for this package, needed to resolve, load, and run\n * commands. Loading it once and reusing it across invocations avoids\n * re-reading the command manifest per call. It only reads this package's own\n * installed files — process-lifetime initialization, not per-invocation host\n * state — so it happens outside any execution context.\n *\n * `userPlugins: false` keeps this surface to the plugins this package ships\n * with. oclif otherwise loads whatever `<dataDir>/package.json` lists.\n */\nfunction loadCliCommandConfig(): Promise<Config> {\n return Config.load({root: fileURLToPath(import.meta.url), userPlugins: false})\n}\n\nlet cachedConfig: Promise<Config> | undefined\n\nfunction withoutJsonFlag(argv: string[]): string[] {\n // Anything after `--` belongs to the command, not to us.\n const passThrough = argv.indexOf('--')\n const limit = passThrough === -1 ? argv.length : passThrough\n return argv.filter((token, index) => index >= limit || token !== '--json')\n}\n\nfunction unknownCommandResult(argv: string[], policySet: CommandPolicySet): InvokeSanityCliResult {\n const available = Object.entries(policySet)\n .filter(([, policy]) => policy.kind !== 'deny')\n .map(([id]) => id.replaceAll(':', ' '))\n .toSorted()\n return {\n exitCode: exitCodes.USAGE_ERROR,\n output: [\n `Unknown or unsupported command: ${argv.slice(0, 2).join(' ') || '(none)'}`,\n `Available commands: ${available.join(', ')}`,\n ].join('\\n'),\n }\n}\n\n/**\n * @internal\n */\nexport interface InvokeSanityCliOptions {\n /**\n * Arguments after `sanity` (a leading `sanity` token is tolerated), either\n * as a single string — shell-style quoting is supported, but no shell is\n * ever executed — or as a pre-split argv array.\n */\n args: string | string[]\n\n /**\n * Where this invocation originates. Selects the command policy to enforce:\n * which commands are invokable and which invocations of them are permitted.\n */\n source: InvocationSource\n\n /**\n * Auth token for this invocation. Scoped to this call via the CLI execution\n * context: it never touches process env or the process-wide token cache, so\n * concurrent invocations with different tokens are fully isolated.\n */\n token: string\n\n /**\n * Optional oclif config override (mainly for tests). Defaults to this\n * package's config, loaded once and cached across invocations.\n */\n config?: Config\n\n /**\n * Optional fetch implementation for API requests made by this invocation.\n * Scoped to this call via the CLI execution context; defaults to the CLI's\n * own transport. The execution context's transport hygiene (such as\n * stripping the embedding process's lineage header) is applied on top.\n */\n fetch?: FetchFunction\n\n /**\n * Sanity deployment environment for this invocation. Scoped to this call\n * via the CLI execution context and defaults to production. The embedding\n * process's `SANITY_INTERNAL_ENV` is never consulted.\n */\n sanityEnv?: SanityEnvironment\n}\n\n/**\n * @internal\n */\nexport interface InvokeSanityCliResult {\n /** `0` on success, the command's exit code otherwise. */\n exitCode: number\n\n /** Combined stdout and stderr output, in emission order. */\n output: string\n\n /**\n * Canonical oclif command id when the invocation resolved to a command\n * exposed by the selected policy (for example, `datasets:create`).\n */\n commandId?: string\n}\n\n/**\n * Unlike a shell, string-argv keeps quotes that are glued to unquoted text:\n * `--name=\"my project\"` tokenizes with the quotes intact. Strip a matching\n * wrapping quote pair from the value side of `--flag=`-shaped tokens so the\n * common shell-style form yields the value the caller intended.\n */\nfunction stripFlagQuotes(rawToken: string): string {\n const match = /^(-{1,2}[^\\s=]+=)(['\"])([\\s\\S]*)\\2$/.exec(rawToken)\n return match ? match[1] + match[3] : rawToken\n}\n\n/**\n * Run a policy-permitted CLI command in-process and capture its result.\n *\n * Command-level failures (unknown command, bad flags, API errors) are\n * reported through `exitCode`/`output` rather than thrown, so callers can\n * relay them verbatim.\n *\n * @internal\n */\nexport async function invokeSanityCli(\n options: InvokeSanityCliOptions,\n): Promise<InvokeSanityCliResult> {\n // Always load compiled command modules. Oclif's dev-mode source resolution\n // otherwise probes tsconfigs (reading the filesystem and process.cwd) on\n // every command load, and may register ts-node process-wide.\n settings.enableAutoTranspile = false\n\n const resolvedConfig = options.config ?? (await (cachedConfig ??= loadCliCommandConfig()))\n const output: string[] = []\n const sink = (line: string) => output.push(line)\n const {fetch, sanityEnv, token} = options\n\n // Establish the isolation boundary before rendering help, loading command\n // modules, parsing, or executing. Any code reached by an external\n // invocation can therefore fail closed on context.\n return runWithCliExecutionContext({fetch, sanityEnv, stderr: sink, stdout: sink, token}, () =>\n invokeSanityCliInContext(options, resolvedConfig, output),\n )\n}\n\nasync function invokeSanityCliInContext(\n {args, source}: InvokeSanityCliOptions,\n resolvedConfig: Config,\n output: string[],\n): Promise<InvokeSanityCliResult> {\n // Combines this package's own policies with those each plugin declares for\n // the commands it contributes. Resolved once per config, not per call.\n const policySet = await resolveCommandPolicies(resolvedConfig, source)\n\n // Pre-split argv arrays are taken verbatim; only string input goes through\n // shell-style tokenization and quote normalization.\n let argv =\n typeof args === 'string'\n ? parseArgsStringToArgv(args).map((t) => stripFlagQuotes(t))\n : [...args]\n if (argv[0] === 'sanity') argv = argv.slice(1)\n argv = resolveTopicAliasInArgv(argv)\n\n // Help requests are routed through oclif's help system, scoped to the\n // source's policy: root help for a bare request, topic/command help when a\n // subject is given. Denied subjects get the standard unknown-command\n // response (identical to a truly unknown command, so hosts can't probe the\n // full CLI surface through help), and a help request never executes a\n // command.\n if (isHelpRequest(argv, resolvedConfig)) {\n try {\n // Drop a leading `help` so the rest is the subject, mirroring how\n // oclif's dispatch consumes the token before the help command sees argv\n const helpArgv = argv[0] === 'help' ? argv.slice(1) : argv\n const result = await renderInvokableHelp(resolvedConfig, helpArgv, policySet)\n if (result) return {...result, exitCode: exitCodes.SUCCESS}\n const helpFlags = getHelpFlagAdditions(resolvedConfig)\n return unknownCommandResult(\n helpArgv.filter((token) => !helpFlags.includes(token)),\n policySet,\n )\n } catch (err) {\n return {\n exitCode: exitCodes.RUNTIME_ERROR,\n output: err instanceof Error ? err.message : String(err),\n }\n }\n }\n\n // Resolve the command id the same way oclif's dispatch would (collating\n // space-separated topics, accepting colon-separated ids as-is), then apply\n // the policy. Denied and uncategorized ids fail closed, indistinguishable\n // from commands that don't exist.\n const [commandId = '', ...requestedArgv] = normalizeArgv(resolvedConfig, argv)\n const commandArgv = withoutJsonFlag(requestedArgv)\n const policy = policySet[commandId] ?? deny\n const commandDefinition =\n policy.kind === 'deny' ? undefined : resolvedConfig.findCommand(commandId)\n if (!commandDefinition) return unknownCommandResult(argv, policySet)\n\n const CommandClass = await commandDefinition.load()\n\n // A policy can only speak to whether an invocation is safe; it cannot make\n // a command isolatable. One that isn't is treated as if it did not exist,\n // like every other fail-closed path here.\n if (!supportsIsolatedExecution(CommandClass)) return unknownCommandResult(argv, policySet)\n\n // Parse with the command's real definitions (without executing anything) so\n // conditional policies are evaluated against typed args/flags, not tokens.\n let invocation: {args: Record<string, unknown>; flags: Record<string, unknown>}\n try {\n const parsed = await Parser.parse(commandArgv, {\n args: CommandClass.args,\n flags: {\n ...(CommandClass.enableJsonFlag ? {json: Flags.boolean()} : {}),\n ...CommandClass.baseFlags,\n ...CommandClass.flags,\n },\n strict: CommandClass.strict,\n })\n invocation = {\n args: parsed.args as Record<string, unknown>,\n flags: parsed.flags as Record<string, unknown>,\n }\n } catch (err) {\n return {\n commandId,\n exitCode: exitCodes.USAGE_ERROR,\n output: err instanceof Error ? err.message : String(err),\n }\n }\n\n if (!policy.validate(invocation)) {\n const displayId = commandId.replaceAll(':', ' ')\n let output = `This invocation of \\`${displayId}\\` is not supported here`\n\n if (isConditionalInvocationPolicy(policy)) {\n const usedDeniedFlags = policy.deniedFlags.filter(\n (name) => invocation.flags[name] !== undefined && invocation.flags[name] !== false,\n )\n if (usedDeniedFlags.length > 0) {\n output = `\\nThe ${usedDeniedFlags.map((name) => `--${name}`).join(', ')} flag is not supported here for \\`${displayId}\\``\n }\n }\n\n return {\n commandId,\n exitCode: exitCodes.USAGE_ERROR,\n output,\n }\n }\n\n let command: InvokableCommand\n try {\n command = instantiateCommand(CommandClass, commandArgv, resolvedConfig)\n } catch (err) {\n return {\n commandId,\n exitCode: err.oclif?.exit ?? exitCodes.RUNTIME_ERROR,\n output: prettyPrintError(err) || String(err),\n }\n }\n\n try {\n await command.runInExecutionContext()\n return {commandId, exitCode: exitCodes.SUCCESS, output: output.join('\\n')}\n } catch (err) {\n const exit = err.oclif?.exit\n\n // `this.exit(0)` throws an ExitError but is a successful outcome\n if (exit === exitCodes.SUCCESS) {\n return {commandId, exitCode: exitCodes.SUCCESS, output: output.join('\\n')}\n }\n\n const message = prettyPrintError(err) || String(err)\n if (message) output.push(message)\n\n return {\n commandId,\n exitCode: typeof exit === 'number' ? exit : exitCodes.RUNTIME_ERROR,\n output: output.join('\\n'),\n }\n }\n}\n"],"names":["fileURLToPath","Config","Flags","Parser","settings","getHelpFlagAdditions","normalizeArgv","exitCodes","deny","isConditionalInvocationPolicy","runWithCliExecutionContext","parseArgsStringToArgv","resolveTopicAliasInArgv","resolveCommandPolicies","isHelpRequest","renderInvokableHelp","prettyPrintError","supportsIsolatedExecution","CommandClass","prototype","runInExecutionContext","instantiateCommand","argv","config","ConcreteCommand","loadCliCommandConfig","load","root","url","userPlugins","cachedConfig","withoutJsonFlag","passThrough","indexOf","limit","length","filter","token","index","unknownCommandResult","policySet","available","Object","entries","policy","kind","map","id","replaceAll","toSorted","exitCode","USAGE_ERROR","output","slice","join","stripFlagQuotes","rawToken","match","exec","invokeSanityCli","options","enableAutoTranspile","resolvedConfig","sink","line","push","fetch","sanityEnv","stderr","stdout","invokeSanityCliInContext","args","source","t","helpArgv","result","SUCCESS","helpFlags","includes","err","RUNTIME_ERROR","Error","message","String","commandId","requestedArgv","commandArgv","commandDefinition","undefined","findCommand","invocation","parsed","parse","flags","enableJsonFlag","json","boolean","baseFlags","strict","validate","displayId","usedDeniedFlags","deniedFlags","name","command","oclif","exit"],"mappings":"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"}
|
|
@@ -205,6 +205,7 @@
|
|
|
205
205
|
defaultApiVersion: 'v2025-02-19',
|
|
206
206
|
host: 'global',
|
|
207
207
|
pathPatterns: [
|
|
208
|
+
'projects/{projectId}/datasets/copy',
|
|
208
209
|
'projects/{projectId}/datasets/{dataset}/copy'
|
|
209
210
|
],
|
|
210
211
|
slug: 'copy',
|
|
@@ -231,7 +232,7 @@
|
|
|
231
232
|
title: 'Embeddings Index API reference (deprecated)'
|
|
232
233
|
},
|
|
233
234
|
{
|
|
234
|
-
defaultApiVersion: '
|
|
235
|
+
defaultApiVersion: 'v2025-02-19',
|
|
235
236
|
host: 'project',
|
|
236
237
|
pathPatterns: [
|
|
237
238
|
'data/export/{dataset}'
|
|
@@ -314,28 +315,6 @@
|
|
|
314
315
|
slug: 'media-library',
|
|
315
316
|
title: 'Media Library API reference'
|
|
316
317
|
},
|
|
317
|
-
{
|
|
318
|
-
defaultApiVersion: 'v2025-02-19',
|
|
319
|
-
host: 'project',
|
|
320
|
-
pathPatterns: [
|
|
321
|
-
'media-libraries/{libraryId}/from-url',
|
|
322
|
-
'media-libraries/{libraryId}/mutate',
|
|
323
|
-
'media-libraries/{libraryId}/query',
|
|
324
|
-
'media-libraries/{libraryId}/references/documents/{assetId}/to',
|
|
325
|
-
'media-libraries/{libraryId}/refsearch',
|
|
326
|
-
'media-libraries/{libraryId}/signing-keys',
|
|
327
|
-
'media-libraries/{libraryId}/signing-keys/{keyId}',
|
|
328
|
-
'media-libraries/{libraryId}/upload',
|
|
329
|
-
'media-libraries/{libraryId}/video/{videoId}/playback-info',
|
|
330
|
-
'media-libraries/{libraryId}/video/{videoId}/playback/{type}',
|
|
331
|
-
'media-libraries/{libraryId}/video/{videoId}/renditions/{name}',
|
|
332
|
-
'media-libraries/{libraryId}/video/{videoId}/subtitles',
|
|
333
|
-
'media-libraries/{libraryId}/video/{videoId}/subtitles/upload',
|
|
334
|
-
'media-libraries/{libraryId}/video/{videoId}/subtitles/{subtitleId}'
|
|
335
|
-
],
|
|
336
|
-
slug: 'media-library',
|
|
337
|
-
title: 'Media Library API reference'
|
|
338
|
-
},
|
|
339
318
|
{
|
|
340
319
|
defaultApiVersion: 'v2025-02-19',
|
|
341
320
|
host: 'project',
|
|
@@ -354,6 +333,7 @@
|
|
|
354
333
|
'projects/{projectId}/cors',
|
|
355
334
|
'projects/{projectId}/cors/{id}',
|
|
356
335
|
'projects/{projectId}/datasets',
|
|
336
|
+
'projects/{projectId}/datasets/copy',
|
|
357
337
|
'projects/{projectId}/datasets/{datasetName}/tags/{tagIdentifier}',
|
|
358
338
|
'projects/{projectId}/datasets/{name}',
|
|
359
339
|
'projects/{projectId}/datasets/{name}/copy',
|
|
@@ -383,16 +363,19 @@
|
|
|
383
363
|
defaultApiVersion: 'v2021-10-04',
|
|
384
364
|
host: 'global',
|
|
385
365
|
pathPatterns: [
|
|
366
|
+
'auth/organizations/{organizationId}/providers/{providerId}/projects/{projectId}/role-mappings',
|
|
386
367
|
'organizations/{organizationId}/acl',
|
|
387
368
|
'organizations/{organizationId}/acl/{sanityUserId}',
|
|
388
369
|
'organizations/{organizationId}/grants',
|
|
389
|
-
'organizations/{organizationId}/providers/{providerId}/projects/{projectId}/role-mappings',
|
|
390
370
|
'projects/{projectId}/acl',
|
|
391
|
-
'projects/{projectId}/acl/{
|
|
371
|
+
'projects/{projectId}/acl/{projectUserId}',
|
|
392
372
|
'projects/{projectId}/datasets/{datasetName}/acl',
|
|
393
373
|
'projects/{projectId}/datasets/{datasetName}/grants',
|
|
394
374
|
'projects/{projectId}/grants',
|
|
375
|
+
'projects/{projectId}/grants/{projectUserId}',
|
|
395
376
|
'projects/{projectId}/permissionResourceSchemas',
|
|
377
|
+
'projects/{projectId}/permissionResources',
|
|
378
|
+
'projects/{projectId}/permissionResources/{resourceId}',
|
|
396
379
|
'projects/{projectId}/roles',
|
|
397
380
|
'projects/{projectId}/roles/{roleName}'
|
|
398
381
|
],
|
|
@@ -429,9 +412,11 @@
|
|
|
429
412
|
host: 'project',
|
|
430
413
|
pathPatterns: [
|
|
431
414
|
'hooks/projects/{projectId}',
|
|
415
|
+
'hooks/projects/{projectId}/attempts/{attemptId}',
|
|
432
416
|
'hooks/projects/{projectId}/{id}',
|
|
433
417
|
'hooks/projects/{projectId}/{id}/attempts',
|
|
434
|
-
'hooks/{id}/messages'
|
|
418
|
+
'hooks/projects/{projectId}/{id}/messages',
|
|
419
|
+
'hooks/projects/{projectId}/{id}/messages/{messageId}/attempts'
|
|
435
420
|
],
|
|
436
421
|
slug: 'webhooks',
|
|
437
422
|
title: 'Webhooks API reference'
|