@sanity/cli 7.15.0 → 7.16.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 (138) hide show
  1. package/README.md +88 -1
  2. package/dist/actions/build/shouldAutoUpdate.js +28 -5
  3. package/dist/actions/build/shouldAutoUpdate.js.map +1 -1
  4. package/dist/actions/deploy/deployApp.js +4 -8
  5. package/dist/actions/deploy/deployApp.js.map +1 -1
  6. package/dist/actions/deploy/deployChecks.js +49 -31
  7. package/dist/actions/deploy/deployChecks.js.map +1 -1
  8. package/dist/actions/deploy/deployRunner.js +1 -1
  9. package/dist/actions/deploy/deployRunner.js.map +1 -1
  10. package/dist/actions/deploy/deployStudio.js +12 -10
  11. package/dist/actions/deploy/deployStudio.js.map +1 -1
  12. package/dist/actions/deploy/deploymentPlan.js +2 -2
  13. package/dist/actions/deploy/deploymentPlan.js.map +1 -1
  14. package/dist/actions/deploy/resolveDeployTarget.js +13 -13
  15. package/dist/actions/deploy/resolveDeployTarget.js.map +1 -1
  16. package/dist/actions/init/bootstrapLocalTemplate.js +2 -3
  17. package/dist/actions/init/bootstrapLocalTemplate.js.map +1 -1
  18. package/dist/actions/init/createAppCliConfig.js.map +1 -1
  19. package/dist/actions/init/createCliConfig.js.map +1 -1
  20. package/dist/actions/init/initNextJs.js +1 -1
  21. package/dist/actions/init/initNextJs.js.map +1 -1
  22. package/dist/actions/init/initStudio.js +10 -6
  23. package/dist/actions/init/initStudio.js.map +1 -1
  24. package/dist/actions/init/templates/appSanityUi.js +1 -1
  25. package/dist/actions/init/templates/appSanityUi.js.map +1 -1
  26. package/dist/actions/init/templates/getStarted.js +2 -2
  27. package/dist/actions/init/templates/getStarted.js.map +1 -1
  28. package/dist/actions/init/templates/nextjs/schemaTypes/blog.js +4 -4
  29. package/dist/actions/init/templates/nextjs/schemaTypes/blog.js.map +1 -1
  30. package/dist/actions/init/templates/shopify.js +2 -2
  31. package/dist/actions/init/templates/shopify.js.map +1 -1
  32. package/dist/actions/init/templates/shopifyOnline.js +2 -2
  33. package/dist/actions/init/templates/shopifyOnline.js.map +1 -1
  34. package/dist/actions/manifest/extractCoreAppManifest.js +7 -7
  35. package/dist/actions/manifest/extractCoreAppManifest.js.map +1 -1
  36. package/dist/actions/scaffold/createFrontend.js +107 -0
  37. package/dist/actions/scaffold/createFrontend.js.map +1 -0
  38. package/dist/actions/scaffold/scaffoldProject.js +202 -0
  39. package/dist/actions/scaffold/scaffoldProject.js.map +1 -0
  40. package/dist/actions/telemetry/resolveConsent.js +4 -2
  41. package/dist/actions/telemetry/resolveConsent.js.map +1 -1
  42. package/dist/commands/backups/list.js +1 -1
  43. package/dist/commands/backups/list.js.map +1 -1
  44. package/dist/commands/datasets/copy.js +5 -3
  45. package/dist/commands/datasets/copy.js.map +1 -1
  46. package/dist/commands/documents/query.js +5 -4
  47. package/dist/commands/documents/query.js.map +1 -1
  48. package/dist/commands/migrations/list.js +1 -1
  49. package/dist/commands/migrations/list.js.map +1 -1
  50. package/dist/commands/migrations/run.js +1 -1
  51. package/dist/commands/migrations/run.js.map +1 -1
  52. package/dist/commands/new.js +309 -0
  53. package/dist/commands/new.js.map +1 -0
  54. package/dist/commands/organizations/list.js +1 -1
  55. package/dist/commands/organizations/list.js.map +1 -1
  56. package/dist/commands/projects/unclaimed.js +205 -0
  57. package/dist/commands/projects/unclaimed.js.map +1 -0
  58. package/dist/commands/tokens/list.js +1 -1
  59. package/dist/commands/tokens/list.js.map +1 -1
  60. package/dist/commands/users/list.js +5 -1
  61. package/dist/commands/users/list.js.map +1 -1
  62. package/dist/exports/invokeSanityCli/commandPolicies/mcpPolicy.js +4 -0
  63. package/dist/exports/invokeSanityCli/commandPolicies/mcpPolicy.js.map +1 -1
  64. package/dist/exports/invokeSanityCli/index.d.ts +5 -9
  65. package/dist/exports/invokeSanityCli/index.js +47 -20
  66. package/dist/exports/invokeSanityCli/index.js.map +1 -1
  67. package/dist/exports/runtime.d.ts +12 -0
  68. package/dist/exports/runtime.js.map +1 -1
  69. package/dist/services/mintProject.js +91 -0
  70. package/dist/services/mintProject.js.map +1 -0
  71. package/dist/services/projects.js +19 -0
  72. package/dist/services/projects.js.map +1 -1
  73. package/dist/services/telemetry.js +4 -0
  74. package/dist/services/telemetry.js.map +1 -1
  75. package/dist/util/formatClaimDeadline.js +15 -0
  76. package/dist/util/formatClaimDeadline.js.map +1 -0
  77. package/dist/util/mintProjectConstants.js +6 -0
  78. package/dist/util/mintProjectConstants.js.map +1 -0
  79. package/dist/util/newCommandSplash.js +27 -0
  80. package/dist/util/newCommandSplash.js.map +1 -0
  81. package/dist/util/packageManager/installPackages.js +57 -28
  82. package/dist/util/packageManager/installPackages.js.map +1 -1
  83. package/dist/util/unclaimedProjects.js +105 -0
  84. package/dist/util/unclaimedProjects.js.map +1 -0
  85. package/oclif.manifest.json +150 -41
  86. package/package.json +7 -7
  87. package/templates/get-started/plugins/sanity-plugin-tutorial/GetStartedTutorial.tsx +1 -1
  88. package/templates/shopify/components/inputs/CollectionHidden.tsx +1 -1
  89. package/templates/shopify/components/inputs/ProductHidden.tsx +1 -1
  90. package/templates/shopify/components/inputs/ProductVariantHidden.tsx +1 -1
  91. package/templates/shopify/components/inputs/ProxyString.tsx +1 -1
  92. package/templates/shopify/components/media/ShopifyDocumentStatus.tsx +3 -1
  93. package/templates/shopify/constants.ts +3 -1
  94. package/templates/shopify/plugins/customDocumentActions/shopifyDelete.tsx +1 -1
  95. package/templates/shopify/plugins/customDocumentActions/shopifyLink.ts +1 -1
  96. package/templates/shopify/schemaTypes/documents/collection.tsx +1 -1
  97. package/templates/shopify/schemaTypes/documents/colorTheme.tsx +1 -1
  98. package/templates/shopify/schemaTypes/documents/page.ts +1 -1
  99. package/templates/shopify/schemaTypes/documents/product.tsx +1 -1
  100. package/templates/shopify/schemaTypes/documents/productVariant.tsx +1 -1
  101. package/templates/shopify/schemaTypes/objects/collection/collectionGroupType.ts +1 -1
  102. package/templates/shopify/schemaTypes/objects/hotspot/imageWithProductHotspotsType.ts +1 -1
  103. package/templates/shopify/schemaTypes/objects/link/linkEmailType.tsx +1 -1
  104. package/templates/shopify/schemaTypes/objects/link/linkExternalType.tsx +1 -1
  105. package/templates/shopify/schemaTypes/objects/link/linkInternalType.tsx +1 -1
  106. package/templates/shopify/schemaTypes/objects/link/linkProductType.tsx +1 -1
  107. package/templates/shopify/schemaTypes/objects/module/accordionType.ts +1 -1
  108. package/templates/shopify/schemaTypes/objects/module/callToActionType.tsx +2 -1
  109. package/templates/shopify/schemaTypes/objects/module/calloutType.ts +1 -1
  110. package/templates/shopify/schemaTypes/objects/module/collectionReferenceType.tsx +1 -1
  111. package/templates/shopify/schemaTypes/objects/module/gridType.ts +1 -1
  112. package/templates/shopify/schemaTypes/objects/module/imageFeatureType.ts +1 -1
  113. package/templates/shopify/schemaTypes/objects/module/imageFeaturesType.tsx +1 -1
  114. package/templates/shopify/schemaTypes/objects/module/instagramType.ts +1 -1
  115. package/templates/shopify/schemaTypes/objects/module/productFeaturesType.tsx +1 -1
  116. package/templates/shopify/schemaTypes/objects/module/productReferenceType.tsx +1 -1
  117. package/templates/shopify/schemaTypes/objects/shopify/collectionRuleType.tsx +1 -1
  118. package/templates/shopify/schemaTypes/objects/shopify/optionType.tsx +1 -1
  119. package/templates/shopify/schemaTypes/objects/shopify/productWithVariantType.tsx +1 -1
  120. package/templates/shopify/schemaTypes/singletons/homeType.ts +1 -1
  121. package/templates/shopify/schemaTypes/singletons/settingsType.ts +5 -1
  122. package/templates/shopify/structure/pageStructure.ts +1 -1
  123. package/templates/shopify/structure/productStructure.ts +1 -1
  124. package/templates/shopify-online-storefront/components/inputs/CollectionHidden.tsx +1 -1
  125. package/templates/shopify-online-storefront/components/inputs/ProductHidden.tsx +1 -1
  126. package/templates/shopify-online-storefront/components/inputs/ProductVariantHidden.tsx +1 -1
  127. package/templates/shopify-online-storefront/components/inputs/ProxyString.tsx +1 -1
  128. package/templates/shopify-online-storefront/components/media/ShopifyDocumentStatus.tsx +3 -1
  129. package/templates/shopify-online-storefront/plugins/shopifyDocumentActions/shopifyDelete.tsx +1 -1
  130. package/templates/shopify-online-storefront/plugins/shopifyDocumentActions/shopifyLink.ts +1 -1
  131. package/templates/shopify-online-storefront/schemaTypes/documents/collection.tsx +1 -1
  132. package/templates/shopify-online-storefront/schemaTypes/documents/product.tsx +1 -1
  133. package/templates/shopify-online-storefront/schemaTypes/documents/productVariant.tsx +1 -1
  134. package/templates/shopify-online-storefront/schemaTypes/objects/accordion.ts +1 -1
  135. package/templates/shopify-online-storefront/schemaTypes/objects/callout.ts +1 -1
  136. package/templates/shopify-online-storefront/schemaTypes/objects/option.ts +1 -1
  137. package/templates/shopify-online-storefront/schemaTypes/objects/shopifyCollectionRule.tsx +1 -1
  138. package/templates/shopify-online-storefront/structure/productStructure.ts +1 -1
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/services/projects.ts"],"sourcesContent":["import {debug, getGlobalCliClient, getProjectCliClient} from '@sanity/cli-core'\nimport {SanityProject} from '@sanity/client'\n\nimport {type Invite, type Role} from '../actions/users/types.js'\n\nexport const PROJECTS_API_VERSION = '2025-09-22'\n\nexport const CREATE_PROJECT_API_VERSION = 'v2025-05-14'\n\ninterface CreateProjectOptions {\n displayName: string\n\n metadata?: {\n coupon?: string\n integration?: string\n }\n organizationId?: string\n subscription?: {planId: string}\n}\n\nexport interface CreateProjectResult {\n displayName: string\n projectId: string\n}\n\n/**\n * Create a new Sanity project\n */\nexport async function createProject(options: CreateProjectOptions): Promise<CreateProjectResult> {\n const client = await getGlobalCliClient({\n apiVersion: CREATE_PROJECT_API_VERSION,\n requireUser: true,\n })\n\n try {\n const response = await client.request({\n body: {\n ...options,\n metadata: {\n ...options?.metadata,\n integration: 'cli',\n },\n },\n method: 'POST',\n uri: '/projects',\n })\n\n return {\n displayName: options.displayName || '',\n projectId: response.projectId || response.id,\n }\n } catch (err) {\n debug('Error creating project', err)\n throw err\n }\n}\n\nexport async function getProjectById(projectId: string) {\n const client = await getProjectCliClient({\n apiVersion: PROJECTS_API_VERSION,\n projectId,\n requireUser: true,\n })\n\n return client.projects.getById(projectId)\n}\n\nexport async function getProjectRoles(projectId: string) {\n const client = await getGlobalCliClient({\n apiVersion: PROJECTS_API_VERSION,\n requireUser: true,\n })\n\n return client.request<Role[]>({uri: `/projects/${projectId}/roles`})\n}\n\ninterface InviteUserOptions {\n email: string\n projectId: string\n role: string\n}\n\nexport async function inviteUser({email, projectId, role}: InviteUserOptions) {\n const client = await getGlobalCliClient({\n apiVersion: PROJECTS_API_VERSION,\n requireUser: true,\n })\n\n return client.request({\n body: {email, role},\n maxRedirects: 0,\n method: 'POST',\n uri: `/invitations/project/${projectId}`,\n useGlobalApi: true,\n })\n}\n\nexport async function listProjects({\n onlyExplicitMembership = true,\n}: {\n onlyExplicitMembership?: boolean\n} = {}) {\n const client = await getGlobalCliClient({\n apiVersion: PROJECTS_API_VERSION,\n requireUser: true,\n })\n\n return client.projects.list({onlyExplicitMembership})\n}\n\nexport async function getProjectInvites(projectId: string) {\n const client = await getGlobalCliClient({\n apiVersion: PROJECTS_API_VERSION,\n requireUser: true,\n })\n\n return client.request<Invite[]>({uri: `/invitations/project/${projectId}`})\n}\n\nexport async function updateProjectInitializedAt(projectId: string) {\n const client = await getProjectCliClient({\n apiVersion: PROJECTS_API_VERSION,\n projectId,\n requireUser: true,\n })\n\n const project = await client.request<SanityProject>({uri: `/projects/${projectId}`})\n\n if (!project?.metadata?.cliInitializedAt) {\n await client.request({\n body: {metadata: {cliInitializedAt: new Date().toISOString()}},\n method: 'PATCH',\n uri: `/projects/${projectId}`,\n })\n }\n}\n\nexport async function updateProjectInitalTemplate(projectId: string, templateName: string) {\n const client = await getProjectCliClient({\n apiVersion: PROJECTS_API_VERSION,\n projectId,\n requireUser: true,\n })\n\n await client.request({\n body: {metadata: {initialTemplate: templateName}},\n method: 'PATCH',\n uri: `/projects/${projectId}`,\n })\n}\n"],"names":["debug","getGlobalCliClient","getProjectCliClient","PROJECTS_API_VERSION","CREATE_PROJECT_API_VERSION","createProject","options","client","apiVersion","requireUser","response","request","body","metadata","integration","method","uri","displayName","projectId","id","err","getProjectById","projects","getById","getProjectRoles","inviteUser","email","role","maxRedirects","useGlobalApi","listProjects","onlyExplicitMembership","list","getProjectInvites","updateProjectInitializedAt","project","cliInitializedAt","Date","toISOString","updateProjectInitalTemplate","templateName","initialTemplate"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/services/projects.ts"],"sourcesContent":["import {debug, getGlobalCliClient, getProjectCliClient} from '@sanity/cli-core'\nimport {SanityProject} from '@sanity/client'\n\nimport {type Invite, type Role} from '../actions/users/types.js'\n\nexport const PROJECTS_API_VERSION = '2025-09-22'\n\nexport const CREATE_PROJECT_API_VERSION = 'v2025-05-14'\n\nconst UNCLAIMED_PROJECT_ORGANIZATION_ID = 'oSystemUnclaimed'\n\nexport type ProjectClaimStatus = 'claimed' | 'unclaimed' | 'unknown'\n\ninterface CreateProjectOptions {\n displayName: string\n\n metadata?: {\n coupon?: string\n integration?: string\n }\n organizationId?: string\n subscription?: {planId: string}\n}\n\nexport interface CreateProjectResult {\n displayName: string\n projectId: string\n}\n\n/**\n * Create a new Sanity project\n */\nexport async function createProject(options: CreateProjectOptions): Promise<CreateProjectResult> {\n const client = await getGlobalCliClient({\n apiVersion: CREATE_PROJECT_API_VERSION,\n requireUser: true,\n })\n\n try {\n const response = await client.request({\n body: {\n ...options,\n metadata: {\n ...options?.metadata,\n integration: 'cli',\n },\n },\n method: 'POST',\n uri: '/projects',\n })\n\n return {\n displayName: options.displayName || '',\n projectId: response.projectId || response.id,\n }\n } catch (err) {\n debug('Error creating project', err)\n throw err\n }\n}\n\nexport async function getProjectById(projectId: string) {\n const client = await getProjectCliClient({\n apiVersion: PROJECTS_API_VERSION,\n projectId,\n requireUser: true,\n })\n\n return client.projects.getById(projectId)\n}\n\nexport async function getProjectClaimStatus(\n projectId: string,\n token: string,\n): Promise<ProjectClaimStatus> {\n try {\n const client = await getProjectCliClient({\n apiVersion: PROJECTS_API_VERSION,\n projectId,\n requireUser: true,\n token,\n })\n const project = await client.projects.getById(projectId)\n\n if (typeof project.organizationId !== 'string' || project.organizationId.length === 0) {\n return 'unknown'\n }\n\n return project.organizationId === UNCLAIMED_PROJECT_ORGANIZATION_ID ? 'unclaimed' : 'claimed'\n } catch (error) {\n debug(\n 'failed to check claim status for project %s: %s',\n projectId,\n error instanceof Error ? error.message : `${error}`,\n )\n return 'unknown'\n }\n}\n\nexport async function getProjectRoles(projectId: string) {\n const client = await getGlobalCliClient({\n apiVersion: PROJECTS_API_VERSION,\n requireUser: true,\n })\n\n return client.request<Role[]>({uri: `/projects/${projectId}/roles`})\n}\n\ninterface InviteUserOptions {\n email: string\n projectId: string\n role: string\n}\n\nexport async function inviteUser({email, projectId, role}: InviteUserOptions) {\n const client = await getGlobalCliClient({\n apiVersion: PROJECTS_API_VERSION,\n requireUser: true,\n })\n\n return client.request({\n body: {email, role},\n maxRedirects: 0,\n method: 'POST',\n uri: `/invitations/project/${projectId}`,\n useGlobalApi: true,\n })\n}\n\nexport async function listProjects({\n onlyExplicitMembership = true,\n}: {\n onlyExplicitMembership?: boolean\n} = {}) {\n const client = await getGlobalCliClient({\n apiVersion: PROJECTS_API_VERSION,\n requireUser: true,\n })\n\n return client.projects.list({onlyExplicitMembership})\n}\n\nexport async function getProjectInvites(projectId: string) {\n const client = await getGlobalCliClient({\n apiVersion: PROJECTS_API_VERSION,\n requireUser: true,\n })\n\n return client.request<Invite[]>({uri: `/invitations/project/${projectId}`})\n}\n\nexport async function updateProjectInitializedAt(projectId: string) {\n const client = await getProjectCliClient({\n apiVersion: PROJECTS_API_VERSION,\n projectId,\n requireUser: true,\n })\n\n const project = await client.request<SanityProject>({uri: `/projects/${projectId}`})\n\n if (!project?.metadata?.cliInitializedAt) {\n await client.request({\n body: {metadata: {cliInitializedAt: new Date().toISOString()}},\n method: 'PATCH',\n uri: `/projects/${projectId}`,\n })\n }\n}\n\nexport async function updateProjectInitalTemplate(projectId: string, templateName: string) {\n const client = await getProjectCliClient({\n apiVersion: PROJECTS_API_VERSION,\n projectId,\n requireUser: true,\n })\n\n await client.request({\n body: {metadata: {initialTemplate: templateName}},\n method: 'PATCH',\n uri: `/projects/${projectId}`,\n })\n}\n"],"names":["debug","getGlobalCliClient","getProjectCliClient","PROJECTS_API_VERSION","CREATE_PROJECT_API_VERSION","UNCLAIMED_PROJECT_ORGANIZATION_ID","createProject","options","client","apiVersion","requireUser","response","request","body","metadata","integration","method","uri","displayName","projectId","id","err","getProjectById","projects","getById","getProjectClaimStatus","token","project","organizationId","length","error","Error","message","getProjectRoles","inviteUser","email","role","maxRedirects","useGlobalApi","listProjects","onlyExplicitMembership","list","getProjectInvites","updateProjectInitializedAt","cliInitializedAt","Date","toISOString","updateProjectInitalTemplate","templateName","initialTemplate"],"mappings":"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"}
@@ -1,5 +1,6 @@
1
1
  import { createHash } from 'node:crypto';
