@sanity/cli 8.6.0 → 8.8.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 (103) hide show
  1. package/README.md +918 -40
  2. package/dist/actions/api/distillApiRoutes.js +1 -1
  3. package/dist/actions/api/distillApiRoutes.js.map +1 -1
  4. package/dist/actions/api/resolveEndpoint.js +1 -1
  5. package/dist/actions/api/resolveEndpoint.js.map +1 -1
  6. package/dist/actions/backup/archiveDir.js +7 -3
  7. package/dist/actions/backup/archiveDir.js.map +1 -1
  8. package/dist/actions/context/resolveOrganizationId.js +17 -0
  9. package/dist/actions/context/resolveOrganizationId.js.map +1 -0
  10. package/dist/actions/context/waitForJob.js +24 -0
  11. package/dist/actions/context/waitForJob.js.map +1 -0
  12. package/dist/actions/context/watchJob.js +32 -0
  13. package/dist/actions/context/watchJob.js.map +1 -0
  14. package/dist/actions/deploy/deployApp.js +6 -6
  15. package/dist/actions/deploy/deployApp.js.map +1 -1
  16. package/dist/actions/deploy/deployStudio.js +6 -6
  17. package/dist/actions/deploy/deployStudio.js.map +1 -1
  18. package/dist/actions/exec/execScript.js +6 -18
  19. package/dist/actions/exec/execScript.js.map +1 -1
  20. package/dist/actions/exec/runScript.worker.js +21 -0
  21. package/dist/actions/exec/runScript.worker.js.map +1 -0
  22. package/dist/actions/init/initAction.js +1 -1
  23. package/dist/actions/init/initAction.js.map +1 -1
  24. package/dist/actions/media/importMedia.js +4 -2
  25. package/dist/actions/media/importMedia.js.map +1 -1
  26. package/dist/commands/backups/download.js +8 -17
  27. package/dist/commands/backups/download.js.map +1 -1
  28. package/dist/commands/backups/list.js +1 -1
  29. package/dist/commands/backups/list.js.map +1 -1
  30. package/dist/commands/context/build.js +111 -0
  31. package/dist/commands/context/build.js.map +1 -0
  32. package/dist/commands/context/create.js +106 -0
  33. package/dist/commands/context/create.js.map +1 -0
  34. package/dist/commands/context/delete.js +68 -0
  35. package/dist/commands/context/delete.js.map +1 -0
  36. package/dist/commands/context/get.js +95 -0
  37. package/dist/commands/context/get.js.map +1 -0
  38. package/dist/commands/context/imports/create.js +270 -0
  39. package/dist/commands/context/imports/create.js.map +1 -0
  40. package/dist/commands/context/imports/delete.js +73 -0
  41. package/dist/commands/context/imports/delete.js.map +1 -0
  42. package/dist/commands/context/imports/download.js +65 -0
  43. package/dist/commands/context/imports/download.js.map +1 -0
  44. package/dist/commands/context/imports/get.js +93 -0
  45. package/dist/commands/context/imports/get.js.map +1 -0
  46. package/dist/commands/context/imports/list.js +105 -0
  47. package/dist/commands/context/imports/list.js.map +1 -0
  48. package/dist/commands/context/jobs/get.js +90 -0
  49. package/dist/commands/context/jobs/get.js.map +1 -0
  50. package/dist/commands/context/list.js +109 -0
  51. package/dist/commands/context/list.js.map +1 -0
  52. package/dist/commands/context/refresh.js +46 -0
  53. package/dist/commands/context/refresh.js.map +1 -0
  54. package/dist/commands/context/update.js +127 -0
  55. package/dist/commands/context/update.js.map +1 -0
  56. package/dist/commands/datasets/alias/delete.js +4 -9
  57. package/dist/commands/datasets/alias/delete.js.map +1 -1
  58. package/dist/commands/datasets/alias/unlink.js +4 -9
  59. package/dist/commands/datasets/alias/unlink.js.map +1 -1
  60. package/dist/commands/datasets/copy.js +1 -1
  61. package/dist/commands/datasets/copy.js.map +1 -1
  62. package/dist/commands/datasets/delete.js +4 -9
  63. package/dist/commands/datasets/delete.js.map +1 -1
  64. package/dist/commands/graphql/undeploy.js +4 -9
  65. package/dist/commands/graphql/undeploy.js.map +1 -1
  66. package/dist/commands/init.js +1 -1
  67. package/dist/commands/init.js.map +1 -1
  68. package/dist/commands/media/create-aspect.js +5 -6
  69. package/dist/commands/media/create-aspect.js.map +1 -1
  70. package/dist/commands/media/delete-aspect.js +7 -23
  71. package/dist/commands/media/delete-aspect.js.map +1 -1
  72. package/dist/commands/media/deploy-aspect.js +4 -9
  73. package/dist/commands/media/deploy-aspect.js.map +1 -1
  74. package/dist/commands/media/export.js +3 -7
  75. package/dist/commands/media/export.js.map +1 -1
  76. package/dist/commands/media/import.js +3 -7
  77. package/dist/commands/media/import.js.map +1 -1
  78. package/dist/commands/organizations/create.js +4 -9
  79. package/dist/commands/organizations/create.js.map +1 -1
  80. package/dist/commands/schemas/delete.js +3 -8
  81. package/dist/commands/schemas/delete.js.map +1 -1
  82. package/dist/commands/tokens/delete.js +4 -7
  83. package/dist/commands/tokens/delete.js.map +1 -1
  84. package/dist/commands/users/invite.js +8 -18
  85. package/dist/commands/users/invite.js.map +1 -1
  86. package/dist/exports/index.js +1 -1
  87. package/dist/exports/index.js.map +1 -1
  88. package/dist/exports/invokeSanityCli/commandPolicies/mcpPolicy.js +18 -0
  89. package/dist/exports/invokeSanityCli/commandPolicies/mcpPolicy.js.map +1 -1
  90. package/dist/generated/apiRoutes.js +11 -9
  91. package/dist/generated/apiRoutes.js.map +1 -1
  92. package/dist/prompts/promptForOrganization.js +19 -0
  93. package/dist/prompts/promptForOrganization.js.map +1 -0
  94. package/dist/services/context.js +132 -0
  95. package/dist/services/context.js.map +1 -0
  96. package/dist/util/extractDocumentsFromNdjsonOrTarball.js.map +1 -1
  97. package/dist/util/sharedFlags.js +24 -0
  98. package/dist/util/sharedFlags.js.map +1 -1
  99. package/oclif.config.js +1 -0
  100. package/oclif.manifest.json +1931 -1133
  101. package/package.json +20 -26
  102. package/dist/util/dates.js +0 -125
  103. package/dist/util/dates.js.map +0 -1
@@ -88,7 +88,7 @@ import { API_VERSION_SEGMENT_RE } from './constants.js';
88
88
  const [pathPart = ''] = path.split('?');
89
89
  const segments = pathPart.split('/').filter((segment)=>segment !== '');
90
90
  let version;
