@sanity/cli 8.20.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.
Files changed (85) hide show
  1. package/README.md +106 -47
  2. package/codemods/dashboard.js +111 -0
  3. package/dist/actions/build/buildApp.js +1 -1
  4. package/dist/actions/build/buildApp.js.map +1 -1
  5. package/dist/actions/build/buildStudio.js +1 -1
  6. package/dist/actions/build/buildStudio.js.map +1 -1
  7. package/dist/actions/codemods/dashboard.js +113 -0
  8. package/dist/actions/codemods/dashboard.js.map +1 -0
  9. package/dist/actions/codemods/index.js +2 -0
  10. package/dist/actions/codemods/index.js.map +1 -1
  11. package/dist/actions/codemods/types.js.map +1 -1
  12. package/dist/actions/deploy/deployApp.js +13 -6
  13. package/dist/actions/deploy/deployApp.js.map +1 -1
  14. package/dist/actions/deploy/deployChecks.js +12 -7
  15. package/dist/actions/deploy/deployChecks.js.map +1 -1
  16. package/dist/actions/deploy/deployRunner.js +14 -8
  17. package/dist/actions/deploy/deployRunner.js.map +1 -1
  18. package/dist/actions/deploy/deployStudio.js +39 -4
  19. package/dist/actions/deploy/deployStudio.js.map +1 -1
  20. package/dist/actions/deploy/resolveDeployTarget.js +7 -6
  21. package/dist/actions/deploy/resolveDeployTarget.js.map +1 -1
  22. package/dist/actions/init/project/promptForAppTemplateSetup.js +22 -0
  23. package/dist/actions/init/project/promptForAppTemplateSetup.js.map +1 -1
  24. package/dist/actions/schema/listSchemas.js +2 -3
  25. package/dist/actions/schema/listSchemas.js.map +1 -1
  26. package/dist/actions/tokens/formatTokenAccess.js +18 -0
  27. package/dist/actions/tokens/formatTokenAccess.js.map +1 -0
  28. package/dist/actions/tokens/grants.js +12 -0
  29. package/dist/actions/tokens/grants.js.map +1 -1
  30. package/dist/actions/tokens/types.js.map +1 -1
  31. package/dist/actions/typegen/generateResourceTypes.js +11 -8
  32. package/dist/actions/typegen/generateResourceTypes.js.map +1 -1
  33. package/dist/actions/typegen/watchResourceTypes.js +208 -0
  34. package/dist/actions/typegen/watchResourceTypes.js.map +1 -0
  35. package/dist/actions/undeploy/runUndeploy.js +14 -8
  36. package/dist/actions/undeploy/runUndeploy.js.map +1 -1
  37. package/dist/commands/codemod.js +15 -4
  38. package/dist/commands/codemod.js.map +1 -1
  39. package/dist/commands/context/get.js +3 -8
  40. package/dist/commands/context/get.js.map +1 -1
  41. package/dist/commands/context/imports/download.js +3 -8
  42. package/dist/commands/context/imports/download.js.map +1 -1
  43. package/dist/commands/context/imports/get.js +3 -8
  44. package/dist/commands/context/imports/get.js.map +1 -1
  45. package/dist/commands/context/imports/list.js +3 -8
  46. package/dist/commands/context/imports/list.js.map +1 -1
  47. package/dist/commands/context/jobs/get.js +8 -8
  48. package/dist/commands/context/jobs/get.js.map +1 -1
  49. package/dist/commands/context/list.js +2 -6
  50. package/dist/commands/context/list.js.map +1 -1
  51. package/dist/commands/deploy.js +1 -0
  52. package/dist/commands/deploy.js.map +1 -1
  53. package/dist/commands/doctor.js +2 -1
  54. package/dist/commands/doctor.js.map +1 -1
  55. package/dist/commands/openapi/list.js +2 -4
  56. package/dist/commands/openapi/list.js.map +1 -1
  57. package/dist/commands/projects/create.js +3 -6
  58. package/dist/commands/projects/create.js.map +1 -1
  59. package/dist/commands/schemas/list.js +1 -3
  60. package/dist/commands/schemas/list.js.map +1 -1
  61. package/dist/commands/tokens/create.js +2 -5
  62. package/dist/commands/tokens/create.js.map +1 -1
  63. package/dist/commands/tokens/delete.js +38 -30
  64. package/dist/commands/tokens/delete.js.map +1 -1
  65. package/dist/commands/tokens/list.js +27 -25
  66. package/dist/commands/tokens/list.js.map +1 -1
  67. package/dist/commands/tokens/rotate.js +2 -5
  68. package/dist/commands/tokens/rotate.js.map +1 -1
  69. package/dist/commands/typegen/generate.js +83 -45
  70. package/dist/commands/typegen/generate.js.map +1 -1
  71. package/dist/commands/undeploy.js +1 -0
  72. package/dist/commands/undeploy.js.map +1 -1
  73. package/dist/commands/whoami.js +5 -11
  74. package/dist/commands/whoami.js.map +1 -1
  75. package/dist/exports/invokeSanityCli/index.js +26 -6
  76. package/dist/exports/invokeSanityCli/index.js.map +1 -1
  77. package/dist/generated/apiRoutes.js +11 -26
  78. package/dist/generated/apiRoutes.js.map +1 -1
  79. package/dist/services/tokens.js +32 -22
  80. package/dist/services/tokens.js.map +1 -1
  81. package/dist/telemetry/init.telemetry.js.map +1 -1
  82. package/dist/util/resolveTokenScope.js +24 -0
  83. package/dist/util/resolveTokenScope.js.map +1 -0
  84. package/oclif.manifest.json +2027 -1964
  85. package/package.json +6 -5