2
2
  import { getCliToken, getGlobalCliClient, getUserConfig } from '@sanity/cli-core';
3
+ import { getCliExecutionContext } from '@sanity/cli-core/executionContext';
3
4
  import { telemetryDebug } from '../actions/telemetry/telemetryDebug.js';
4
5
  import { createExpiringConfig } from '../util/createExpiringConfig.js';
5
6
  export const TELEMETRY_API_VERSION = 'v2026-01-22';
@@ -74,6 +75,9 @@ const FIVE_MINUTES = 1000 * 60 * 5;
74
75
  *
75
76
  * @internal
76
77
  */ export async function fetchTelemetryConsent() {
78
+ // Programmatic invocations must not use the host user's disk-backed consent
79
+ // cache. The request is already authenticated with the invocation token.
80
+ if (getCliExecutionContext()) return getTelemetryConsent();
77
81
  const token = await getCliToken();
78
82
  const cacheKey = getTelemetryConsentCacheKey(token);
79
83
  // NOTE: createExpiringConfig is instantiated on every call, so in-flight request
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/services/telemetry.ts"],"sourcesContent":["import {createHash} from 'node:crypto'\n\nimport {getCliToken, getGlobalCliClient, getUserConfig} from '@sanity/cli-core'\nimport {type TelemetryEvent} from '@sanity/telemetry'\n\nimport {telemetryDebug} from '../actions/telemetry/telemetryDebug.js'\nimport {createExpiringConfig} from '../util/createExpiringConfig.js'\n\nexport const TELEMETRY_API_VERSION = 'v2026-01-22'\n\nexport const VALID_API_STATUSES = ['granted', 'denied', 'unset'] as const\nexport type ValidApiConsentStatus = (typeof VALID_API_STATUSES)[number]\n\nexport async function sendEvents(batch: TelemetryEvent[]) {\n const client = await getGlobalCliClient({\n apiVersion: TELEMETRY_API_VERSION,\n requireUser: true,\n })\n\n const projectId = process.env.SANITY_TELEMETRY_PROJECT_ID\n\n return client.request({\n body: {batch, projectId},\n json: true,\n method: 'POST',\n uri: '/intake/batch',\n })\n}\n\nasync function getTelemetryConsent(): Promise<{\n status: ValidApiConsentStatus\n}> {\n const client = await getGlobalCliClient({\n apiVersion: TELEMETRY_API_VERSION,\n requireUser: false,\n })\n\n return client.request({tag: 'telemetry-consent', uri: '/intake/telemetry-status'})\n}\n\n/**\n * Check if the given status is a valid consent status\n *\n * @param status - The status to check\n * @returns True if the status is valid, false otherwise\n * @internal\n */\nexport function isValidApiConsentStatus(status: string): status is ValidApiConsentStatus {\n return VALID_API_STATUSES.includes(status as ValidApiConsentStatus)\n}\n\n/**\n * Check if the given response is a valid API consent response\n *\n * @param response - The response to check\n * @returns True if the response is valid, false otherwise\n * @internal\n */\nfunction isValidApiConsentResponse(response: unknown): response is {status: ValidApiConsentStatus} {\n return (\n typeof response === 'object' &&\n response !== null &&\n 'status' in response &&\n typeof response.status === 'string' &&\n isValidApiConsentStatus(response.status)\n )\n}\n\nexport const TELEMETRY_CONSENT_CONFIG_KEY = 'telemetryConsent'\nconst FIVE_MINUTES = 1000 * 60 * 5\n\n/**\n * Get a token-scoped cache key for telemetry consent. This ensures that switching\n * users (via login/logout) always results in a cache miss, preventing one user\n * from inheriting another user's cached consent status.\n *\n * @param token - The current auth token, or undefined if not logged in\n * @returns A cache key scoped to the token\n */\nexport function getTelemetryConsentCacheKey(token: string | undefined): string {\n if (!token) {\n return TELEMETRY_CONSENT_CONFIG_KEY\n }\n\n const hash = createHash('sha256').update(token).digest('hex').slice(0, 12)\n return `${TELEMETRY_CONSENT_CONFIG_KEY}:${hash}`\n}\n\n/**\n * Fetch the telemetry consent status for the current user\n * @returns The telemetry consent status\n *\n * @internal\n */\nexport async function fetchTelemetryConsent(): Promise<{\n status: ValidApiConsentStatus\n}> {\n const token = await getCliToken()\n const cacheKey = getTelemetryConsentCacheKey(token)\n\n // NOTE: createExpiringConfig is instantiated on every call, so in-flight request\n // deduplication (via currentFetch) does not work across concurrent calls to\n // fetchTelemetryConsent(). Two concurrent callers will make two HTTP requests.\n // Consider moving to module-level instance if this becomes a bottleneck.\n const telemetryConsentConfig = createExpiringConfig<{\n status: ValidApiConsentStatus\n }>({\n fetchValue: () => getTelemetryConsent(),\n key: cacheKey,\n onCacheHit() {\n telemetryDebug('Retrieved telemetry consent status from cache')\n },\n onFetch() {\n telemetryDebug('Fetching telemetry consent status...')\n },\n onRevalidate() {\n telemetryDebug('Revalidating cached telemetry consent status...')\n },\n store: getUserConfig(),\n ttl: FIVE_MINUTES,\n validateValue: isValidApiConsentResponse,\n })\n\n return telemetryConsentConfig.get()\n}\n"],"names":["createHash","getCliToken","getGlobalCliClient","getUserConfig","telemetryDebug","createExpiringConfig","TELEMETRY_API_VERSION","VALID_API_STATUSES","sendEvents","batch","client","apiVersion","requireUser","projectId","process","env","SANITY_TELEMETRY_PROJECT_ID","request","body","json","method","uri","getTelemetryConsent","tag","isValidApiConsentStatus","status","includes","isValidApiConsentResponse","response","TELEMETRY_CONSENT_CONFIG_KEY","FIVE_MINUTES","getTelemetryConsentCacheKey","token","hash","update","digest","slice","fetchTelemetryConsent","cacheKey","telemetryConsentConfig","fetchValue","key","onCacheHit","onFetch","onRevalidate","store","ttl","validateValue","get"],"mappings":"AAAA,SAAQA,UAAU,QAAO,cAAa;AAEtC,SAAQC,WAAW,EAAEC,kBAAkB,EAAEC,aAAa,QAAO,mBAAkB;AAG/E,SAAQC,cAAc,QAAO,yCAAwC;AACrE,SAAQC,oBAAoB,QAAO,kCAAiC;AAEpE,OAAO,MAAMC,wBAAwB,cAAa;AAElD,OAAO,MAAMC,qBAAqB;IAAC;IAAW;IAAU;CAAQ,CAAS;AAGzE,OAAO,eAAeC,WAAWC,KAAuB;IACtD,MAAMC,SAAS,MAAMR,mBAAmB;QACtCS,YAAYL;QACZM,aAAa;IACf;IAEA,MAAMC,YAAYC,QAAQC,GAAG,CAACC,2BAA2B;IAEzD,OAAON,OAAOO,OAAO,CAAC;QACpBC,MAAM;YAACT;YAAOI;QAAS;QACvBM,MAAM;QACNC,QAAQ;QACRC,KAAK;IACP;AACF;AAEA,eAAeC;IAGb,MAAMZ,SAAS,MAAMR,mBAAmB;QACtCS,YAAYL;QACZM,aAAa;IACf;IAEA,OAAOF,OAAOO,OAAO,CAAC;QAACM,KAAK;QAAqBF,KAAK;IAA0B;AAClF;AAEA;;;;;;CAMC,GACD,OAAO,SAASG,wBAAwBC,MAAc;IACpD,OAAOlB,mBAAmBmB,QAAQ,CAACD;AACrC;AAEA;;;;;;CAMC,GACD,SAASE,0BAA0BC,QAAiB;IAClD,OACE,OAAOA,aAAa,YACpBA,aAAa,QACb,YAAYA,YACZ,OAAOA,SAASH,MAAM,KAAK,YAC3BD,wBAAwBI,SAASH,MAAM;AAE3C;AAEA,OAAO,MAAMI,+BAA+B,mBAAkB;AAC9D,MAAMC,eAAe,OAAO,KAAK;AAEjC;;;;;;;CAOC,GACD,OAAO,SAASC,4BAA4BC,KAAyB;IACnE,IAAI,CAACA,OAAO;QACV,OAAOH;IACT;IAEA,MAAMI,OAAOjC,WAAW,UAAUkC,MAAM,CAACF,OAAOG,MAAM,CAAC,OAAOC,KAAK,CAAC,GAAG;IACvE,OAAO,GAAGP,6BAA6B,CAAC,EAAEI,MAAM;AAClD;AAEA;;;;;CAKC,GACD,OAAO,eAAeI;IAGpB,MAAML,QAAQ,MAAM/B;IACpB,MAAMqC,WAAWP,4BAA4BC;IAE7C,iFAAiF;IACjF,4EAA4E;IAC5E,+EAA+E;IAC/E,yEAAyE;IACzE,MAAMO,yBAAyBlC,qBAE5B;QACDmC,YAAY,IAAMlB;QAClBmB,KAAKH;QACLI;YACEtC,eAAe;QACjB;QACAuC;YACEvC,eAAe;QACjB;QACAwC;YACExC,eAAe;QACjB;QACAyC,OAAO1C;QACP2C,KAAKhB;QACLiB,eAAepB;IACjB;IAEA,OAAOY,uBAAuBS,GAAG;AACnC"}
1
+ {"version":3,"sources":["../../src/services/telemetry.ts"],"sourcesContent":["import {createHash} from 'node:crypto'\n\nimport {getCliToken, getGlobalCliClient, getUserConfig} from '@sanity/cli-core'\nimport {getCliExecutionContext} from '@sanity/cli-core/executionContext'\nimport {type TelemetryEvent} from '@sanity/telemetry'\n\nimport {telemetryDebug} from '../actions/telemetry/telemetryDebug.js'\nimport {createExpiringConfig} from '../util/createExpiringConfig.js'\n\nexport const TELEMETRY_API_VERSION = 'v2026-01-22'\n\nexport const VALID_API_STATUSES = ['granted', 'denied', 'unset'] as const\nexport type ValidApiConsentStatus = (typeof VALID_API_STATUSES)[number]\n\nexport async function sendEvents(batch: TelemetryEvent[]) {\n const client = await getGlobalCliClient({\n apiVersion: TELEMETRY_API_VERSION,\n requireUser: true,\n })\n\n const projectId = process.env.SANITY_TELEMETRY_PROJECT_ID\n\n return client.request({\n body: {batch, projectId},\n json: true,\n method: 'POST',\n uri: '/intake/batch',\n })\n}\n\nasync function getTelemetryConsent(): Promise<{\n status: ValidApiConsentStatus\n}> {\n const client = await getGlobalCliClient({\n apiVersion: TELEMETRY_API_VERSION,\n requireUser: false,\n })\n\n return client.request({tag: 'telemetry-consent', uri: '/intake/telemetry-status'})\n}\n\n/**\n * Check if the given status is a valid consent status\n *\n * @param status - The status to check\n * @returns True if the status is valid, false otherwise\n * @internal\n */\nexport function isValidApiConsentStatus(status: string): status is ValidApiConsentStatus {\n return VALID_API_STATUSES.includes(status as ValidApiConsentStatus)\n}\n\n/**\n * Check if the given response is a valid API consent response\n *\n * @param response - The response to check\n * @returns True if the response is valid, false otherwise\n * @internal\n */\nfunction isValidApiConsentResponse(response: unknown): response is {status: ValidApiConsentStatus} {\n return (\n typeof response === 'object' &&\n response !== null &&\n 'status' in response &&\n typeof response.status === 'string' &&\n isValidApiConsentStatus(response.status)\n )\n}\n\nexport const TELEMETRY_CONSENT_CONFIG_KEY = 'telemetryConsent'\nconst FIVE_MINUTES = 1000 * 60 * 5\n\n/**\n * Get a token-scoped cache key for telemetry consent. This ensures that switching\n * users (via login/logout) always results in a cache miss, preventing one user\n * from inheriting another user's cached consent status.\n *\n * @param token - The current auth token, or undefined if not logged in\n * @returns A cache key scoped to the token\n */\nexport function getTelemetryConsentCacheKey(token: string | undefined): string {\n if (!token) {\n return TELEMETRY_CONSENT_CONFIG_KEY\n }\n\n const hash = createHash('sha256').update(token).digest('hex').slice(0, 12)\n return `${TELEMETRY_CONSENT_CONFIG_KEY}:${hash}`\n}\n\n/**\n * Fetch the telemetry consent status for the current user\n * @returns The telemetry consent status\n *\n * @internal\n */\nexport async function fetchTelemetryConsent(): Promise<{\n status: ValidApiConsentStatus\n}> {\n // Programmatic invocations must not use the host user's disk-backed consent\n // cache. The request is already authenticated with the invocation token.\n if (getCliExecutionContext()) return getTelemetryConsent()\n\n const token = await getCliToken()\n const cacheKey = getTelemetryConsentCacheKey(token)\n\n // NOTE: createExpiringConfig is instantiated on every call, so in-flight request\n // deduplication (via currentFetch) does not work across concurrent calls to\n // fetchTelemetryConsent(). Two concurrent callers will make two HTTP requests.\n // Consider moving to module-level instance if this becomes a bottleneck.\n const telemetryConsentConfig = createExpiringConfig<{\n status: ValidApiConsentStatus\n }>({\n fetchValue: () => getTelemetryConsent(),\n key: cacheKey,\n onCacheHit() {\n telemetryDebug('Retrieved telemetry consent status from cache')\n },\n onFetch() {\n telemetryDebug('Fetching telemetry consent status...')\n },\n onRevalidate() {\n telemetryDebug('Revalidating cached telemetry consent status...')\n },\n store: getUserConfig(),\n ttl: FIVE_MINUTES,\n validateValue: isValidApiConsentResponse,\n })\n\n return telemetryConsentConfig.get()\n}\n"],"names":["createHash","getCliToken","getGlobalCliClient","getUserConfig","getCliExecutionContext","telemetryDebug","createExpiringConfig","TELEMETRY_API_VERSION","VALID_API_STATUSES","sendEvents","batch","client","apiVersion","requireUser","projectId","process","env","SANITY_TELEMETRY_PROJECT_ID","request","body","json","method","uri","getTelemetryConsent","tag","isValidApiConsentStatus","status","includes","isValidApiConsentResponse","response","TELEMETRY_CONSENT_CONFIG_KEY","FIVE_MINUTES","getTelemetryConsentCacheKey","token","hash","update","digest","slice","fetchTelemetryConsent","cacheKey","telemetryConsentConfig","fetchValue","key","onCacheHit","onFetch","onRevalidate","store","ttl","validateValue","get"],"mappings":"AAAA,SAAQA,UAAU,QAAO,cAAa;AAEtC,SAAQC,WAAW,EAAEC,kBAAkB,EAAEC,aAAa,QAAO,mBAAkB;AAC/E,SAAQC,sBAAsB,QAAO,oCAAmC;AAGxE,SAAQC,cAAc,QAAO,yCAAwC;AACrE,SAAQC,oBAAoB,QAAO,kCAAiC;AAEpE,OAAO,MAAMC,wBAAwB,cAAa;AAElD,OAAO,MAAMC,qBAAqB;IAAC;IAAW;IAAU;CAAQ,CAAS;AAGzE,OAAO,eAAeC,WAAWC,KAAuB;IACtD,MAAMC,SAAS,MAAMT,mBAAmB;QACtCU,YAAYL;QACZM,aAAa;IACf;IAEA,MAAMC,YAAYC,QAAQC,GAAG,CAACC,2BAA2B;IAEzD,OAAON,OAAOO,OAAO,CAAC;QACpBC,MAAM;YAACT;YAAOI;QAAS;QACvBM,MAAM;QACNC,QAAQ;QACRC,KAAK;IACP;AACF;AAEA,eAAeC;IAGb,MAAMZ,SAAS,MAAMT,mBAAmB;QACtCU,YAAYL;QACZM,aAAa;IACf;IAEA,OAAOF,OAAOO,OAAO,CAAC;QAACM,KAAK;QAAqBF,KAAK;IAA0B;AAClF;AAEA;;;;;;CAMC,GACD,OAAO,SAASG,wBAAwBC,MAAc;IACpD,OAAOlB,mBAAmBmB,QAAQ,CAACD;AACrC;AAEA;;;;;;CAMC,GACD,SAASE,0BAA0BC,QAAiB;IAClD,OACE,OAAOA,aAAa,YACpBA,aAAa,QACb,YAAYA,YACZ,OAAOA,SAASH,MAAM,KAAK,YAC3BD,wBAAwBI,SAASH,MAAM;AAE3C;AAEA,OAAO,MAAMI,+BAA+B,mBAAkB;AAC9D,MAAMC,eAAe,OAAO,KAAK;AAEjC;;;;;;;CAOC,GACD,OAAO,SAASC,4BAA4BC,KAAyB;IACnE,IAAI,CAACA,OAAO;QACV,OAAOH;IACT;IAEA,MAAMI,OAAOlC,WAAW,UAAUmC,MAAM,CAACF,OAAOG,MAAM,CAAC,OAAOC,KAAK,CAAC,GAAG;IACvE,OAAO,GAAGP,6BAA6B,CAAC,EAAEI,MAAM;AAClD;AAEA;;;;;CAKC,GACD,OAAO,eAAeI;IAGpB,4EAA4E;IAC5E,yEAAyE;IACzE,IAAIlC,0BAA0B,OAAOmB;IAErC,MAAMU,QAAQ,MAAMhC;IACpB,MAAMsC,WAAWP,4BAA4BC;IAE7C,iFAAiF;IACjF,4EAA4E;IAC5E,+EAA+E;IAC/E,yEAAyE;IACzE,MAAMO,yBAAyBlC,qBAE5B;QACDmC,YAAY,IAAMlB;QAClBmB,KAAKH;QACLI;YACEtC,eAAe;QACjB;QACAuC;YACEvC,eAAe;QACjB;QACAwC;YACExC,eAAe;QACjB;QACAyC,OAAO3C;QACP4C,KAAKhB;QACLiB,eAAepB;IACjB;IAEA,OAAOY,uBAAuBS,GAAG;AACnC"}
@@ -0,0 +1,15 @@
1
+ export function formatClaimDeadline(expiresAt) {
2
+ const deadline = new Date(expiresAt);
3
+ if (!Number.isFinite(deadline.getTime())) return expiresAt;
4
+ return new Intl.DateTimeFormat('en-GB', {
5
+ day: 'numeric',
6
+ hour: '2-digit',
7
+ hour12: false,
8
+ minute: '2-digit',
9
+ month: 'long',
10
+ timeZone: 'UTC',
11
+ year: 'numeric'
12
+ }).format(deadline).replace(' at ', ', ') + ' UTC';
13
+ }
14
+
15
+ //# sourceMappingURL=formatClaimDeadline.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/util/formatClaimDeadline.ts"],"sourcesContent":["export function formatClaimDeadline(expiresAt: string): string {\n const deadline = new Date(expiresAt)\n if (!Number.isFinite(deadline.getTime())) return expiresAt\n return (\n new Intl.DateTimeFormat('en-GB', {\n day: 'numeric',\n hour: '2-digit',\n hour12: false,\n minute: '2-digit',\n month: 'long',\n timeZone: 'UTC',\n year: 'numeric',\n })\n .format(deadline)\n .replace(' at ', ', ') + ' UTC'\n )\n}\n"],"names":["formatClaimDeadline","expiresAt","deadline","Date","Number","isFinite","getTime","Intl","DateTimeFormat","day","hour","hour12","minute","month","timeZone","year","format","replace"],"mappings":"AAAA,OAAO,SAASA,oBAAoBC,SAAiB;IACnD,MAAMC,WAAW,IAAIC,KAAKF;IAC1B,IAAI,CAACG,OAAOC,QAAQ,CAACH,SAASI,OAAO,KAAK,OAAOL;IACjD,OACE,IAAIM,KAAKC,cAAc,CAAC,SAAS;QAC/BC,KAAK;QACLC,MAAM;QACNC,QAAQ;QACRC,QAAQ;QACRC,OAAO;QACPC,UAAU;QACVC,MAAM;IACR,GACGC,MAAM,CAACd,UACPe,OAAO,CAAC,QAAQ,QAAQ;AAE/B"}
@@ -0,0 +1,6 @@
1
+ /** Product window in which an unclaimed project must be claimed. */ export const CLAIM_WINDOW_HOURS = 72;
2
+ export const SANITY_NEW_URL = 'https://sanity.new';
3
+ export const TERMS_OF_SERVICE_FALLBACK_URL = 'https://www.sanity.io/legal/tos';
4
+ export const TERMS_OF_SERVICE_FALLBACK_NOTICE = 'By continuing to use this project you accept the Sanity Terms of Service.';
5
+
6
+ //# sourceMappingURL=mintProjectConstants.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/util/mintProjectConstants.ts"],"sourcesContent":["/** Product window in which an unclaimed project must be claimed. */\nexport const CLAIM_WINDOW_HOURS = 72\n\nexport const SANITY_NEW_URL = 'https://sanity.new'\n\nexport const TERMS_OF_SERVICE_FALLBACK_URL = 'https://www.sanity.io/legal/tos'\n\nexport const TERMS_OF_SERVICE_FALLBACK_NOTICE =\n 'By continuing to use this project you accept the Sanity Terms of Service.'\n"],"names":["CLAIM_WINDOW_HOURS","SANITY_NEW_URL","TERMS_OF_SERVICE_FALLBACK_URL","TERMS_OF_SERVICE_FALLBACK_NOTICE"],"mappings":"AAAA,kEAAkE,GAClE,OAAO,MAAMA,qBAAqB,GAAE;AAEpC,OAAO,MAAMC,iBAAiB,qBAAoB;AAElD,OAAO,MAAMC,gCAAgC,kCAAiC;AAE9E,OAAO,MAAMC,mCACX,4EAA2E"}
@@ -0,0 +1,27 @@
1
+ import { styleText } from 'node:util';
2
+ const ART = [
3
+ ' - #: @@@@',
4
+ ' @@@ @@@@@ -@@@= @@@',
5
+ ' @@@@ %@@@@@@. @@@@ %@@@@@@',
6
+ ' @@@% @@@@@@@# %@@@@@@@@@-',
7
+ ' @@@@@@@@@@@@@ @@@@@@@@.',
8
+ ' @@@@@@@= @@@# @@@@@@@ @@@@@',
9
+ ' @@@@ @@@@ @@@@@@ @@@@@@@',
10
+ ' @@@@ @@@@@@@@ @@@@@@@@',
11
+ ' +@@@@@@@@@@@@@ @@@@@@@@@@',
12
+ ' @@@@@@@@ @@@@ @@@@@@ @@@@',
13
+ ' @@@@@% *@@@% .@@@@@% .@@@@ .@@@@',
14
+ ' .- @@@@ .@@@@@% #@@@.@@@@@@@@',
15
+ ' *@@@@@@@@@% @@@@@@@@#@@@@',
16
+ ' @@@@@@@@ #@@@@@@# @@@@',
17
+ ' @@@@@@@ @@@@# @@@@',
18
+ ' #@@@@ * @@@+',
19
+ ' ='
20
+ ];
21
+ export function renderNewCommandSplash(log) {
22
+ log('');
23
+ for (const line of ART)log(styleText('cyan', line));
24
+ log('');
25
+ }
26
+
27
+ //# sourceMappingURL=newCommandSplash.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/util/newCommandSplash.ts"],"sourcesContent":["import {styleText} from 'node:util'\n\ntype LogFn = (message?: string) => void\n\nconst ART = [\n ' - #: @@@@',\n ' @@@ @@@@@ -@@@= @@@',\n ' @@@@ %@@@@@@. @@@@ %@@@@@@',\n ' @@@% @@@@@@@# %@@@@@@@@@-',\n ' @@@@@@@@@@@@@ @@@@@@@@.',\n ' @@@@@@@= @@@# @@@@@@@ @@@@@',\n ' @@@@ @@@@ @@@@@@ @@@@@@@',\n ' @@@@ @@@@@@@@ @@@@@@@@',\n ' +@@@@@@@@@@@@@ @@@@@@@@@@',\n ' @@@@@@@@ @@@@ @@@@@@ @@@@',\n ' @@@@@% *@@@% .@@@@@% .@@@@ .@@@@',\n ' .- @@@@ .@@@@@% #@@@.@@@@@@@@',\n ' *@@@@@@@@@% @@@@@@@@#@@@@',\n ' @@@@@@@@ #@@@@@@# @@@@',\n ' @@@@@@@ @@@@# @@@@',\n ' #@@@@ * @@@+',\n ' =',\n]\n\nexport function renderNewCommandSplash(log: LogFn): void {\n log('')\n for (const line of ART) log(styleText('cyan', line))\n log('')\n}\n"],"names":["styleText","ART","renderNewCommandSplash","log","line"],"mappings":"AAAA,SAAQA,SAAS,QAAO,YAAW;AAInC,MAAMC,MAAM;IACV;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;CACD;AAED,OAAO,SAASC,uBAAuBC,GAAU;IAC/CA,IAAI;IACJ,KAAK,MAAMC,QAAQH,IAAKE,IAAIH,UAAU,QAAQI;IAC9CD,IAAI;AACN"}
@@ -1,3 +1,5 @@
1
+ import { CLIError } from '@oclif/core/errors';
2
+ import { exitCodes } from '@sanity/cli-core';
1
3
  import { spinner } from '@sanity/cli-core/ux';
2
4
  import { execa } from 'execa';
3
5
  import { getPartialEnvWithNpmPath } from './packageManagerChoice.js';
@@ -58,34 +60,59 @@ function isEsbuild(ignoredEntry) {
58
60
  return ignoredEntry.replace(/@[^@]+$/, '') === 'esbuild';
59
61
  }
60
62
  async function executePackageManagerCommand(packageManager, args, execOptions, output, errorMessage) {
61
- const progress = spinner(`Running ${packageManager} ${args.join(' ')}\n`).start();
62
- const result = await execa(packageManager, args, execOptions);
63
- if (result?.exitCode || result?.failed) {
64
- // pnpm exits non-zero if dependency build scripts were skipped, even though
65
- // the install itself succeeded. Treat it as a success, but point to
66
- // `pnpm approve-builds` if anything other than esbuild was skipped
67
- // (esbuild works without its build script through a JS fallback).
68
- const commandOutput = [
69
- result.stdout,
70
- result.stderr
71
- ].filter((chunk)=>typeof chunk === 'string').join('\n');
72
- const ignoredBuilds = packageManager === 'pnpm' ? getIgnoredBuildScripts(commandOutput) : undefined;
73
- if (ignoredBuilds) {
74
- progress.succeed();
75
- if (ignoredBuilds.some((entry)=>!isEsbuild(entry))) {
76
- output.warn(IGNORED_BUILDS_NOTICE);
77
- }
78
- return;
79
- }
63
+ const progress = spinner({
64
+ discardStdin: !execOptions.cancelSignal,
65
+ text: `Running ${packageManager} ${args.join(' ')}\n`
66
+ }).start();
67
+ let progressSettled = false;
68
+ const fail = ()=>{
69
+ progressSettled = true;
80
70
  progress.fail();
81
- // Log both streams - package managers often print the actionable error
82
- // details to stderr, so logging stdout alone can hide the failure reason.
83
- output.log(commandOutput);
84
- output.error(errorMessage, {
85
- exit: 1
86
- });
87
- } else {
71
+ };
72
+ const succeed = ()=>{
73
+ progressSettled = true;
88
74
  progress.succeed();
75
+ };
76
+ try {
77
+ const result = await execa(packageManager, args, execOptions);
78
+ if (execOptions.cancelSignal?.aborted) {
79
+ fail();
80
+ execOptions.cancelSignal.throwIfAborted();
81
+ }
82
+ if (result?.exitCode || result?.failed) {
83
+ // pnpm exits non-zero if dependency build scripts were skipped, even though
84
+ // the install itself succeeded. Treat it as a success, but point to
85
+ // `pnpm approve-builds` if anything other than esbuild was skipped
86
+ // (esbuild works without its build script through a JS fallback).
87
+ const commandOutput = [
88
+ result.stdout,
89
+ result.stderr
90
+ ].filter((chunk)=>typeof chunk === 'string').join('\n');
91
+ const ignoredBuilds = packageManager === 'pnpm' ? getIgnoredBuildScripts(commandOutput) : undefined;
92
+ if (ignoredBuilds) {
93
+ succeed();
94
+ if (ignoredBuilds.some((entry)=>!isEsbuild(entry))) {
95
+ output.warn(IGNORED_BUILDS_NOTICE);
96
+ }
97
+ return;
98
+ }
99
+ fail();
100
+ // Log both streams - package managers often print the actionable error
101
+ // details to stderr, so logging stdout alone can hide the failure reason.
102
+ output.log(commandOutput);
103
+ throw new CLIError(errorMessage, {
104
+ exit: exitCodes.RUNTIME_ERROR
105
+ });
106
+ } else {
107
+ succeed();
108
+ }
109
+ } catch (err) {
110
+ if (!progressSettled) {
111
+ fail();
112
+ }
113
+ throw err;
114
+ } finally{
115
+ progress.stop();
89
116
  }
90
117
  }
91
118
  export async function installDeclaredPackages(cwd, packageManager, context) {
@@ -107,13 +134,15 @@ export async function installDeclaredPackages(cwd, packageManager, context) {
107
134
  }
108
135
  export async function installNewPackages(options, context) {
109
136
  const { packageManager, packages } = options;
110
- const { output, workDir } = context;
137
+ const { cancelSignal, output, timeout, workDir } = context;
111
138
  const execOptions = {
139
+ cancelSignal,
112
140
  cwd: workDir,
113
141
  encoding: 'utf8',
114
142
  env: getPartialEnvWithNpmPath(workDir),
115
143
  reject: false,
116
- stdio: 'pipe'
144
+ stdio: 'pipe',
145
+ timeout
117
146
  };
118
147
  if (packageManager === 'manual') {
119
148
  const npmCommand = PACKAGE_MANAGER_COMMANDS.add.npm(packages);
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/util/packageManager/installPackages.ts"],"sourcesContent":["import {type Output} from '@sanity/cli-core'\nimport {spinner} from '@sanity/cli-core/ux'\nimport {execa, type Options} from 'execa'\n\nimport {getPartialEnvWithNpmPath, type PackageManager} from './packageManagerChoice.js'\n\ntype PackageManagerLibs = Exclude<PackageManager, 'manual'>\n\n/**\n * @internal\n */\ninterface InstallOptions {\n packageManager: PackageManager\n packages: string[]\n}\n\ninterface PackageManagerCommands {\n add: {[key in PackageManagerLibs]: (packages: string[]) => string[]}\n install: {[key in PackageManagerLibs]: string[]}\n}\n\nconst PACKAGE_MANAGER_COMMANDS: PackageManagerCommands = {\n add: {\n bun: (packages) => ['add', ...packages],\n npm: (packages) => ['install', '--save', ...packages],\n pnpm: (packages) => ['add', '--save-prod', ...packages],\n yarn: (packages) => ['add', ...packages],\n },\n install: {\n bun: ['install'],\n npm: ['install'],\n pnpm: ['install'],\n yarn: ['install'],\n },\n}\n\nconst IGNORED_BUILDS_NOTICE =\n 'pnpm skipped build scripts for some dependencies. Run \"pnpm approve-builds\" in the project directory to pick which dependencies should be allowed to run scripts.'\n\n// Matches pnpm's `ERR_PNPM_IGNORED_BUILDS` error against whitespace-normalized\n// output (pnpm may wrap the message), capturing the list of skipped packages,\n// eg `esbuild@0.25.0, sharp@0.34.0.` - the `<pkg>@<version>` token sequence\n// ends the capture where the trailing `Run \"pnpm approve-builds\"…` hint starts\nconst IGNORED_BUILDS_PATTERN =\n /ERR_PNPM_IGNORED_BUILDS.*?Ignored build scripts: ?((?:[^\\s,]+@[^\\s,]+[, ]*)+)/\n\nfunction getIgnoredBuildScripts(commandOutput: string): string[] | undefined {\n const match = commandOutput.replaceAll(/\\s+/g, ' ').match(IGNORED_BUILDS_PATTERN)\n if (!match) {\n return undefined\n }\n\n // The capture allows both comma and whitespace separators (pnpm may print\n // either, and wrapping can drop the comma), so split on both.\n return match[1]\n .split(/[\\s,]+/)\n .map((entry) => entry.replace(/\\.$/, ''))\n .filter(Boolean)\n}\n\nfunction isEsbuild(ignoredEntry: string): boolean {\n // Entries are on the form `<pkg-name>@<version>` - strip the version,\n // keeping in mind that scoped package names also start with `@`\n return ignoredEntry.replace(/@[^@]+$/, '') === 'esbuild'\n}\n\nasync function executePackageManagerCommand(\n packageManager: PackageManagerLibs,\n args: string[],\n execOptions: Options,\n output: Output,\n errorMessage: string,\n): Promise<void> {\n const progress = spinner(`Running ${packageManager} ${args.join(' ')}\\n`).start()\n\n const result = await execa(packageManager, args, execOptions)\n\n if (result?.exitCode || result?.failed) {\n // pnpm exits non-zero if dependency build scripts were skipped, even though\n // the install itself succeeded. Treat it as a success, but point to\n // `pnpm approve-builds` if anything other than esbuild was skipped\n // (esbuild works without its build script through a JS fallback).\n const commandOutput = [result.stdout, result.stderr]\n .filter((chunk): chunk is string => typeof chunk === 'string')\n .join('\\n')\n const ignoredBuilds =\n packageManager === 'pnpm' ? getIgnoredBuildScripts(commandOutput) : undefined\n\n if (ignoredBuilds) {\n progress.succeed()\n if (ignoredBuilds.some((entry) => !isEsbuild(entry))) {\n output.warn(IGNORED_BUILDS_NOTICE)\n }\n return\n }\n\n progress.fail()\n // Log both streams - package managers often print the actionable error\n // details to stderr, so logging stdout alone can hide the failure reason.\n output.log(commandOutput)\n output.error(errorMessage, {exit: 1})\n } else {\n progress.succeed()\n }\n}\n\nexport async function installDeclaredPackages(\n cwd: string,\n packageManager: PackageManager,\n context: {output: Output; workDir: string},\n): Promise<void> {\n const {output} = context\n const execOptions: Options = {\n cwd,\n encoding: 'utf8',\n env: getPartialEnvWithNpmPath(cwd),\n reject: false,\n stdio: 'pipe',\n }\n\n if (packageManager === 'manual') {\n const npmCommand = PACKAGE_MANAGER_COMMANDS.install.npm\n output.log(`Manual installation selected — run 'npm ${npmCommand.join(' ')}' or equivalent`)\n } else {\n const args = PACKAGE_MANAGER_COMMANDS.install[packageManager]\n await executePackageManagerCommand(\n packageManager,\n args,\n execOptions,\n output,\n 'Dependency installation failed',\n )\n }\n}\n\nexport async function installNewPackages(\n options: InstallOptions,\n context: {output: Output; workDir: string},\n): Promise<void> {\n const {packageManager, packages} = options\n const {output, workDir} = context\n const execOptions: Options = {\n cwd: workDir,\n encoding: 'utf8',\n env: getPartialEnvWithNpmPath(workDir),\n reject: false,\n stdio: 'pipe',\n }\n\n if (packageManager === 'manual') {\n const npmCommand = PACKAGE_MANAGER_COMMANDS.add.npm(packages)\n output.log(`Manual installation selected - run 'npm ${npmCommand.join(' ')}' or equivalent`)\n } else {\n const args = PACKAGE_MANAGER_COMMANDS.add[packageManager](packages)\n await executePackageManagerCommand(\n packageManager,\n args,\n execOptions,\n output,\n 'Package installation failed',\n )\n }\n}\n"],"names":["spinner","execa","getPartialEnvWithNpmPath","PACKAGE_MANAGER_COMMANDS","add","bun","packages","npm","pnpm","yarn","install","IGNORED_BUILDS_NOTICE","IGNORED_BUILDS_PATTERN","getIgnoredBuildScripts","commandOutput","match","replaceAll","undefined","split","map","entry","replace","filter","Boolean","isEsbuild","ignoredEntry","executePackageManagerCommand","packageManager","args","execOptions","output","errorMessage","progress","join","start","result","exitCode","failed","stdout","stderr","chunk","ignoredBuilds","succeed","some","warn","fail","log","error","exit","installDeclaredPackages","cwd","context","encoding","env","reject","stdio","npmCommand","installNewPackages","options","workDir"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../src/util/packageManager/installPackages.ts"],"sourcesContent":["import {CLIError} from '@oclif/core/errors'\nimport {exitCodes, type Output} from '@sanity/cli-core'\nimport {spinner} from '@sanity/cli-core/ux'\nimport {execa, type Options} from 'execa'\n\nimport {getPartialEnvWithNpmPath, type PackageManager} from './packageManagerChoice.js'\n\ntype PackageManagerLibs = Exclude<PackageManager, 'manual'>\n\n/**\n * @internal\n */\ninterface InstallOptions {\n packageManager: PackageManager\n packages: string[]\n}\n\ninterface PackageManagerCommands {\n add: {[key in PackageManagerLibs]: (packages: string[]) => string[]}\n install: {[key in PackageManagerLibs]: string[]}\n}\n\nconst PACKAGE_MANAGER_COMMANDS: PackageManagerCommands = {\n add: {\n bun: (packages) => ['add', ...packages],\n npm: (packages) => ['install', '--save', ...packages],\n pnpm: (packages) => ['add', '--save-prod', ...packages],\n yarn: (packages) => ['add', ...packages],\n },\n install: {\n bun: ['install'],\n npm: ['install'],\n pnpm: ['install'],\n yarn: ['install'],\n },\n}\n\nconst IGNORED_BUILDS_NOTICE =\n 'pnpm skipped build scripts for some dependencies. Run \"pnpm approve-builds\" in the project directory to pick which dependencies should be allowed to run scripts.'\n\n// Matches pnpm's `ERR_PNPM_IGNORED_BUILDS` error against whitespace-normalized\n// output (pnpm may wrap the message), capturing the list of skipped packages,\n// eg `esbuild@0.25.0, sharp@0.34.0.` - the `<pkg>@<version>` token sequence\n// ends the capture where the trailing `Run \"pnpm approve-builds\"…` hint starts\nconst IGNORED_BUILDS_PATTERN =\n /ERR_PNPM_IGNORED_BUILDS.*?Ignored build scripts: ?((?:[^\\s,]+@[^\\s,]+[, ]*)+)/\n\nfunction getIgnoredBuildScripts(commandOutput: string): string[] | undefined {\n const match = commandOutput.replaceAll(/\\s+/g, ' ').match(IGNORED_BUILDS_PATTERN)\n if (!match) {\n return undefined\n }\n\n // The capture allows both comma and whitespace separators (pnpm may print\n // either, and wrapping can drop the comma), so split on both.\n return match[1]\n .split(/[\\s,]+/)\n .map((entry) => entry.replace(/\\.$/, ''))\n .filter(Boolean)\n}\n\nfunction isEsbuild(ignoredEntry: string): boolean {\n // Entries are on the form `<pkg-name>@<version>` - strip the version,\n // keeping in mind that scoped package names also start with `@`\n return ignoredEntry.replace(/@[^@]+$/, '') === 'esbuild'\n}\n\nasync function executePackageManagerCommand(\n packageManager: PackageManagerLibs,\n args: string[],\n execOptions: Options,\n output: Output,\n errorMessage: string,\n): Promise<void> {\n const progress = spinner({\n discardStdin: !execOptions.cancelSignal,\n text: `Running ${packageManager} ${args.join(' ')}\\n`,\n }).start()\n let progressSettled = false\n const fail = () => {\n progressSettled = true\n progress.fail()\n }\n const succeed = () => {\n progressSettled = true\n progress.succeed()\n }\n\n try {\n const result = await execa(packageManager, args, execOptions)\n\n if (execOptions.cancelSignal?.aborted) {\n fail()\n execOptions.cancelSignal.throwIfAborted()\n }\n\n if (result?.exitCode || result?.failed) {\n // pnpm exits non-zero if dependency build scripts were skipped, even though\n // the install itself succeeded. Treat it as a success, but point to\n // `pnpm approve-builds` if anything other than esbuild was skipped\n // (esbuild works without its build script through a JS fallback).\n const commandOutput = [result.stdout, result.stderr]\n .filter((chunk): chunk is string => typeof chunk === 'string')\n .join('\\n')\n const ignoredBuilds =\n packageManager === 'pnpm' ? getIgnoredBuildScripts(commandOutput) : undefined\n\n if (ignoredBuilds) {\n succeed()\n if (ignoredBuilds.some((entry) => !isEsbuild(entry))) {\n output.warn(IGNORED_BUILDS_NOTICE)\n }\n return\n }\n\n fail()\n // Log both streams - package managers often print the actionable error\n // details to stderr, so logging stdout alone can hide the failure reason.\n output.log(commandOutput)\n throw new CLIError(errorMessage, {exit: exitCodes.RUNTIME_ERROR})\n } else {\n succeed()\n }\n } catch (err) {\n if (!progressSettled) {\n fail()\n }\n throw err\n } finally {\n progress.stop()\n }\n}\n\nexport async function installDeclaredPackages(\n cwd: string,\n packageManager: PackageManager,\n context: {output: Output; workDir: string},\n): Promise<void> {\n const {output} = context\n const execOptions: Options = {\n cwd,\n encoding: 'utf8',\n env: getPartialEnvWithNpmPath(cwd),\n reject: false,\n stdio: 'pipe',\n }\n\n if (packageManager === 'manual') {\n const npmCommand = PACKAGE_MANAGER_COMMANDS.install.npm\n output.log(`Manual installation selected — run 'npm ${npmCommand.join(' ')}' or equivalent`)\n } else {\n const args = PACKAGE_MANAGER_COMMANDS.install[packageManager]\n await executePackageManagerCommand(\n packageManager,\n args,\n execOptions,\n output,\n 'Dependency installation failed',\n )\n }\n}\n\nexport async function installNewPackages(\n options: InstallOptions,\n context: {cancelSignal?: AbortSignal; output: Output; timeout?: number; workDir: string},\n): Promise<void> {\n const {packageManager, packages} = options\n const {cancelSignal, output, timeout, workDir} = context\n const execOptions: Options = {\n cancelSignal,\n cwd: workDir,\n encoding: 'utf8',\n env: getPartialEnvWithNpmPath(workDir),\n reject: false,\n stdio: 'pipe',\n timeout,\n }\n\n if (packageManager === 'manual') {\n const npmCommand = PACKAGE_MANAGER_COMMANDS.add.npm(packages)\n output.log(`Manual installation selected - run 'npm ${npmCommand.join(' ')}' or equivalent`)\n } else {\n const args = PACKAGE_MANAGER_COMMANDS.add[packageManager](packages)\n await executePackageManagerCommand(\n packageManager,\n args,\n execOptions,\n output,\n 'Package installation failed',\n )\n }\n}\n"],"names":["CLIError","exitCodes","spinner","execa","getPartialEnvWithNpmPath","PACKAGE_MANAGER_COMMANDS","add","bun","packages","npm","pnpm","yarn","install","IGNORED_BUILDS_NOTICE","IGNORED_BUILDS_PATTERN","getIgnoredBuildScripts","commandOutput","match","replaceAll","undefined","split","map","entry","replace","filter","Boolean","isEsbuild","ignoredEntry","executePackageManagerCommand","packageManager","args","execOptions","output","errorMessage","progress","discardStdin","cancelSignal","text","join","start","progressSettled","fail","succeed","result","aborted","throwIfAborted","exitCode","failed","stdout","stderr","chunk","ignoredBuilds","some","warn","log","exit","RUNTIME_ERROR","err","stop","installDeclaredPackages","cwd","context","encoding","env","reject","stdio","npmCommand","installNewPackages","options","timeout","workDir"],"mappings":"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"}
@@ -0,0 +1,105 @@
1
+ import { getUserConfig } from '@sanity/cli-core/config';
2
+ import { subdebug } from '@sanity/cli-core/debug';
3
+ const debug = subdebug('projects:unclaimed:registry');
4
+ export const UNCLAIMED_PROJECTS_CONFIG_KEY = 'unclaimedProjects';
5
+ function asRecord(value) {
6
+ return value && typeof value === 'object' && !Array.isArray(value) ? value : {};
7
+ }
8
+ /**
9
+ * Record a mint response in the passive, project-ID-keyed user-config registry.
10
+ *
11
+ * This storage is deliberately not connected to CLI credential resolution.
12
+ */ export function recordUnclaimedProject(minted, mintedAt = new Date().toISOString()) {
13
+ try {
14
+ const config = getUserConfig();
15
+ const records = asRecord(config.get(UNCLAIMED_PROJECTS_CONFIG_KEY));
16
+ const record = {
17
+ claimToken: minted.claimToken,
18
+ claimUrl: minted.claimUrl,
19
+ dataset: minted.datasetName,
20
+ expiresAt: minted.expiresAt,
21
+ mintedAt,
22
+ projectId: minted.resourceId,
23
+ token: minted.token
24
+ };
25
+ config.set(UNCLAIMED_PROJECTS_CONFIG_KEY, {
26
+ ...records,
27
+ [minted.resourceId]: record
28
+ });
29
+ return true;
30
+ } catch (error) {
31
+ debug('failed to record unclaimed project: %s', error instanceof Error ? error.message : `${error}`);
32
+ return false;
33
+ }
34
+ }
35
+ function requireString(value, key, projectId) {
36
+ const field = value[key];
37
+ if (typeof field !== 'string' || field.length === 0) {
38
+ throw new Error(`Local recovery record for project "${projectId}" is malformed: "${key}" is missing or invalid.`);
39
+ }
40
+ return field;
41
+ }
42
+ function parseRecord(projectId, value) {
43
+ const record = asRecord(value);
44
+ const parsed = {
45
+ claimToken: requireString(record, 'claimToken', projectId),
46
+ claimUrl: requireString(record, 'claimUrl', projectId),
47
+ dataset: requireString(record, 'dataset', projectId),
48
+ expiresAt: requireString(record, 'expiresAt', projectId),
49
+ mintedAt: requireString(record, 'mintedAt', projectId),
50
+ projectId: requireString(record, 'projectId', projectId),
51
+ token: requireString(record, 'token', projectId)
52
+ };
53
+ if (parsed.projectId !== projectId) {
54
+ throw new Error(`Local recovery record for project "${projectId}" is malformed: its project ID does not match.`);
55
+ }
56
+ let claimUrlValid = false;
57
+ try {
58
+ const protocol = new URL(parsed.claimUrl).protocol;
59
+ claimUrlValid = protocol === 'https:' || protocol === 'http:';
60
+ } catch {
61
+ // The actionable error is reported below.
62
+ }
63
+ if (!claimUrlValid) {
64
+ throw new TypeError(`Local recovery record for project "${projectId}" is malformed: "claimUrl" is not a valid URL.`);
65
+ }
66
+ if (!Number.isFinite(Date.parse(parsed.mintedAt))) {
67
+ throw new TypeError(`Local recovery record for project "${projectId}" is malformed: "mintedAt" is not a valid date.`);
68
+ }
69
+ if (!Number.isFinite(Date.parse(parsed.expiresAt))) {
70
+ throw new TypeError(`Local recovery record for project "${projectId}" is malformed: "expiresAt" is not a valid date.`);
71
+ }
72
+ return parsed;
73
+ }
74
+ /**
75
+ * Read and validate the passive local recovery registry without changing it.
76
+ */ export function readUnclaimedProjects() {
77
+ const stored = getUserConfig().get(UNCLAIMED_PROJECTS_CONFIG_KEY);
78
+ if (stored === undefined) return [];
79
+ if (!stored || typeof stored !== 'object' || Array.isArray(stored)) {
80
+ throw new Error('The local unclaimed-project registry is malformed.');
81
+ }
82
+ return Object.entries(stored).map(([projectId, record])=>parseRecord(projectId, record)).toSorted((left, right)=>Date.parse(left.expiresAt) - Date.parse(right.expiresAt));
83
+ }
84
+ /**
85
+ * Remove a record only when its claim token still matches the record that was checked.
86
+ */ export function removeUnclaimedProject(projectId, expectedClaimToken) {
87
+ try {
88
+ const config = getUserConfig();
89
+ const records = asRecord(config.get(UNCLAIMED_PROJECTS_CONFIG_KEY));
90
+ const current = asRecord(records[projectId]);
91
+ if (current.claimToken !== expectedClaimToken) return false;
92
+ const { [projectId]: _, ...remaining } = records;
93
+ if (Object.keys(remaining).length === 0) {
94
+ config.delete(UNCLAIMED_PROJECTS_CONFIG_KEY);
95
+ } else {
96
+ config.set(UNCLAIMED_PROJECTS_CONFIG_KEY, remaining);
97
+ }
98
+ return true;
99
+ } catch (error) {
100
+ debug('failed to remove unclaimed project: %s', error instanceof Error ? error.message : `${error}`);
101
+ return false;
102
+ }
103
+ }
104
+
105
+ //# sourceMappingURL=unclaimedProjects.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/util/unclaimedProjects.ts"],"sourcesContent":["import {getUserConfig} from '@sanity/cli-core/config'\nimport {subdebug} from '@sanity/cli-core/debug'\n\nimport {type MintedProject} from '../services/mintProject.js'\n\nconst debug = subdebug('projects:unclaimed:registry')\n\nexport const UNCLAIMED_PROJECTS_CONFIG_KEY = 'unclaimedProjects'\n\nexport interface UnclaimedProjectRecord {\n claimToken: string\n claimUrl: string\n dataset: string\n expiresAt: string\n mintedAt: string\n projectId: string\n token: string\n}\n\nfunction asRecord(value: unknown): Record<string, unknown> {\n return value && typeof value === 'object' && !Array.isArray(value)\n ? (value as Record<string, unknown>)\n : {}\n}\n\n/**\n * Record a mint response in the passive, project-ID-keyed user-config registry.\n *\n * This storage is deliberately not connected to CLI credential resolution.\n */\nexport function recordUnclaimedProject(\n minted: MintedProject,\n mintedAt: string = new Date().toISOString(),\n): boolean {\n try {\n const config = getUserConfig()\n const records = asRecord(config.get(UNCLAIMED_PROJECTS_CONFIG_KEY))\n const record: UnclaimedProjectRecord = {\n claimToken: minted.claimToken,\n claimUrl: minted.claimUrl,\n dataset: minted.datasetName,\n expiresAt: minted.expiresAt,\n mintedAt,\n projectId: minted.resourceId,\n token: minted.token,\n }\n\n config.set(UNCLAIMED_PROJECTS_CONFIG_KEY, {\n ...records,\n [minted.resourceId]: record,\n })\n return true\n } catch (error) {\n debug(\n 'failed to record unclaimed project: %s',\n error instanceof Error ? error.message : `${error}`,\n )\n return false\n }\n}\n\nfunction requireString(\n value: Record<string, unknown>,\n key: keyof UnclaimedProjectRecord,\n projectId: string,\n): string {\n const field = value[key]\n if (typeof field !== 'string' || field.length === 0) {\n throw new Error(\n `Local recovery record for project \"${projectId}\" is malformed: \"${key}\" is missing or invalid.`,\n )\n }\n return field\n}\n\nfunction parseRecord(projectId: string, value: unknown): UnclaimedProjectRecord {\n const record = asRecord(value)\n const parsed: UnclaimedProjectRecord = {\n claimToken: requireString(record, 'claimToken', projectId),\n claimUrl: requireString(record, 'claimUrl', projectId),\n dataset: requireString(record, 'dataset', projectId),\n expiresAt: requireString(record, 'expiresAt', projectId),\n mintedAt: requireString(record, 'mintedAt', projectId),\n projectId: requireString(record, 'projectId', projectId),\n token: requireString(record, 'token', projectId),\n }\n\n if (parsed.projectId !== projectId) {\n throw new Error(\n `Local recovery record for project \"${projectId}\" is malformed: its project ID does not match.`,\n )\n }\n let claimUrlValid = false\n try {\n const protocol = new URL(parsed.claimUrl).protocol\n claimUrlValid = protocol === 'https:' || protocol === 'http:'\n } catch {\n // The actionable error is reported below.\n }\n if (!claimUrlValid) {\n throw new TypeError(\n `Local recovery record for project \"${projectId}\" is malformed: \"claimUrl\" is not a valid URL.`,\n )\n }\n if (!Number.isFinite(Date.parse(parsed.mintedAt))) {\n throw new TypeError(\n `Local recovery record for project \"${projectId}\" is malformed: \"mintedAt\" is not a valid date.`,\n )\n }\n if (!Number.isFinite(Date.parse(parsed.expiresAt))) {\n throw new TypeError(\n `Local recovery record for project \"${projectId}\" is malformed: \"expiresAt\" is not a valid date.`,\n )\n }\n\n return parsed\n}\n\n/**\n * Read and validate the passive local recovery registry without changing it.\n */\nexport function readUnclaimedProjects(): UnclaimedProjectRecord[] {\n const stored = getUserConfig().get(UNCLAIMED_PROJECTS_CONFIG_KEY)\n if (stored === undefined) return []\n if (!stored || typeof stored !== 'object' || Array.isArray(stored)) {\n throw new Error('The local unclaimed-project registry is malformed.')\n }\n\n return Object.entries(stored)\n .map(([projectId, record]) => parseRecord(projectId, record))\n .toSorted((left, right) => Date.parse(left.expiresAt) - Date.parse(right.expiresAt))\n}\n\n/**\n * Remove a record only when its claim token still matches the record that was checked.\n */\nexport function removeUnclaimedProject(projectId: string, expectedClaimToken: string): boolean {\n try {\n const config = getUserConfig()\n const records = asRecord(config.get(UNCLAIMED_PROJECTS_CONFIG_KEY))\n const current = asRecord(records[projectId])\n if (current.claimToken !== expectedClaimToken) return false\n\n const {[projectId]: _, ...remaining} = records\n if (Object.keys(remaining).length === 0) {\n config.delete(UNCLAIMED_PROJECTS_CONFIG_KEY)\n } else {\n config.set(UNCLAIMED_PROJECTS_CONFIG_KEY, remaining)\n }\n return true\n } catch (error) {\n debug(\n 'failed to remove unclaimed project: %s',\n error instanceof Error ? error.message : `${error}`,\n )\n return false\n }\n}\n"],"names":["getUserConfig","subdebug","debug","UNCLAIMED_PROJECTS_CONFIG_KEY","asRecord","value","Array","isArray","recordUnclaimedProject","minted","mintedAt","Date","toISOString","config","records","get","record","claimToken","claimUrl","dataset","datasetName","expiresAt","projectId","resourceId","token","set","error","Error","message","requireString","key","field","length","parseRecord","parsed","claimUrlValid","protocol","URL","TypeError","Number","isFinite","parse","readUnclaimedProjects","stored","undefined","Object","entries","map","toSorted","left","right","removeUnclaimedProject","expectedClaimToken","current","_","remaining","keys","delete"],"mappings":"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"}