91
- if (segments[0] === '{apiVersion}') {
91
+ if (segments[0] === '{apiVersion}' || segments[0] === '{apiV}') {
92
92
  segments.shift();
93
93
  } else if (segments.length > 0 && API_VERSION_SEGMENT_RE.test(segments[0])) {
94
94
  version = segments.shift();
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/actions/api/distillApiRoutes.ts"],"sourcesContent":["import {API_VERSION_SEGMENT_RE} from './constants.js'\nimport {type ApiHost, type ApiRouteEntry, type OpenApiDocument} from './types.js'\n\n/**\n * A fetched OpenAPI specification, ready for distillation.\n */\nexport interface SpecSource {\n document: OpenApiDocument\n slug: string\n title: string\n}\n\ninterface ServerBase {\n host: ApiHost\n segments: string[]\n\n defaultApiVersion?: string\n}\n\n/**\n * Distill fetched OpenAPI specifications into the routing manifest used by\n * `sanity api` to decide which host serves a request path and which API\n * version to default to.\n *\n * The output is deterministic (sorted) so the generated manifest can be\n * compared against a fresh distillation to detect drift.\n */\nexport function distillApiRoutes(specs: SpecSource[]): ApiRouteEntry[] {\n const entries: ApiRouteEntry[] = []\n\n for (const {document, slug, title} of specs) {\n const servers = document.servers ?? []\n const paths = Object.keys(document.paths ?? {})\n if (servers.length === 0 || paths.length === 0) continue\n\n // A spec may be served on both hosts (eg the Applications API). Emit one\n // entry per host, each carrying the full set of path patterns.\n const byHost = new Map<ApiHost, ServerBase>()\n for (const server of servers) {\n const base = parseServerUrl(server.url, server.variables)\n if (!base) continue\n if (!byHost.has(base.host)) byHost.set(base.host, base)\n }\n\n for (const base of byHost.values()) {\n const patterns = new Set<string>()\n let defaultApiVersion = base.defaultApiVersion\n\n for (const path of paths) {\n const {segments, version} = normalizePathSegments(path)\n defaultApiVersion = defaultApiVersion ?? version\n const pattern = [...base.segments, ...segments].join('/')\n if (pattern !== '') patterns.add(pattern)\n }\n\n if (patterns.size === 0) continue\n\n entries.push({\n ...(defaultApiVersion === undefined ? {} : {defaultApiVersion}),\n host: base.host,\n pathPatterns: [...patterns].toSorted(),\n slug,\n title,\n })\n }\n }\n\n return entries.toSorted((a, b) => a.slug.localeCompare(b.slug) || a.host.localeCompare(b.host))\n}\n\n/**\n * Parse an OpenAPI server URL template (eg\n * `https://{projectId}.api.sanity.io/{apiVersion}/agent/action`) into a host\n * classification, base path segments and a default API version.\n *\n * Returns `undefined` for URLs that don't look like a Sanity API host.\n */\nfunction parseServerUrl(\n url: string,\n variables?: Record<string, {default?: string}>,\n): ServerBase | undefined {\n const withoutScheme = url.replace(/^https?:\\/\\//, '')\n const [hostname = '', ...pathSegments] = withoutScheme.split('/')\n\n if (!hostname.includes('api.sanity.io') && !hostname.includes('api.sanity.work')) {\n return undefined\n }\n\n const host: ApiHost = hostname.includes('{projectId}') ? 'project' : 'global'\n\n let defaultApiVersion = normalizeVersion(variables?.apiVersion?.default)\n const segments: string[] = []\n for (const segment of pathSegments) {\n if (segment === '') continue\n if (segment === '{apiVersion}') continue\n if (API_VERSION_SEGMENT_RE.test(segment)) {\n defaultApiVersion = defaultApiVersion ?? segment\n continue\n }\n segments.push(segment)\n }\n\n return {defaultApiVersion, host, segments}\n}\n\n/**\n * Normalize an OpenAPI path template into version-less path segments, plus the\n * API version if one was embedded in the path (eg `/v2024-07-01/access/...`).\n *\n * Some specs carry a stray query marker in the path key (eg `/foo/{id}?`) -\n * anything from `?` on is not part of the path and is dropped.\n */\nfunction normalizePathSegments(path: string): {segments: string[]; version?: string} {\n const [pathPart = ''] = path.split('?')\n const segments = pathPart.split('/').filter((segment) => segment !== '')\n let version: string | undefined\n\n if (segments[0] === '{apiVersion}') {\n segments.shift()\n } else if (segments.length > 0 && API_VERSION_SEGMENT_RE.test(segments[0])) {\n version = segments.shift()\n }\n\n return {segments, version}\n}\n\nfunction normalizeVersion(version: string | undefined): string | undefined {\n if (!version) return undefined\n return API_VERSION_SEGMENT_RE.test(version) ? version : undefined\n}\n"],"names":["API_VERSION_SEGMENT_RE","distillApiRoutes","specs","entries","document","slug","title","servers","paths","Object","keys","length","byHost","Map","server","base","parseServerUrl","url","variables","has","host","set","values","patterns","Set","defaultApiVersion","path","segments","version","normalizePathSegments","pattern","join","add","size","push","undefined","pathPatterns","toSorted","a","b","localeCompare","withoutScheme","replace","hostname","pathSegments","split","includes","normalizeVersion","apiVersion","default","segment","test","pathPart","filter","shift"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../src/actions/api/distillApiRoutes.ts"],"sourcesContent":["import {API_VERSION_SEGMENT_RE} from './constants.js'\nimport {type ApiHost, type ApiRouteEntry, type OpenApiDocument} from './types.js'\n\n/**\n * A fetched OpenAPI specification, ready for distillation.\n */\nexport interface SpecSource {\n document: OpenApiDocument\n slug: string\n title: string\n}\n\ninterface ServerBase {\n host: ApiHost\n segments: string[]\n\n defaultApiVersion?: string\n}\n\n/**\n * Distill fetched OpenAPI specifications into the routing manifest used by\n * `sanity api` to decide which host serves a request path and which API\n * version to default to.\n *\n * The output is deterministic (sorted) so the generated manifest can be\n * compared against a fresh distillation to detect drift.\n */\nexport function distillApiRoutes(specs: SpecSource[]): ApiRouteEntry[] {\n const entries: ApiRouteEntry[] = []\n\n for (const {document, slug, title} of specs) {\n const servers = document.servers ?? []\n const paths = Object.keys(document.paths ?? {})\n if (servers.length === 0 || paths.length === 0) continue\n\n // A spec may be served on both hosts (eg the Applications API). Emit one\n // entry per host, each carrying the full set of path patterns.\n const byHost = new Map<ApiHost, ServerBase>()\n for (const server of servers) {\n const base = parseServerUrl(server.url, server.variables)\n if (!base) continue\n if (!byHost.has(base.host)) byHost.set(base.host, base)\n }\n\n for (const base of byHost.values()) {\n const patterns = new Set<string>()\n let defaultApiVersion = base.defaultApiVersion\n\n for (const path of paths) {\n const {segments, version} = normalizePathSegments(path)\n defaultApiVersion = defaultApiVersion ?? version\n const pattern = [...base.segments, ...segments].join('/')\n if (pattern !== '') patterns.add(pattern)\n }\n\n if (patterns.size === 0) continue\n\n entries.push({\n ...(defaultApiVersion === undefined ? {} : {defaultApiVersion}),\n host: base.host,\n pathPatterns: [...patterns].toSorted(),\n slug,\n title,\n })\n }\n }\n\n return entries.toSorted((a, b) => a.slug.localeCompare(b.slug) || a.host.localeCompare(b.host))\n}\n\n/**\n * Parse an OpenAPI server URL template (eg\n * `https://{projectId}.api.sanity.io/{apiVersion}/agent/action`) into a host\n * classification, base path segments and a default API version.\n *\n * Returns `undefined` for URLs that don't look like a Sanity API host.\n */\nfunction parseServerUrl(\n url: string,\n variables?: Record<string, {default?: string}>,\n): ServerBase | undefined {\n const withoutScheme = url.replace(/^https?:\\/\\//, '')\n const [hostname = '', ...pathSegments] = withoutScheme.split('/')\n\n if (!hostname.includes('api.sanity.io') && !hostname.includes('api.sanity.work')) {\n return undefined\n }\n\n const host: ApiHost = hostname.includes('{projectId}') ? 'project' : 'global'\n\n let defaultApiVersion = normalizeVersion(variables?.apiVersion?.default)\n const segments: string[] = []\n for (const segment of pathSegments) {\n if (segment === '') continue\n if (segment === '{apiVersion}') continue\n if (API_VERSION_SEGMENT_RE.test(segment)) {\n defaultApiVersion = defaultApiVersion ?? segment\n continue\n }\n segments.push(segment)\n }\n\n return {defaultApiVersion, host, segments}\n}\n\n/**\n * Normalize an OpenAPI path template into version-less path segments, plus the\n * API version if one was embedded in the path (eg `/v2024-07-01/access/...`).\n *\n * Some specs carry a stray query marker in the path key (eg `/foo/{id}?`) -\n * anything from `?` on is not part of the path and is dropped.\n */\nfunction normalizePathSegments(path: string): {segments: string[]; version?: string} {\n const [pathPart = ''] = path.split('?')\n const segments = pathPart.split('/').filter((segment) => segment !== '')\n let version: string | undefined\n\n if (segments[0] === '{apiVersion}' || segments[0] === '{apiV}') {\n segments.shift()\n } else if (segments.length > 0 && API_VERSION_SEGMENT_RE.test(segments[0])) {\n version = segments.shift()\n }\n\n return {segments, version}\n}\n\nfunction normalizeVersion(version: string | undefined): string | undefined {\n if (!version) return undefined\n return API_VERSION_SEGMENT_RE.test(version) ? version : undefined\n}\n"],"names":["API_VERSION_SEGMENT_RE","distillApiRoutes","specs","entries","document","slug","title","servers","paths","Object","keys","length","byHost","Map","server","base","parseServerUrl","url","variables","has","host","set","values","patterns","Set","defaultApiVersion","path","segments","version","normalizePathSegments","pattern","join","add","size","push","undefined","pathPatterns","toSorted","a","b","localeCompare","withoutScheme","replace","hostname","pathSegments","split","includes","normalizeVersion","apiVersion","default","segment","test","pathPart","filter","shift"],"mappings":"AAAA,SAAQA,sBAAsB,QAAO,iBAAgB;AAmBrD;;;;;;;CAOC,GACD,OAAO,SAASC,iBAAiBC,KAAmB;IAClD,MAAMC,UAA2B,EAAE;IAEnC,KAAK,MAAM,EAACC,QAAQ,EAAEC,IAAI,EAAEC,KAAK,EAAC,IAAIJ,MAAO;QAC3C,MAAMK,UAAUH,SAASG,OAAO,IAAI,EAAE;QACtC,MAAMC,QAAQC,OAAOC,IAAI,CAACN,SAASI,KAAK,IAAI,CAAC;QAC7C,IAAID,QAAQI,MAAM,KAAK,KAAKH,MAAMG,MAAM,KAAK,GAAG;QAEhD,yEAAyE;QACzE,+DAA+D;QAC/D,MAAMC,SAAS,IAAIC;QACnB,KAAK,MAAMC,UAAUP,QAAS;YAC5B,MAAMQ,OAAOC,eAAeF,OAAOG,GAAG,EAAEH,OAAOI,SAAS;YACxD,IAAI,CAACH,MAAM;YACX,IAAI,CAACH,OAAOO,GAAG,CAACJ,KAAKK,IAAI,GAAGR,OAAOS,GAAG,CAACN,KAAKK,IAAI,EAAEL;QACpD;QAEA,KAAK,MAAMA,QAAQH,OAAOU,MAAM,GAAI;YAClC,MAAMC,WAAW,IAAIC;YACrB,IAAIC,oBAAoBV,KAAKU,iBAAiB;YAE9C,KAAK,MAAMC,QAAQlB,MAAO;gBACxB,MAAM,EAACmB,QAAQ,EAAEC,OAAO,EAAC,GAAGC,sBAAsBH;gBAClDD,oBAAoBA,qBAAqBG;gBACzC,MAAME,UAAU;uBAAIf,KAAKY,QAAQ;uBAAKA;iBAAS,CAACI,IAAI,CAAC;gBACrD,IAAID,YAAY,IAAIP,SAASS,GAAG,CAACF;YACnC;YAEA,IAAIP,SAASU,IAAI,KAAK,GAAG;YAEzB9B,QAAQ+B,IAAI,CAAC;gBACX,GAAIT,sBAAsBU,YAAY,CAAC,IAAI;oBAACV;gBAAiB,CAAC;gBAC9DL,MAAML,KAAKK,IAAI;gBACfgB,cAAc;uBAAIb;iBAAS,CAACc,QAAQ;gBACpChC;gBACAC;YACF;QACF;IACF;IAEA,OAAOH,QAAQkC,QAAQ,CAAC,CAACC,GAAGC,IAAMD,EAAEjC,IAAI,CAACmC,aAAa,CAACD,EAAElC,IAAI,KAAKiC,EAAElB,IAAI,CAACoB,aAAa,CAACD,EAAEnB,IAAI;AAC/F;AAEA;;;;;;CAMC,GACD,SAASJ,eACPC,GAAW,EACXC,SAA8C;IAE9C,MAAMuB,gBAAgBxB,IAAIyB,OAAO,CAAC,gBAAgB;IAClD,MAAM,CAACC,WAAW,EAAE,EAAE,GAAGC,aAAa,GAAGH,cAAcI,KAAK,CAAC;IAE7D,IAAI,CAACF,SAASG,QAAQ,CAAC,oBAAoB,CAACH,SAASG,QAAQ,CAAC,oBAAoB;QAChF,OAAOX;IACT;IAEA,MAAMf,OAAgBuB,SAASG,QAAQ,CAAC,iBAAiB,YAAY;IAErE,IAAIrB,oBAAoBsB,iBAAiB7B,WAAW8B,YAAYC;IAChE,MAAMtB,WAAqB,EAAE;IAC7B,KAAK,MAAMuB,WAAWN,aAAc;QAClC,IAAIM,YAAY,IAAI;QACpB,IAAIA,YAAY,gBAAgB;QAChC,IAAIlD,uBAAuBmD,IAAI,CAACD,UAAU;YACxCzB,oBAAoBA,qBAAqByB;YACzC;QACF;QACAvB,SAASO,IAAI,CAACgB;IAChB;IAEA,OAAO;QAACzB;QAAmBL;QAAMO;IAAQ;AAC3C;AAEA;;;;;;CAMC,GACD,SAASE,sBAAsBH,IAAY;IACzC,MAAM,CAAC0B,WAAW,EAAE,CAAC,GAAG1B,KAAKmB,KAAK,CAAC;IACnC,MAAMlB,WAAWyB,SAASP,KAAK,CAAC,KAAKQ,MAAM,CAAC,CAACH,UAAYA,YAAY;IACrE,IAAItB;IAEJ,IAAID,QAAQ,CAAC,EAAE,KAAK,kBAAkBA,QAAQ,CAAC,EAAE,KAAK,UAAU;QAC9DA,SAAS2B,KAAK;IAChB,OAAO,IAAI3B,SAAShB,MAAM,GAAG,KAAKX,uBAAuBmD,IAAI,CAACxB,QAAQ,CAAC,EAAE,GAAG;QAC1EC,UAAUD,SAAS2B,KAAK;IAC1B;IAEA,OAAO;QAAC3B;QAAUC;IAAO;AAC3B;AAEA,SAASmB,iBAAiBnB,OAA2B;IACnD,IAAI,CAACA,SAAS,OAAOO;IACrB,OAAOnC,uBAAuBmD,IAAI,CAACvB,WAAWA,UAAUO;AAC1D"}
@@ -23,7 +23,7 @@ const ALLOWED_URL_HOST_RE = /(?:^|\.)api\.sanity\.(?:io|work)$/;
23
23
  // An API version embedded in the path (eg `v2021-06-07/projects`) is peeled
24
24
  // off and re-applied as the version segment of the final URL.
25
25
  let embeddedVersion;
26
- if (segments[0] === '{apiVersion}') {
26
+ if (segments[0] === '{apiVersion}' || segments[0] === '{apiV}') {
27
27
  segments.shift();
28
28
  } else if (segments.length > 0 && API_VERSION_SEGMENT_RE.test(segments[0])) {
29
29
  embeddedVersion = segments.shift();
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/actions/api/resolveEndpoint.ts"],"sourcesContent":["import {parse} from 'node:querystring'\n\nimport {API_DEFAULT_VERSION, API_VERSION_SEGMENT_RE} from './constants.js'\nimport {ApiUsageError, ProjectIdRequiredError} from './errors.js'\nimport {type ApiHost, type ApiRouteEntry} from './types.js'\n\n/**\n * Options for {@link resolveEndpoint}.\n */\nexport interface ResolveEndpointOptions {\n /** The endpoint argument: a path, optionally with placeholders, or a full URL. */\n endpoint: string\n\n /** The generated routing manifest. */\n routes: ApiRouteEntry[]\n\n /** Explicit API version (`--api-version`), wins over everything else. */\n apiVersion?: string\n\n /** Dataset used to fill `{dataset}` / `{datasetName}` placeholders. */\n dataset?: string\n\n /** Force a host family (`--global` / `--project-hosted`), restricting route matching to it. */\n forceHost?: ApiHost\n\n /** Project ID used to fill `{projectId}` placeholders and project-hosted requests. */\n projectId?: string\n}\n\n/**\n * A fully resolved request target.\n */\nexport type ResolvedEndpoint =\n | {\n /** API version path segment, eg `v2021-06-07`. */\n apiVersion: string\n host: ApiHost\n kind: 'path'\n /** Slug of the OpenAPI spec whose paths matched, if any. */\n matchedSlug?: string\n /** Version-less path, without leading slash. */\n path: string\n /** Project ID; always set when `host` is `project`. */\n projectId?: string\n /** Query parameters parsed from the endpoint argument. */\n query: Record<string, string | string[]>\n }\n | {\n kind: 'url'\n query: Record<string, string | string[]>\n /** Absolute URL, used verbatim (query string stripped into `query`). */\n url: string\n }\n\nconst PLACEHOLDER_RE = /^\\{([^{}]+)\\}$/\n\nconst ALLOWED_URL_HOST_RE = /(?:^|\\.)api\\.sanity\\.(?:io|work)$/\n\n/**\n * Resolve the endpoint argument of `sanity api` into a concrete request\n * target: substitute placeholders, split off the query string, determine the\n * host family (via the generated OpenAPI routing manifest) and the API\n * version.\n *\n * Throws {@link ProjectIdRequiredError} when the request needs a project ID\n * that hasn't been provided - the command catches this to resolve one (flags,\n * CLI config or interactive prompt) and retries.\n */\nexport function resolveEndpoint(options: ResolveEndpointOptions): ResolvedEndpoint {\n const {apiVersion, dataset, endpoint, forceHost, projectId, routes} = options\n\n if (/^https?:\\/\\//.test(endpoint)) {\n return resolveUrlEndpoint(endpoint)\n }\n\n const [pathPart = '', ...queryParts] = endpoint.split('?')\n const query = parseQueryString(queryParts.join('?'))\n\n const segments = pathPart.split('/').filter((segment) => segment !== '')\n\n // An API version embedded in the path (eg `v2021-06-07/projects`) is peeled\n // off and re-applied as the version segment of the final URL.\n let embeddedVersion: string | undefined\n if (segments[0] === '{apiVersion}') {\n segments.shift()\n } else if (segments.length > 0 && API_VERSION_SEGMENT_RE.test(segments[0])) {\n embeddedVersion = segments.shift()\n }\n\n // Checked after version peeling so a bare version (eg `v2025-02-19`) is\n // also rejected as an empty path.\n if (segments.length === 0) {\n throw new ApiUsageError('Endpoint path is empty')\n }\n\n const unresolved: string[] = []\n const substituted = segments.map((segment, index) => {\n const placeholder = PLACEHOLDER_RE.exec(segment)?.[1]\n if (!placeholder) return segment\n if (placeholder === 'projectId') {\n if (!projectId) throw new ProjectIdRequiredError()\n return projectId\n }\n // The projects spec names the dataset placeholder `{name}` (eg\n // `projects/{projectId}/datasets/{name}`) - only that context is a\n // dataset; `{name}` elsewhere (eg video renditions) stays unresolved.\n const isDatasetName = placeholder === 'name' && segments[index - 1] === 'datasets'\n if (placeholder === 'dataset' || placeholder === 'datasetName' || isDatasetName) {\n if (!dataset) {\n throw new ApiUsageError(\n `Unable to resolve {${placeholder}} - provide a dataset with --dataset or configure one in sanity.cli.ts`,\n )\n }\n return dataset\n }\n unresolved.push(segment)\n return segment\n })\n\n if (unresolved.length > 0) {\n throw new ApiUsageError(\n `Unable to resolve placeholder(s) ${unresolved.join(', ')} - replace them with actual values`,\n )\n }\n\n // Forcing a host restricts matching to specs served on that host, so the\n // matched spec's default API version still applies when one exists there.\n const candidates = forceHost ? routes.filter((entry) => entry.host === forceHost) : routes\n const match = matchRoutes(substituted, candidates)\n const host = forceHost ?? match?.host ?? 'global'\n\n if (host === 'project' && !projectId) {\n throw new ProjectIdRequiredError()\n }\n\n return {\n apiVersion: apiVersion ?? embeddedVersion ?? match?.defaultApiVersion ?? API_DEFAULT_VERSION,\n host,\n kind: 'path',\n matchedSlug: match?.slug,\n path: substituted.join('/'),\n ...(host === 'project' ? {projectId} : {}),\n query,\n }\n}\n\nfunction resolveUrlEndpoint(endpoint: string): ResolvedEndpoint {\n let url: URL\n try {\n url = new URL(endpoint)\n } catch {\n throw new ApiUsageError(`Invalid URL \"${endpoint}\"`)\n }\n\n // Never put the token on the wire unencrypted\n if (url.protocol !== 'https:') {\n throw new ApiUsageError(\n `Refusing to send requests over \"${url.protocol}//\" - only https:// URLs are supported`,\n )\n }\n\n if (!ALLOWED_URL_HOST_RE.test(url.hostname)) {\n throw new ApiUsageError(\n `Refusing to send authenticated requests to \"${url.hostname}\" - only *.api.sanity.io hosts are supported`,\n )\n }\n\n const query = parseQueryString(url.search.replace(/^\\?/, ''))\n url.search = ''\n\n return {kind: 'url', query, url: url.toString()}\n}\n\ninterface RouteMatch {\n host: ApiHost\n score: number\n slug: string\n\n defaultApiVersion?: string\n}\n\n/**\n * Find the route entry whose path pattern best matches the request segments.\n *\n * A pattern only matches when the request path consumes it completely, and\n * segments are compared pairwise: literal matches score higher than\n * placeholder matches, and a literal mismatch disqualifies the pattern. On\n * equal scores across hosts the global host wins (APIs served on both hosts\n * don't need a project ID there); on equal scores within the same host the\n * first entry wins, keeping the result independent of later entries.\n */\nfunction matchRoutes(segments: string[], routes: ApiRouteEntry[]): RouteMatch | undefined {\n let best: RouteMatch | undefined\n\n for (const entry of routes) {\n for (const pattern of entry.pathPatterns) {\n const score = scorePattern(segments, pattern.split('/'))\n if (score === 0) continue\n const isBetter =\n !best ||\n score > best.score ||\n (score === best.score && best.host === 'project' && entry.host === 'global')\n if (isBetter) {\n best = {\n defaultApiVersion: entry.defaultApiVersion,\n host: entry.host,\n score,\n slug: entry.slug,\n }\n }\n }\n }\n\n return best\n}\n\nfunction scorePattern(segments: string[], patternSegments: string[]): number {\n // A pattern only matches when the request path consumes it completely - a\n // request that is a mere prefix of a longer pattern (eg `data` vs\n // `data/query/{dataset}`) must not inherit that route's host or version.\n if (patternSegments.length > segments.length) return 0\n\n let score = 0\n let literalMatches = 0\n\n for (const [index, patternSegment] of patternSegments.entries()) {\n if (PLACEHOLDER_RE.test(patternSegment)) {\n score += 1\n } else if (patternSegment === segments[index]) {\n score += 2\n literalMatches += 1\n } else {\n return 0\n }\n }\n\n // Require at least one literal segment match so a placeholder-only pattern\n // like `{resourceType}/{resourceId}` can't capture arbitrary paths.\n return literalMatches === 0 ? 0 : score\n}\n\nfunction parseQueryString(queryString: string): Record<string, string | string[]> {\n // node:querystring collects repeated keys into arrays and returns a\n // null-prototype object, so user-supplied keys like `__proto__` stay\n // ordinary own properties. Parsed values are never `undefined`, hence the\n // narrowing cast.\n return parse(queryString) as Record<string, string | string[]>\n}\n"],"names":["parse","API_DEFAULT_VERSION","API_VERSION_SEGMENT_RE","ApiUsageError","ProjectIdRequiredError","PLACEHOLDER_RE","ALLOWED_URL_HOST_RE","resolveEndpoint","options","apiVersion","dataset","endpoint","forceHost","projectId","routes","test","resolveUrlEndpoint","pathPart","queryParts","split","query","parseQueryString","join","segments","filter","segment","embeddedVersion","shift","length","unresolved","substituted","map","index","placeholder","exec","isDatasetName","push","candidates","entry","host","match","matchRoutes","defaultApiVersion","kind","matchedSlug","slug","path","url","URL","protocol","hostname","search","replace","toString","best","pattern","pathPatterns","score","scorePattern","isBetter","patternSegments","literalMatches","patternSegment","entries","queryString"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../src/actions/api/resolveEndpoint.ts"],"sourcesContent":["import {parse} from 'node:querystring'\n\nimport {API_DEFAULT_VERSION, API_VERSION_SEGMENT_RE} from './constants.js'\nimport {ApiUsageError, ProjectIdRequiredError} from './errors.js'\nimport {type ApiHost, type ApiRouteEntry} from './types.js'\n\n/**\n * Options for {@link resolveEndpoint}.\n */\nexport interface ResolveEndpointOptions {\n /** The endpoint argument: a path, optionally with placeholders, or a full URL. */\n endpoint: string\n\n /** The generated routing manifest. */\n routes: ApiRouteEntry[]\n\n /** Explicit API version (`--api-version`), wins over everything else. */\n apiVersion?: string\n\n /** Dataset used to fill `{dataset}` / `{datasetName}` placeholders. */\n dataset?: string\n\n /** Force a host family (`--global` / `--project-hosted`), restricting route matching to it. */\n forceHost?: ApiHost\n\n /** Project ID used to fill `{projectId}` placeholders and project-hosted requests. */\n projectId?: string\n}\n\n/**\n * A fully resolved request target.\n */\nexport type ResolvedEndpoint =\n | {\n /** API version path segment, eg `v2021-06-07`. */\n apiVersion: string\n host: ApiHost\n kind: 'path'\n /** Slug of the OpenAPI spec whose paths matched, if any. */\n matchedSlug?: string\n /** Version-less path, without leading slash. */\n path: string\n /** Project ID; always set when `host` is `project`. */\n projectId?: string\n /** Query parameters parsed from the endpoint argument. */\n query: Record<string, string | string[]>\n }\n | {\n kind: 'url'\n query: Record<string, string | string[]>\n /** Absolute URL, used verbatim (query string stripped into `query`). */\n url: string\n }\n\nconst PLACEHOLDER_RE = /^\\{([^{}]+)\\}$/\n\nconst ALLOWED_URL_HOST_RE = /(?:^|\\.)api\\.sanity\\.(?:io|work)$/\n\n/**\n * Resolve the endpoint argument of `sanity api` into a concrete request\n * target: substitute placeholders, split off the query string, determine the\n * host family (via the generated OpenAPI routing manifest) and the API\n * version.\n *\n * Throws {@link ProjectIdRequiredError} when the request needs a project ID\n * that hasn't been provided - the command catches this to resolve one (flags,\n * CLI config or interactive prompt) and retries.\n */\nexport function resolveEndpoint(options: ResolveEndpointOptions): ResolvedEndpoint {\n const {apiVersion, dataset, endpoint, forceHost, projectId, routes} = options\n\n if (/^https?:\\/\\//.test(endpoint)) {\n return resolveUrlEndpoint(endpoint)\n }\n\n const [pathPart = '', ...queryParts] = endpoint.split('?')\n const query = parseQueryString(queryParts.join('?'))\n\n const segments = pathPart.split('/').filter((segment) => segment !== '')\n\n // An API version embedded in the path (eg `v2021-06-07/projects`) is peeled\n // off and re-applied as the version segment of the final URL.\n let embeddedVersion: string | undefined\n if (segments[0] === '{apiVersion}' || segments[0] === '{apiV}') {\n segments.shift()\n } else if (segments.length > 0 && API_VERSION_SEGMENT_RE.test(segments[0])) {\n embeddedVersion = segments.shift()\n }\n\n // Checked after version peeling so a bare version (eg `v2025-02-19`) is\n // also rejected as an empty path.\n if (segments.length === 0) {\n throw new ApiUsageError('Endpoint path is empty')\n }\n\n const unresolved: string[] = []\n const substituted = segments.map((segment, index) => {\n const placeholder = PLACEHOLDER_RE.exec(segment)?.[1]\n if (!placeholder) return segment\n if (placeholder === 'projectId') {\n if (!projectId) throw new ProjectIdRequiredError()\n return projectId\n }\n // The projects spec names the dataset placeholder `{name}` (eg\n // `projects/{projectId}/datasets/{name}`) - only that context is a\n // dataset; `{name}` elsewhere (eg video renditions) stays unresolved.\n const isDatasetName = placeholder === 'name' && segments[index - 1] === 'datasets'\n if (placeholder === 'dataset' || placeholder === 'datasetName' || isDatasetName) {\n if (!dataset) {\n throw new ApiUsageError(\n `Unable to resolve {${placeholder}} - provide a dataset with --dataset or configure one in sanity.cli.ts`,\n )\n }\n return dataset\n }\n unresolved.push(segment)\n return segment\n })\n\n if (unresolved.length > 0) {\n throw new ApiUsageError(\n `Unable to resolve placeholder(s) ${unresolved.join(', ')} - replace them with actual values`,\n )\n }\n\n // Forcing a host restricts matching to specs served on that host, so the\n // matched spec's default API version still applies when one exists there.\n const candidates = forceHost ? routes.filter((entry) => entry.host === forceHost) : routes\n const match = matchRoutes(substituted, candidates)\n const host = forceHost ?? match?.host ?? 'global'\n\n if (host === 'project' && !projectId) {\n throw new ProjectIdRequiredError()\n }\n\n return {\n apiVersion: apiVersion ?? embeddedVersion ?? match?.defaultApiVersion ?? API_DEFAULT_VERSION,\n host,\n kind: 'path',\n matchedSlug: match?.slug,\n path: substituted.join('/'),\n ...(host === 'project' ? {projectId} : {}),\n query,\n }\n}\n\nfunction resolveUrlEndpoint(endpoint: string): ResolvedEndpoint {\n let url: URL\n try {\n url = new URL(endpoint)\n } catch {\n throw new ApiUsageError(`Invalid URL \"${endpoint}\"`)\n }\n\n // Never put the token on the wire unencrypted\n if (url.protocol !== 'https:') {\n throw new ApiUsageError(\n `Refusing to send requests over \"${url.protocol}//\" - only https:// URLs are supported`,\n )\n }\n\n if (!ALLOWED_URL_HOST_RE.test(url.hostname)) {\n throw new ApiUsageError(\n `Refusing to send authenticated requests to \"${url.hostname}\" - only *.api.sanity.io hosts are supported`,\n )\n }\n\n const query = parseQueryString(url.search.replace(/^\\?/, ''))\n url.search = ''\n\n return {kind: 'url', query, url: url.toString()}\n}\n\ninterface RouteMatch {\n host: ApiHost\n score: number\n slug: string\n\n defaultApiVersion?: string\n}\n\n/**\n * Find the route entry whose path pattern best matches the request segments.\n *\n * A pattern only matches when the request path consumes it completely, and\n * segments are compared pairwise: literal matches score higher than\n * placeholder matches, and a literal mismatch disqualifies the pattern. On\n * equal scores across hosts the global host wins (APIs served on both hosts\n * don't need a project ID there); on equal scores within the same host the\n * first entry wins, keeping the result independent of later entries.\n */\nfunction matchRoutes(segments: string[], routes: ApiRouteEntry[]): RouteMatch | undefined {\n let best: RouteMatch | undefined\n\n for (const entry of routes) {\n for (const pattern of entry.pathPatterns) {\n const score = scorePattern(segments, pattern.split('/'))\n if (score === 0) continue\n const isBetter =\n !best ||\n score > best.score ||\n (score === best.score && best.host === 'project' && entry.host === 'global')\n if (isBetter) {\n best = {\n defaultApiVersion: entry.defaultApiVersion,\n host: entry.host,\n score,\n slug: entry.slug,\n }\n }\n }\n }\n\n return best\n}\n\nfunction scorePattern(segments: string[], patternSegments: string[]): number {\n // A pattern only matches when the request path consumes it completely - a\n // request that is a mere prefix of a longer pattern (eg `data` vs\n // `data/query/{dataset}`) must not inherit that route's host or version.\n if (patternSegments.length > segments.length) return 0\n\n let score = 0\n let literalMatches = 0\n\n for (const [index, patternSegment] of patternSegments.entries()) {\n if (PLACEHOLDER_RE.test(patternSegment)) {\n score += 1\n } else if (patternSegment === segments[index]) {\n score += 2\n literalMatches += 1\n } else {\n return 0\n }\n }\n\n // Require at least one literal segment match so a placeholder-only pattern\n // like `{resourceType}/{resourceId}` can't capture arbitrary paths.\n return literalMatches === 0 ? 0 : score\n}\n\nfunction parseQueryString(queryString: string): Record<string, string | string[]> {\n // node:querystring collects repeated keys into arrays and returns a\n // null-prototype object, so user-supplied keys like `__proto__` stay\n // ordinary own properties. Parsed values are never `undefined`, hence the\n // narrowing cast.\n return parse(queryString) as Record<string, string | string[]>\n}\n"],"names":["parse","API_DEFAULT_VERSION","API_VERSION_SEGMENT_RE","ApiUsageError","ProjectIdRequiredError","PLACEHOLDER_RE","ALLOWED_URL_HOST_RE","resolveEndpoint","options","apiVersion","dataset","endpoint","forceHost","projectId","routes","test","resolveUrlEndpoint","pathPart","queryParts","split","query","parseQueryString","join","segments","filter","segment","embeddedVersion","shift","length","unresolved","substituted","map","index","placeholder","exec","isDatasetName","push","candidates","entry","host","match","matchRoutes","defaultApiVersion","kind","matchedSlug","slug","path","url","URL","protocol","hostname","search","replace","toString","best","pattern","pathPatterns","score","scorePattern","isBetter","patternSegments","literalMatches","patternSegment","entries","queryString"],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  import { createWriteStream } from 'node:fs';
2
2
  import { createGzip } from 'node:zlib';
3
- import { pack } from 'tar-fs';
3
+ import { c as createTar } from 'tar';
4
4
  import { backupDownloadDebug } from './backupDownloadDebug.js';
5
5
  /**
6
6
  * Creates a compressed tarball of the given directory and writes it to the specified file path
@@ -25,9 +25,13 @@ import { backupDownloadDebug } from './backupDownloadDebug.js';
25
25
  backupDownloadDebug('Gzip stream error: %s', err.message);
26
26
  reject(err);
27
27
  });
28
- const tarStream = pack(tmpOutDir);
28
+ const tarStream = createTar({
29
+ cwd: tmpOutDir
30
+ }, [
31
+ '.'
32
+ ]);
29
33
  tarStream.on('error', (err)=>{
30
- backupDownloadDebug('Tar stream error: %s', err.message);
34
+ backupDownloadDebug('Tar stream error: %s', err instanceof Error ? err.message : String(err));
31
35
  reject(err);
32
36
  });
33
37
  // Track progress by listening to data events
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/actions/backup/archiveDir.ts"],"sourcesContent":["import {createWriteStream} from 'node:fs'\nimport {createGzip} from 'node:zlib'\n\nimport {pack} from 'tar-fs'\n\nimport {backupDownloadDebug} from './backupDownloadDebug.js'\n\n// ProgressCb is a callback that is called with the number of bytes processed so far.\ntype ProgressCb = (processedBytes: number) => void\n\n/**\n * Creates a compressed tarball of the given directory and writes it to the specified file path\n *\n * @param tmpOutDir - The directory to archive\n * @param outFilePath - The output file path for the compressed tarball\n * @param progressCb - Callback function called with the number of bytes processed\n */\nexport function archiveDir(\n tmpOutDir: string,\n outFilePath: string,\n progressCb: ProgressCb,\n): Promise<void> {\n return new Promise((resolve, reject) => {\n const archiveDestination = createWriteStream(outFilePath)\n const gzipStream = createGzip()\n let processedBytes = 0\n\n archiveDestination.on('error', (err: Error) => {\n backupDownloadDebug('Archive destination error: %s', err.message)\n reject(err)\n })\n\n archiveDestination.on('close', () => {\n backupDownloadDebug('Archive completed successfully')\n resolve()\n })\n\n gzipStream.on('error', (err: Error) => {\n backupDownloadDebug('Gzip stream error: %s', err.message)\n reject(err)\n })\n\n const tarStream = pack(tmpOutDir)\n\n tarStream.on('error', (err: Error) => {\n backupDownloadDebug('Tar stream error: %s', err.message)\n reject(err)\n })\n\n // Track progress by listening to data events\n tarStream.on('data', (chunk: Buffer) => {\n processedBytes += chunk.length\n progressCb(processedBytes)\n })\n\n // Pipe tar -> gzip -> file\n tarStream.pipe(gzipStream).pipe(archiveDestination)\n })\n}\n"],"names":["createWriteStream","createGzip","pack","backupDownloadDebug","archiveDir","tmpOutDir","outFilePath","progressCb","Promise","resolve","reject","archiveDestination","gzipStream","processedBytes","on","err","message","tarStream","chunk","length","pipe"],"mappings":"AAAA,SAAQA,iBAAiB,QAAO,UAAS;AACzC,SAAQC,UAAU,QAAO,YAAW;AAEpC,SAAQC,IAAI,QAAO,SAAQ;AAE3B,SAAQC,mBAAmB,QAAO,2BAA0B;AAK5D;;;;;;CAMC,GACD,OAAO,SAASC,WACdC,SAAiB,EACjBC,WAAmB,EACnBC,UAAsB;IAEtB,OAAO,IAAIC,QAAQ,CAACC,SAASC;QAC3B,MAAMC,qBAAqBX,kBAAkBM;QAC7C,MAAMM,aAAaX;QACnB,IAAIY,iBAAiB;QAErBF,mBAAmBG,EAAE,CAAC,SAAS,CAACC;YAC9BZ,oBAAoB,iCAAiCY,IAAIC,OAAO;YAChEN,OAAOK;QACT;QAEAJ,mBAAmBG,EAAE,CAAC,SAAS;YAC7BX,oBAAoB;YACpBM;QACF;QAEAG,WAAWE,EAAE,CAAC,SAAS,CAACC;YACtBZ,oBAAoB,yBAAyBY,IAAIC,OAAO;YACxDN,OAAOK;QACT;QAEA,MAAME,YAAYf,KAAKG;QAEvBY,UAAUH,EAAE,CAAC,SAAS,CAACC;YACrBZ,oBAAoB,wBAAwBY,IAAIC,OAAO;YACvDN,OAAOK;QACT;QAEA,6CAA6C;QAC7CE,UAAUH,EAAE,CAAC,QAAQ,CAACI;YACpBL,kBAAkBK,MAAMC,MAAM;YAC9BZ,WAAWM;QACb;QAEA,2BAA2B;QAC3BI,UAAUG,IAAI,CAACR,YAAYQ,IAAI,CAACT;IAClC;AACF"}
1
+ {"version":3,"sources":["../../../src/actions/backup/archiveDir.ts"],"sourcesContent":["import {createWriteStream} from 'node:fs'\nimport {createGzip} from 'node:zlib'\n\nimport {c as createTar} from 'tar'\n\nimport {backupDownloadDebug} from './backupDownloadDebug.js'\n\n// ProgressCb is a callback that is called with the number of bytes processed so far.\ntype ProgressCb = (processedBytes: number) => void\n\n/**\n * Creates a compressed tarball of the given directory and writes it to the specified file path\n *\n * @param tmpOutDir - The directory to archive\n * @param outFilePath - The output file path for the compressed tarball\n * @param progressCb - Callback function called with the number of bytes processed\n */\nexport function archiveDir(\n tmpOutDir: string,\n outFilePath: string,\n progressCb: ProgressCb,\n): Promise<void> {\n return new Promise((resolve, reject) => {\n const archiveDestination = createWriteStream(outFilePath)\n const gzipStream = createGzip()\n let processedBytes = 0\n\n archiveDestination.on('error', (err: Error) => {\n backupDownloadDebug('Archive destination error: %s', err.message)\n reject(err)\n })\n\n archiveDestination.on('close', () => {\n backupDownloadDebug('Archive completed successfully')\n resolve()\n })\n\n gzipStream.on('error', (err: Error) => {\n backupDownloadDebug('Gzip stream error: %s', err.message)\n reject(err)\n })\n\n const tarStream = createTar({cwd: tmpOutDir}, ['.'])\n\n tarStream.on('error', (err) => {\n backupDownloadDebug('Tar stream error: %s', err instanceof Error ? err.message : String(err))\n reject(err)\n })\n\n // Track progress by listening to data events\n tarStream.on('data', (chunk: Buffer) => {\n processedBytes += chunk.length\n progressCb(processedBytes)\n })\n\n // Pipe tar -> gzip -> file\n tarStream.pipe(gzipStream).pipe(archiveDestination)\n })\n}\n"],"names":["createWriteStream","createGzip","c","createTar","backupDownloadDebug","archiveDir","tmpOutDir","outFilePath","progressCb","Promise","resolve","reject","archiveDestination","gzipStream","processedBytes","on","err","message","tarStream","cwd","Error","String","chunk","length","pipe"],"mappings":"AAAA,SAAQA,iBAAiB,QAAO,UAAS;AACzC,SAAQC,UAAU,QAAO,YAAW;AAEpC,SAAQC,KAAKC,SAAS,QAAO,MAAK;AAElC,SAAQC,mBAAmB,QAAO,2BAA0B;AAK5D;;;;;;CAMC,GACD,OAAO,SAASC,WACdC,SAAiB,EACjBC,WAAmB,EACnBC,UAAsB;IAEtB,OAAO,IAAIC,QAAQ,CAACC,SAASC;QAC3B,MAAMC,qBAAqBZ,kBAAkBO;QAC7C,MAAMM,aAAaZ;QACnB,IAAIa,iBAAiB;QAErBF,mBAAmBG,EAAE,CAAC,SAAS,CAACC;YAC9BZ,oBAAoB,iCAAiCY,IAAIC,OAAO;YAChEN,OAAOK;QACT;QAEAJ,mBAAmBG,EAAE,CAAC,SAAS;YAC7BX,oBAAoB;YACpBM;QACF;QAEAG,WAAWE,EAAE,CAAC,SAAS,CAACC;YACtBZ,oBAAoB,yBAAyBY,IAAIC,OAAO;YACxDN,OAAOK;QACT;QAEA,MAAME,YAAYf,UAAU;YAACgB,KAAKb;QAAS,GAAG;YAAC;SAAI;QAEnDY,UAAUH,EAAE,CAAC,SAAS,CAACC;YACrBZ,oBAAoB,wBAAwBY,eAAeI,QAAQJ,IAAIC,OAAO,GAAGI,OAAOL;YACxFL,OAAOK;QACT;QAEA,6CAA6C;QAC7CE,UAAUH,EAAE,CAAC,QAAQ,CAACO;YACpBR,kBAAkBQ,MAAMC,MAAM;YAC9Bf,WAAWM;QACb;QAEA,2BAA2B;QAC3BI,UAAUM,IAAI,CAACX,YAAYW,IAAI,CAACZ;IAClC;AACF"}
@@ -0,0 +1,17 @@
1
+ import { promptForOrganization } from '../../prompts/promptForOrganization.js';
2
+ /** The organization could not be determined and prompting is not possible. */ export class MissingOrganizationError extends Error {
3
+ }
4
+ /**
5
+ * Resolve the organization to operate on: the `--organization` flag wins,
6
+ * then the CLI config's `app.organizationId`, then an interactive prompt.
7
+ */ export async function resolveOrganizationId(options) {
8
+ const { configuredOrganizationId, flagOrganizationId, unattended } = options;
9
+ if (flagOrganizationId) return flagOrganizationId;
10
+ if (configuredOrganizationId) return configuredOrganizationId;
11
+ if (unattended) {
12
+ throw new MissingOrganizationError('Organization ID is required. Provide it with the --organization flag.');
13
+ }
14
+ return promptForOrganization();
15
+ }
16
+
17
+ //# sourceMappingURL=resolveOrganizationId.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/actions/context/resolveOrganizationId.ts"],"sourcesContent":["import {promptForOrganization} from '../../prompts/promptForOrganization.js'\n\n/** The organization could not be determined and prompting is not possible. */\nexport class MissingOrganizationError extends Error {}\n\n/**\n * Resolve the organization to operate on: the `--organization` flag wins,\n * then the CLI config's `app.organizationId`, then an interactive prompt.\n */\nexport async function resolveOrganizationId(options: {\n configuredOrganizationId: string | undefined\n flagOrganizationId: string | undefined\n unattended: boolean\n}): Promise<string> {\n const {configuredOrganizationId, flagOrganizationId, unattended} = options\n\n if (flagOrganizationId) return flagOrganizationId\n if (configuredOrganizationId) return configuredOrganizationId\n\n if (unattended) {\n throw new MissingOrganizationError(\n 'Organization ID is required. Provide it with the --organization flag.',\n )\n }\n\n return promptForOrganization()\n}\n"],"names":["promptForOrganization","MissingOrganizationError","Error","resolveOrganizationId","options","configuredOrganizationId","flagOrganizationId","unattended"],"mappings":"AAAA,SAAQA,qBAAqB,QAAO,yCAAwC;AAE5E,4EAA4E,GAC5E,OAAO,MAAMC,iCAAiCC;AAAO;AAErD;;;CAGC,GACD,OAAO,eAAeC,sBAAsBC,OAI3C;IACC,MAAM,EAACC,wBAAwB,EAAEC,kBAAkB,EAAEC,UAAU,EAAC,GAAGH;IAEnE,IAAIE,oBAAoB,OAAOA;IAC/B,IAAID,0BAA0B,OAAOA;IAErC,IAAIE,YAAY;QACd,MAAM,IAAIN,yBACR;IAEJ;IAEA,OAAOD;AACT"}
@@ -0,0 +1,24 @@
1
+ import { setTimeout as sleep } from 'node:timers/promises';
2
+ import { getJob } from '../../services/context.js';
3
+ const JOB_POLL_INTERVAL_MS = 5000;
4
+ const TERMINAL_JOB_STATUSES = new Set([
5
+ 'cancelled',
6
+ 'failed',
7
+ 'succeeded'
8
+ ]);
9
+ /**
10
+ * Poll a knowledge base job until it reaches a terminal state
11
+ * (succeeded, failed or cancelled), resolving with the final job.
12
+ */ export async function waitForJob(knowledgeBaseId, jobId, options) {
13
+ const pollIntervalMs = options?.pollIntervalMs ?? JOB_POLL_INTERVAL_MS;
14
+ while(true){
15
+ const job = await getJob(knowledgeBaseId, jobId);
16
+ if (TERMINAL_JOB_STATUSES.has(job.status)) {
17
+ return job;
18
+ }
19
+ options?.onPoll?.(job);
20
+ await sleep(pollIntervalMs);
21
+ }
22
+ }
23
+
24
+ //# sourceMappingURL=waitForJob.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/actions/context/waitForJob.ts"],"sourcesContent":["import {setTimeout as sleep} from 'node:timers/promises'\n\nimport {type Context} from '@sanity/client'\n\nimport {getJob} from '../../services/context.js'\n\nconst JOB_POLL_INTERVAL_MS = 5000\n\nconst TERMINAL_JOB_STATUSES: ReadonlySet<Context.Job['status']> = new Set([\n 'cancelled',\n 'failed',\n 'succeeded',\n])\n\n/**\n * Poll a knowledge base job until it reaches a terminal state\n * (succeeded, failed or cancelled), resolving with the final job.\n */\nexport async function waitForJob(\n knowledgeBaseId: string,\n jobId: string,\n options?: {\n onPoll?: (job: Context.Job) => void\n pollIntervalMs?: number\n },\n): Promise<Context.Job> {\n const pollIntervalMs = options?.pollIntervalMs ?? JOB_POLL_INTERVAL_MS\n\n while (true) {\n const job = await getJob(knowledgeBaseId, jobId)\n if (TERMINAL_JOB_STATUSES.has(job.status)) {\n return job\n }\n options?.onPoll?.(job)\n await sleep(pollIntervalMs)\n }\n}\n"],"names":["setTimeout","sleep","getJob","JOB_POLL_INTERVAL_MS","TERMINAL_JOB_STATUSES","Set","waitForJob","knowledgeBaseId","jobId","options","pollIntervalMs","job","has","status","onPoll"],"mappings":"AAAA,SAAQA,cAAcC,KAAK,QAAO,uBAAsB;AAIxD,SAAQC,MAAM,QAAO,4BAA2B;AAEhD,MAAMC,uBAAuB;AAE7B,MAAMC,wBAA4D,IAAIC,IAAI;IACxE;IACA;IACA;CACD;AAED;;;CAGC,GACD,OAAO,eAAeC,WACpBC,eAAuB,EACvBC,KAAa,EACbC,OAGC;IAED,MAAMC,iBAAiBD,SAASC,kBAAkBP;IAElD,MAAO,KAAM;QACX,MAAMQ,MAAM,MAAMT,OAAOK,iBAAiBC;QAC1C,IAAIJ,sBAAsBQ,GAAG,CAACD,IAAIE,MAAM,GAAG;YACzC,OAAOF;QACT;QACAF,SAASK,SAASH;QAClB,MAAMV,MAAMS;IACd;AACF"}
@@ -0,0 +1,32 @@
1
+ import { spinner } from '@sanity/cli-core/ux';
2
+ import { waitForJob } from './waitForJob.js';
3
+ /**
4
+ * Watch a knowledge base job with a spinner until it reaches a terminal
5
+ * state, updating the spinner text with the job status on each poll.
6
+ *
7
+ * Fails the spinner and rethrows on polling errors, and fails it when the
8
+ * terminal status is not `succeeded` — turning either outcome into a
9
+ * command error (and exit code) is the caller's responsibility.
10
+ */ export async function watchJob(knowledgeBaseId, jobId, options) {
11
+ const { label, successText } = options;
12
+ const spin = spinner(label).start();
13
+ let job;
14
+ try {
15
+ job = await waitForJob(knowledgeBaseId, jobId, {
16
+ onPoll: (pending)=>{
17
+ spin.text = `${label} (${pending.status})`;
18
+ }
19
+ });
20
+ } catch (error) {
21
+ spin.fail();
22
+ throw error;
23
+ }
24
+ if (job.status === 'succeeded') {
25
+ spin.succeed(successText);
26
+ } else {
27
+ spin.fail();
28
+ }
29
+ return job;
30
+ }
31
+
32
+ //# sourceMappingURL=watchJob.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/actions/context/watchJob.ts"],"sourcesContent":["import {spinner} from '@sanity/cli-core/ux'\nimport {type Context} from '@sanity/client'\n\nimport {waitForJob} from './waitForJob.js'\n\n/**\n * Watch a knowledge base job with a spinner until it reaches a terminal\n * state, updating the spinner text with the job status on each poll.\n *\n * Fails the spinner and rethrows on polling errors, and fails it when the\n * terminal status is not `succeeded` — turning either outcome into a\n * command error (and exit code) is the caller's responsibility.\n */\nexport async function watchJob(\n knowledgeBaseId: string,\n jobId: string,\n options: {label: string; successText?: string},\n): Promise<Context.Job> {\n const {label, successText} = options\n const spin = spinner(label).start()\n\n let job: Context.Job\n try {\n job = await waitForJob(knowledgeBaseId, jobId, {\n onPoll: (pending) => {\n spin.text = `${label} (${pending.status})`\n },\n })\n } catch (error) {\n spin.fail()\n throw error\n }\n\n if (job.status === 'succeeded') {\n spin.succeed(successText)\n } else {\n spin.fail()\n }\n\n return job\n}\n"],"names":["spinner","waitForJob","watchJob","knowledgeBaseId","jobId","options","label","successText","spin","start","job","onPoll","pending","text","status","error","fail","succeed"],"mappings":"AAAA,SAAQA,OAAO,QAAO,sBAAqB;AAG3C,SAAQC,UAAU,QAAO,kBAAiB;AAE1C;;;;;;;CAOC,GACD,OAAO,eAAeC,SACpBC,eAAuB,EACvBC,KAAa,EACbC,OAA8C;IAE9C,MAAM,EAACC,KAAK,EAAEC,WAAW,EAAC,GAAGF;IAC7B,MAAMG,OAAOR,QAAQM,OAAOG,KAAK;IAEjC,IAAIC;IACJ,IAAI;QACFA,MAAM,MAAMT,WAAWE,iBAAiBC,OAAO;YAC7CO,QAAQ,CAACC;gBACPJ,KAAKK,IAAI,GAAG,GAAGP,MAAM,EAAE,EAAEM,QAAQE,MAAM,CAAC,CAAC,CAAC;YAC5C;QACF;IACF,EAAE,OAAOC,OAAO;QACdP,KAAKQ,IAAI;QACT,MAAMD;IACR;IAEA,IAAIL,IAAII,MAAM,KAAK,aAAa;QAC9BN,KAAKS,OAAO,CAACV;IACf,OAAO;QACLC,KAAKQ,IAAI;IACX;IAEA,OAAON;AACT"}
@@ -7,7 +7,7 @@ import { getErrorMessage } from '@sanity/cli-core/errors';
7
7
  import { getCoreAppUrl } from '@sanity/cli-core/util';
8
8
  import { spinner } from '@sanity/cli-core/ux';
9
9
  import { createCoreApp, deployConfig, deployWorkbenchApp, getApplicationUrl, getWorkbench, resolveInstallationId, resolveWorkbenchConfig, summarizeConfig, toWorkbenchPayload } from '@sanity/workbench-cli/deploy';
10
- import { pack } from 'tar-fs';
10
+ import { c as createTar } from 'tar';
11
11
  import { createDeployment, updateUserApplication } from '../../services/userApplications.js';
12
12
  import { getAppId } from '../../util/appId.js';
13
13
  import { EXTERNAL_APP_NOT_SUPPORTED, NO_ORGANIZATION_ID } from '../../util/errorMessages.js';
@@ -418,11 +418,11 @@ export function deployApp(options) {
418
418
  }
419
419
  }
420
420
  async function shipAppDeployment({ application, isAutoUpdating, manifest, sourceDir, version }) {
421
- const tarball = pack(dirname(sourceDir), {
422
- entries: [
423
- basename(sourceDir)
424
- ]
425
- }).pipe(createGzip());
421
+ const tarball = createTar({
422
+ cwd: dirname(sourceDir)
423
+ }, [
424
+ basename(sourceDir)
425
+ ]).pipe(createGzip());
426
426
  const spin = spinner('Deploying...').start();
427
427
  try {
428
428
  await createDeployment({
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/actions/deploy/deployApp.ts"],"sourcesContent":["import {basename, dirname} from 'node:path'\nimport {styleText} from 'node:util'\nimport {createGzip} from 'node:zlib'\n\nimport {\n type CoreAppManifest,\n extractCoreAppManifest,\n readIconFromPath,\n resolveTitleUpdate,\n} from '@sanity/cli-build/_internal/manifest'\nimport {type AppVisibility, exitCodes} from '@sanity/cli-core'\nimport {getErrorMessage} from '@sanity/cli-core/errors'\nimport {getCoreAppUrl} from '@sanity/cli-core/util'\nimport {spinner} from '@sanity/cli-core/ux'\nimport {\n createCoreApp,\n deployConfig,\n deployWorkbenchApp,\n getApplicationUrl,\n getWorkbench,\n resolveInstallationId,\n resolveWorkbenchConfig,\n summarizeConfig,\n toWorkbenchPayload,\n} from '@sanity/workbench-cli/deploy'\nimport {pack} from 'tar-fs'\n\nimport {\n createDeployment,\n updateUserApplication,\n type UserApplication,\n type UserApplicationResolved,\n} from '../../services/userApplications.js'\nimport {getAppId} from '../../util/appId.js'\nimport {EXTERNAL_APP_NOT_SUPPORTED, NO_ORGANIZATION_ID} from '../../util/errorMessages.js'\nimport {buildApp} from '../build/buildApp.js'\nimport {createUserApplication} from './createUserApplication.js'\nimport {\n checkAppId,\n checkAppTarget,\n checkAutoUpdates,\n checkBuild,\n checkPackageVersion,\n type DeployCheckReporter,\n verifyOutputDir,\n} from './deployChecks.js'\nimport {deployDebug} from './deployDebug.js'\nimport {listDeploymentFiles, reportInterfaces} from './deploymentPlan.js'\nimport {type DeployPayload, type DeployResult, runDeploy} from './deployRunner.js'\nimport {findUserApplication} from './findUserApplication.js'\nimport {type DeployAppOptions} from './types.js'\n\nconst APP_PACKAGE = '@sanity/sdk-react'\n\nexport function deployApp(options: DeployAppOptions): Promise<void> {\n return runDeploy(options, {\n listFiles: ({projectRoot, sourceDir}) => listDeploymentFiles(sourceDir, projectRoot.directory),\n run: runAppDeployment,\n type: 'coreApp',\n })\n}\n\n/** Validates the deploy, syncs the title from the manifest, and ships the build. */\nasync function runAppDeployment(\n options: DeployAppOptions,\n reporter: DeployCheckReporter,\n): Promise<DeployResult | void> {\n const {cliConfig, flags, output, sourceDir} = options\n const workDir = options.projectRoot.directory\n const organizationId = cliConfig.app?.organizationId\n const appId = getAppId(cliConfig)\n const workbench = getWorkbench(cliConfig)\n // A config (the Media Library) is not an app — it resolves through its own\n // brand and persists to the org's installation instead of hosting an application.\n const config = resolveWorkbenchConfig(cliConfig)\n const dryRun = !!flags['dry-run']\n\n const deployConfigOnly = !!config\n const deployApplication = !config && (!workbench || workbench.hasInterfaces)\n\n const appTitle = workbench\n ? flags.title?.trim() || cliConfig.app?.title?.trim() || workbench.slug\n : ''\n\n // A federated app with no entry, view or service would ship a remote with\n // nothing to load — reported first so it fails before any prompt or API call.\n if (workbench) {\n try {\n workbench.assertDeployable()\n } catch (err) {\n reporter.report({\n exitCode: exitCodes.USAGE_ERROR,\n message: getErrorMessage(err),\n solution: 'Declare at least one entry, view, or service in the app',\n status: 'fail',\n })\n }\n }\n\n // A config with no fields would overwrite the org's live config with an empty\n // snapshot, so block it here — same \"nothing to deploy\" gate an app gets.\n if (config && config.fields.length === 0) {\n reporter.report({\n exitCode: exitCodes.USAGE_ERROR,\n message: 'Nothing to deploy: the media library config declares no fields.',\n solution: 'Add at least one field to the media library config',\n status: 'fail',\n })\n }\n\n const isAutoUpdating = checkAutoUpdates(reporter, {cliConfig, flags})\n\n // An application ships the SDK runtime; a media-library config stamps its\n // `sanity` version instead.\n let version: string | null = null\n if (deployApplication) {\n version = await checkPackageVersion(reporter, {moduleName: APP_PACKAGE, workDir})\n } else if (deployConfigOnly) {\n version = await checkPackageVersion(reporter, {moduleName: 'sanity', workDir})\n }\n\n reporter.report(\n organizationId\n ? {message: `Organization: ${organizationId}`, status: 'pass'}\n : {\n message: NO_ORGANIZATION_ID,\n solution: 'Add `app.organizationId` to sanity.cli.ts',\n status: 'fail',\n },\n )\n\n checkAppId(reporter, {cliConfig})\n\n let application: UserApplicationResolved | null = null\n let appCreated = false\n let workbenchApp: object | undefined\n if (flags.external) {\n reporter.report({\n message: EXTERNAL_APP_NOT_SUPPORTED,\n solution: 'Remove the --external flag — apps deploy to Sanity hosting',\n status: 'fail',\n })\n } else if (deployApplication && workbench) {\n workbenchApp = (\n await checkAppTarget(reporter, {\n appId,\n isWorkbenchApp: true,\n organizationId,\n slug: workbench.slug,\n title: appTitle,\n })\n )?.application\n } else if (deployApplication) {\n ;({application, created: appCreated} = await resolveAppApplication(options, {dryRun, reporter}))\n }\n\n // A first deploy mints the app id and the build inlines it; --no-build would\n // ship an existing bundle carrying a different id, so it can't be a first deploy.\n if (deployApplication && workbench && !appId && !flags.external && !flags.build) {\n reporter.report({\n exitCode: exitCodes.USAGE_ERROR,\n message: 'A first deploy cannot skip the build (--no-build)',\n solution: 'Drop --no-build so the new application id is inlined into the build',\n status: 'fail',\n })\n }\n\n // Read up front so a bad icon path fails before we create or build.\n const appIcon =\n !dryRun && workbench?.icon ? await readIconFromPath(workDir, workbench.icon) : undefined\n\n // Create the app before the build so the bundle carries its real id. A\n // redeploy already has it from `deployment.appId`; a dry run skips creation.\n let applicationId = appId\n let applicationCreated = false\n let rollbackApp: (() => Promise<void>) | undefined\n if (!dryRun && deployApplication && workbench && organizationId && !applicationId) {\n const created = await createCoreApp({\n isSingleton: workbench.isSingleton,\n name: workbench.name,\n organizationId,\n slug: workbench.slug,\n title: appTitle,\n visibility: workbench.visibility,\n })\n workbenchApp = created.application\n applicationId = created.application.id\n rollbackApp = created.rollback\n applicationCreated = true\n }\n\n // A record created above is stranded at its slug (and blocks retries) if any\n // step before it fully deploys fails, so undo the creation on failure.\n try {\n await checkBuild(reporter, {\n build: () =>\n buildApp({\n applicationId: workbench ? applicationId : undefined,\n autoUpdatesEnabled: isAutoUpdating,\n calledFromDeploy: true,\n cliConfig,\n flags,\n outDir: sourceDir,\n output,\n workDir,\n }),\n skipReason: flags.build\n ? undefined\n : 'Build skipped (--no-build) — validating existing output directory',\n successMessage: 'App built',\n })\n\n await verifyOutputDir({\n isWorkbenchApp: workbench !== null || config !== null,\n reporter,\n sourceDir,\n })\n\n // Workbench apps and configs ship a federation remote and don't read the\n // core-app manifest; only plain core-apps do. Manifests aren't strictly\n // essential, so a failure warns and continues.\n let manifest: CoreAppManifest | undefined\n if (!workbench && !config) {\n try {\n manifest = await extractCoreAppManifest({workDir})\n } catch (err) {\n deployDebug('Error extracting app manifest', err)\n reporter.report({\n message: `Error extracting app manifest: ${getErrorMessage(err)}`,\n status: 'warn',\n })\n }\n }\n\n // Resolve the installation in both modes so the report — dry-run and real —\n // shows whether the config is deployable; a missing one fails the deploy here.\n let installationId: string | undefined\n let configSummary: string | undefined\n const configAppType = config?.appType\n if (deployConfigOnly && organizationId && config && configAppType) {\n installationId = await resolveInstallationId({appType: configAppType, organizationId})\n configSummary = summarizeConfig(config)\n reporter.report(\n installationId\n ? {message: configSummary, status: 'pass'}\n : {\n exitCode: exitCodes.USAGE_ERROR,\n message: `No active \"${configAppType}\" installation for organization \"${organizationId}\"`,\n solution:\n 'Install the Media Library for the organization before deploying its config',\n status: 'fail',\n },\n )\n }\n\n const interfaces = deployApplication && workbench ? reportInterfaces(reporter, workbench) : null\n\n // Applied after the app is live (see below) so a failed deploy never leaves\n // the org's installation config without its application.\n const deployApplicationConfig = async (): Promise<void> => {\n if (installationId && version && configAppType && organizationId) {\n await deployConfig({\n appType: configAppType,\n installationId,\n organizationId,\n output,\n sourceDir,\n version,\n })\n }\n }\n\n const payload: DeployPayload = {\n appId: appId ?? null,\n isAutoUpdating,\n ...(organizationId ? {organizationId} : {}),\n type: 'coreApp',\n version,\n ...toWorkbenchPayload(workbench, {config: configSummary, interfaces, title: appTitle}),\n ...(configSummary ? {config: configSummary} : {}),\n }\n\n // Dry run stops here — everything below mutates.\n if (dryRun) return {application: null, payload}\n\n // A config-only singleton ships no application, only its config.\n if (!deployApplication) {\n await deployApplicationConfig()\n if (installationId && version) {\n return {application: null, installationId, payload}\n }\n return\n }\n\n // A real deploy already exited on a version-resolution failure; this narrows the type.\n if (!version) return\n\n // The app was created (or resolved from `deployment.appId`) before the build,\n // so this only ships the deployment; plain coreApps use user-applications below.\n if (workbench && organizationId && applicationId) {\n await deployWorkbenchApp({\n app: cliConfig.app,\n applicationId,\n icon: appIcon,\n isApp: true,\n isAutoUpdating,\n // Once the deployment is live, a metadata-sync or later config failure\n // must not delete the app.\n onDeployed: () => {\n rollbackApp = undefined\n },\n sourceDir,\n title: appTitle,\n version,\n visibility: workbench.visibility,\n })\n await deployApplicationConfig()\n const url = getApplicationUrl({id: applicationId, organizationId, type: 'coreApp'})\n logAppDeployed({\n applicationId,\n cliConfig,\n created: applicationCreated,\n organizationId,\n output,\n title: appTitle,\n url,\n })\n return {\n action: applicationCreated ? 'create' : 'update',\n application: workbenchApp ?? null,\n payload,\n url,\n }\n }\n\n // A real deploy has already exited if anything failed; landing here without a\n // resolved application means the deploy target was never resolved.\n if (!application) return\n\n application = await syncApplicationMetadata({\n application,\n manifest,\n output,\n visibility: cliConfig.app?.visibility,\n })\n await shipAppDeployment({application, isAutoUpdating, manifest, sourceDir, version})\n logAppDeployed({\n applicationId: application.id,\n cliConfig,\n created: appCreated,\n organizationId: application.organizationId,\n output,\n title: application.title,\n })\n return {\n action: appCreated ? 'create' : 'update',\n application,\n payload,\n url: getCoreAppUrl(application.organizationId, application.id),\n }\n } catch (err) {\n await rollbackApp?.()\n throw err\n }\n}\n\n/**\n * Finds the application a real deploy targets, creating one when none is\n * configured. A dry run resolves and reports the target read-only instead.\n */\nasync function resolveAppApplication(\n options: DeployAppOptions,\n {dryRun, reporter}: {dryRun: boolean; reporter: DeployCheckReporter},\n): Promise<{application: UserApplicationResolved | null; created: boolean}> {\n const {cliConfig, flags, output} = options\n const organizationId = cliConfig.app?.organizationId ?? ''\n // Create name from --title or `app.title` config; blank falls back to the prompt\n const title = flags.title?.trim() || cliConfig.app?.title?.trim() || undefined\n\n if (dryRun) {\n await checkAppTarget(reporter, {appId: getAppId(cliConfig), organizationId, title})\n return {application: null, created: false}\n }\n\n let application = await findUserApplication({\n cliConfig,\n organizationId,\n output,\n title,\n unattended: !!flags.yes,\n })\n deployDebug('User application found', application)\n\n if (!application) {\n deployDebug('No user application found. Creating a new one')\n application = await createUserApplication(organizationId, title, cliConfig.app?.visibility)\n deployDebug('User application created', application)\n return {application, created: true}\n }\n\n return {application, created: false}\n}\n\n/**\n * Syncs application metadata on redeploy when it has changed: the title from the\n * manifest and the dashboard visibility from config. Sends a single PATCH with\n * only the changed fields, and skips the request entirely when nothing changed.\n */\nexport async function syncApplicationMetadata({\n application,\n manifest,\n output,\n visibility,\n}: {\n application: UserApplicationResolved\n manifest: CoreAppManifest | undefined\n output: DeployAppOptions['output']\n visibility: AppVisibility | undefined\n}): Promise<UserApplicationResolved> {\n const titleUpdate = resolveTitleUpdate(manifest, application)\n // Treat an unset server value as `default` so a config of `default` is a no-op.\n const visibilityChanged =\n visibility !== undefined && visibility !== (application.dashboardStatus ?? 'default')\n\n if (!titleUpdate && !visibilityChanged) return application\n\n if (titleUpdate) {\n deployDebug('Updating application title from manifest', titleUpdate)\n output.log(\n titleUpdate.from\n ? `Updating title from \"${titleUpdate.from}\" to \"${titleUpdate.to}\"`\n : `Setting application title to \"${titleUpdate.to}\"`,\n )\n }\n if (visibilityChanged) {\n output.log(`Setting dashboard visibility to \"${visibility}\"`)\n }\n\n const spin = spinner('Updating application').start()\n try {\n const updated = await updateUserApplication({\n applicationId: application.id,\n appType: 'coreApp',\n body: {\n ...(titleUpdate ? {title: titleUpdate.to} : {}),\n ...(visibilityChanged ? {dashboardStatus: visibility} : {}),\n },\n })\n spin.succeed()\n return updated\n } catch (err) {\n spin.fail()\n const message = getErrorMessage(err)\n deployDebug('Error updating application metadata', {message})\n output.warn(`Error updating application metadata: ${message}`)\n return application\n }\n}\n\nasync function shipAppDeployment({\n application,\n isAutoUpdating,\n manifest,\n sourceDir,\n version,\n}: {\n application: UserApplication\n isAutoUpdating: boolean\n manifest: CoreAppManifest | undefined\n sourceDir: string\n version: string\n}): Promise<void> {\n const tarball = pack(dirname(sourceDir), {entries: [basename(sourceDir)]}).pipe(createGzip())\n\n const spin = spinner('Deploying...').start()\n try {\n await createDeployment({\n applicationId: application.id,\n isApp: true,\n isAutoUpdating,\n manifest,\n tarball,\n version,\n })\n } catch (error) {\n spin.clear()\n throw error\n }\n spin.succeed()\n}\n\nexport function logAppDeployed({\n applicationId,\n cliConfig,\n created,\n organizationId,\n output,\n title,\n url = getCoreAppUrl(organizationId, applicationId),\n}: {\n applicationId: string\n cliConfig: DeployAppOptions['cliConfig']\n created: boolean\n organizationId: string\n output: DeployAppOptions['output']\n title: string | null\n url?: string\n}): void {\n const named = title ? ` — \"${title}\"` : ''\n output.log(`\\nSuccess! Application deployed to ${styleText('cyan', url)}${named}`)\n output.log(created ? 'Created a new application.' : 'Updated the existing application.')\n\n if (getAppId(cliConfig)) return\n\n output.log(`\\n════ ${styleText('bold', 'Next step:')} ════`)\n if (created) {\n output.log(\n styleText(\n 'yellow',\n '\\nDeploying again without `deployment.appId` creates another new application.',\n ),\n )\n }\n output.log(\n styleText('bold', '\\nAdd the deployment.appId to your sanity.cli.js or sanity.cli.ts file:'),\n )\n output.log(`\n${styleText(\n 'dim',\n `app: {\n // your application config here…\n}`,\n)},\n${styleText(\n ['bold', 'green'],\n `deployment: {\n appId: '${applicationId}',\n}\\n`,\n)}`)\n}\n"],"names":["basename","dirname","styleText","createGzip","extractCoreAppManifest","readIconFromPath","resolveTitleUpdate","exitCodes","getErrorMessage","getCoreAppUrl","spinner","createCoreApp","deployConfig","deployWorkbenchApp","getApplicationUrl","getWorkbench","resolveInstallationId","resolveWorkbenchConfig","summarizeConfig","toWorkbenchPayload","pack","createDeployment","updateUserApplication","getAppId","EXTERNAL_APP_NOT_SUPPORTED","NO_ORGANIZATION_ID","buildApp","createUserApplication","checkAppId","checkAppTarget","checkAutoUpdates","checkBuild","checkPackageVersion","verifyOutputDir","deployDebug","listDeploymentFiles","reportInterfaces","runDeploy","findUserApplication","APP_PACKAGE","deployApp","options","listFiles","projectRoot","sourceDir","directory","run","runAppDeployment","type","reporter","cliConfig","flags","output","workDir","organizationId","app","appId","workbench","config","dryRun","deployConfigOnly","deployApplication","hasInterfaces","appTitle","title","trim","slug","assertDeployable","err","report","exitCode","USAGE_ERROR","message","solution","status","fields","length","isAutoUpdating","version","moduleName","application","appCreated","workbenchApp","external","isWorkbenchApp","created","resolveAppApplication","build","appIcon","icon","undefined","applicationId","applicationCreated","rollbackApp","isSingleton","name","visibility","id","rollback","autoUpdatesEnabled","calledFromDeploy","outDir","skipReason","successMessage","manifest","installationId","configSummary","configAppType","appType","interfaces","deployApplicationConfig","payload","isApp","onDeployed","url","logAppDeployed","action","syncApplicationMetadata","shipAppDeployment","unattended","yes","titleUpdate","visibilityChanged","dashboardStatus","log","from","to","spin","start","updated","body","succeed","fail","warn","tarball","entries","pipe","error","clear","named"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../src/actions/deploy/deployApp.ts"],"sourcesContent":["import {basename, dirname} from 'node:path'\nimport {styleText} from 'node:util'\nimport {createGzip} from 'node:zlib'\n\nimport {\n type CoreAppManifest,\n extractCoreAppManifest,\n readIconFromPath,\n resolveTitleUpdate,\n} from '@sanity/cli-build/_internal/manifest'\nimport {type AppVisibility, exitCodes} from '@sanity/cli-core'\nimport {getErrorMessage} from '@sanity/cli-core/errors'\nimport {getCoreAppUrl} from '@sanity/cli-core/util'\nimport {spinner} from '@sanity/cli-core/ux'\nimport {\n createCoreApp,\n deployConfig,\n deployWorkbenchApp,\n getApplicationUrl,\n getWorkbench,\n resolveInstallationId,\n resolveWorkbenchConfig,\n summarizeConfig,\n toWorkbenchPayload,\n} from '@sanity/workbench-cli/deploy'\nimport {c as createTar} from 'tar'\n\nimport {\n createDeployment,\n updateUserApplication,\n type UserApplication,\n type UserApplicationResolved,\n} from '../../services/userApplications.js'\nimport {getAppId} from '../../util/appId.js'\nimport {EXTERNAL_APP_NOT_SUPPORTED, NO_ORGANIZATION_ID} from '../../util/errorMessages.js'\nimport {buildApp} from '../build/buildApp.js'\nimport {createUserApplication} from './createUserApplication.js'\nimport {\n checkAppId,\n checkAppTarget,\n checkAutoUpdates,\n checkBuild,\n checkPackageVersion,\n type DeployCheckReporter,\n verifyOutputDir,\n} from './deployChecks.js'\nimport {deployDebug} from './deployDebug.js'\nimport {listDeploymentFiles, reportInterfaces} from './deploymentPlan.js'\nimport {type DeployPayload, type DeployResult, runDeploy} from './deployRunner.js'\nimport {findUserApplication} from './findUserApplication.js'\nimport {type DeployAppOptions} from './types.js'\n\nconst APP_PACKAGE = '@sanity/sdk-react'\n\nexport function deployApp(options: DeployAppOptions): Promise<void> {\n return runDeploy(options, {\n listFiles: ({projectRoot, sourceDir}) => listDeploymentFiles(sourceDir, projectRoot.directory),\n run: runAppDeployment,\n type: 'coreApp',\n })\n}\n\n/** Validates the deploy, syncs the title from the manifest, and ships the build. */\nasync function runAppDeployment(\n options: DeployAppOptions,\n reporter: DeployCheckReporter,\n): Promise<DeployResult | void> {\n const {cliConfig, flags, output, sourceDir} = options\n const workDir = options.projectRoot.directory\n const organizationId = cliConfig.app?.organizationId\n const appId = getAppId(cliConfig)\n const workbench = getWorkbench(cliConfig)\n // A config (the Media Library) is not an app — it resolves through its own\n // brand and persists to the org's installation instead of hosting an application.\n const config = resolveWorkbenchConfig(cliConfig)\n const dryRun = !!flags['dry-run']\n\n const deployConfigOnly = !!config\n const deployApplication = !config && (!workbench || workbench.hasInterfaces)\n\n const appTitle = workbench\n ? flags.title?.trim() || cliConfig.app?.title?.trim() || workbench.slug\n : ''\n\n // A federated app with no entry, view or service would ship a remote with\n // nothing to load — reported first so it fails before any prompt or API call.\n if (workbench) {\n try {\n workbench.assertDeployable()\n } catch (err) {\n reporter.report({\n exitCode: exitCodes.USAGE_ERROR,\n message: getErrorMessage(err),\n solution: 'Declare at least one entry, view, or service in the app',\n status: 'fail',\n })\n }\n }\n\n // A config with no fields would overwrite the org's live config with an empty\n // snapshot, so block it here — same \"nothing to deploy\" gate an app gets.\n if (config && config.fields.length === 0) {\n reporter.report({\n exitCode: exitCodes.USAGE_ERROR,\n message: 'Nothing to deploy: the media library config declares no fields.',\n solution: 'Add at least one field to the media library config',\n status: 'fail',\n })\n }\n\n const isAutoUpdating = checkAutoUpdates(reporter, {cliConfig, flags})\n\n // An application ships the SDK runtime; a media-library config stamps its\n // `sanity` version instead.\n let version: string | null = null\n if (deployApplication) {\n version = await checkPackageVersion(reporter, {moduleName: APP_PACKAGE, workDir})\n } else if (deployConfigOnly) {\n version = await checkPackageVersion(reporter, {moduleName: 'sanity', workDir})\n }\n\n reporter.report(\n organizationId\n ? {message: `Organization: ${organizationId}`, status: 'pass'}\n : {\n message: NO_ORGANIZATION_ID,\n solution: 'Add `app.organizationId` to sanity.cli.ts',\n status: 'fail',\n },\n )\n\n checkAppId(reporter, {cliConfig})\n\n let application: UserApplicationResolved | null = null\n let appCreated = false\n let workbenchApp: object | undefined\n if (flags.external) {\n reporter.report({\n message: EXTERNAL_APP_NOT_SUPPORTED,\n solution: 'Remove the --external flag — apps deploy to Sanity hosting',\n status: 'fail',\n })\n } else if (deployApplication && workbench) {\n workbenchApp = (\n await checkAppTarget(reporter, {\n appId,\n isWorkbenchApp: true,\n organizationId,\n slug: workbench.slug,\n title: appTitle,\n })\n )?.application\n } else if (deployApplication) {\n ;({application, created: appCreated} = await resolveAppApplication(options, {dryRun, reporter}))\n }\n\n // A first deploy mints the app id and the build inlines it; --no-build would\n // ship an existing bundle carrying a different id, so it can't be a first deploy.\n if (deployApplication && workbench && !appId && !flags.external && !flags.build) {\n reporter.report({\n exitCode: exitCodes.USAGE_ERROR,\n message: 'A first deploy cannot skip the build (--no-build)',\n solution: 'Drop --no-build so the new application id is inlined into the build',\n status: 'fail',\n })\n }\n\n // Read up front so a bad icon path fails before we create or build.\n const appIcon =\n !dryRun && workbench?.icon ? await readIconFromPath(workDir, workbench.icon) : undefined\n\n // Create the app before the build so the bundle carries its real id. A\n // redeploy already has it from `deployment.appId`; a dry run skips creation.\n let applicationId = appId\n let applicationCreated = false\n let rollbackApp: (() => Promise<void>) | undefined\n if (!dryRun && deployApplication && workbench && organizationId && !applicationId) {\n const created = await createCoreApp({\n isSingleton: workbench.isSingleton,\n name: workbench.name,\n organizationId,\n slug: workbench.slug,\n title: appTitle,\n visibility: workbench.visibility,\n })\n workbenchApp = created.application\n applicationId = created.application.id\n rollbackApp = created.rollback\n applicationCreated = true\n }\n\n // A record created above is stranded at its slug (and blocks retries) if any\n // step before it fully deploys fails, so undo the creation on failure.\n try {\n await checkBuild(reporter, {\n build: () =>\n buildApp({\n applicationId: workbench ? applicationId : undefined,\n autoUpdatesEnabled: isAutoUpdating,\n calledFromDeploy: true,\n cliConfig,\n flags,\n outDir: sourceDir,\n output,\n workDir,\n }),\n skipReason: flags.build\n ? undefined\n : 'Build skipped (--no-build) — validating existing output directory',\n successMessage: 'App built',\n })\n\n await verifyOutputDir({\n isWorkbenchApp: workbench !== null || config !== null,\n reporter,\n sourceDir,\n })\n\n // Workbench apps and configs ship a federation remote and don't read the\n // core-app manifest; only plain core-apps do. Manifests aren't strictly\n // essential, so a failure warns and continues.\n let manifest: CoreAppManifest | undefined\n if (!workbench && !config) {\n try {\n manifest = await extractCoreAppManifest({workDir})\n } catch (err) {\n deployDebug('Error extracting app manifest', err)\n reporter.report({\n message: `Error extracting app manifest: ${getErrorMessage(err)}`,\n status: 'warn',\n })\n }\n }\n\n // Resolve the installation in both modes so the report — dry-run and real —\n // shows whether the config is deployable; a missing one fails the deploy here.\n let installationId: string | undefined\n let configSummary: string | undefined\n const configAppType = config?.appType\n if (deployConfigOnly && organizationId && config && configAppType) {\n installationId = await resolveInstallationId({appType: configAppType, organizationId})\n configSummary = summarizeConfig(config)\n reporter.report(\n installationId\n ? {message: configSummary, status: 'pass'}\n : {\n exitCode: exitCodes.USAGE_ERROR,\n message: `No active \"${configAppType}\" installation for organization \"${organizationId}\"`,\n solution:\n 'Install the Media Library for the organization before deploying its config',\n status: 'fail',\n },\n )\n }\n\n const interfaces = deployApplication && workbench ? reportInterfaces(reporter, workbench) : null\n\n // Applied after the app is live (see below) so a failed deploy never leaves\n // the org's installation config without its application.\n const deployApplicationConfig = async (): Promise<void> => {\n if (installationId && version && configAppType && organizationId) {\n await deployConfig({\n appType: configAppType,\n installationId,\n organizationId,\n output,\n sourceDir,\n version,\n })\n }\n }\n\n const payload: DeployPayload = {\n appId: appId ?? null,\n isAutoUpdating,\n ...(organizationId ? {organizationId} : {}),\n type: 'coreApp',\n version,\n ...toWorkbenchPayload(workbench, {config: configSummary, interfaces, title: appTitle}),\n ...(configSummary ? {config: configSummary} : {}),\n }\n\n // Dry run stops here — everything below mutates.\n if (dryRun) return {application: null, payload}\n\n // A config-only singleton ships no application, only its config.\n if (!deployApplication) {\n await deployApplicationConfig()\n if (installationId && version) {\n return {application: null, installationId, payload}\n }\n return\n }\n\n // A real deploy already exited on a version-resolution failure; this narrows the type.\n if (!version) return\n\n // The app was created (or resolved from `deployment.appId`) before the build,\n // so this only ships the deployment; plain coreApps use user-applications below.\n if (workbench && organizationId && applicationId) {\n await deployWorkbenchApp({\n app: cliConfig.app,\n applicationId,\n icon: appIcon,\n isApp: true,\n isAutoUpdating,\n // Once the deployment is live, a metadata-sync or later config failure\n // must not delete the app.\n onDeployed: () => {\n rollbackApp = undefined\n },\n sourceDir,\n title: appTitle,\n version,\n visibility: workbench.visibility,\n })\n await deployApplicationConfig()\n const url = getApplicationUrl({id: applicationId, organizationId, type: 'coreApp'})\n logAppDeployed({\n applicationId,\n cliConfig,\n created: applicationCreated,\n organizationId,\n output,\n title: appTitle,\n url,\n })\n return {\n action: applicationCreated ? 'create' : 'update',\n application: workbenchApp ?? null,\n payload,\n url,\n }\n }\n\n // A real deploy has already exited if anything failed; landing here without a\n // resolved application means the deploy target was never resolved.\n if (!application) return\n\n application = await syncApplicationMetadata({\n application,\n manifest,\n output,\n visibility: cliConfig.app?.visibility,\n })\n await shipAppDeployment({application, isAutoUpdating, manifest, sourceDir, version})\n logAppDeployed({\n applicationId: application.id,\n cliConfig,\n created: appCreated,\n organizationId: application.organizationId,\n output,\n title: application.title,\n })\n return {\n action: appCreated ? 'create' : 'update',\n application,\n payload,\n url: getCoreAppUrl(application.organizationId, application.id),\n }\n } catch (err) {\n await rollbackApp?.()\n throw err\n }\n}\n\n/**\n * Finds the application a real deploy targets, creating one when none is\n * configured. A dry run resolves and reports the target read-only instead.\n */\nasync function resolveAppApplication(\n options: DeployAppOptions,\n {dryRun, reporter}: {dryRun: boolean; reporter: DeployCheckReporter},\n): Promise<{application: UserApplicationResolved | null; created: boolean}> {\n const {cliConfig, flags, output} = options\n const organizationId = cliConfig.app?.organizationId ?? ''\n // Create name from --title or `app.title` config; blank falls back to the prompt\n const title = flags.title?.trim() || cliConfig.app?.title?.trim() || undefined\n\n if (dryRun) {\n await checkAppTarget(reporter, {appId: getAppId(cliConfig), organizationId, title})\n return {application: null, created: false}\n }\n\n let application = await findUserApplication({\n cliConfig,\n organizationId,\n output,\n title,\n unattended: !!flags.yes,\n })\n deployDebug('User application found', application)\n\n if (!application) {\n deployDebug('No user application found. Creating a new one')\n application = await createUserApplication(organizationId, title, cliConfig.app?.visibility)\n deployDebug('User application created', application)\n return {application, created: true}\n }\n\n return {application, created: false}\n}\n\n/**\n * Syncs application metadata on redeploy when it has changed: the title from the\n * manifest and the dashboard visibility from config. Sends a single PATCH with\n * only the changed fields, and skips the request entirely when nothing changed.\n */\nexport async function syncApplicationMetadata({\n application,\n manifest,\n output,\n visibility,\n}: {\n application: UserApplicationResolved\n manifest: CoreAppManifest | undefined\n output: DeployAppOptions['output']\n visibility: AppVisibility | undefined\n}): Promise<UserApplicationResolved> {\n const titleUpdate = resolveTitleUpdate(manifest, application)\n // Treat an unset server value as `default` so a config of `default` is a no-op.\n const visibilityChanged =\n visibility !== undefined && visibility !== (application.dashboardStatus ?? 'default')\n\n if (!titleUpdate && !visibilityChanged) return application\n\n if (titleUpdate) {\n deployDebug('Updating application title from manifest', titleUpdate)\n output.log(\n titleUpdate.from\n ? `Updating title from \"${titleUpdate.from}\" to \"${titleUpdate.to}\"`\n : `Setting application title to \"${titleUpdate.to}\"`,\n )\n }\n if (visibilityChanged) {\n output.log(`Setting dashboard visibility to \"${visibility}\"`)\n }\n\n const spin = spinner('Updating application').start()\n try {\n const updated = await updateUserApplication({\n applicationId: application.id,\n appType: 'coreApp',\n body: {\n ...(titleUpdate ? {title: titleUpdate.to} : {}),\n ...(visibilityChanged ? {dashboardStatus: visibility} : {}),\n },\n })\n spin.succeed()\n return updated\n } catch (err) {\n spin.fail()\n const message = getErrorMessage(err)\n deployDebug('Error updating application metadata', {message})\n output.warn(`Error updating application metadata: ${message}`)\n return application\n }\n}\n\nasync function shipAppDeployment({\n application,\n isAutoUpdating,\n manifest,\n sourceDir,\n version,\n}: {\n application: UserApplication\n isAutoUpdating: boolean\n manifest: CoreAppManifest | undefined\n sourceDir: string\n version: string\n}): Promise<void> {\n const tarball = createTar({cwd: dirname(sourceDir)}, [basename(sourceDir)]).pipe(createGzip())\n\n const spin = spinner('Deploying...').start()\n try {\n await createDeployment({\n applicationId: application.id,\n isApp: true,\n isAutoUpdating,\n manifest,\n tarball,\n version,\n })\n } catch (error) {\n spin.clear()\n throw error\n }\n spin.succeed()\n}\n\nexport function logAppDeployed({\n applicationId,\n cliConfig,\n created,\n organizationId,\n output,\n title,\n url = getCoreAppUrl(organizationId, applicationId),\n}: {\n applicationId: string\n cliConfig: DeployAppOptions['cliConfig']\n created: boolean\n organizationId: string\n output: DeployAppOptions['output']\n title: string | null\n url?: string\n}): void {\n const named = title ? ` — \"${title}\"` : ''\n output.log(`\\nSuccess! Application deployed to ${styleText('cyan', url)}${named}`)\n output.log(created ? 'Created a new application.' : 'Updated the existing application.')\n\n if (getAppId(cliConfig)) return\n\n output.log(`\\n════ ${styleText('bold', 'Next step:')} ════`)\n if (created) {\n output.log(\n styleText(\n 'yellow',\n '\\nDeploying again without `deployment.appId` creates another new application.',\n ),\n )\n }\n output.log(\n styleText('bold', '\\nAdd the deployment.appId to your sanity.cli.js or sanity.cli.ts file:'),\n )\n output.log(`\n${styleText(\n 'dim',\n `app: {\n // your application config here…\n}`,\n)},\n${styleText(\n ['bold', 'green'],\n `deployment: {\n appId: '${applicationId}',\n}\\n`,\n)}`)\n}\n"],"names":["basename","dirname","styleText","createGzip","extractCoreAppManifest","readIconFromPath","resolveTitleUpdate","exitCodes","getErrorMessage","getCoreAppUrl","spinner","createCoreApp","deployConfig","deployWorkbenchApp","getApplicationUrl","getWorkbench","resolveInstallationId","resolveWorkbenchConfig","summarizeConfig","toWorkbenchPayload","c","createTar","createDeployment","updateUserApplication","getAppId","EXTERNAL_APP_NOT_SUPPORTED","NO_ORGANIZATION_ID","buildApp","createUserApplication","checkAppId","checkAppTarget","checkAutoUpdates","checkBuild","checkPackageVersion","verifyOutputDir","deployDebug","listDeploymentFiles","reportInterfaces","runDeploy","findUserApplication","APP_PACKAGE","deployApp","options","listFiles","projectRoot","sourceDir","directory","run","runAppDeployment","type","reporter","cliConfig","flags","output","workDir","organizationId","app","appId","workbench","config","dryRun","deployConfigOnly","deployApplication","hasInterfaces","appTitle","title","trim","slug","assertDeployable","err","report","exitCode","USAGE_ERROR","message","solution","status","fields","length","isAutoUpdating","version","moduleName","application","appCreated","workbenchApp","external","isWorkbenchApp","created","resolveAppApplication","build","appIcon","icon","undefined","applicationId","applicationCreated","rollbackApp","isSingleton","name","visibility","id","rollback","autoUpdatesEnabled","calledFromDeploy","outDir","skipReason","successMessage","manifest","installationId","configSummary","configAppType","appType","interfaces","deployApplicationConfig","payload","isApp","onDeployed","url","logAppDeployed","action","syncApplicationMetadata","shipAppDeployment","unattended","yes","titleUpdate","visibilityChanged","dashboardStatus","log","from","to","spin","start","updated","body","succeed","fail","warn","tarball","cwd","pipe","error","clear","named"],"mappings":"AAAA,SAAQA,QAAQ,EAAEC,OAAO,QAAO,YAAW;AAC3C,SAAQC,SAAS,QAAO,YAAW;AACnC,SAAQC,UAAU,QAAO,YAAW;AAEpC,SAEEC,sBAAsB,EACtBC,gBAAgB,EAChBC,kBAAkB,QACb,uCAAsC;AAC7C,SAA4BC,SAAS,QAAO,mBAAkB;AAC9D,SAAQC,eAAe,QAAO,0BAAyB;AACvD,SAAQC,aAAa,QAAO,wBAAuB;AACnD,SAAQC,OAAO,QAAO,sBAAqB;AAC3C,SACEC,aAAa,EACbC,YAAY,EACZC,kBAAkB,EAClBC,iBAAiB,EACjBC,YAAY,EACZC,qBAAqB,EACrBC,sBAAsB,EACtBC,eAAe,EACfC,kBAAkB,QACb,+BAA8B;AACrC,SAAQC,KAAKC,SAAS,QAAO,MAAK;AAElC,SACEC,gBAAgB,EAChBC,qBAAqB,QAGhB,qCAAoC;AAC3C,SAAQC,QAAQ,QAAO,sBAAqB;AAC5C,SAAQC,0BAA0B,EAAEC,kBAAkB,QAAO,8BAA6B;AAC1F,SAAQC,QAAQ,QAAO,uBAAsB;AAC7C,SAAQC,qBAAqB,QAAO,6BAA4B;AAChE,SACEC,UAAU,EACVC,cAAc,EACdC,gBAAgB,EAChBC,UAAU,EACVC,mBAAmB,EAEnBC,eAAe,QACV,oBAAmB;AAC1B,SAAQC,WAAW,QAAO,mBAAkB;AAC5C,SAAQC,mBAAmB,EAAEC,gBAAgB,QAAO,sBAAqB;AACzE,SAA+CC,SAAS,QAAO,oBAAmB;AAClF,SAAQC,mBAAmB,QAAO,2BAA0B;AAG5D,MAAMC,cAAc;AAEpB,OAAO,SAASC,UAAUC,OAAyB;IACjD,OAAOJ,UAAUI,SAAS;QACxBC,WAAW,CAAC,EAACC,WAAW,EAAEC,SAAS,EAAC,GAAKT,oBAAoBS,WAAWD,YAAYE,SAAS;QAC7FC,KAAKC;QACLC,MAAM;IACR;AACF;AAEA,kFAAkF,GAClF,eAAeD,iBACbN,OAAyB,EACzBQ,QAA6B;IAE7B,MAAM,EAACC,SAAS,EAAEC,KAAK,EAAEC,MAAM,EAAER,SAAS,EAAC,GAAGH;IAC9C,MAAMY,UAAUZ,QAAQE,WAAW,CAACE,SAAS;IAC7C,MAAMS,iBAAiBJ,UAAUK,GAAG,EAAED;IACtC,MAAME,QAAQjC,SAAS2B;IACvB,MAAMO,YAAY3C,aAAaoC;IAC/B,2EAA2E;IAC3E,kFAAkF;IAClF,MAAMQ,SAAS1C,uBAAuBkC;IACtC,MAAMS,SAAS,CAAC,CAACR,KAAK,CAAC,UAAU;IAEjC,MAAMS,mBAAmB,CAAC,CAACF;IAC3B,MAAMG,oBAAoB,CAACH,UAAW,CAAA,CAACD,aAAaA,UAAUK,aAAa,AAAD;IAE1E,MAAMC,WAAWN,YACbN,MAAMa,KAAK,EAAEC,UAAUf,UAAUK,GAAG,EAAES,OAAOC,UAAUR,UAAUS,IAAI,GACrE;IAEJ,0EAA0E;IAC1E,8EAA8E;IAC9E,IAAIT,WAAW;QACb,IAAI;YACFA,UAAUU,gBAAgB;QAC5B,EAAE,OAAOC,KAAK;YACZnB,SAASoB,MAAM,CAAC;gBACdC,UAAUhE,UAAUiE,WAAW;gBAC/BC,SAASjE,gBAAgB6D;gBACzBK,UAAU;gBACVC,QAAQ;YACV;QACF;IACF;IAEA,8EAA8E;IAC9E,0EAA0E;IAC1E,IAAIhB,UAAUA,OAAOiB,MAAM,CAACC,MAAM,KAAK,GAAG;QACxC3B,SAASoB,MAAM,CAAC;YACdC,UAAUhE,UAAUiE,WAAW;YAC/BC,SAAS;YACTC,UAAU;YACVC,QAAQ;QACV;IACF;IAEA,MAAMG,iBAAiB/C,iBAAiBmB,UAAU;QAACC;QAAWC;IAAK;IAEnE,0EAA0E;IAC1E,4BAA4B;IAC5B,IAAI2B,UAAyB;IAC7B,IAAIjB,mBAAmB;QACrBiB,UAAU,MAAM9C,oBAAoBiB,UAAU;YAAC8B,YAAYxC;YAAac;QAAO;IACjF,OAAO,IAAIO,kBAAkB;QAC3BkB,UAAU,MAAM9C,oBAAoBiB,UAAU;YAAC8B,YAAY;YAAU1B;QAAO;IAC9E;IAEAJ,SAASoB,MAAM,CACbf,iBACI;QAACkB,SAAS,CAAC,cAAc,EAAElB,gBAAgB;QAAEoB,QAAQ;IAAM,IAC3D;QACEF,SAAS/C;QACTgD,UAAU;QACVC,QAAQ;IACV;IAGN9C,WAAWqB,UAAU;QAACC;IAAS;IAE/B,IAAI8B,cAA8C;IAClD,IAAIC,aAAa;IACjB,IAAIC;IACJ,IAAI/B,MAAMgC,QAAQ,EAAE;QAClBlC,SAASoB,MAAM,CAAC;YACdG,SAAShD;YACTiD,UAAU;YACVC,QAAQ;QACV;IACF,OAAO,IAAIb,qBAAqBJ,WAAW;QACzCyB,eACE,CAAA,MAAMrD,eAAeoB,UAAU;YAC7BO;YACA4B,gBAAgB;YAChB9B;YACAY,MAAMT,UAAUS,IAAI;YACpBF,OAAOD;QACT,EAAC,GACAiB;IACL,OAAO,IAAInB,mBAAmB;;QAC1B,CAAA,EAACmB,WAAW,EAAEK,SAASJ,UAAU,EAAC,GAAG,MAAMK,sBAAsB7C,SAAS;YAACkB;YAAQV;QAAQ,EAAC;IAChG;IAEA,6EAA6E;IAC7E,kFAAkF;IAClF,IAAIY,qBAAqBJ,aAAa,CAACD,SAAS,CAACL,MAAMgC,QAAQ,IAAI,CAAChC,MAAMoC,KAAK,EAAE;QAC/EtC,SAASoB,MAAM,CAAC;YACdC,UAAUhE,UAAUiE,WAAW;YAC/BC,SAAS;YACTC,UAAU;YACVC,QAAQ;QACV;IACF;IAEA,oEAAoE;IACpE,MAAMc,UACJ,CAAC7B,UAAUF,WAAWgC,OAAO,MAAMrF,iBAAiBiD,SAASI,UAAUgC,IAAI,IAAIC;IAEjF,uEAAuE;IACvE,6EAA6E;IAC7E,IAAIC,gBAAgBnC;IACpB,IAAIoC,qBAAqB;IACzB,IAAIC;IACJ,IAAI,CAAClC,UAAUE,qBAAqBJ,aAAaH,kBAAkB,CAACqC,eAAe;QACjF,MAAMN,UAAU,MAAM3E,cAAc;YAClCoF,aAAarC,UAAUqC,WAAW;YAClCC,MAAMtC,UAAUsC,IAAI;YACpBzC;YACAY,MAAMT,UAAUS,IAAI;YACpBF,OAAOD;YACPiC,YAAYvC,UAAUuC,UAAU;QAClC;QACAd,eAAeG,QAAQL,WAAW;QAClCW,gBAAgBN,QAAQL,WAAW,CAACiB,EAAE;QACtCJ,cAAcR,QAAQa,QAAQ;QAC9BN,qBAAqB;IACvB;IAEA,6EAA6E;IAC7E,uEAAuE;IACvE,IAAI;QACF,MAAM7D,WAAWkB,UAAU;YACzBsC,OAAO,IACL7D,SAAS;oBACPiE,eAAelC,YAAYkC,gBAAgBD;oBAC3CS,oBAAoBtB;oBACpBuB,kBAAkB;oBAClBlD;oBACAC;oBACAkD,QAAQzD;oBACRQ;oBACAC;gBACF;YACFiD,YAAYnD,MAAMoC,KAAK,GACnBG,YACA;YACJa,gBAAgB;QAClB;QAEA,MAAMtE,gBAAgB;YACpBmD,gBAAgB3B,cAAc,QAAQC,WAAW;YACjDT;YACAL;QACF;QAEA,yEAAyE;QACzE,wEAAwE;QACxE,+CAA+C;QAC/C,IAAI4D;QACJ,IAAI,CAAC/C,aAAa,CAACC,QAAQ;YACzB,IAAI;gBACF8C,WAAW,MAAMrG,uBAAuB;oBAACkD;gBAAO;YAClD,EAAE,OAAOe,KAAK;gBACZlC,YAAY,iCAAiCkC;gBAC7CnB,SAASoB,MAAM,CAAC;oBACdG,SAAS,CAAC,+BAA+B,EAAEjE,gBAAgB6D,MAAM;oBACjEM,QAAQ;gBACV;YACF;QACF;QAEA,4EAA4E;QAC5E,+EAA+E;QAC/E,IAAI+B;QACJ,IAAIC;QACJ,MAAMC,gBAAgBjD,QAAQkD;QAC9B,IAAIhD,oBAAoBN,kBAAkBI,UAAUiD,eAAe;YACjEF,iBAAiB,MAAM1F,sBAAsB;gBAAC6F,SAASD;gBAAerD;YAAc;YACpFoD,gBAAgBzF,gBAAgByC;YAChCT,SAASoB,MAAM,CACboC,iBACI;gBAACjC,SAASkC;gBAAehC,QAAQ;YAAM,IACvC;gBACEJ,UAAUhE,UAAUiE,WAAW;gBAC/BC,SAAS,CAAC,WAAW,EAAEmC,cAAc,iCAAiC,EAAErD,eAAe,CAAC,CAAC;gBACzFmB,UACE;gBACFC,QAAQ;YACV;QAER;QAEA,MAAMmC,aAAahD,qBAAqBJ,YAAYrB,iBAAiBa,UAAUQ,aAAa;QAE5F,4EAA4E;QAC5E,yDAAyD;QACzD,MAAMqD,0BAA0B;YAC9B,IAAIL,kBAAkB3B,WAAW6B,iBAAiBrD,gBAAgB;gBAChE,MAAM3C,aAAa;oBACjBiG,SAASD;oBACTF;oBACAnD;oBACAF;oBACAR;oBACAkC;gBACF;YACF;QACF;QAEA,MAAMiC,UAAyB;YAC7BvD,OAAOA,SAAS;YAChBqB;YACA,GAAIvB,iBAAiB;gBAACA;YAAc,IAAI,CAAC,CAAC;YAC1CN,MAAM;YACN8B;YACA,GAAG5D,mBAAmBuC,WAAW;gBAACC,QAAQgD;gBAAeG;gBAAY7C,OAAOD;YAAQ,EAAE;YACtF,GAAI2C,gBAAgB;gBAAChD,QAAQgD;YAAa,IAAI,CAAC,CAAC;QAClD;QAEA,iDAAiD;QACjD,IAAI/C,QAAQ,OAAO;YAACqB,aAAa;YAAM+B;QAAO;QAE9C,iEAAiE;QACjE,IAAI,CAAClD,mBAAmB;YACtB,MAAMiD;YACN,IAAIL,kBAAkB3B,SAAS;gBAC7B,OAAO;oBAACE,aAAa;oBAAMyB;oBAAgBM;gBAAO;YACpD;YACA;QACF;QAEA,uFAAuF;QACvF,IAAI,CAACjC,SAAS;QAEd,8EAA8E;QAC9E,iFAAiF;QACjF,IAAIrB,aAAaH,kBAAkBqC,eAAe;YAChD,MAAM/E,mBAAmB;gBACvB2C,KAAKL,UAAUK,GAAG;gBAClBoC;gBACAF,MAAMD;gBACNwB,OAAO;gBACPnC;gBACA,uEAAuE;gBACvE,2BAA2B;gBAC3BoC,YAAY;oBACVpB,cAAcH;gBAChB;gBACA9C;gBACAoB,OAAOD;gBACPe;gBACAkB,YAAYvC,UAAUuC,UAAU;YAClC;YACA,MAAMc;YACN,MAAMI,MAAMrG,kBAAkB;gBAACoF,IAAIN;gBAAerC;gBAAgBN,MAAM;YAAS;YACjFmE,eAAe;gBACbxB;gBACAzC;gBACAmC,SAASO;gBACTtC;gBACAF;gBACAY,OAAOD;gBACPmD;YACF;YACA,OAAO;gBACLE,QAAQxB,qBAAqB,WAAW;gBACxCZ,aAAaE,gBAAgB;gBAC7B6B;gBACAG;YACF;QACF;QAEA,8EAA8E;QAC9E,mEAAmE;QACnE,IAAI,CAAClC,aAAa;QAElBA,cAAc,MAAMqC,wBAAwB;YAC1CrC;YACAwB;YACApD;YACA4C,YAAY9C,UAAUK,GAAG,EAAEyC;QAC7B;QACA,MAAMsB,kBAAkB;YAACtC;YAAaH;YAAgB2B;YAAU5D;YAAWkC;QAAO;QAClFqC,eAAe;YACbxB,eAAeX,YAAYiB,EAAE;YAC7B/C;YACAmC,SAASJ;YACT3B,gBAAgB0B,YAAY1B,cAAc;YAC1CF;YACAY,OAAOgB,YAAYhB,KAAK;QAC1B;QACA,OAAO;YACLoD,QAAQnC,aAAa,WAAW;YAChCD;YACA+B;YACAG,KAAK1G,cAAcwE,YAAY1B,cAAc,EAAE0B,YAAYiB,EAAE;QAC/D;IACF,EAAE,OAAO7B,KAAK;QACZ,MAAMyB;QACN,MAAMzB;IACR;AACF;AAEA;;;CAGC,GACD,eAAekB,sBACb7C,OAAyB,EACzB,EAACkB,MAAM,EAAEV,QAAQ,EAAmD;IAEpE,MAAM,EAACC,SAAS,EAAEC,KAAK,EAAEC,MAAM,EAAC,GAAGX;IACnC,MAAMa,iBAAiBJ,UAAUK,GAAG,EAAED,kBAAkB;IACxD,iFAAiF;IACjF,MAAMU,QAAQb,MAAMa,KAAK,EAAEC,UAAUf,UAAUK,GAAG,EAAES,OAAOC,UAAUyB;IAErE,IAAI/B,QAAQ;QACV,MAAM9B,eAAeoB,UAAU;YAACO,OAAOjC,SAAS2B;YAAYI;YAAgBU;QAAK;QACjF,OAAO;YAACgB,aAAa;YAAMK,SAAS;QAAK;IAC3C;IAEA,IAAIL,cAAc,MAAM1C,oBAAoB;QAC1CY;QACAI;QACAF;QACAY;QACAuD,YAAY,CAAC,CAACpE,MAAMqE,GAAG;IACzB;IACAtF,YAAY,0BAA0B8C;IAEtC,IAAI,CAACA,aAAa;QAChB9C,YAAY;QACZ8C,cAAc,MAAMrD,sBAAsB2B,gBAAgBU,OAAOd,UAAUK,GAAG,EAAEyC;QAChF9D,YAAY,4BAA4B8C;QACxC,OAAO;YAACA;YAAaK,SAAS;QAAI;IACpC;IAEA,OAAO;QAACL;QAAaK,SAAS;IAAK;AACrC;AAEA;;;;CAIC,GACD,OAAO,eAAegC,wBAAwB,EAC5CrC,WAAW,EACXwB,QAAQ,EACRpD,MAAM,EACN4C,UAAU,EAMX;IACC,MAAMyB,cAAcpH,mBAAmBmG,UAAUxB;IACjD,gFAAgF;IAChF,MAAM0C,oBACJ1B,eAAeN,aAAaM,eAAgBhB,CAAAA,YAAY2C,eAAe,IAAI,SAAQ;IAErF,IAAI,CAACF,eAAe,CAACC,mBAAmB,OAAO1C;IAE/C,IAAIyC,aAAa;QACfvF,YAAY,4CAA4CuF;QACxDrE,OAAOwE,GAAG,CACRH,YAAYI,IAAI,GACZ,CAAC,qBAAqB,EAAEJ,YAAYI,IAAI,CAAC,MAAM,EAAEJ,YAAYK,EAAE,CAAC,CAAC,CAAC,GAClE,CAAC,8BAA8B,EAAEL,YAAYK,EAAE,CAAC,CAAC,CAAC;IAE1D;IACA,IAAIJ,mBAAmB;QACrBtE,OAAOwE,GAAG,CAAC,CAAC,iCAAiC,EAAE5B,WAAW,CAAC,CAAC;IAC9D;IAEA,MAAM+B,OAAOtH,QAAQ,wBAAwBuH,KAAK;IAClD,IAAI;QACF,MAAMC,UAAU,MAAM3G,sBAAsB;YAC1CqE,eAAeX,YAAYiB,EAAE;YAC7BW,SAAS;YACTsB,MAAM;gBACJ,GAAIT,cAAc;oBAACzD,OAAOyD,YAAYK,EAAE;gBAAA,IAAI,CAAC,CAAC;gBAC9C,GAAIJ,oBAAoB;oBAACC,iBAAiB3B;gBAAU,IAAI,CAAC,CAAC;YAC5D;QACF;QACA+B,KAAKI,OAAO;QACZ,OAAOF;IACT,EAAE,OAAO7D,KAAK;QACZ2D,KAAKK,IAAI;QACT,MAAM5D,UAAUjE,gBAAgB6D;QAChClC,YAAY,uCAAuC;YAACsC;QAAO;QAC3DpB,OAAOiF,IAAI,CAAC,CAAC,qCAAqC,EAAE7D,SAAS;QAC7D,OAAOQ;IACT;AACF;AAEA,eAAesC,kBAAkB,EAC/BtC,WAAW,EACXH,cAAc,EACd2B,QAAQ,EACR5D,SAAS,EACTkC,OAAO,EAOR;IACC,MAAMwD,UAAUlH,UAAU;QAACmH,KAAKvI,QAAQ4C;IAAU,GAAG;QAAC7C,SAAS6C;KAAW,EAAE4F,IAAI,CAACtI;IAEjF,MAAM6H,OAAOtH,QAAQ,gBAAgBuH,KAAK;IAC1C,IAAI;QACF,MAAM3G,iBAAiB;YACrBsE,eAAeX,YAAYiB,EAAE;YAC7Be,OAAO;YACPnC;YACA2B;YACA8B;YACAxD;QACF;IACF,EAAE,OAAO2D,OAAO;QACdV,KAAKW,KAAK;QACV,MAAMD;IACR;IACAV,KAAKI,OAAO;AACd;AAEA,OAAO,SAAShB,eAAe,EAC7BxB,aAAa,EACbzC,SAAS,EACTmC,OAAO,EACP/B,cAAc,EACdF,MAAM,EACNY,KAAK,EACLkD,MAAM1G,cAAc8C,gBAAgBqC,cAAc,EASnD;IACC,MAAMgD,QAAQ3E,QAAQ,CAAC,IAAI,EAAEA,MAAM,CAAC,CAAC,GAAG;IACxCZ,OAAOwE,GAAG,CAAC,CAAC,mCAAmC,EAAE3H,UAAU,QAAQiH,OAAOyB,OAAO;IACjFvF,OAAOwE,GAAG,CAACvC,UAAU,+BAA+B;IAEpD,IAAI9D,SAAS2B,YAAY;IAEzBE,OAAOwE,GAAG,CAAC,CAAC,OAAO,EAAE3H,UAAU,QAAQ,cAAc,KAAK,CAAC;IAC3D,IAAIoF,SAAS;QACXjC,OAAOwE,GAAG,CACR3H,UACE,UACA;IAGN;IACAmD,OAAOwE,GAAG,CACR3H,UAAU,QAAQ;IAEpBmD,OAAOwE,GAAG,CAAC,CAAC;AACd,EAAE3H,UACA,OACA,CAAC;;CAEF,CAAC,EACA;AACF,EAAEA,UACA;QAAC;QAAQ;KAAQ,EACjB,CAAC;UACO,EAAE0F,cAAc;GACvB,CAAC,GACD;AACH"}
@@ -6,7 +6,7 @@ import { readIconFromPath } from '@sanity/cli-build/_internal/manifest';
6
6
  import { exitCodes } from '@sanity/cli-core';
7
7
  import { spinner } from '@sanity/cli-core/ux';
8
8
  import { createStudio, deployWorkbenchApp, getApplicationUrl, getWorkbench, toWorkbenchPayload } from '@sanity/workbench-cli/deploy';
9
- import { pack } from 'tar-fs';
9
+ import { c as createTar } from 'tar';
10
10
  import { createDeployment } from '../../services/userApplications.js';
11
11
  import { getAppId } from '../../util/appId.js';
12
12
  import { NO_ORGANIZATION_ID, NO_PROJECT_ID } from '../../util/errorMessages.js';
@@ -336,11 +336,11 @@ async function shipStudioDeployment({ application, isAutoUpdating, isExternal, o
336
336
  const { cliConfig, output, sourceDir } = options;
337
337
  let tarball;
338
338
  if (!isExternal) {
339
- tarball = pack(dirname(sourceDir), {
340
- entries: [
341
- basename(sourceDir)
342
- ]
343
- }).pipe(createGzip());
339
+ tarball = createTar({
340
+ cwd: dirname(sourceDir)
341
+ }, [
342
+ basename(sourceDir)
343
+ ]).pipe(createGzip());
344
344
  }
345
345
  const spin = spinner(isExternal ? 'Registering studio' : 'Deploying to sanity.studio').start();
346
346
  let location;