@@ -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 { flags } = await this.parse(WhoamiCommand);
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 (flags.json) {
46
- this.log(JSON.stringify({
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
- }, null, 2));
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 {Flags} from '@oclif/core'\nimport {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 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 static override flags = {\n json: Flags.boolean({\n default: false,\n description: 'Output as JSON',\n }),\n }\n\n public async run(): Promise<void> {\n const {flags} = await this.parse(WhoamiCommand)\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 (flags.json) {\n this.log(\n JSON.stringify(\n {\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 null,\n 2,\n ),\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":["Flags","exitCodes","getCliTokenInfo","SanityCommand","isHttpError","getProviderName","formatKeyValue","getSamlProviderId","resolveSSOProvider","getCliUser","WhoamiCommand","description","examples","command","flags","json","boolean","default","run","parse","tokenInfo","token","error","exit","RUNTIME_ERROR","user","catch","err","source","ENV_TOKEN_SOURCE","isRejectedToken","samlProviderId","provider","sso","undefined","log","JSON","stringify","email","id","name","tokenSource","padTo","indent","formatProvider","formatOrganization","statusCode","formatSamlProvider","organizationSlug","organizationName","providerName","trim","test"],"mappings":"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"}
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 = '', ...commandArgv] = normalizeArgv(resolvedConfig, argv);
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
- baseFlags: CommandClass.baseFlags,
180
- enableJsonFlag: CommandClass.enableJsonFlag,
181
- flags: CommandClass.flags,
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: 'v2021-03-25',
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/{userId}',
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'
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/generated/apiRoutes.ts"],"sourcesContent":["/**\n * GENERATED FILE - DO NOT EDIT\n *\n * Routing manifest for `sanity api`, distilled from the published OpenAPI\n * specifications at https://www.sanity.io/docs/api/openapi\n *\n * Regenerate with: pnpm generate:api-routes\n */\nimport {type ApiRouteEntry} from '../actions/api/types.js'\n\nexport const apiRoutes: ApiRouteEntry[] = [\n {\n defaultApiVersion: 'v2025-07-11',\n host: 'global',\n pathPatterns: [\n 'access/invites/me',\n 'access/organization/{resourceId}/users/roles/default',\n 'access/requests/me',\n 'access/robots/me',\n 'access/robots/me/rotate',\n 'access/{resourceType}/{resourceId}/invites',\n 'access/{resourceType}/{resourceId}/invites/token/{inviteToken}',\n 'access/{resourceType}/{resourceId}/invites/token/{inviteToken}/accept',\n 'access/{resourceType}/{resourceId}/invites/token/{inviteToken}/eligibility',\n 'access/{resourceType}/{resourceId}/invites/{inviteId}',\n 'access/{resourceType}/{resourceId}/permissions',\n 'access/{resourceType}/{resourceId}/permissions/{permissionName}',\n 'access/{resourceType}/{resourceId}/requests',\n 'access/{resourceType}/{resourceId}/requests/state',\n 'access/{resourceType}/{resourceId}/requests/{requestId}/accept',\n 'access/{resourceType}/{resourceId}/requests/{requestId}/decline',\n 'access/{resourceType}/{resourceId}/robots',\n 'access/{resourceType}/{resourceId}/robots/{robotId}',\n 'access/{resourceType}/{resourceId}/roles',\n 'access/{resourceType}/{resourceId}/roles/{roleName}',\n 'access/{resourceType}/{resourceId}/user-permissions/me',\n 'access/{resourceType}/{resourceId}/user-permissions/me/check',\n 'access/{resourceType}/{resourceId}/users',\n 'access/{resourceType}/{resourceId}/users/me',\n 'access/{resourceType}/{resourceId}/users/{sanityUserId}',\n 'access/{resourceType}/{resourceId}/users/{sanityUserId}/roles',\n 'access/{resourceType}/{resourceId}/users/{sanityUserId}/roles/{roleName}'\n ],\n slug: 'access-api',\n title: 'Access API reference'\n },\n {\n defaultApiVersion: 'v2025-02-19',\n host: 'project',\n pathPatterns: [\n 'data/actions/{dataset}'\n ],\n slug: 'actions',\n title: 'Actions API reference'\n },\n {\n defaultApiVersion: 'v2021-02-01',\n host: 'global',\n pathPatterns: [\n 'activity',\n 'activity/export/csv'\n ],\n slug: 'activity-log',\n title: 'Activity Log API Reference'\n },\n {\n defaultApiVersion: 'vX',\n host: 'project',\n pathPatterns: [\n 'agent/action/generate/{dataset}',\n 'agent/action/patch/{dataset}',\n 'agent/action/prompt/{dataset}',\n 'agent/action/transform/{dataset}',\n 'agent/action/translate/{dataset}'\n ],\n slug: 'agent-actions',\n title: 'Agent Actions'\n },\n {\n host: 'global',\n pathPatterns: [\n 'applications',\n 'applications/{applicationId}',\n 'applications/{applicationId}/access',\n 'applications/{applicationId}/deployments',\n 'applications/{applicationId}/embeddable',\n 'applications/{applicationId}/installations',\n 'applications/{applicationId}/interfaces',\n 'applications/{applicationId}/workspaces',\n 'deploy',\n 'deploy/quickstart',\n 'installations',\n 'installations/ai-features',\n 'installations/catalog',\n 'installations/defaults',\n 'installations/{installationId}',\n 'installations/{installationId}/access',\n 'installations/{installationId}/configs',\n 'installations/{installationId}/configs/{configId}',\n 'installations/{installationId}/interfaces',\n 'organizations/{organizationId}/applications/{applicationId}',\n 'projects/{projectId}/user-applications',\n 'projects/{projectId}/user-applications/{userApplicationId}',\n 'projects/{projectId}/user-applications/{userApplicationId}/config/{configKey}',\n 'projects/{projectId}/user-applications/{userApplicationId}/deployments',\n 'studiohosts/{appHost}/availability',\n 'user-applications',\n 'user-applications/auto-update-version/{userApplicationId}',\n 'user-applications/resolve/application',\n 'user-applications/resolve/project',\n 'user-applications/workspaces',\n 'user-applications/{userApplicationId}',\n 'user-applications/{userApplicationId}/applicationData',\n 'user-applications/{userApplicationId}/config/{configKey}',\n 'user-applications/{userApplicationId}/deployments',\n 'user-applications/{userApplicationId}/workspaces'\n ],\n slug: 'applications-api',\n title: 'Applications API Reference'\n },\n {\n host: 'project',\n pathPatterns: [\n 'applications',\n 'applications/{applicationId}',\n 'applications/{applicationId}/access',\n 'applications/{applicationId}/deployments',\n 'applications/{applicationId}/embeddable',\n 'applications/{applicationId}/installations',\n 'applications/{applicationId}/interfaces',\n 'applications/{applicationId}/workspaces',\n 'deploy',\n 'deploy/quickstart',\n 'installations',\n 'installations/ai-features',\n 'installations/catalog',\n 'installations/defaults',\n 'installations/{installationId}',\n 'installations/{installationId}/access',\n 'installations/{installationId}/configs',\n 'installations/{installationId}/configs/{configId}',\n 'installations/{installationId}/interfaces',\n 'organizations/{organizationId}/applications/{applicationId}',\n 'projects/{projectId}/user-applications',\n 'projects/{projectId}/user-applications/{userApplicationId}',\n 'projects/{projectId}/user-applications/{userApplicationId}/config/{configKey}',\n 'projects/{projectId}/user-applications/{userApplicationId}/deployments',\n 'studiohosts/{appHost}/availability',\n 'user-applications',\n 'user-applications/auto-update-version/{userApplicationId}',\n 'user-applications/resolve/application',\n 'user-applications/resolve/project',\n 'user-applications/workspaces',\n 'user-applications/{userApplicationId}',\n 'user-applications/{userApplicationId}/applicationData',\n 'user-applications/{userApplicationId}/config/{configKey}',\n 'user-applications/{userApplicationId}/deployments',\n 'user-applications/{userApplicationId}/workspaces'\n ],\n slug: 'applications-api',\n title: 'Applications API Reference'\n },\n {\n defaultApiVersion: 'v2024-06-24',\n host: 'project',\n pathPatterns: [\n 'assets/files/{dataset}',\n 'assets/files/{dataset}/from-url',\n 'assets/images/{dataset}',\n 'assets/images/{dataset}/from-url',\n 'assets/media-library-link/{dataset}'\n ],\n slug: 'assets',\n title: 'Assets API reference'\n },\n {\n defaultApiVersion: 'v2025-02-19',\n host: 'global',\n pathPatterns: [\n 'projects/{projectId}/datasets/{datasetName}/backups',\n 'projects/{projectId}/datasets/{datasetName}/backups/{backupId}',\n 'projects/{projectId}/datasets/{datasetName}/settings/backups'\n ],\n slug: 'backups',\n title: 'Backups API reference'\n },\n {\n defaultApiVersion: 'v1',\n host: 'global',\n pathPatterns: [\n 'projects/{project_id}/datasets/{dataset_name}/assets/{asset_id}/purges',\n 'projects/{project_id}/datasets/{dataset_name}/purges'\n ],\n slug: 'cdn-cache-purge',\n title: 'CDN Cache Purge API Reference'\n },\n {\n defaultApiVersion: 'vX',\n host: 'global',\n pathPatterns: [\n 'agent/prompt',\n 'agent/{organizationId}/threads/{threadId}'\n ],\n slug: 'content-agent',\n title: 'Content Agent API reference'\n },\n {\n defaultApiVersion: 'v2025-02-19',\n host: 'global',\n pathPatterns: [\n 'projects/{projectId}/datasets/{dataset}/copy'\n ],\n slug: 'copy',\n title: 'Copy API reference'\n },\n {\n defaultApiVersion: 'v2025-02-19',\n host: 'project',\n pathPatterns: [\n 'data/doc/{dataset}/{documentId}'\n ],\n slug: 'doc',\n title: 'Doc API reference'\n },\n {\n defaultApiVersion: 'vX',\n host: 'project',\n pathPatterns: [\n 'embeddings-index/query/{dataset}/{indexName}',\n 'embeddings-index/{dataset}',\n 'embeddings-index/{dataset}/{indexName}'\n ],\n slug: 'embeddings-index',\n title: 'Embeddings Index API reference (deprecated)'\n },\n {\n defaultApiVersion: 'v2021-03-25',\n host: 'project',\n pathPatterns: [\n 'data/export/{dataset}'\n ],\n slug: 'export',\n title: 'Export API reference'\n },\n {\n host: 'global',\n pathPatterns: [\n 'functions',\n 'functions/{functionId}',\n 'functions/{functionId}/envvars',\n 'functions/{functionId}/envvars/{envVarKey}',\n 'functions/{functionId}/invoke',\n 'functions/{functionId}/logs',\n 'functions/{functionId}/logs/stream'\n ],\n slug: 'functions-api',\n title: 'Functions API reference'\n },\n {\n defaultApiVersion: 'v2025-02-19',\n host: 'project',\n pathPatterns: [\n 'data/history/{dataset}/documents/{documentId}',\n 'data/history/{dataset}/transactions',\n 'data/history/{dataset}/transactions/{documentIds}'\n ],\n slug: 'history',\n title: 'History API reference'\n },\n {\n defaultApiVersion: 'v2021-06-07',\n host: 'global',\n pathPatterns: [\n 'jobs/{jobId}',\n 'jobs/{jobId}/listen'\n ],\n slug: 'jobs',\n title: 'Jobs API reference'\n },\n {\n defaultApiVersion: 'v2025-02-19',\n host: 'project',\n pathPatterns: [\n 'data/listen/{dataset}'\n ],\n slug: 'listen',\n title: 'Listen API reference'\n },\n {\n defaultApiVersion: 'v2025-02-19',\n host: 'project',\n pathPatterns: [\n 'data/live/events/{dataset}'\n ],\n slug: 'live',\n title: 'Live Content API reference'\n },\n {\n defaultApiVersion: 'v2025-02-19',\n host: 'global',\n pathPatterns: [\n 'media-libraries/{libraryId}/from-url',\n 'media-libraries/{libraryId}/mutate',\n 'media-libraries/{libraryId}/query',\n 'media-libraries/{libraryId}/references/documents/{assetId}/to',\n 'media-libraries/{libraryId}/refsearch',\n 'media-libraries/{libraryId}/signing-keys',\n 'media-libraries/{libraryId}/signing-keys/{keyId}',\n 'media-libraries/{libraryId}/upload',\n 'media-libraries/{libraryId}/video/{videoId}/playback-info',\n 'media-libraries/{libraryId}/video/{videoId}/playback/{type}',\n 'media-libraries/{libraryId}/video/{videoId}/renditions/{name}',\n 'media-libraries/{libraryId}/video/{videoId}/subtitles',\n 'media-libraries/{libraryId}/video/{videoId}/subtitles/upload',\n 'media-libraries/{libraryId}/video/{videoId}/subtitles/{subtitleId}'\n ],\n slug: 'media-library',\n title: 'Media Library API reference'\n },\n {\n defaultApiVersion: 'v2025-02-19',\n host: 'project',\n pathPatterns: [\n 'media-libraries/{libraryId}/from-url',\n 'media-libraries/{libraryId}/mutate',\n 'media-libraries/{libraryId}/query',\n 'media-libraries/{libraryId}/references/documents/{assetId}/to',\n 'media-libraries/{libraryId}/refsearch',\n 'media-libraries/{libraryId}/signing-keys',\n 'media-libraries/{libraryId}/signing-keys/{keyId}',\n 'media-libraries/{libraryId}/upload',\n 'media-libraries/{libraryId}/video/{videoId}/playback-info',\n 'media-libraries/{libraryId}/video/{videoId}/playback/{type}',\n 'media-libraries/{libraryId}/video/{videoId}/renditions/{name}',\n 'media-libraries/{libraryId}/video/{videoId}/subtitles',\n 'media-libraries/{libraryId}/video/{videoId}/subtitles/upload',\n 'media-libraries/{libraryId}/video/{videoId}/subtitles/{subtitleId}'\n ],\n slug: 'media-library',\n title: 'Media Library API reference'\n },\n {\n defaultApiVersion: 'v2025-02-19',\n host: 'project',\n pathPatterns: [\n 'data/mutate/{dataset}'\n ],\n slug: 'mutation',\n title: 'Mutation API reference'\n },\n {\n defaultApiVersion: 'v2021-06-07',\n host: 'global',\n pathPatterns: [\n 'projects',\n 'projects/{projectId}',\n 'projects/{projectId}/cors',\n 'projects/{projectId}/cors/{id}',\n 'projects/{projectId}/datasets',\n 'projects/{projectId}/datasets/{datasetName}/tags/{tagIdentifier}',\n 'projects/{projectId}/datasets/{name}',\n 'projects/{projectId}/datasets/{name}/copy',\n 'projects/{projectId}/datasets/{name}/settings/embeddings',\n 'projects/{projectId}/datasets/{name}/tags',\n 'projects/{projectId}/features',\n 'projects/{projectId}/permissions',\n 'projects/{projectId}/tags',\n 'projects/{projectId}/tags/{tagIdentifier}',\n 'projects/{projectId}/tokens',\n 'projects/{projectId}/tokens/{tokenId}',\n 'projects/{projectId}/users/{userId}'\n ],\n slug: 'projects-api',\n title: 'Projects API reference'\n },\n {\n defaultApiVersion: 'v2025-02-19',\n host: 'project',\n pathPatterns: [\n 'data/query/{dataset}'\n ],\n slug: 'query',\n title: 'Query API reference'\n },\n {\n defaultApiVersion: 'v2021-10-04',\n host: 'global',\n pathPatterns: [\n 'organizations/{organizationId}/acl',\n 'organizations/{organizationId}/acl/{sanityUserId}',\n 'organizations/{organizationId}/grants',\n 'organizations/{organizationId}/providers/{providerId}/projects/{projectId}/role-mappings',\n 'projects/{projectId}/acl',\n 'projects/{projectId}/acl/{userId}',\n 'projects/{projectId}/datasets/{datasetName}/acl',\n 'projects/{projectId}/datasets/{datasetName}/grants',\n 'projects/{projectId}/grants',\n 'projects/{projectId}/permissionResourceSchemas',\n 'projects/{projectId}/roles',\n 'projects/{projectId}/roles/{roleName}'\n ],\n slug: 'roles',\n title: 'Roles API reference'\n },\n {\n defaultApiVersion: 'v2022-04-01',\n host: 'project',\n pathPatterns: [\n 'publish/{projectId}/{dataset}',\n 'schedules/{projectId}/{dataset}',\n 'schedules/{projectId}/{dataset}/{scheduleId}',\n 'schedules/{projectId}/{dataset}/{scheduleId}/publish',\n 'unpublish/{projectId}/{dataset}'\n ],\n slug: 'scheduling',\n title: 'Scheduling API reference'\n },\n {\n defaultApiVersion: 'v2026-04-27',\n host: 'global',\n pathPatterns: [\n 'organizations/{organizationId}/attribute-definitions',\n 'organizations/{organizationId}/attribute-definitions/{key}',\n 'organizations/{organizationId}/users/me/attributes',\n 'organizations/{organizationId}/users/{sanityUserId}/attributes'\n ],\n slug: 'user-attributes',\n title: 'User attributes API reference'\n },\n {\n defaultApiVersion: 'v2025-02-19',\n host: 'project',\n pathPatterns: [\n 'hooks/projects/{projectId}',\n 'hooks/projects/{projectId}/{id}',\n 'hooks/projects/{projectId}/{id}/attempts',\n 'hooks/{id}/messages'\n ],\n slug: 'webhooks',\n title: 'Webhooks API reference'\n }\n]\n"],"names":["apiRoutes","defaultApiVersion","host","pathPatterns","slug","title"],"mappings":"AAAA;;;;;;;CAOC,GAGD,OAAO,MAAMA,YAA6B;IACxC;QACEC,mBAAmB;QACnBC,MAAM;QACNC,cAAc;YACZ;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;SACD;QACDC,MAAM;QACNC,OAAO;IACT;IACA;QACEJ,mBAAmB;QACnBC,MAAM;QACNC,cAAc;YACZ;SACD;QACDC,MAAM;QACNC,OAAO;IACT;IACA;QACEJ,mBAAmB;QACnBC,MAAM;QACNC,cAAc;YACZ;YACA;SACD;QACDC,MAAM;QACNC,OAAO;IACT;IACA;QACEJ,mBAAmB;QACnBC,MAAM;QACNC,cAAc;YACZ;YACA;YACA;YACA;YACA;SACD;QACDC,MAAM;QACNC,OAAO;IACT;IACA;QACEH,MAAM;QACNC,cAAc;YACZ;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;SACD;QACDC,MAAM;QACNC,OAAO;IACT;IACA;QACEH,MAAM;QACNC,cAAc;YACZ;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;SACD;QACDC,MAAM;QACNC,OAAO;IACT;IACA;QACEJ,mBAAmB;QACnBC,MAAM;QACNC,cAAc;YACZ;YACA;YACA;YACA;YACA;SACD;QACDC,MAAM;QACNC,OAAO;IACT;IACA;QACEJ,mBAAmB;QACnBC,MAAM;QACNC,cAAc;YACZ;YACA;YACA;SACD;QACDC,MAAM;QACNC,OAAO;IACT;IACA;QACEJ,mBAAmB;QACnBC,MAAM;QACNC,cAAc;YACZ;YACA;SACD;QACDC,MAAM;QACNC,OAAO;IACT;IACA;QACEJ,mBAAmB;QACnBC,MAAM;QACNC,cAAc;YACZ;YACA;SACD;QACDC,MAAM;QACNC,OAAO;IACT;IACA;QACEJ,mBAAmB;QACnBC,MAAM;QACNC,cAAc;YACZ;SACD;QACDC,MAAM;QACNC,OAAO;IACT;IACA;QACEJ,mBAAmB;QACnBC,MAAM;QACNC,cAAc;YACZ;SACD;QACDC,MAAM;QACNC,OAAO;IACT;IACA;QACEJ,mBAAmB;QACnBC,MAAM;QACNC,cAAc;YACZ;YACA;YACA;SACD;QACDC,MAAM;QACNC,OAAO;IACT;IACA;QACEJ,mBAAmB;QACnBC,MAAM;QACNC,cAAc;YACZ;SACD;QACDC,MAAM;QACNC,OAAO;IACT;IACA;QACEH,MAAM;QACNC,cAAc;YACZ;YACA;YACA;YACA;YACA;YACA;YACA;SACD;QACDC,MAAM;QACNC,OAAO;IACT;IACA;QACEJ,mBAAmB;QACnBC,MAAM;QACNC,cAAc;YACZ;YACA;YACA;SACD;QACDC,MAAM;QACNC,OAAO;IACT;IACA;QACEJ,mBAAmB;QACnBC,MAAM;QACNC,cAAc;YACZ;YACA;SACD;QACDC,MAAM;QACNC,OAAO;IACT;IACA;QACEJ,mBAAmB;QACnBC,MAAM;QACNC,cAAc;YACZ;SACD;QACDC,MAAM;QACNC,OAAO;IACT;IACA;QACEJ,mBAAmB;QACnBC,MAAM;QACNC,cAAc;YACZ;SACD;QACDC,MAAM;QACNC,OAAO;IACT;IACA;QACEJ,mBAAmB;QACnBC,MAAM;QACNC,cAAc;YACZ;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;SACD;QACDC,MAAM;QACNC,OAAO;IACT;IACA;QACEJ,mBAAmB;QACnBC,MAAM;QACNC,cAAc;YACZ;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;SACD;QACDC,MAAM;QACNC,OAAO;IACT;IACA;QACEJ,mBAAmB;QACnBC,MAAM;QACNC,cAAc;YACZ;SACD;QACDC,MAAM;QACNC,OAAO;IACT;IACA;QACEJ,mBAAmB;QACnBC,MAAM;QACNC,cAAc;YACZ;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;SACD;QACDC,MAAM;QACNC,OAAO;IACT;IACA;QACEJ,mBAAmB;QACnBC,MAAM;QACNC,cAAc;YACZ;SACD;QACDC,MAAM;QACNC,OAAO;IACT;IACA;QACEJ,mBAAmB;QACnBC,MAAM;QACNC,cAAc;YACZ;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;SACD;QACDC,MAAM;QACNC,OAAO;IACT;IACA;QACEJ,mBAAmB;QACnBC,MAAM;QACNC,cAAc;YACZ;YACA;YACA;YACA;YACA;SACD;QACDC,MAAM;QACNC,OAAO;IACT;IACA;QACEJ,mBAAmB;QACnBC,MAAM;QACNC,cAAc;YACZ;YACA;YACA;YACA;SACD;QACDC,MAAM;QACNC,OAAO;IACT;IACA;QACEJ,mBAAmB;QACnBC,MAAM;QACNC,cAAc;YACZ;YACA;YACA;YACA;SACD;QACDC,MAAM;QACNC,OAAO;IACT;CACD,CAAA"}
1
+ {"version":3,"sources":["../../src/generated/apiRoutes.ts"],"sourcesContent":["/**\n * GENERATED FILE - DO NOT EDIT\n *\n * Routing manifest for `sanity api`, distilled from the published OpenAPI\n * specifications at https://www.sanity.io/docs/api/openapi\n *\n * Regenerate with: pnpm generate:api-routes\n */\nimport {type ApiRouteEntry} from '../actions/api/types.js'\n\nexport const apiRoutes: ApiRouteEntry[] = [\n {\n defaultApiVersion: 'v2025-07-11',\n host: 'global',\n pathPatterns: [\n 'access/invites/me',\n 'access/organization/{resourceId}/users/roles/default',\n 'access/requests/me',\n 'access/robots/me',\n 'access/robots/me/rotate',\n 'access/{resourceType}/{resourceId}/invites',\n 'access/{resourceType}/{resourceId}/invites/token/{inviteToken}',\n 'access/{resourceType}/{resourceId}/invites/token/{inviteToken}/accept',\n 'access/{resourceType}/{resourceId}/invites/token/{inviteToken}/eligibility',\n 'access/{resourceType}/{resourceId}/invites/{inviteId}',\n 'access/{resourceType}/{resourceId}/permissions',\n 'access/{resourceType}/{resourceId}/permissions/{permissionName}',\n 'access/{resourceType}/{resourceId}/requests',\n 'access/{resourceType}/{resourceId}/requests/state',\n 'access/{resourceType}/{resourceId}/requests/{requestId}/accept',\n 'access/{resourceType}/{resourceId}/requests/{requestId}/decline',\n 'access/{resourceType}/{resourceId}/robots',\n 'access/{resourceType}/{resourceId}/robots/{robotId}',\n 'access/{resourceType}/{resourceId}/roles',\n 'access/{resourceType}/{resourceId}/roles/{roleName}',\n 'access/{resourceType}/{resourceId}/user-permissions/me',\n 'access/{resourceType}/{resourceId}/user-permissions/me/check',\n 'access/{resourceType}/{resourceId}/users',\n 'access/{resourceType}/{resourceId}/users/me',\n 'access/{resourceType}/{resourceId}/users/{sanityUserId}',\n 'access/{resourceType}/{resourceId}/users/{sanityUserId}/roles',\n 'access/{resourceType}/{resourceId}/users/{sanityUserId}/roles/{roleName}'\n ],\n slug: 'access-api',\n title: 'Access API reference'\n },\n {\n defaultApiVersion: 'v2025-02-19',\n host: 'project',\n pathPatterns: [\n 'data/actions/{dataset}'\n ],\n slug: 'actions',\n title: 'Actions API reference'\n },\n {\n defaultApiVersion: 'v2021-02-01',\n host: 'global',\n pathPatterns: [\n 'activity',\n 'activity/export/csv'\n ],\n slug: 'activity-log',\n title: 'Activity Log API Reference'\n },\n {\n defaultApiVersion: 'vX',\n host: 'project',\n pathPatterns: [\n 'agent/action/generate/{dataset}',\n 'agent/action/patch/{dataset}',\n 'agent/action/prompt/{dataset}',\n 'agent/action/transform/{dataset}',\n 'agent/action/translate/{dataset}'\n ],\n slug: 'agent-actions',\n title: 'Agent Actions'\n },\n {\n host: 'global',\n pathPatterns: [\n 'applications',\n 'applications/{applicationId}',\n 'applications/{applicationId}/access',\n 'applications/{applicationId}/deployments',\n 'applications/{applicationId}/embeddable',\n 'applications/{applicationId}/installations',\n 'applications/{applicationId}/interfaces',\n 'applications/{applicationId}/workspaces',\n 'deploy',\n 'deploy/quickstart',\n 'installations',\n 'installations/ai-features',\n 'installations/catalog',\n 'installations/defaults',\n 'installations/{installationId}',\n 'installations/{installationId}/access',\n 'installations/{installationId}/configs',\n 'installations/{installationId}/configs/{configId}',\n 'installations/{installationId}/interfaces',\n 'organizations/{organizationId}/applications/{applicationId}',\n 'projects/{projectId}/user-applications',\n 'projects/{projectId}/user-applications/{userApplicationId}',\n 'projects/{projectId}/user-applications/{userApplicationId}/config/{configKey}',\n 'projects/{projectId}/user-applications/{userApplicationId}/deployments',\n 'studiohosts/{appHost}/availability',\n 'user-applications',\n 'user-applications/auto-update-version/{userApplicationId}',\n 'user-applications/resolve/application',\n 'user-applications/resolve/project',\n 'user-applications/workspaces',\n 'user-applications/{userApplicationId}',\n 'user-applications/{userApplicationId}/applicationData',\n 'user-applications/{userApplicationId}/config/{configKey}',\n 'user-applications/{userApplicationId}/deployments',\n 'user-applications/{userApplicationId}/workspaces'\n ],\n slug: 'applications-api',\n title: 'Applications API Reference'\n },\n {\n host: 'project',\n pathPatterns: [\n 'applications',\n 'applications/{applicationId}',\n 'applications/{applicationId}/access',\n 'applications/{applicationId}/deployments',\n 'applications/{applicationId}/embeddable',\n 'applications/{applicationId}/installations',\n 'applications/{applicationId}/interfaces',\n 'applications/{applicationId}/workspaces',\n 'deploy',\n 'deploy/quickstart',\n 'installations',\n 'installations/ai-features',\n 'installations/catalog',\n 'installations/defaults',\n 'installations/{installationId}',\n 'installations/{installationId}/access',\n 'installations/{installationId}/configs',\n 'installations/{installationId}/configs/{configId}',\n 'installations/{installationId}/interfaces',\n 'organizations/{organizationId}/applications/{applicationId}',\n 'projects/{projectId}/user-applications',\n 'projects/{projectId}/user-applications/{userApplicationId}',\n 'projects/{projectId}/user-applications/{userApplicationId}/config/{configKey}',\n 'projects/{projectId}/user-applications/{userApplicationId}/deployments',\n 'studiohosts/{appHost}/availability',\n 'user-applications',\n 'user-applications/auto-update-version/{userApplicationId}',\n 'user-applications/resolve/application',\n 'user-applications/resolve/project',\n 'user-applications/workspaces',\n 'user-applications/{userApplicationId}',\n 'user-applications/{userApplicationId}/applicationData',\n 'user-applications/{userApplicationId}/config/{configKey}',\n 'user-applications/{userApplicationId}/deployments',\n 'user-applications/{userApplicationId}/workspaces'\n ],\n slug: 'applications-api',\n title: 'Applications API Reference'\n },\n {\n defaultApiVersion: 'v2024-06-24',\n host: 'project',\n pathPatterns: [\n 'assets/files/{dataset}',\n 'assets/files/{dataset}/from-url',\n 'assets/images/{dataset}',\n 'assets/images/{dataset}/from-url',\n 'assets/media-library-link/{dataset}'\n ],\n slug: 'assets',\n title: 'Assets API reference'\n },\n {\n defaultApiVersion: 'v2025-02-19',\n host: 'global',\n pathPatterns: [\n 'projects/{projectId}/datasets/{datasetName}/backups',\n 'projects/{projectId}/datasets/{datasetName}/backups/{backupId}',\n 'projects/{projectId}/datasets/{datasetName}/settings/backups'\n ],\n slug: 'backups',\n title: 'Backups API reference'\n },\n {\n defaultApiVersion: 'v1',\n host: 'global',\n pathPatterns: [\n 'projects/{project_id}/datasets/{dataset_name}/assets/{asset_id}/purges',\n 'projects/{project_id}/datasets/{dataset_name}/purges'\n ],\n slug: 'cdn-cache-purge',\n title: 'CDN Cache Purge API Reference'\n },\n {\n defaultApiVersion: 'vX',\n host: 'global',\n pathPatterns: [\n 'agent/prompt',\n 'agent/{organizationId}/threads/{threadId}'\n ],\n slug: 'content-agent',\n title: 'Content Agent API reference'\n },\n {\n defaultApiVersion: 'v2025-02-19',\n host: 'global',\n pathPatterns: [\n 'projects/{projectId}/datasets/copy',\n 'projects/{projectId}/datasets/{dataset}/copy'\n ],\n slug: 'copy',\n title: 'Copy API reference'\n },\n {\n defaultApiVersion: 'v2025-02-19',\n host: 'project',\n pathPatterns: [\n 'data/doc/{dataset}/{documentId}'\n ],\n slug: 'doc',\n title: 'Doc API reference'\n },\n {\n defaultApiVersion: 'vX',\n host: 'project',\n pathPatterns: [\n 'embeddings-index/query/{dataset}/{indexName}',\n 'embeddings-index/{dataset}',\n 'embeddings-index/{dataset}/{indexName}'\n ],\n slug: 'embeddings-index',\n title: 'Embeddings Index API reference (deprecated)'\n },\n {\n defaultApiVersion: 'v2025-02-19',\n host: 'project',\n pathPatterns: [\n 'data/export/{dataset}'\n ],\n slug: 'export',\n title: 'Export API reference'\n },\n {\n host: 'global',\n pathPatterns: [\n 'functions',\n 'functions/{functionId}',\n 'functions/{functionId}/envvars',\n 'functions/{functionId}/envvars/{envVarKey}',\n 'functions/{functionId}/invoke',\n 'functions/{functionId}/logs',\n 'functions/{functionId}/logs/stream'\n ],\n slug: 'functions-api',\n title: 'Functions API reference'\n },\n {\n defaultApiVersion: 'v2025-02-19',\n host: 'project',\n pathPatterns: [\n 'data/history/{dataset}/documents/{documentId}',\n 'data/history/{dataset}/transactions',\n 'data/history/{dataset}/transactions/{documentIds}'\n ],\n slug: 'history',\n title: 'History API reference'\n },\n {\n defaultApiVersion: 'v2021-06-07',\n host: 'global',\n pathPatterns: [\n 'jobs/{jobId}',\n 'jobs/{jobId}/listen'\n ],\n slug: 'jobs',\n title: 'Jobs API reference'\n },\n {\n defaultApiVersion: 'v2025-02-19',\n host: 'project',\n pathPatterns: [\n 'data/listen/{dataset}'\n ],\n slug: 'listen',\n title: 'Listen API reference'\n },\n {\n defaultApiVersion: 'v2025-02-19',\n host: 'project',\n pathPatterns: [\n 'data/live/events/{dataset}'\n ],\n slug: 'live',\n title: 'Live Content API reference'\n },\n {\n defaultApiVersion: 'v2025-02-19',\n host: 'global',\n pathPatterns: [\n 'media-libraries/{libraryId}/from-url',\n 'media-libraries/{libraryId}/mutate',\n 'media-libraries/{libraryId}/query',\n 'media-libraries/{libraryId}/references/documents/{assetId}/to',\n 'media-libraries/{libraryId}/refsearch',\n 'media-libraries/{libraryId}/signing-keys',\n 'media-libraries/{libraryId}/signing-keys/{keyId}',\n 'media-libraries/{libraryId}/upload',\n 'media-libraries/{libraryId}/video/{videoId}/playback-info',\n 'media-libraries/{libraryId}/video/{videoId}/playback/{type}',\n 'media-libraries/{libraryId}/video/{videoId}/renditions/{name}',\n 'media-libraries/{libraryId}/video/{videoId}/subtitles',\n 'media-libraries/{libraryId}/video/{videoId}/subtitles/upload',\n 'media-libraries/{libraryId}/video/{videoId}/subtitles/{subtitleId}'\n ],\n slug: 'media-library',\n title: 'Media Library API reference'\n },\n {\n defaultApiVersion: 'v2025-02-19',\n host: 'project',\n pathPatterns: [\n 'data/mutate/{dataset}'\n ],\n slug: 'mutation',\n title: 'Mutation API reference'\n },\n {\n defaultApiVersion: 'v2021-06-07',\n host: 'global',\n pathPatterns: [\n 'projects',\n 'projects/{projectId}',\n 'projects/{projectId}/cors',\n 'projects/{projectId}/cors/{id}',\n 'projects/{projectId}/datasets',\n 'projects/{projectId}/datasets/copy',\n 'projects/{projectId}/datasets/{datasetName}/tags/{tagIdentifier}',\n 'projects/{projectId}/datasets/{name}',\n 'projects/{projectId}/datasets/{name}/copy',\n 'projects/{projectId}/datasets/{name}/settings/embeddings',\n 'projects/{projectId}/datasets/{name}/tags',\n 'projects/{projectId}/features',\n 'projects/{projectId}/permissions',\n 'projects/{projectId}/tags',\n 'projects/{projectId}/tags/{tagIdentifier}',\n 'projects/{projectId}/tokens',\n 'projects/{projectId}/tokens/{tokenId}',\n 'projects/{projectId}/users/{userId}'\n ],\n slug: 'projects-api',\n title: 'Projects API reference'\n },\n {\n defaultApiVersion: 'v2025-02-19',\n host: 'project',\n pathPatterns: [\n 'data/query/{dataset}'\n ],\n slug: 'query',\n title: 'Query API reference'\n },\n {\n defaultApiVersion: 'v2021-10-04',\n host: 'global',\n pathPatterns: [\n 'auth/organizations/{organizationId}/providers/{providerId}/projects/{projectId}/role-mappings',\n 'organizations/{organizationId}/acl',\n 'organizations/{organizationId}/acl/{sanityUserId}',\n 'organizations/{organizationId}/grants',\n 'projects/{projectId}/acl',\n 'projects/{projectId}/acl/{projectUserId}',\n 'projects/{projectId}/datasets/{datasetName}/acl',\n 'projects/{projectId}/datasets/{datasetName}/grants',\n 'projects/{projectId}/grants',\n 'projects/{projectId}/grants/{projectUserId}',\n 'projects/{projectId}/permissionResourceSchemas',\n 'projects/{projectId}/permissionResources',\n 'projects/{projectId}/permissionResources/{resourceId}',\n 'projects/{projectId}/roles',\n 'projects/{projectId}/roles/{roleName}'\n ],\n slug: 'roles',\n title: 'Roles API reference'\n },\n {\n defaultApiVersion: 'v2022-04-01',\n host: 'project',\n pathPatterns: [\n 'publish/{projectId}/{dataset}',\n 'schedules/{projectId}/{dataset}',\n 'schedules/{projectId}/{dataset}/{scheduleId}',\n 'schedules/{projectId}/{dataset}/{scheduleId}/publish',\n 'unpublish/{projectId}/{dataset}'\n ],\n slug: 'scheduling',\n title: 'Scheduling API reference'\n },\n {\n defaultApiVersion: 'v2026-04-27',\n host: 'global',\n pathPatterns: [\n 'organizations/{organizationId}/attribute-definitions',\n 'organizations/{organizationId}/attribute-definitions/{key}',\n 'organizations/{organizationId}/users/me/attributes',\n 'organizations/{organizationId}/users/{sanityUserId}/attributes'\n ],\n slug: 'user-attributes',\n title: 'User attributes API reference'\n },\n {\n defaultApiVersion: 'v2025-02-19',\n host: 'project',\n pathPatterns: [\n 'hooks/projects/{projectId}',\n 'hooks/projects/{projectId}/attempts/{attemptId}',\n 'hooks/projects/{projectId}/{id}',\n 'hooks/projects/{projectId}/{id}/attempts',\n 'hooks/projects/{projectId}/{id}/messages',\n 'hooks/projects/{projectId}/{id}/messages/{messageId}/attempts'\n ],\n slug: 'webhooks',\n title: 'Webhooks API reference'\n }\n]\n"],"names":["apiRoutes","defaultApiVersion","host","pathPatterns","slug","title"],"mappings":"AAAA;;;;;;;CAOC,GAGD,OAAO,MAAMA,YAA6B;IACxC;QACEC,mBAAmB;QACnBC,MAAM;QACNC,cAAc;YACZ;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;SACD;QACDC,MAAM;QACNC,OAAO;IACT;IACA;QACEJ,mBAAmB;QACnBC,MAAM;QACNC,cAAc;YACZ;SACD;QACDC,MAAM;QACNC,OAAO;IACT;IACA;QACEJ,mBAAmB;QACnBC,MAAM;QACNC,cAAc;YACZ;YACA;SACD;QACDC,MAAM;QACNC,OAAO;IACT;IACA;QACEJ,mBAAmB;QACnBC,MAAM;QACNC,cAAc;YACZ;YACA;YACA;YACA;YACA;SACD;QACDC,MAAM;QACNC,OAAO;IACT;IACA;QACEH,MAAM;QACNC,cAAc;YACZ;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;SACD;QACDC,MAAM;QACNC,OAAO;IACT;IACA;QACEH,MAAM;QACNC,cAAc;YACZ;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;SACD;QACDC,MAAM;QACNC,OAAO;IACT;IACA;QACEJ,mBAAmB;QACnBC,MAAM;QACNC,cAAc;YACZ;YACA;YACA;YACA;YACA;SACD;QACDC,MAAM;QACNC,OAAO;IACT;IACA;QACEJ,mBAAmB;QACnBC,MAAM;QACNC,cAAc;YACZ;YACA;YACA;SACD;QACDC,MAAM;QACNC,OAAO;IACT;IACA;QACEJ,mBAAmB;QACnBC,MAAM;QACNC,cAAc;YACZ;YACA;SACD;QACDC,MAAM;QACNC,OAAO;IACT;IACA;QACEJ,mBAAmB;QACnBC,MAAM;QACNC,cAAc;YACZ;YACA;SACD;QACDC,MAAM;QACNC,OAAO;IACT;IACA;QACEJ,mBAAmB;QACnBC,MAAM;QACNC,cAAc;YACZ;YACA;SACD;QACDC,MAAM;QACNC,OAAO;IACT;IACA;QACEJ,mBAAmB;QACnBC,MAAM;QACNC,cAAc;YACZ;SACD;QACDC,MAAM;QACNC,OAAO;IACT;IACA;QACEJ,mBAAmB;QACnBC,MAAM;QACNC,cAAc;YACZ;YACA;YACA;SACD;QACDC,MAAM;QACNC,OAAO;IACT;IACA;QACEJ,mBAAmB;QACnBC,MAAM;QACNC,cAAc;YACZ;SACD;QACDC,MAAM;QACNC,OAAO;IACT;IACA;QACEH,MAAM;QACNC,cAAc;YACZ;YACA;YACA;YACA;YACA;YACA;YACA;SACD;QACDC,MAAM;QACNC,OAAO;IACT;IACA;QACEJ,mBAAmB;QACnBC,MAAM;QACNC,cAAc;YACZ;YACA;YACA;SACD;QACDC,MAAM;QACNC,OAAO;IACT;IACA;QACEJ,mBAAmB;QACnBC,MAAM;QACNC,cAAc;YACZ;YACA;SACD;QACDC,MAAM;QACNC,OAAO;IACT;IACA;QACEJ,mBAAmB;QACnBC,MAAM;QACNC,cAAc;YACZ;SACD;QACDC,MAAM;QACNC,OAAO;IACT;IACA;QACEJ,mBAAmB;QACnBC,MAAM;QACNC,cAAc;YACZ;SACD;QACDC,MAAM;QACNC,OAAO;IACT;IACA;QACEJ,mBAAmB;QACnBC,MAAM;QACNC,cAAc;YACZ;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;SACD;QACDC,MAAM;QACNC,OAAO;IACT;IACA;QACEJ,mBAAmB;QACnBC,MAAM;QACNC,cAAc;YACZ;SACD;QACDC,MAAM;QACNC,OAAO;IACT;IACA;QACEJ,mBAAmB;QACnBC,MAAM;QACNC,cAAc;YACZ;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;SACD;QACDC,MAAM;QACNC,OAAO;IACT;IACA;QACEJ,mBAAmB;QACnBC,MAAM;QACNC,cAAc;YACZ;SACD;QACDC,MAAM;QACNC,OAAO;IACT;IACA;QACEJ,mBAAmB;QACnBC,MAAM;QACNC,cAAc;YACZ;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;SACD;QACDC,MAAM;QACNC,OAAO;IACT;IACA;QACEJ,mBAAmB;QACnBC,MAAM;QACNC,cAAc;YACZ;YACA;YACA;YACA;YACA;SACD;QACDC,MAAM;QACNC,OAAO;IACT;IACA;QACEJ,mBAAmB;QACnBC,MAAM;QACNC,cAAc;YACZ;YACA;YACA;YACA;SACD;QACDC,MAAM;QACNC,OAAO;IACT;IACA;QACEJ,mBAAmB;QACnBC,MAAM;QACNC,cAAc;YACZ;YACA;YACA;YACA;YACA;YACA;SACD;QACDC,MAAM;QACNC,OAAO;IACT;CACD,CAAA"}
@@ -9,13 +9,16 @@ function getClient(token) {
9
9
  }
10
10
  });
11
11
  }
12
- async function fetchAllPages(client, url) {
12
+ async function fetchAllPages(client, url, query = {}) {
13
13
  const items = [];
14
14
  let cursor = null;
15
15
  do {
16
16
  const response = await client.request({
17
- query: cursor === null ? {} : {
18
- nextCursor: cursor
17
+ query: {
18
+ ...query,
19
+ ...cursor === null ? {} : {
20
+ nextCursor: cursor
21
+ }
19
22
  },
20
23
  url
21
24
  });
@@ -80,19 +83,26 @@ async function postRobot(url, { expiresAt, ...body }, query = {}) {
80
83
  const { organizationId, ...body } = options;
81
84
  return postRobot(`/access/organization/${organizationId}/robots`, body);
82
85
  }
83
- /**
84
- * Delete a token from a project
85
- * @param options - The options for deleting a token from a project; `tokenId`
86
- * is the id reported by `getTokens`/`createToken`
87
- * @returns A promise that resolves when the token is deleted
88
- *
89
- * @internal
90
- */ export async function deleteToken(options) {
91
- const { projectId, tokenId } = options;
86
+ function robotsUrl({ resourceId, resourceType }) {
87
+ return `/access/${resourceType}/${resourceId}/robots`;
88
+ }
89
+ function isManagedByOrganization(robot, organizationId) {
90
+ return robot.managedBy?.resourceType === 'organization' && robot.managedBy.resourceId === organizationId;
91
+ }
92
+ /** Delete a token from the requested scope. @internal */ export async function deleteToken(scope, tokenId) {
92
93
  const client = await getClient();
94
+ const url = `${robotsUrl(scope)}/${tokenId}`;
95
+ if (scope.resourceType === 'organization') {
96
+ const robot = await client.request({
97
+ url
98
+ });
99
+ if (!isManagedByOrganization(robot, scope.resourceId)) {
100
+ throw new Error(`Token "${tokenId}" is not managed by organization "${scope.resourceId}". Use tokens list --organization ${scope.resourceId} to find tokens managed by this organization.`);
101
+ }
102
+ }
93
103
  return client.request({
94
104
  method: 'DELETE',
95
- url: `/access/project/${projectId}/robots/${tokenId}`
105
+ url
96
106
  });
97
107
  }
98
108
  /**
@@ -110,16 +120,16 @@ async function postRobot(url, { expiresAt, ...body }, query = {}) {
110
120
  url: '/access/robots/me/rotate'
111
121
  });
112
122
  }
113
- /**
114
- * Get all tokens for a project. Tokens managed by an organization are
115
- * excluded: they cannot be managed at the project scope.
116
- * @param projectId - The project ID
117
- * @returns A promise that resolves to an array of robots
118
- *
119
- * @internal
120
- */ export async function getTokens(projectId) {
123
+ /** List tokens managed at the requested scope. @internal */ export async function getTokens(scope) {
121
124
  const client = await getClient();
122
- const robots = await fetchAllPages(client, `/access/project/${projectId}/robots`);
125
+ const query = scope.resourceType === 'organization' ? {
126
+ includeChildren: 'true',
127
+ limit: '500'
128
+ } : {};
129
+ const robots = await fetchAllPages(client, robotsUrl(scope), query);
130
+ if (scope.resourceType === 'organization') {
131
+ return robots.filter((robot)=>isManagedByOrganization(robot, scope.resourceId));
132
+ }
123
133
  return robots.filter((robot)=>robot.managedBy?.resourceType !== 'organization');
124
134
  }
125
135
  /**
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/services/tokens.ts"],"sourcesContent":["import {getGlobalCliClient} from '@sanity/cli-core'\nimport {type SanityClient} from '@sanity/client'\n\nimport {TOKENS_API_VERSION} from '../actions/tokens/constants.js'\nimport {\n type Membership,\n type Robot,\n type RobotWithToken,\n type Role,\n} from '../actions/tokens/types.js'\n\ninterface PaginatedResponse<T> {\n data: T[]\n nextCursor: string | null\n}\n\nfunction getClient(token?: string): Promise<SanityClient> {\n return getGlobalCliClient({\n apiVersion: TOKENS_API_VERSION,\n requireUser: true,\n ...(token === undefined ? {} : {token}),\n })\n}\n\nasync function fetchAllPages<T>(client: SanityClient, url: string): Promise<T[]> {\n const items: T[] = []\n let cursor: string | null = null\n\n do {\n const response: PaginatedResponse<T> = await client.request<PaginatedResponse<T>>({\n query: cursor === null ? {} : {nextCursor: cursor},\n url,\n })\n items.push(...response.data)\n cursor = response.nextCursor\n } while (cursor !== null)\n\n return items\n}\n\n/**\n * Get the membership granting a robot access to the given project\n * @param robot - The robot to inspect\n * @param projectId - The project ID\n * @returns The project membership, if any\n *\n * @internal\n */\nexport function getProjectMembership(robot: Robot, projectId: string): Membership | undefined {\n return robot.memberships.find(\n (membership) => membership.resourceType === 'project' && membership.resourceId === projectId,\n )\n}\n\ninterface RobotBody {\n label: string\n memberships: Membership[]\n\n expiresAt?: string\n}\n\nasync function postRobot(\n url: string,\n {expiresAt, ...body}: RobotBody,\n query: Record<string, string> = {},\n): Promise<RobotWithToken> {\n const client = await getClient()\n\n return client.request<RobotWithToken>({\n body: {...body, ...(expiresAt === undefined ? {} : {expiresAt})},\n method: 'POST',\n query,\n url,\n })\n}\n\ninterface CreateTokenOptions {\n label: string\n projectId: string\n roleNames: string[]\n\n expiresAt?: string\n sendNotification?: boolean\n}\n\n/**\n * Add a token to a project\n * @param options - The options for adding a token to a project\n * @returns A promise that resolves to the created robot, including its secret token\n *\n * @internal\n */\nexport async function createToken(options: CreateTokenOptions): Promise<RobotWithToken> {\n const {expiresAt, label, projectId, roleNames, sendNotification} = options\n\n return postRobot(\n `/access/project/${projectId}/robots`,\n {\n expiresAt,\n label,\n memberships: [{resourceId: projectId, resourceType: 'project', roleNames}],\n },\n sendNotification === false ? {sendNotification: 'false'} : {},\n )\n}\n\ninterface CreateOrganizationTokenOptions extends RobotBody {\n organizationId: string\n}\n\n/**\n * Create an organization token, which can hold organization permissions and roles on several projects\n * @param options - The options for the organization token\n * @returns A promise that resolves to the created robot, including its secret token\n *\n * @internal\n */\nexport async function createOrganizationToken(\n options: CreateOrganizationTokenOptions,\n): Promise<RobotWithToken> {\n const {organizationId, ...body} = options\n\n return postRobot(`/access/organization/${organizationId}/robots`, body)\n}\n\ninterface DeleteTokenOptions {\n projectId: string\n tokenId: string\n}\n\n/**\n * Delete a token from a project\n * @param options - The options for deleting a token from a project; `tokenId`\n * is the id reported by `getTokens`/`createToken`\n * @returns A promise that resolves when the token is deleted\n *\n * @internal\n */\nexport async function deleteToken(options: DeleteTokenOptions): Promise<void> {\n const {projectId, tokenId} = options\n\n const client = await getClient()\n\n return client.request({\n method: 'DELETE',\n url: `/access/project/${projectId}/robots/${tokenId}`,\n })\n}\n\n/**\n * Rotate a robot token, replacing its secret while preserving the robot,\n * its roles, and the token's expiry. The request authenticates as the robot\n * itself; the previous secret is revoked immediately.\n * @param token - The current robot token secret\n * @returns A promise that resolves to the robot with its new secret token\n *\n * @internal\n */\nexport async function rotateToken(token: string): Promise<RobotWithToken> {\n const client = await getClient(token)\n\n return client.request<RobotWithToken>({\n method: 'POST',\n url: '/access/robots/me/rotate',\n })\n}\n\n/**\n * Get all tokens for a project. Tokens managed by an organization are\n * excluded: they cannot be managed at the project scope.\n * @param projectId - The project ID\n * @returns A promise that resolves to an array of robots\n *\n * @internal\n */\nexport async function getTokens(projectId: string): Promise<Robot[]> {\n const client = await getClient()\n\n const robots = await fetchAllPages<Robot>(client, `/access/project/${projectId}/robots`)\n\n return robots.filter((robot) => robot.managedBy?.resourceType !== 'organization')\n}\n\n/**\n * Get all roles for a project\n * @param projectId - The project ID\n * @returns A promise that resolves to an array of project roles\n *\n * @internal\n */\nexport async function getTokenRoles(projectId: string): Promise<Role[]> {\n const client = await getClient()\n\n return fetchAllPages<Role>(client, `/access/project/${projectId}/roles`)\n}\n"],"names":["getGlobalCliClient","TOKENS_API_VERSION","getClient","token","apiVersion","requireUser","undefined","fetchAllPages","client","url","items","cursor","response","request","query","nextCursor","push","data","getProjectMembership","robot","projectId","memberships","find","membership","resourceType","resourceId","postRobot","expiresAt","body","method","createToken","options","label","roleNames","sendNotification","createOrganizationToken","organizationId","deleteToken","tokenId","rotateToken","getTokens","robots","filter","managedBy","getTokenRoles"],"mappings":"AAAA,SAAQA,kBAAkB,QAAO,mBAAkB;AAGnD,SAAQC,kBAAkB,QAAO,iCAAgC;AAajE,SAASC,UAAUC,KAAc;IAC/B,OAAOH,mBAAmB;QACxBI,YAAYH;QACZI,aAAa;QACb,GAAIF,UAAUG,YAAY,CAAC,IAAI;YAACH;QAAK,CAAC;IACxC;AACF;AAEA,eAAeI,cAAiBC,MAAoB,EAAEC,GAAW;IAC/D,MAAMC,QAAa,EAAE;IACrB,IAAIC,SAAwB;IAE5B,GAAG;QACD,MAAMC,WAAiC,MAAMJ,OAAOK,OAAO,CAAuB;YAChFC,OAAOH,WAAW,OAAO,CAAC,IAAI;gBAACI,YAAYJ;YAAM;YACjDF;QACF;QACAC,MAAMM,IAAI,IAAIJ,SAASK,IAAI;QAC3BN,SAASC,SAASG,UAAU;IAC9B,QAASJ,WAAW,KAAK;IAEzB,OAAOD;AACT;AAEA;;;;;;;CAOC,GACD,OAAO,SAASQ,qBAAqBC,KAAY,EAAEC,SAAiB;IAClE,OAAOD,MAAME,WAAW,CAACC,IAAI,CAC3B,CAACC,aAAeA,WAAWC,YAAY,KAAK,aAAaD,WAAWE,UAAU,KAAKL;AAEvF;AASA,eAAeM,UACbjB,GAAW,EACX,EAACkB,SAAS,EAAE,GAAGC,MAAgB,EAC/Bd,QAAgC,CAAC,CAAC;IAElC,MAAMN,SAAS,MAAMN;IAErB,OAAOM,OAAOK,OAAO,CAAiB;QACpCe,MAAM;YAAC,GAAGA,IAAI;YAAE,GAAID,cAAcrB,YAAY,CAAC,IAAI;gBAACqB;YAAS,CAAC;QAAC;QAC/DE,QAAQ;QACRf;QACAL;IACF;AACF;AAWA;;;;;;CAMC,GACD,OAAO,eAAeqB,YAAYC,OAA2B;IAC3D,MAAM,EAACJ,SAAS,EAAEK,KAAK,EAAEZ,SAAS,EAAEa,SAAS,EAAEC,gBAAgB,EAAC,GAAGH;IAEnE,OAAOL,UACL,CAAC,gBAAgB,EAAEN,UAAU,OAAO,CAAC,EACrC;QACEO;QACAK;QACAX,aAAa;YAAC;gBAACI,YAAYL;gBAAWI,cAAc;gBAAWS;YAAS;SAAE;IAC5E,GACAC,qBAAqB,QAAQ;QAACA,kBAAkB;IAAO,IAAI,CAAC;AAEhE;AAMA;;;;;;CAMC,GACD,OAAO,eAAeC,wBACpBJ,OAAuC;IAEvC,MAAM,EAACK,cAAc,EAAE,GAAGR,MAAK,GAAGG;IAElC,OAAOL,UAAU,CAAC,qBAAqB,EAAEU,eAAe,OAAO,CAAC,EAAER;AACpE;AAOA;;;;;;;CAOC,GACD,OAAO,eAAeS,YAAYN,OAA2B;IAC3D,MAAM,EAACX,SAAS,EAAEkB,OAAO,EAAC,GAAGP;IAE7B,MAAMvB,SAAS,MAAMN;IAErB,OAAOM,OAAOK,OAAO,CAAC;QACpBgB,QAAQ;QACRpB,KAAK,CAAC,gBAAgB,EAAEW,UAAU,QAAQ,EAAEkB,SAAS;IACvD;AACF;AAEA;;;;;;;;CAQC,GACD,OAAO,eAAeC,YAAYpC,KAAa;IAC7C,MAAMK,SAAS,MAAMN,UAAUC;IAE/B,OAAOK,OAAOK,OAAO,CAAiB;QACpCgB,QAAQ;QACRpB,KAAK;IACP;AACF;AAEA;;;;;;;CAOC,GACD,OAAO,eAAe+B,UAAUpB,SAAiB;IAC/C,MAAMZ,SAAS,MAAMN;IAErB,MAAMuC,SAAS,MAAMlC,cAAqBC,QAAQ,CAAC,gBAAgB,EAAEY,UAAU,OAAO,CAAC;IAEvF,OAAOqB,OAAOC,MAAM,CAAC,CAACvB,QAAUA,MAAMwB,SAAS,EAAEnB,iBAAiB;AACpE;AAEA;;;;;;CAMC,GACD,OAAO,eAAeoB,cAAcxB,SAAiB;IACnD,MAAMZ,SAAS,MAAMN;IAErB,OAAOK,cAAoBC,QAAQ,CAAC,gBAAgB,EAAEY,UAAU,MAAM,CAAC;AACzE"}
1
+ {"version":3,"sources":["../../src/services/tokens.ts"],"sourcesContent":["import {getGlobalCliClient} from '@sanity/cli-core'\nimport {type SanityClient} from '@sanity/client'\n\nimport {TOKENS_API_VERSION} from '../actions/tokens/constants.js'\nimport {\n type Membership,\n type Robot,\n type RobotWithToken,\n type Role,\n type TokenScope,\n} from '../actions/tokens/types.js'\n\ninterface PaginatedResponse<T> {\n data: T[]\n nextCursor: string | null\n}\n\nfunction getClient(token?: string): Promise<SanityClient> {\n return getGlobalCliClient({\n apiVersion: TOKENS_API_VERSION,\n requireUser: true,\n ...(token === undefined ? {} : {token}),\n })\n}\n\nasync function fetchAllPages<T>(\n client: SanityClient,\n url: string,\n query: Record<string, string> = {},\n): Promise<T[]> {\n const items: T[] = []\n let cursor: string | null = null\n\n do {\n const response: PaginatedResponse<T> = await client.request<PaginatedResponse<T>>({\n query: {...query, ...(cursor === null ? {} : {nextCursor: cursor})},\n url,\n })\n items.push(...response.data)\n cursor = response.nextCursor\n } while (cursor !== null)\n\n return items\n}\n\n/**\n * Get the membership granting a robot access to the given project\n * @param robot - The robot to inspect\n * @param projectId - The project ID\n * @returns The project membership, if any\n *\n * @internal\n */\nexport function getProjectMembership(robot: Robot, projectId: string): Membership | undefined {\n return robot.memberships.find(\n (membership) => membership.resourceType === 'project' && membership.resourceId === projectId,\n )\n}\n\ninterface RobotBody {\n label: string\n memberships: Membership[]\n\n expiresAt?: string\n}\n\nasync function postRobot(\n url: string,\n {expiresAt, ...body}: RobotBody,\n query: Record<string, string> = {},\n): Promise<RobotWithToken> {\n const client = await getClient()\n\n return client.request<RobotWithToken>({\n body: {...body, ...(expiresAt === undefined ? {} : {expiresAt})},\n method: 'POST',\n query,\n url,\n })\n}\n\ninterface CreateTokenOptions {\n label: string\n projectId: string\n roleNames: string[]\n\n expiresAt?: string\n sendNotification?: boolean\n}\n\n/**\n * Add a token to a project\n * @param options - The options for adding a token to a project\n * @returns A promise that resolves to the created robot, including its secret token\n *\n * @internal\n */\nexport async function createToken(options: CreateTokenOptions): Promise<RobotWithToken> {\n const {expiresAt, label, projectId, roleNames, sendNotification} = options\n\n return postRobot(\n `/access/project/${projectId}/robots`,\n {\n expiresAt,\n label,\n memberships: [{resourceId: projectId, resourceType: 'project', roleNames}],\n },\n sendNotification === false ? {sendNotification: 'false'} : {},\n )\n}\n\ninterface CreateOrganizationTokenOptions extends RobotBody {\n organizationId: string\n}\n\n/**\n * Create an organization token, which can hold organization permissions and roles on several projects\n * @param options - The options for the organization token\n * @returns A promise that resolves to the created robot, including its secret token\n *\n * @internal\n */\nexport async function createOrganizationToken(\n options: CreateOrganizationTokenOptions,\n): Promise<RobotWithToken> {\n const {organizationId, ...body} = options\n\n return postRobot(`/access/organization/${organizationId}/robots`, body)\n}\n\nfunction robotsUrl({resourceId, resourceType}: TokenScope): string {\n return `/access/${resourceType}/${resourceId}/robots`\n}\n\nfunction isManagedByOrganization(robot: Robot, organizationId: string): boolean {\n return (\n robot.managedBy?.resourceType === 'organization' &&\n robot.managedBy.resourceId === organizationId\n )\n}\n\n/** Delete a token from the requested scope. @internal */\nexport async function deleteToken(scope: TokenScope, tokenId: string): Promise<void> {\n const client = await getClient()\n const url = `${robotsUrl(scope)}/${tokenId}`\n\n if (scope.resourceType === 'organization') {\n const robot = await client.request<Robot>({url})\n if (!isManagedByOrganization(robot, scope.resourceId)) {\n throw new Error(\n `Token \"${tokenId}\" is not managed by organization \"${scope.resourceId}\". Use tokens list --organization ${scope.resourceId} to find tokens managed by this organization.`,\n )\n }\n }\n\n return client.request({method: 'DELETE', url})\n}\n\n/**\n * Rotate a robot token, replacing its secret while preserving the robot,\n * its roles, and the token's expiry. The request authenticates as the robot\n * itself; the previous secret is revoked immediately.\n * @param token - The current robot token secret\n * @returns A promise that resolves to the robot with its new secret token\n *\n * @internal\n */\nexport async function rotateToken(token: string): Promise<RobotWithToken> {\n const client = await getClient(token)\n\n return client.request<RobotWithToken>({\n method: 'POST',\n url: '/access/robots/me/rotate',\n })\n}\n\n/** List tokens managed at the requested scope. @internal */\nexport async function getTokens(scope: TokenScope): Promise<Robot[]> {\n const client = await getClient()\n const query: Record<string, string> =\n scope.resourceType === 'organization' ? {includeChildren: 'true', limit: '500'} : {}\n const robots = await fetchAllPages<Robot>(client, robotsUrl(scope), query)\n\n if (scope.resourceType === 'organization') {\n return robots.filter((robot) => isManagedByOrganization(robot, scope.resourceId))\n }\n\n return robots.filter((robot) => robot.managedBy?.resourceType !== 'organization')\n}\n\n/**\n * Get all roles for a project\n * @param projectId - The project ID\n * @returns A promise that resolves to an array of project roles\n *\n * @internal\n */\nexport async function getTokenRoles(projectId: string): Promise<Role[]> {\n const client = await getClient()\n\n return fetchAllPages<Role>(client, `/access/project/${projectId}/roles`)\n}\n"],"names":["getGlobalCliClient","TOKENS_API_VERSION","getClient","token","apiVersion","requireUser","undefined","fetchAllPages","client","url","query","items","cursor","response","request","nextCursor","push","data","getProjectMembership","robot","projectId","memberships","find","membership","resourceType","resourceId","postRobot","expiresAt","body","method","createToken","options","label","roleNames","sendNotification","createOrganizationToken","organizationId","robotsUrl","isManagedByOrganization","managedBy","deleteToken","scope","tokenId","Error","rotateToken","getTokens","includeChildren","limit","robots","filter","getTokenRoles"],"mappings":"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"}