@sanity/cli 7.18.0 → 8.0.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 (131) hide show
  1. package/README.md +74 -4
  2. package/dist/SanityHelp.js +1 -35
  3. package/dist/SanityHelp.js.map +1 -1
  4. package/dist/actions/assets/assetFileError.js +9 -0
  5. package/dist/actions/assets/assetFileError.js.map +1 -0
  6. package/dist/actions/assets/uploadAssetFromFile.js +40 -0
  7. package/dist/actions/assets/uploadAssetFromFile.js.map +1 -0
  8. package/dist/actions/assets/uploadAssetWithProgress.js +76 -0
  9. package/dist/actions/assets/uploadAssetWithProgress.js.map +1 -0
  10. package/dist/actions/deploy/deployApp.js +39 -44
  11. package/dist/actions/deploy/deployApp.js.map +1 -1
  12. package/dist/actions/deploy/deployChecks.js +21 -13
  13. package/dist/actions/deploy/deployChecks.js.map +1 -1
  14. package/dist/actions/deploy/deployRunner.js +8 -7
  15. package/dist/actions/deploy/deployRunner.js.map +1 -1
  16. package/dist/actions/deploy/deployStudio.js +55 -35
  17. package/dist/actions/deploy/deployStudio.js.map +1 -1
  18. package/dist/actions/deploy/deploymentPlan.js +17 -29
  19. package/dist/actions/deploy/deploymentPlan.js.map +1 -1
  20. package/dist/actions/deploy/resolveDeployTarget.js +2 -8
  21. package/dist/actions/deploy/resolveDeployTarget.js.map +1 -1
  22. package/dist/actions/dev/servers/getDevServerConfig.js +2 -8
  23. package/dist/actions/dev/servers/getDevServerConfig.js.map +1 -1
  24. package/dist/actions/dev/servers/startStudioDevServer.js +7 -1
  25. package/dist/actions/dev/servers/startStudioDevServer.js.map +1 -1
  26. package/dist/actions/init/bootstrapRemoteTemplate.js +2 -2
  27. package/dist/actions/init/bootstrapRemoteTemplate.js.map +1 -1
  28. package/dist/actions/schema/listSchemas.js +1 -1
  29. package/dist/actions/schema/listSchemas.js.map +1 -1
  30. package/dist/actions/tokens/constants.js +2 -2
  31. package/dist/actions/tokens/constants.js.map +1 -1
  32. package/dist/actions/tokens/expiry.js +35 -0
  33. package/dist/actions/tokens/expiry.js.map +1 -0
  34. package/dist/actions/tokens/types.js.map +1 -1
  35. package/dist/actions/tokens/validateRole.js +5 -2
  36. package/dist/actions/tokens/validateRole.js.map +1 -1
  37. package/dist/actions/typegen/count.js +6 -0
  38. package/dist/actions/typegen/count.js.map +1 -0
  39. package/dist/actions/typegen/formatPath.js +5 -0
  40. package/dist/actions/typegen/formatPath.js.map +1 -0
  41. package/dist/actions/typegen/percent.js +8 -0
  42. package/dist/actions/typegen/percent.js.map +1 -0
  43. package/dist/actions/typegen/renderTypegenProgress.js +88 -0
  44. package/dist/actions/typegen/renderTypegenProgress.js.map +1 -0
  45. package/dist/actions/undeploy/adapters.js +6 -9
  46. package/dist/actions/undeploy/adapters.js.map +1 -1
  47. package/dist/actions/undeploy/runUndeploy.js +12 -4
  48. package/dist/actions/undeploy/runUndeploy.js.map +1 -1
  49. package/dist/actions/undeploy/undeployPlan.js +6 -14
  50. package/dist/actions/undeploy/undeployPlan.js.map +1 -1
  51. package/dist/commands/assets/upload.js +126 -0
  52. package/dist/commands/assets/upload.js.map +1 -0
  53. package/dist/commands/backups/list.js +1 -1
  54. package/dist/commands/backups/list.js.map +1 -1
  55. package/dist/commands/datasets/copy.js +1 -1
  56. package/dist/commands/datasets/copy.js.map +1 -1
  57. package/dist/commands/login.js +2 -8
  58. package/dist/commands/login.js.map +1 -1
  59. package/dist/commands/mcp/configure.js.map +1 -1
  60. package/dist/commands/migrations/list.js +1 -1
  61. package/dist/commands/migrations/list.js.map +1 -1
  62. package/dist/commands/migrations/run.js +67 -3
  63. package/dist/commands/migrations/run.js.map +1 -1
  64. package/dist/commands/new.js +4 -3
  65. package/dist/commands/new.js.map +1 -1
  66. package/dist/commands/organizations/list.js +1 -1
  67. package/dist/commands/organizations/list.js.map +1 -1
  68. package/dist/commands/projects/list.js +39 -12
  69. package/dist/commands/projects/list.js.map +1 -1
  70. package/dist/commands/projects/unclaimed.js +39 -33
  71. package/dist/commands/projects/unclaimed.js.map +1 -1
  72. package/dist/commands/tokens/create.js +92 -7
  73. package/dist/commands/tokens/create.js.map +1 -1
  74. package/dist/commands/tokens/delete.js +2 -2
  75. package/dist/commands/tokens/delete.js.map +1 -1
  76. package/dist/commands/tokens/list.js +12 -11
  77. package/dist/commands/tokens/list.js.map +1 -1
  78. package/dist/commands/tokens/rotate.js +95 -0
  79. package/dist/commands/tokens/rotate.js.map +1 -0
  80. package/dist/commands/typegen/generate.js +222 -0
  81. package/dist/commands/typegen/generate.js.map +1 -0
  82. package/dist/commands/users/list.js +8 -8
  83. package/dist/commands/users/list.js.map +1 -1
  84. package/dist/exports/_internal.d.ts +29 -0
  85. package/dist/exports/_internal.js +1 -0
  86. package/dist/exports/_internal.js.map +1 -1
  87. package/dist/exports/invokeSanityCli/commandPolicies/mcpPolicy.js +6 -0
  88. package/dist/exports/invokeSanityCli/commandPolicies/mcpPolicy.js.map +1 -1
  89. package/dist/exports/invokeSanityCli/help.js +4 -0
  90. package/dist/exports/invokeSanityCli/help.js.map +1 -1
  91. package/dist/exports/invokeSanityCli/index.js +2 -0
  92. package/dist/exports/invokeSanityCli/index.js.map +1 -1
  93. package/dist/hooks/commandNotFound/topicAliases.js +13 -40
  94. package/dist/hooks/commandNotFound/topicAliases.js.map +1 -1
  95. package/dist/hooks/prerun/setupTelemetry.js +3 -2
  96. package/dist/hooks/prerun/setupTelemetry.js.map +1 -1
  97. package/dist/server/vite/plugin-typegen.js +4 -16
  98. package/dist/server/vite/plugin-typegen.js.map +1 -1
  99. package/dist/services/assets.js +46 -0
  100. package/dist/services/assets.js.map +1 -0
  101. package/dist/services/tokens.js +81 -31
  102. package/dist/services/tokens.js.map +1 -1
  103. package/dist/topicAliases.js +43 -0
  104. package/dist/topicAliases.js.map +1 -1
  105. package/dist/util/parseArguments.js +7 -2
  106. package/dist/util/parseArguments.js.map +1 -1
  107. package/dist/util/readTokenFromStdin.js +17 -0
  108. package/dist/util/readTokenFromStdin.js.map +1 -0
  109. package/dist/util/responsiveTable.js +97 -0
  110. package/dist/util/responsiveTable.js.map +1 -0
  111. package/dist/util/telemetry/commandTelemetry.js +34 -0
  112. package/dist/util/telemetry/commandTelemetry.js.map +1 -0
  113. package/dist/util/unclaimedProjects.js +10 -0
  114. package/dist/util/unclaimedProjects.js.map +1 -1
  115. package/oclif.config.js +2 -4
  116. package/oclif.manifest.json +213 -1
  117. package/package.json +12 -10
  118. package/templates/shopify/components/inputs/ShopifyMetafield.tsx +20 -0
  119. package/templates/shopify/docs/features.md +24 -0
  120. package/templates/shopify/schemaTypes/index.ts +2 -0
  121. package/templates/shopify/schemaTypes/objects/shopify/shopifyCollectionType.ts +18 -1
  122. package/templates/shopify/schemaTypes/objects/shopify/shopifyMetafieldType.ts +47 -0
  123. package/templates/shopify/schemaTypes/objects/shopify/shopifyProductType.ts +17 -0
  124. package/templates/shopify/utils/formatMetafieldValue.ts +30 -0
  125. package/templates/shopify-online-storefront/components/inputs/ShopifyMetafield.tsx +22 -0
  126. package/templates/shopify-online-storefront/schemaTypes/index.ts +4 -0
  127. package/templates/shopify-online-storefront/schemaTypes/objects/shop.ts +16 -0
  128. package/templates/shopify-online-storefront/schemaTypes/objects/shopifyCollection.ts +19 -0
  129. package/templates/shopify-online-storefront/schemaTypes/objects/shopifyMetafield.ts +53 -0
  130. package/templates/shopify-online-storefront/schemaTypes/objects/shopifyProduct.ts +19 -0
  131. package/templates/shopify-online-storefront/utils/formatMetafieldValue.ts +30 -0
@@ -1,58 +1,113 @@
1
1
  import { getGlobalCliClient } from '@sanity/cli-core';
2
- const TOKENS_API_VERSION = 'v2025-08-18';
2
+ import { TOKENS_API_VERSION } from '../actions/tokens/constants.js';
3
+ function getClient(token) {
4
+ return getGlobalCliClient({
5
+ apiVersion: TOKENS_API_VERSION,
6
+ requireUser: true,
7
+ ...token === undefined ? {} : {
8
+ token
9
+ }
10
+ });
11
+ }
12
+ async function fetchAllPages(client, uri) {
13
+ const items = [];
14
+ let cursor = null;
15
+ do {
16
+ const response = await client.request({
17
+ query: cursor === null ? {} : {
18
+ nextCursor: cursor
19
+ },
20
+ uri
21
+ });
22
+ items.push(...response.data);
23
+ cursor = response.nextCursor;
24
+ }while (cursor !== null)
25
+ return items;
26
+ }
27
+ /**
28
+ * Get the membership granting a robot access to the given project
29
+ * @param robot - The robot to inspect
30
+ * @param projectId - The project ID
31
+ * @returns The project membership, if any
32
+ *
33
+ * @internal
34
+ */ export function getProjectMembership(robot, projectId) {
35
+ return robot.memberships.find((membership)=>membership.resourceType === 'project' && membership.resourceId === projectId);
36
+ }
3
37
  /**
4
38
  * Add a token to a project
5
39
  * @param options - The options for adding a token to a project
6
- * @returns A promise that resolves to the token response
40
+ * @returns A promise that resolves to the created robot, including its secret token
7
41
  *
8
42
  * @internal
9
43
  */ export async function createToken(options) {
10
- const { label, projectId, roleName } = options;
11
- const client = await getGlobalCliClient({
12
- apiVersion: TOKENS_API_VERSION,
13
- requireUser: true
14
- });
44
+ const { expiresAt, label, projectId, roleName, sendNotification } = options;
45
+ const client = await getClient();
15
46
  return client.request({
16
47
  body: {
17
48
  label,
18
- roleName
49
+ memberships: [
50
+ {
51
+ resourceId: projectId,
52
+ resourceType: 'project',
53
+ roleNames: [
54
+ roleName
55
+ ]
56
+ }
57
+ ],
58
+ ...expiresAt === undefined ? {} : {
59
+ expiresAt
60
+ }
19
61
  },
20
62
  method: 'POST',
21
- uri: `/projects/${projectId}/tokens`
63
+ query: sendNotification === false ? {
64
+ sendNotification: 'false'
65
+ } : {},
66
+ uri: `/access/project/${projectId}/robots`
22
67
  });
23
68
  }
24
69
  /**
25
70
  * Delete a token from a project
26
- * @param options - The options for deleting a token from a project
71
+ * @param options - The options for deleting a token from a project; `tokenId`
72
+ * is the id reported by `getTokens`/`createToken`
27
73
  * @returns A promise that resolves when the token is deleted
28
74
  *
29
75
  * @internal
30
76
  */ export async function deleteToken(options) {
31
77
  const { projectId, tokenId } = options;
32
- const client = await getGlobalCliClient({
33
- apiVersion: TOKENS_API_VERSION,
34
- requireUser: true
35
- });
78
+ const client = await getClient();
36
79
  return client.request({
37
80
  method: 'DELETE',
38
- uri: `/projects/${projectId}/tokens/${tokenId}`
81
+ uri: `/access/project/${projectId}/robots/${tokenId}`
39
82
  });
40
83
  }
41
84
  /**
42
- * Get all tokens for a project
43
- * @param projectId - The project ID
44
- * @returns A promise that resolves to an array of tokens
85
+ * Rotate a robot token, replacing its secret while preserving the robot,
86
+ * its roles, and the token's expiry. The request authenticates as the robot
87
+ * itself; the previous secret is revoked immediately.
88
+ * @param token - The current robot token secret
89
+ * @returns A promise that resolves to the robot with its new secret token
45
90
  *
46
91
  * @internal
47
- */ export async function getTokens(projectId) {
48
- const client = await getGlobalCliClient({
49
- apiVersion: TOKENS_API_VERSION,
50
- requireUser: true
51
- });
92
+ */ export async function rotateToken(token) {
93
+ const client = await getClient(token);
52
94
  return client.request({
53
- uri: `/projects/${projectId}/tokens`
95
+ method: 'POST',
96
+ uri: '/access/robots/me/rotate'
54
97
  });
55
98
  }
99
+ /**
100
+ * Get all tokens for a project. Tokens managed by an organization are
101
+ * excluded: they cannot be managed at the project scope.
102
+ * @param projectId - The project ID
103
+ * @returns A promise that resolves to an array of robots
104
+ *
105
+ * @internal
106
+ */ export async function getTokens(projectId) {
107
+ const client = await getClient();
108
+ const robots = await fetchAllPages(client, `/access/project/${projectId}/robots`);
109
+ return robots.filter((robot)=>robot.managedBy?.resourceType !== 'organization');
110
+ }
56
111
  /**
57
112
  * Get all roles for a project
58
113
  * @param projectId - The project ID
@@ -60,13 +115,8 @@ const TOKENS_API_VERSION = 'v2025-08-18';
60
115
  *
61
116
  * @internal
62
117
  */ export async function getTokenRoles(projectId) {
63
- const client = await getGlobalCliClient({
64
- apiVersion: TOKENS_API_VERSION,
65
- requireUser: true
66
- });
67
- return client.request({
68
- uri: `/projects/${projectId}/roles`
69
- });
118
+ const client = await getClient();
119
+ return fetchAllPages(client, `/access/project/${projectId}/roles`);
70
120
  }
71
121
 
72
122
  //# sourceMappingURL=tokens.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/services/tokens.ts"],"sourcesContent":["import {getGlobalCliClient} from '@sanity/cli-core'\n\nimport {type ProjectRole, type Token, type TokenResponse} from '../actions/tokens/types.js'\n\nconst TOKENS_API_VERSION = 'v2025-08-18'\n\ninterface CreateTokenOptions {\n label: string\n projectId: string\n roleName: string\n}\n\n/**\n * Add a token to a project\n * @param options - The options for adding a token to a project\n * @returns A promise that resolves to the token response\n *\n * @internal\n */\nexport async function createToken(options: CreateTokenOptions): Promise<TokenResponse> {\n const {label, projectId, roleName} = options\n\n const client = await getGlobalCliClient({\n apiVersion: TOKENS_API_VERSION,\n requireUser: true,\n })\n\n return client.request<TokenResponse>({\n body: {label, roleName},\n method: 'POST',\n uri: `/projects/${projectId}/tokens`,\n })\n}\n\ninterface DeleteTokenOptions {\n projectId: string\n tokenId: string\n}\n\n/**\n * Delete a token from a project\n * @param options - The options for deleting a token from a project\n * @returns A promise that resolves when the token is deleted\n *\n * @internal\n */\nexport async function deleteToken(options: DeleteTokenOptions): Promise<void> {\n const {projectId, tokenId} = options\n\n const client = await getGlobalCliClient({\n apiVersion: TOKENS_API_VERSION,\n requireUser: true,\n })\n\n return client.request({\n method: 'DELETE',\n uri: `/projects/${projectId}/tokens/${tokenId}`,\n })\n}\n\n/**\n * Get all tokens for a project\n * @param projectId - The project ID\n * @returns A promise that resolves to an array of tokens\n *\n * @internal\n */\nexport async function getTokens(projectId: string): Promise<Token[]> {\n const client = await getGlobalCliClient({\n apiVersion: TOKENS_API_VERSION,\n requireUser: true,\n })\n\n return client.request<Token[]>({\n uri: `/projects/${projectId}/tokens`,\n })\n}\n\n/**\n * Get all roles for a project\n * @param projectId - The project ID\n * @returns A promise that resolves to an array of project roles\n *\n * @internal\n */\nexport async function getTokenRoles(projectId: string): Promise<ProjectRole[]> {\n const client = await getGlobalCliClient({\n apiVersion: TOKENS_API_VERSION,\n requireUser: true,\n })\n\n return client.request<ProjectRole[]>({uri: `/projects/${projectId}/roles`})\n}\n"],"names":["getGlobalCliClient","TOKENS_API_VERSION","createToken","options","label","projectId","roleName","client","apiVersion","requireUser","request","body","method","uri","deleteToken","tokenId","getTokens","getTokenRoles"],"mappings":"AAAA,SAAQA,kBAAkB,QAAO,mBAAkB;AAInD,MAAMC,qBAAqB;AAQ3B;;;;;;CAMC,GACD,OAAO,eAAeC,YAAYC,OAA2B;IAC3D,MAAM,EAACC,KAAK,EAAEC,SAAS,EAAEC,QAAQ,EAAC,GAAGH;IAErC,MAAMI,SAAS,MAAMP,mBAAmB;QACtCQ,YAAYP;QACZQ,aAAa;IACf;IAEA,OAAOF,OAAOG,OAAO,CAAgB;QACnCC,MAAM;YAACP;YAAOE;QAAQ;QACtBM,QAAQ;QACRC,KAAK,CAAC,UAAU,EAAER,UAAU,OAAO,CAAC;IACtC;AACF;AAOA;;;;;;CAMC,GACD,OAAO,eAAeS,YAAYX,OAA2B;IAC3D,MAAM,EAACE,SAAS,EAAEU,OAAO,EAAC,GAAGZ;IAE7B,MAAMI,SAAS,MAAMP,mBAAmB;QACtCQ,YAAYP;QACZQ,aAAa;IACf;IAEA,OAAOF,OAAOG,OAAO,CAAC;QACpBE,QAAQ;QACRC,KAAK,CAAC,UAAU,EAAER,UAAU,QAAQ,EAAEU,SAAS;IACjD;AACF;AAEA;;;;;;CAMC,GACD,OAAO,eAAeC,UAAUX,SAAiB;IAC/C,MAAME,SAAS,MAAMP,mBAAmB;QACtCQ,YAAYP;QACZQ,aAAa;IACf;IAEA,OAAOF,OAAOG,OAAO,CAAU;QAC7BG,KAAK,CAAC,UAAU,EAAER,UAAU,OAAO,CAAC;IACtC;AACF;AAEA;;;;;;CAMC,GACD,OAAO,eAAeY,cAAcZ,SAAiB;IACnD,MAAME,SAAS,MAAMP,mBAAmB;QACtCQ,YAAYP;QACZQ,aAAa;IACf;IAEA,OAAOF,OAAOG,OAAO,CAAgB;QAACG,KAAK,CAAC,UAAU,EAAER,UAAU,MAAM,CAAC;IAAA;AAC3E"}
1
+ {"version":3,"sources":["../../src/services/tokens.ts"],"sourcesContent":["import {getGlobalCliClient} from '@sanity/cli-core'\nimport {type SanityClient} from '@sanity/client'\n\nimport {TOKENS_API_VERSION} from '../actions/tokens/constants.js'\nimport {\n type Membership,\n type Robot,\n type RobotWithToken,\n type Role,\n} from '../actions/tokens/types.js'\n\ninterface PaginatedResponse<T> {\n data: T[]\n nextCursor: string | null\n}\n\nfunction getClient(token?: string): Promise<SanityClient> {\n return getGlobalCliClient({\n apiVersion: TOKENS_API_VERSION,\n requireUser: true,\n ...(token === undefined ? {} : {token}),\n })\n}\n\nasync function fetchAllPages<T>(client: SanityClient, uri: string): Promise<T[]> {\n const items: T[] = []\n let cursor: string | null = null\n\n do {\n const response: PaginatedResponse<T> = await client.request<PaginatedResponse<T>>({\n query: cursor === null ? {} : {nextCursor: cursor},\n uri,\n })\n items.push(...response.data)\n cursor = response.nextCursor\n } while (cursor !== null)\n\n return items\n}\n\n/**\n * Get the membership granting a robot access to the given project\n * @param robot - The robot to inspect\n * @param projectId - The project ID\n * @returns The project membership, if any\n *\n * @internal\n */\nexport function getProjectMembership(robot: Robot, projectId: string): Membership | undefined {\n return robot.memberships.find(\n (membership) => membership.resourceType === 'project' && membership.resourceId === projectId,\n )\n}\n\ninterface CreateTokenOptions {\n label: string\n projectId: string\n roleName: string\n\n expiresAt?: string\n sendNotification?: boolean\n}\n\n/**\n * Add a token to a project\n * @param options - The options for adding a token to a project\n * @returns A promise that resolves to the created robot, including its secret token\n *\n * @internal\n */\nexport async function createToken(options: CreateTokenOptions): Promise<RobotWithToken> {\n const {expiresAt, label, projectId, roleName, sendNotification} = options\n\n const client = await getClient()\n\n return client.request<RobotWithToken>({\n body: {\n label,\n memberships: [{resourceId: projectId, resourceType: 'project', roleNames: [roleName]}],\n ...(expiresAt === undefined ? {} : {expiresAt}),\n },\n method: 'POST',\n query: sendNotification === false ? {sendNotification: 'false'} : {},\n uri: `/access/project/${projectId}/robots`,\n })\n}\n\ninterface DeleteTokenOptions {\n projectId: string\n tokenId: string\n}\n\n/**\n * Delete a token from a project\n * @param options - The options for deleting a token from a project; `tokenId`\n * is the id reported by `getTokens`/`createToken`\n * @returns A promise that resolves when the token is deleted\n *\n * @internal\n */\nexport async function deleteToken(options: DeleteTokenOptions): Promise<void> {\n const {projectId, tokenId} = options\n\n const client = await getClient()\n\n return client.request({\n method: 'DELETE',\n uri: `/access/project/${projectId}/robots/${tokenId}`,\n })\n}\n\n/**\n * Rotate a robot token, replacing its secret while preserving the robot,\n * its roles, and the token's expiry. The request authenticates as the robot\n * itself; the previous secret is revoked immediately.\n * @param token - The current robot token secret\n * @returns A promise that resolves to the robot with its new secret token\n *\n * @internal\n */\nexport async function rotateToken(token: string): Promise<RobotWithToken> {\n const client = await getClient(token)\n\n return client.request<RobotWithToken>({\n method: 'POST',\n uri: '/access/robots/me/rotate',\n })\n}\n\n/**\n * Get all tokens for a project. Tokens managed by an organization are\n * excluded: they cannot be managed at the project scope.\n * @param projectId - The project ID\n * @returns A promise that resolves to an array of robots\n *\n * @internal\n */\nexport async function getTokens(projectId: string): Promise<Robot[]> {\n const client = await getClient()\n\n const robots = await fetchAllPages<Robot>(client, `/access/project/${projectId}/robots`)\n\n return robots.filter((robot) => robot.managedBy?.resourceType !== 'organization')\n}\n\n/**\n * Get all roles for a project\n * @param projectId - The project ID\n * @returns A promise that resolves to an array of project roles\n *\n * @internal\n */\nexport async function getTokenRoles(projectId: string): Promise<Role[]> {\n const client = await getClient()\n\n return fetchAllPages<Role>(client, `/access/project/${projectId}/roles`)\n}\n"],"names":["getGlobalCliClient","TOKENS_API_VERSION","getClient","token","apiVersion","requireUser","undefined","fetchAllPages","client","uri","items","cursor","response","request","query","nextCursor","push","data","getProjectMembership","robot","projectId","memberships","find","membership","resourceType","resourceId","createToken","options","expiresAt","label","roleName","sendNotification","body","roleNames","method","deleteToken","tokenId","rotateToken","getTokens","robots","filter","managedBy","getTokenRoles"],"mappings":"AAAA,SAAQA,kBAAkB,QAAO,mBAAkB;AAGnD,SAAQC,kBAAkB,QAAO,iCAAgC;AAajE,SAASC,UAAUC,KAAc;IAC/B,OAAOH,mBAAmB;QACxBI,YAAYH;QACZI,aAAa;QACb,GAAIF,UAAUG,YAAY,CAAC,IAAI;YAACH;QAAK,CAAC;IACxC;AACF;AAEA,eAAeI,cAAiBC,MAAoB,EAAEC,GAAW;IAC/D,MAAMC,QAAa,EAAE;IACrB,IAAIC,SAAwB;IAE5B,GAAG;QACD,MAAMC,WAAiC,MAAMJ,OAAOK,OAAO,CAAuB;YAChFC,OAAOH,WAAW,OAAO,CAAC,IAAI;gBAACI,YAAYJ;YAAM;YACjDF;QACF;QACAC,MAAMM,IAAI,IAAIJ,SAASK,IAAI;QAC3BN,SAASC,SAASG,UAAU;IAC9B,QAASJ,WAAW,KAAK;IAEzB,OAAOD;AACT;AAEA;;;;;;;CAOC,GACD,OAAO,SAASQ,qBAAqBC,KAAY,EAAEC,SAAiB;IAClE,OAAOD,MAAME,WAAW,CAACC,IAAI,CAC3B,CAACC,aAAeA,WAAWC,YAAY,KAAK,aAAaD,WAAWE,UAAU,KAAKL;AAEvF;AAWA;;;;;;CAMC,GACD,OAAO,eAAeM,YAAYC,OAA2B;IAC3D,MAAM,EAACC,SAAS,EAAEC,KAAK,EAAET,SAAS,EAAEU,QAAQ,EAAEC,gBAAgB,EAAC,GAAGJ;IAElE,MAAMnB,SAAS,MAAMN;IAErB,OAAOM,OAAOK,OAAO,CAAiB;QACpCmB,MAAM;YACJH;YACAR,aAAa;gBAAC;oBAACI,YAAYL;oBAAWI,cAAc;oBAAWS,WAAW;wBAACH;qBAAS;gBAAA;aAAE;YACtF,GAAIF,cAActB,YAAY,CAAC,IAAI;gBAACsB;YAAS,CAAC;QAChD;QACAM,QAAQ;QACRpB,OAAOiB,qBAAqB,QAAQ;YAACA,kBAAkB;QAAO,IAAI,CAAC;QACnEtB,KAAK,CAAC,gBAAgB,EAAEW,UAAU,OAAO,CAAC;IAC5C;AACF;AAOA;;;;;;;CAOC,GACD,OAAO,eAAee,YAAYR,OAA2B;IAC3D,MAAM,EAACP,SAAS,EAAEgB,OAAO,EAAC,GAAGT;IAE7B,MAAMnB,SAAS,MAAMN;IAErB,OAAOM,OAAOK,OAAO,CAAC;QACpBqB,QAAQ;QACRzB,KAAK,CAAC,gBAAgB,EAAEW,UAAU,QAAQ,EAAEgB,SAAS;IACvD;AACF;AAEA;;;;;;;;CAQC,GACD,OAAO,eAAeC,YAAYlC,KAAa;IAC7C,MAAMK,SAAS,MAAMN,UAAUC;IAE/B,OAAOK,OAAOK,OAAO,CAAiB;QACpCqB,QAAQ;QACRzB,KAAK;IACP;AACF;AAEA;;;;;;;CAOC,GACD,OAAO,eAAe6B,UAAUlB,SAAiB;IAC/C,MAAMZ,SAAS,MAAMN;IAErB,MAAMqC,SAAS,MAAMhC,cAAqBC,QAAQ,CAAC,gBAAgB,EAAEY,UAAU,OAAO,CAAC;IAEvF,OAAOmB,OAAOC,MAAM,CAAC,CAACrB,QAAUA,MAAMsB,SAAS,EAAEjB,iBAAiB;AACpE;AAEA;;;;;;CAMC,GACD,OAAO,eAAekB,cAActB,SAAiB;IACnD,MAAMZ,SAAS,MAAMN;IAErB,OAAOK,cAAoBC,QAAQ,CAAC,gBAAgB,EAAEY,UAAU,MAAM,CAAC;AACzE"}
@@ -3,6 +3,8 @@
3
3
  *
4
4
  * Maps canonical topic names to their aliases. Used by:
5
5
  * - The command_not_found hook (runtime alias resolution)
6
+ * - Programmatic CLI invocation
7
+ * - Help rendering
6
8
  * - The check-topic-aliases script (build-time validation)
7
9
  *
8
10
  * Every topic with aliases must be listed here. The key is the canonical
@@ -16,6 +18,9 @@
16
18
  * While the config technically supports any direction, keeping it consistent
17
19
  * (plural to singular) makes the CLI predictable for users.
18
20
  */ export const topicAliases = {
21
+ assets: [
22
+ 'asset'
23
+ ],
19
24
  backups: [
20
25
  'backup'
21
26
  ],
@@ -57,5 +62,43 @@
57
62
  'user'
58
63
  ]
59
64
  };
65
+ const canonicalTopicByAlias = new Map(Object.entries(topicAliases).flatMap(([canonical, aliases])=>aliases.map((alias)=>[
66
+ alias,
67
+ canonical
68
+ ])));
69
+ /**
70
+ * Resolve the topic portion of a command ID from an alias to its canonical name.
71
+ * Handles both bare topics (`hook`) and colon-separated command IDs (`hook:list`).
72
+ *
73
+ * @internal
74
+ */ export function resolveTopicAlias(id) {
75
+ const separatorIndex = id.indexOf(':');
76
+ const topic = separatorIndex === -1 ? id : id.slice(0, separatorIndex);
77
+ const canonical = canonicalTopicByAlias.get(topic);
78
+ if (!canonical) return undefined;
79
+ const suffix = separatorIndex === -1 ? '' : id.slice(separatorIndex);
80
+ return `${canonical}${suffix}`;
81
+ }
82
+ /**
83
+ * Resolve the first positional topic in argv, preserving flags and arguments.
84
+ *
85
+ * @internal
86
+ */ export function resolveTopicAliasInArgv(argv) {
87
+ for(let i = 0; i < argv.length; i++){
88
+ const arg = argv[i];
89
+ if (arg === '--') break;
90
+ if (arg.startsWith('-')) continue;
91
+ const resolvedTopic = resolveTopicAlias(arg);
92
+ if (resolvedTopic) {
93
+ const resolved = [
94
+ ...argv
95
+ ];
96
+ resolved[i] = resolvedTopic;
97
+ return resolved;
98
+ }
99
+ break;
100
+ }
101
+ return argv;
102
+ }
60
103
 
61
104
  //# sourceMappingURL=topicAliases.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/topicAliases.ts"],"sourcesContent":["/**\n * Topic Alias Configuration\n *\n * Maps canonical topic names to their aliases. Used by:\n * - The command_not_found hook (runtime alias resolution)\n * - The check-topic-aliases script (build-time validation)\n *\n * Every topic with aliases must be listed here. The key is the canonical\n * topic name (the actual directory under commands/), and values are\n * alternative names that should resolve to it.\n *\n * Convention: prefer plural canonical names with singular aliases.\n * datasets: ['dataset'] - \"sanity dataset create\" works\n * cors: [] - no alias needed (no natural singular/plural pair)\n *\n * While the config technically supports any direction, keeping it consistent\n * (plural to singular) makes the CLI predictable for users.\n */\nexport const topicAliases: Record<string, string[]> = {\n backups: ['backup'],\n blueprints: ['blueprint'],\n datasets: ['dataset'],\n documents: ['document'],\n functions: ['function'],\n hooks: ['hook'],\n migrations: ['migration'],\n organizations: ['organization', 'organisations', 'organisation', 'org', 'orgs'],\n projects: ['project'],\n schemas: ['schema'],\n tokens: ['token'],\n users: ['user'],\n}\n"],"names":["topicAliases","backups","blueprints","datasets","documents","functions","hooks","migrations","organizations","projects","schemas","tokens","users"],"mappings":"AAAA;;;;;;;;;;;;;;;;;CAiBC,GACD,OAAO,MAAMA,eAAyC;IACpDC,SAAS;QAAC;KAAS;IACnBC,YAAY;QAAC;KAAY;IACzBC,UAAU;QAAC;KAAU;IACrBC,WAAW;QAAC;KAAW;IACvBC,WAAW;QAAC;KAAW;IACvBC,OAAO;QAAC;KAAO;IACfC,YAAY;QAAC;KAAY;IACzBC,eAAe;QAAC;QAAgB;QAAiB;QAAgB;QAAO;KAAO;IAC/EC,UAAU;QAAC;KAAU;IACrBC,SAAS;QAAC;KAAS;IACnBC,QAAQ;QAAC;KAAQ;IACjBC,OAAO;QAAC;KAAO;AACjB,EAAC"}
1
+ {"version":3,"sources":["../src/topicAliases.ts"],"sourcesContent":["/**\n * Topic Alias Configuration\n *\n * Maps canonical topic names to their aliases. Used by:\n * - The command_not_found hook (runtime alias resolution)\n * - Programmatic CLI invocation\n * - Help rendering\n * - The check-topic-aliases script (build-time validation)\n *\n * Every topic with aliases must be listed here. The key is the canonical\n * topic name (the actual directory under commands/), and values are\n * alternative names that should resolve to it.\n *\n * Convention: prefer plural canonical names with singular aliases.\n * datasets: ['dataset'] - \"sanity dataset create\" works\n * cors: [] - no alias needed (no natural singular/plural pair)\n *\n * While the config technically supports any direction, keeping it consistent\n * (plural to singular) makes the CLI predictable for users.\n */\nexport const topicAliases: Record<string, string[]> = {\n assets: ['asset'],\n backups: ['backup'],\n blueprints: ['blueprint'],\n datasets: ['dataset'],\n documents: ['document'],\n functions: ['function'],\n hooks: ['hook'],\n migrations: ['migration'],\n organizations: ['organization', 'organisations', 'organisation', 'org', 'orgs'],\n projects: ['project'],\n schemas: ['schema'],\n tokens: ['token'],\n users: ['user'],\n}\n\nconst canonicalTopicByAlias = new Map(\n Object.entries(topicAliases).flatMap(([canonical, aliases]) =>\n aliases.map((alias) => [alias, canonical]),\n ),\n)\n\n/**\n * Resolve the topic portion of a command ID from an alias to its canonical name.\n * Handles both bare topics (`hook`) and colon-separated command IDs (`hook:list`).\n *\n * @internal\n */\nexport function resolveTopicAlias(id: string): string | undefined {\n const separatorIndex = id.indexOf(':')\n const topic = separatorIndex === -1 ? id : id.slice(0, separatorIndex)\n const canonical = canonicalTopicByAlias.get(topic)\n if (!canonical) return undefined\n\n const suffix = separatorIndex === -1 ? '' : id.slice(separatorIndex)\n return `${canonical}${suffix}`\n}\n\n/**\n * Resolve the first positional topic in argv, preserving flags and arguments.\n *\n * @internal\n */\nexport function resolveTopicAliasInArgv(argv: string[]): string[] {\n for (let i = 0; i < argv.length; i++) {\n const arg = argv[i]\n if (arg === '--') break\n if (arg.startsWith('-')) continue\n\n const resolvedTopic = resolveTopicAlias(arg)\n if (resolvedTopic) {\n const resolved = [...argv]\n resolved[i] = resolvedTopic\n return resolved\n }\n break\n }\n return argv\n}\n"],"names":["topicAliases","assets","backups","blueprints","datasets","documents","functions","hooks","migrations","organizations","projects","schemas","tokens","users","canonicalTopicByAlias","Map","Object","entries","flatMap","canonical","aliases","map","alias","resolveTopicAlias","id","separatorIndex","indexOf","topic","slice","get","undefined","suffix","resolveTopicAliasInArgv","argv","i","length","arg","startsWith","resolvedTopic","resolved"],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;CAmBC,GACD,OAAO,MAAMA,eAAyC;IACpDC,QAAQ;QAAC;KAAQ;IACjBC,SAAS;QAAC;KAAS;IACnBC,YAAY;QAAC;KAAY;IACzBC,UAAU;QAAC;KAAU;IACrBC,WAAW;QAAC;KAAW;IACvBC,WAAW;QAAC;KAAW;IACvBC,OAAO;QAAC;KAAO;IACfC,YAAY;QAAC;KAAY;IACzBC,eAAe;QAAC;QAAgB;QAAiB;QAAgB;QAAO;KAAO;IAC/EC,UAAU;QAAC;KAAU;IACrBC,SAAS;QAAC;KAAS;IACnBC,QAAQ;QAAC;KAAQ;IACjBC,OAAO;QAAC;KAAO;AACjB,EAAC;AAED,MAAMC,wBAAwB,IAAIC,IAChCC,OAAOC,OAAO,CAACjB,cAAckB,OAAO,CAAC,CAAC,CAACC,WAAWC,QAAQ,GACxDA,QAAQC,GAAG,CAAC,CAACC,QAAU;YAACA;YAAOH;SAAU;AAI7C;;;;;CAKC,GACD,OAAO,SAASI,kBAAkBC,EAAU;IAC1C,MAAMC,iBAAiBD,GAAGE,OAAO,CAAC;IAClC,MAAMC,QAAQF,mBAAmB,CAAC,IAAID,KAAKA,GAAGI,KAAK,CAAC,GAAGH;IACvD,MAAMN,YAAYL,sBAAsBe,GAAG,CAACF;IAC5C,IAAI,CAACR,WAAW,OAAOW;IAEvB,MAAMC,SAASN,mBAAmB,CAAC,IAAI,KAAKD,GAAGI,KAAK,CAACH;IACrD,OAAO,GAAGN,YAAYY,QAAQ;AAChC;AAEA;;;;CAIC,GACD,OAAO,SAASC,wBAAwBC,IAAc;IACpD,IAAK,IAAIC,IAAI,GAAGA,IAAID,KAAKE,MAAM,EAAED,IAAK;QACpC,MAAME,MAAMH,IAAI,CAACC,EAAE;QACnB,IAAIE,QAAQ,MAAM;QAClB,IAAIA,IAAIC,UAAU,CAAC,MAAM;QAEzB,MAAMC,gBAAgBf,kBAAkBa;QACxC,IAAIE,eAAe;YACjB,MAAMC,WAAW;mBAAIN;aAAK;YAC1BM,QAAQ,CAACL,EAAE,GAAGI;YACd,OAAOC;QACT;QACA;IACF;IACA,OAAON;AACT"}
@@ -1,10 +1,15 @@
1
1
  import minimist from 'minimist';
2
+ import { redactTelemetryArguments } from './telemetry/commandTelemetry.js';
3
+ function collectOptionArguments(argv, commandTelemetry) {
4
+ return redactTelemetryArguments(argv, commandTelemetry).filter((argument)=>argument.startsWith('-'));
5
+ }
2
6
  /**
3
7
  * Parse the arguments from the command line
4
8
  *
5
9
  * @param argv - The arguments from the command line
10
+ * @param commandTelemetry - Resolved telemetry behavior for the command
6
11
  * @returns The parsed arguments
7
- */ export function parseArguments(argv = process.argv) {
12
+ */ export function parseArguments(argv = process.argv, commandTelemetry) {
8
13
  const args = argv.slice(2);
9
14
  const { '--': extraArguments, _, version, ...extOptions } = minimist(args, {
10
15
  '--': true,
@@ -18,7 +23,7 @@ import minimist from 'minimist';
18
23
  const [groupOrCommand, ...argsWithoutOptions] = _;
19
24
  const finalExtraArguments = [
20
25
  ...extraArguments || [],
21
- ...argv.filter((arg)=>arg.startsWith('-'))
26
+ ...collectOptionArguments(argv, commandTelemetry)
22
27
  ];
23
28
  // oclif allows to run `sanity help` or `sanity help <command>`
24
29
  // It does not fire the hooks on `--help` so this is okay to track
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/util/parseArguments.ts"],"sourcesContent":["import minimist from 'minimist'\n\ninterface ParsedArguments<F = Record<string, string>> {\n /**\n * Command arguments, eg any arguments after `sanity <command>` (no flags)\n */\n argsWithoutOptions: string[]\n\n // Raw, forwarded arguments, for commands that want to be more explicit about parsing\n argv: string[]\n\n /**\n * Options mostly relevant for the core CLI runner\n */\n coreOptions: {\n debug: boolean\n\n help: boolean\n\n version: boolean\n }\n\n /**\n * Command flags, without the core options (help, debug, version etc)\n */\n extOptions: F\n\n /**\n * Arguments after the ended argument list (--)\n */\n extraArguments: string[]\n\n /**\n * Group or command name, eg `dataset` (`sanity dataset`) or `import` (`sanity dataset import`)\n */\n groupOrCommand: string\n}\n\n/**\n * Parse the arguments from the command line\n *\n * @param argv - The arguments from the command line\n * @returns The parsed arguments\n */\nexport function parseArguments(argv = process.argv): ParsedArguments {\n const args = argv.slice(2)\n\n const {\n '--': extraArguments,\n _,\n version,\n ...extOptions\n } = minimist(args, {\n '--': true,\n boolean: ['version'],\n string: ['_'],\n })\n\n const [groupOrCommand, ...argsWithoutOptions] = _\n\n const finalExtraArguments = [\n ...(extraArguments || []),\n ...argv.filter((arg) => arg.startsWith('-')),\n ]\n\n // oclif allows to run `sanity help` or `sanity help <command>`\n // It does not fire the hooks on `--help` so this is okay to track\n const hasHelp = args.includes('help')\n\n // We only have global debug via env var\n const hasDebug = !!process.env.DEBUG\n\n return {\n groupOrCommand,\n\n argsWithoutOptions,\n argv,\n extOptions,\n extraArguments: finalExtraArguments,\n\n coreOptions: {\n debug: hasDebug,\n help: hasHelp,\n version,\n },\n }\n}\n"],"names":["minimist","parseArguments","argv","process","args","slice","extraArguments","_","version","extOptions","boolean","string","groupOrCommand","argsWithoutOptions","finalExtraArguments","filter","arg","startsWith","hasHelp","includes","hasDebug","env","DEBUG","coreOptions","debug","help"],"mappings":"AAAA,OAAOA,cAAc,WAAU;AAsC/B;;;;;CAKC,GACD,OAAO,SAASC,eAAeC,OAAOC,QAAQD,IAAI;IAChD,MAAME,OAAOF,KAAKG,KAAK,CAAC;IAExB,MAAM,EACJ,MAAMC,cAAc,EACpBC,CAAC,EACDC,OAAO,EACP,GAAGC,YACJ,GAAGT,SAASI,MAAM;QACjB,MAAM;QACNM,SAAS;YAAC;SAAU;QACpBC,QAAQ;YAAC;SAAI;IACf;IAEA,MAAM,CAACC,gBAAgB,GAAGC,mBAAmB,GAAGN;IAEhD,MAAMO,sBAAsB;WACtBR,kBAAkB,EAAE;WACrBJ,KAAKa,MAAM,CAAC,CAACC,MAAQA,IAAIC,UAAU,CAAC;KACxC;IAED,+DAA+D;IAC/D,kEAAkE;IAClE,MAAMC,UAAUd,KAAKe,QAAQ,CAAC;IAE9B,wCAAwC;IACxC,MAAMC,WAAW,CAAC,CAACjB,QAAQkB,GAAG,CAACC,KAAK;IAEpC,OAAO;QACLV;QAEAC;QACAX;QACAO;QACAH,gBAAgBQ;QAEhBS,aAAa;YACXC,OAAOJ;YACPK,MAAMP;YACNV;QACF;IACF;AACF"}
1
+ {"version":3,"sources":["../../src/util/parseArguments.ts"],"sourcesContent":["import minimist from 'minimist'\n\nimport {type CommandTelemetry, redactTelemetryArguments} from './telemetry/commandTelemetry.js'\n\ninterface ParsedArguments<F = Record<string, string>> {\n /**\n * Command arguments, eg any arguments after `sanity <command>` (no flags)\n */\n argsWithoutOptions: string[]\n\n // Raw, forwarded arguments, for commands that want to be more explicit about parsing\n argv: string[]\n\n /**\n * Options mostly relevant for the core CLI runner\n */\n coreOptions: {\n debug: boolean\n\n help: boolean\n\n version: boolean\n }\n\n /**\n * Command flags, without the core options (help, debug, version etc)\n */\n extOptions: F\n\n /**\n * Arguments after the ended argument list (--)\n */\n extraArguments: string[]\n\n /**\n * Group or command name, eg `dataset` (`sanity dataset`) or `import` (`sanity dataset import`)\n */\n groupOrCommand: string\n}\n\nfunction collectOptionArguments(argv: string[], commandTelemetry?: CommandTelemetry): string[] {\n return redactTelemetryArguments(argv, commandTelemetry).filter((argument) =>\n argument.startsWith('-'),\n )\n}\n\n/**\n * Parse the arguments from the command line\n *\n * @param argv - The arguments from the command line\n * @param commandTelemetry - Resolved telemetry behavior for the command\n * @returns The parsed arguments\n */\nexport function parseArguments(\n argv = process.argv,\n commandTelemetry?: CommandTelemetry,\n): ParsedArguments {\n const args = argv.slice(2)\n const {\n '--': extraArguments,\n _,\n version,\n ...extOptions\n } = minimist(args, {\n '--': true,\n boolean: ['version'],\n string: ['_'],\n })\n\n const [groupOrCommand, ...argsWithoutOptions] = _\n\n const finalExtraArguments = [\n ...(extraArguments || []),\n ...collectOptionArguments(argv, commandTelemetry),\n ]\n\n // oclif allows to run `sanity help` or `sanity help <command>`\n // It does not fire the hooks on `--help` so this is okay to track\n const hasHelp = args.includes('help')\n\n // We only have global debug via env var\n const hasDebug = !!process.env.DEBUG\n\n return {\n groupOrCommand,\n\n argsWithoutOptions,\n argv,\n extOptions,\n extraArguments: finalExtraArguments,\n\n coreOptions: {\n debug: hasDebug,\n help: hasHelp,\n version,\n },\n }\n}\n"],"names":["minimist","redactTelemetryArguments","collectOptionArguments","argv","commandTelemetry","filter","argument","startsWith","parseArguments","process","args","slice","extraArguments","_","version","extOptions","boolean","string","groupOrCommand","argsWithoutOptions","finalExtraArguments","hasHelp","includes","hasDebug","env","DEBUG","coreOptions","debug","help"],"mappings":"AAAA,OAAOA,cAAc,WAAU;AAE/B,SAA+BC,wBAAwB,QAAO,kCAAiC;AAsC/F,SAASC,uBAAuBC,IAAc,EAAEC,gBAAmC;IACjF,OAAOH,yBAAyBE,MAAMC,kBAAkBC,MAAM,CAAC,CAACC,WAC9DA,SAASC,UAAU,CAAC;AAExB;AAEA;;;;;;CAMC,GACD,OAAO,SAASC,eACdL,OAAOM,QAAQN,IAAI,EACnBC,gBAAmC;IAEnC,MAAMM,OAAOP,KAAKQ,KAAK,CAAC;IACxB,MAAM,EACJ,MAAMC,cAAc,EACpBC,CAAC,EACDC,OAAO,EACP,GAAGC,YACJ,GAAGf,SAASU,MAAM;QACjB,MAAM;QACNM,SAAS;YAAC;SAAU;QACpBC,QAAQ;YAAC;SAAI;IACf;IAEA,MAAM,CAACC,gBAAgB,GAAGC,mBAAmB,GAAGN;IAEhD,MAAMO,sBAAsB;WACtBR,kBAAkB,EAAE;WACrBV,uBAAuBC,MAAMC;KACjC;IAED,+DAA+D;IAC/D,kEAAkE;IAClE,MAAMiB,UAAUX,KAAKY,QAAQ,CAAC;IAE9B,wCAAwC;IACxC,MAAMC,WAAW,CAAC,CAACd,QAAQe,GAAG,CAACC,KAAK;IAEpC,OAAO;QACLP;QAEAC;QACAhB;QACAY;QACAH,gBAAgBQ;QAEhBM,aAAa;YACXC,OAAOJ;YACPK,MAAMP;YACNP;QACF;IACF;AACF"}
@@ -0,0 +1,17 @@
1
+ import { text } from 'node:stream/consumers';
2
+ /**
3
+ * Read a secret token from standard input. Reading from stdin keeps the
4
+ * secret out of shell history, process lists, and terminal logs.
5
+ * @param usageHint - Error message shown when stdin is a TTY (i.e. nothing
6
+ * was piped in)
7
+ * @returns The piped input, trimmed
8
+ *
9
+ * @internal
10
+ */ export async function readTokenFromStdin(usageHint) {
11
+ if (process.stdin.isTTY) {
12
+ throw new Error(usageHint);
13
+ }
14
+ return (await text(process.stdin)).trim();
15
+ }
16
+
17
+ //# sourceMappingURL=readTokenFromStdin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/util/readTokenFromStdin.ts"],"sourcesContent":["import {text} from 'node:stream/consumers'\n\n/**\n * Read a secret token from standard input. Reading from stdin keeps the\n * secret out of shell history, process lists, and terminal logs.\n * @param usageHint - Error message shown when stdin is a TTY (i.e. nothing\n * was piped in)\n * @returns The piped input, trimmed\n *\n * @internal\n */\nexport async function readTokenFromStdin(usageHint: string): Promise<string> {\n if (process.stdin.isTTY) {\n throw new Error(usageHint)\n }\n\n return (await text(process.stdin)).trim()\n}\n"],"names":["text","readTokenFromStdin","usageHint","process","stdin","isTTY","Error","trim"],"mappings":"AAAA,SAAQA,IAAI,QAAO,wBAAuB;AAE1C;;;;;;;;CAQC,GACD,OAAO,eAAeC,mBAAmBC,SAAiB;IACxD,IAAIC,QAAQC,KAAK,CAACC,KAAK,EAAE;QACvB,MAAM,IAAIC,MAAMJ;IAClB;IAEA,OAAO,AAAC,CAAA,MAAMF,KAAKG,QAAQC,KAAK,CAAA,EAAGG,IAAI;AACzC"}
@@ -0,0 +1,97 @@
1
+ import { Table as ConsoleTable } from 'console-table-printer';
2
+ import stringWidth from 'string-width';
3
+ import wrapAnsi from 'wrap-ansi';
4
+ const cellPaddingWidth = 2;
5
+ const borderCharacterWidth = 1;
6
+ function cellText(value) {
7
+ return value === undefined || value === null ? '' : String(value);
8
+ }
9
+ function maxLineWidth(value) {
10
+ return Math.max(...value.split('\n').map((line)=>stringWidth(line)));
11
+ }
12
+ export class Table {
13
+ #options;
14
+ #rows = [];
15
+ constructor(options){
16
+ this.#options = options;
17
+ }
18
+ addRow(cells, options) {
19
+ this.#rows.push({
20
+ cells,
21
+ options
22
+ });
23
+ return this;
24
+ }
25
+ addRows(rows, options) {
26
+ for (const row of rows)this.addRow(row, options);
27
+ return this;
28
+ }
29
+ render() {
30
+ const columns = this.#options.columns ?? [];
31
+ const columnTitles = columns.map(({ name, title = name })=>title);
32
+ const minimumColumnWidths = columns.map(({ minLen = 1 })=>Math.max(minLen, 1));
33
+ const columnWidths = columns.map(({ name }, index)=>Math.max(stringWidth(columnTitles[index]), ...this.#rows.map(({ cells })=>maxLineWidth(cellText(cells[name])))));
34
+ const borderWidth = borderCharacterWidth + columns.length * (cellPaddingWidth + borderCharacterWidth);
35
+ const minimumContentWidth = minimumColumnWidths.reduce((total, width)=>total + width, 0);
36
+ const availableContentWidth = Math.max((process.stdout.columns || Infinity) - borderWidth, minimumContentWidth);
37
+ let excessWidth = columnWidths.reduce((total, width)=>total + width, 0) - availableContentWidth;
38
+ while(excessWidth > 0){
39
+ const widestColumnIndex = columnWidths.map((width, index)=>({
40
+ index,
41
+ width: width - minimumColumnWidths[index]
42
+ })).toSorted((left, right)=>right.width - left.width)[0].index;
43
+ columnWidths[widestColumnIndex] -= 1;
44
+ excessWidth -= 1;
45
+ }
46
+ const tableWidth = borderWidth + columnWidths.reduce((total, width)=>total + width, 0);
47
+ const renderedColumns = columns.map((column, index)=>({
48
+ ...column,
49
+ maxLen: columnWidths[index],
50
+ title: wrapAnsi(columnTitles[index], columnWidths[index], {
51
+ hard: true
52
+ })
53
+ }));
54
+ const table = new ConsoleTable({
55
+ rowSeparator: true,
56
+ ...this.#options,
57
+ columns: renderedColumns,
58
+ title: undefined
59
+ });
60
+ for (const { cells, options } of this.#rows){
61
+ const wrappedCells = {
62
+ ...cells
63
+ };
64
+ for (const [index, { name }] of columns.entries()){
65
+ wrappedCells[name] = wrapAnsi(cellText(cells[name]), columnWidths[index], {
66
+ hard: true
67
+ });
68
+ }
69
+ table.addRow(wrappedCells, options);
70
+ }
71
+ const renderedTable = table.render();
72
+ if (!this.#options.title) return renderedTable;
73
+ // Use empty tables to preserve the printer's title styling without invoking row callbacks again.
74
+ const titleTableOptions = {
75
+ ...this.#options,
76
+ columns: renderedColumns,
77
+ rows: undefined
78
+ };
79
+ const renderedTitleTable = new ConsoleTable({
80
+ ...titleTableOptions,
81
+ title: this.#options.title
82
+ }).render();
83
+ const renderedEmptyTable = new ConsoleTable({
84
+ ...titleTableOptions,
85
+ title: undefined
86
+ }).render();
87
+ const emptyTableSuffix = `\n${renderedEmptyTable}`;
88
+ const renderedTitle = renderedTitleTable.slice(0, -emptyTableSuffix.length);
89
+ const wrappedTitle = wrapAnsi(renderedTitle, tableWidth, {
90
+ hard: true,
91
+ trim: false
92
+ });
93
+ return `${wrappedTitle}\n${renderedTable}`;
94
+ }
95
+ }
96
+
97
+ //# sourceMappingURL=responsiveTable.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/util/responsiveTable.ts"],"sourcesContent":["import {Table as ConsoleTable} from 'console-table-printer'\nimport stringWidth from 'string-width'\nimport wrapAnsi from 'wrap-ansi'\n\ntype ConsoleTableOptions = Exclude<\n ConstructorParameters<typeof ConsoleTable>[0],\n string[] | undefined\n>\ntype ConsoleTableRow = Parameters<ConsoleTable['addRow']>[0]\ntype ConsoleTableRowOptions = Parameters<ConsoleTable['addRow']>[1]\n\ntype StoredRow = {\n cells: ConsoleTableRow\n options?: ConsoleTableRowOptions\n}\n\nconst cellPaddingWidth = 2\nconst borderCharacterWidth = 1\n\nfunction cellText(value: ConsoleTableRow[string]): string {\n return value === undefined || value === null ? '' : String(value)\n}\n\nfunction maxLineWidth(value: string): number {\n return Math.max(...value.split('\\n').map((line) => stringWidth(line)))\n}\n\nexport class Table {\n readonly #options: ConsoleTableOptions\n readonly #rows: StoredRow[] = []\n\n constructor(options: ConsoleTableOptions) {\n this.#options = options\n }\n\n addRow(cells: ConsoleTableRow, options?: ConsoleTableRowOptions): this {\n this.#rows.push({cells, options})\n return this\n }\n\n addRows(rows: ConsoleTableRow[], options?: ConsoleTableRowOptions): this {\n for (const row of rows) this.addRow(row, options)\n return this\n }\n\n render(): string {\n const columns = this.#options.columns ?? []\n const columnTitles = columns.map(({name, title = name}) => title)\n const minimumColumnWidths = columns.map(({minLen = 1}) => Math.max(minLen, 1))\n const columnWidths = columns.map(({name}, index) =>\n Math.max(\n stringWidth(columnTitles[index]),\n ...this.#rows.map(({cells}) => maxLineWidth(cellText(cells[name]))),\n ),\n )\n const borderWidth =\n borderCharacterWidth + columns.length * (cellPaddingWidth + borderCharacterWidth)\n const minimumContentWidth = minimumColumnWidths.reduce((total, width) => total + width, 0)\n const availableContentWidth = Math.max(\n (process.stdout.columns || Infinity) - borderWidth,\n minimumContentWidth,\n )\n\n let excessWidth =\n columnWidths.reduce((total, width) => total + width, 0) - availableContentWidth\n while (excessWidth > 0) {\n const widestColumnIndex = columnWidths\n .map((width, index) => ({index, width: width - minimumColumnWidths[index]}))\n .toSorted((left, right) => right.width - left.width)[0].index\n columnWidths[widestColumnIndex] -= 1\n excessWidth -= 1\n }\n\n const tableWidth = borderWidth + columnWidths.reduce((total, width) => total + width, 0)\n const renderedColumns = columns.map((column, index) => ({\n ...column,\n maxLen: columnWidths[index],\n title: wrapAnsi(columnTitles[index], columnWidths[index], {hard: true}),\n }))\n const table = new ConsoleTable({\n rowSeparator: true,\n ...this.#options,\n columns: renderedColumns,\n title: undefined,\n })\n\n for (const {cells, options} of this.#rows) {\n const wrappedCells = {...cells}\n for (const [index, {name}] of columns.entries()) {\n wrappedCells[name] = wrapAnsi(cellText(cells[name]), columnWidths[index], {hard: true})\n }\n table.addRow(wrappedCells, options)\n }\n\n const renderedTable = table.render()\n if (!this.#options.title) return renderedTable\n\n // Use empty tables to preserve the printer's title styling without invoking row callbacks again.\n const titleTableOptions = {\n ...this.#options,\n columns: renderedColumns,\n rows: undefined,\n }\n const renderedTitleTable = new ConsoleTable({\n ...titleTableOptions,\n title: this.#options.title,\n }).render()\n const renderedEmptyTable = new ConsoleTable({...titleTableOptions, title: undefined}).render()\n const emptyTableSuffix = `\\n${renderedEmptyTable}`\n const renderedTitle = renderedTitleTable.slice(0, -emptyTableSuffix.length)\n const wrappedTitle = wrapAnsi(renderedTitle, tableWidth, {hard: true, trim: false})\n return `${wrappedTitle}\\n${renderedTable}`\n }\n}\n"],"names":["Table","ConsoleTable","stringWidth","wrapAnsi","cellPaddingWidth","borderCharacterWidth","cellText","value","undefined","String","maxLineWidth","Math","max","split","map","line","options","addRow","cells","push","addRows","rows","row","render","columns","columnTitles","name","title","minimumColumnWidths","minLen","columnWidths","index","borderWidth","length","minimumContentWidth","reduce","total","width","availableContentWidth","process","stdout","Infinity","excessWidth","widestColumnIndex","toSorted","left","right","tableWidth","renderedColumns","column","maxLen","hard","table","rowSeparator","wrappedCells","entries","renderedTable","titleTableOptions","renderedTitleTable","renderedEmptyTable","emptyTableSuffix","renderedTitle","slice","wrappedTitle","trim"],"mappings":"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"}
@@ -0,0 +1,34 @@
1
+ /** @internal */ export function defineCommandTelemetry(flags, config) {
2
+ return {
3
+ redactedFlags: (config.redact ?? []).map((name)=>{
4
+ const flag = flags[name];
5
+ const aliases = flag?.aliases ?? [];
6
+ return {
7
+ canonical: `--${name}`,
8
+ flags: [
9
+ `--${name}`,
10
+ ...aliases.map((alias)=>`${alias.length === 1 ? '-' : '--'}${alias}`),
11
+ ...flag?.char ? [
12
+ `-${flag.char}`
13
+ ] : [],
14
+ ...(flag?.charAliases ?? []).map((alias)=>`-${alias}`)
15
+ ]
16
+ };
17
+ })
18
+ };
19
+ }
20
+ export function redactTelemetryArguments(arguments_, commandTelemetry) {
21
+ let forwarding = false;
22
+ return arguments_.map((argument)=>{
23
+ if (argument === '--') {
24
+ forwarding = true;
25
+ return argument;
26
+ }
27
+ if (forwarding) return argument;
28
+ const isShortOption = argument.startsWith('-') && !argument.startsWith('--');
29
+ const redactedFlag = commandTelemetry?.redactedFlags.find(({ flags })=>flags.some((syntax)=>syntax.startsWith('--') ? argument === syntax || argument.startsWith(`${syntax}=`) : isShortOption && argument.startsWith(syntax)));
30
+ return redactedFlag?.canonical ?? argument;
31
+ });
32
+ }
33
+
34
+ //# sourceMappingURL=commandTelemetry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/util/telemetry/commandTelemetry.ts"],"sourcesContent":["import {type Interfaces} from '@oclif/core'\n\ninterface RedactedFlag {\n canonical: string\n flags: readonly string[]\n}\n\n/** @internal */\nexport interface CommandTelemetry {\n redactedFlags: readonly RedactedFlag[]\n}\n\ntype OptionFlagName<Flags extends Interfaces.FlagInput> = string &\n {\n [Name in keyof Flags]: Flags[Name] extends {type: 'option'} ? Name : never\n }[keyof Flags]\n\ntype CommandTelemetryConfig<Flags extends Interfaces.FlagInput> = {\n redact?: readonly OptionFlagName<Flags>[]\n}\n\n/** @internal */\nexport function defineCommandTelemetry<const Flags extends Interfaces.FlagInput>(\n flags: Flags,\n config: CommandTelemetryConfig<Flags>,\n): CommandTelemetry {\n return {\n redactedFlags: (config.redact ?? []).map((name) => {\n const flag = flags[name]\n const aliases = flag?.aliases ?? []\n\n return {\n canonical: `--${name}`,\n flags: [\n `--${name}`,\n ...aliases.map((alias) => `${alias.length === 1 ? '-' : '--'}${alias}`),\n ...(flag?.char ? [`-${flag.char}`] : []),\n ...(flag?.charAliases ?? []).map((alias) => `-${alias}`),\n ],\n }\n }),\n }\n}\n\nexport function redactTelemetryArguments(\n arguments_: string[],\n commandTelemetry?: CommandTelemetry,\n): string[] {\n let forwarding = false\n\n return arguments_.map((argument) => {\n if (argument === '--') {\n forwarding = true\n return argument\n }\n\n if (forwarding) return argument\n\n const isShortOption = argument.startsWith('-') && !argument.startsWith('--')\n const redactedFlag = commandTelemetry?.redactedFlags.find(({flags}) =>\n flags.some((syntax) =>\n syntax.startsWith('--')\n ? argument === syntax || argument.startsWith(`${syntax}=`)\n : isShortOption && argument.startsWith(syntax),\n ),\n )\n\n return redactedFlag?.canonical ?? argument\n })\n}\n"],"names":["defineCommandTelemetry","flags","config","redactedFlags","redact","map","name","flag","aliases","canonical","alias","length","char","charAliases","redactTelemetryArguments","arguments_","commandTelemetry","forwarding","argument","isShortOption","startsWith","redactedFlag","find","some","syntax"],"mappings":"AAqBA,cAAc,GACd,OAAO,SAASA,uBACdC,KAAY,EACZC,MAAqC;IAErC,OAAO;QACLC,eAAe,AAACD,CAAAA,OAAOE,MAAM,IAAI,EAAE,AAAD,EAAGC,GAAG,CAAC,CAACC;YACxC,MAAMC,OAAON,KAAK,CAACK,KAAK;YACxB,MAAME,UAAUD,MAAMC,WAAW,EAAE;YAEnC,OAAO;gBACLC,WAAW,CAAC,EAAE,EAAEH,MAAM;gBACtBL,OAAO;oBACL,CAAC,EAAE,EAAEK,MAAM;uBACRE,QAAQH,GAAG,CAAC,CAACK,QAAU,GAAGA,MAAMC,MAAM,KAAK,IAAI,MAAM,OAAOD,OAAO;uBAClEH,MAAMK,OAAO;wBAAC,CAAC,CAAC,EAAEL,KAAKK,IAAI,EAAE;qBAAC,GAAG,EAAE;uBACpC,AAACL,CAAAA,MAAMM,eAAe,EAAE,AAAD,EAAGR,GAAG,CAAC,CAACK,QAAU,CAAC,CAAC,EAAEA,OAAO;iBACxD;YACH;QACF;IACF;AACF;AAEA,OAAO,SAASI,yBACdC,UAAoB,EACpBC,gBAAmC;IAEnC,IAAIC,aAAa;IAEjB,OAAOF,WAAWV,GAAG,CAAC,CAACa;QACrB,IAAIA,aAAa,MAAM;YACrBD,aAAa;YACb,OAAOC;QACT;QAEA,IAAID,YAAY,OAAOC;QAEvB,MAAMC,gBAAgBD,SAASE,UAAU,CAAC,QAAQ,CAACF,SAASE,UAAU,CAAC;QACvE,MAAMC,eAAeL,kBAAkBb,cAAcmB,KAAK,CAAC,EAACrB,KAAK,EAAC,GAChEA,MAAMsB,IAAI,CAAC,CAACC,SACVA,OAAOJ,UAAU,CAAC,QACdF,aAAaM,UAAUN,SAASE,UAAU,CAAC,GAAGI,OAAO,CAAC,CAAC,IACvDL,iBAAiBD,SAASE,UAAU,CAACI;QAI7C,OAAOH,cAAcZ,aAAaS;IACpC;AACF"}
@@ -71,6 +71,16 @@ function parseRecord(projectId, value) {
71
71
  }
72
72
  return parsed;
73
73
  }
74
+ export function hasLocalUnclaimedProject(projectId) {
75
+ if (!projectId) return false;
76
+ try {
77
+ const stored = getUserConfig().get(UNCLAIMED_PROJECTS_CONFIG_KEY);
78
+ if (!stored || typeof stored !== 'object' || Array.isArray(stored)) return false;
79
+ return Object.hasOwn(stored, projectId);
80
+ } catch {
81
+ return false;
82
+ }
83
+ }
74
84
  /**
75
85
  * Read and validate the passive local recovery registry without changing it.
76
86
  */ export function readUnclaimedProjects() {
@@ -1 +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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"}
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\nexport function hasLocalUnclaimedProject(projectId: string): boolean {\n if (!projectId) return false\n try {\n const stored = getUserConfig().get(UNCLAIMED_PROJECTS_CONFIG_KEY)\n if (!stored || typeof stored !== 'object' || Array.isArray(stored)) return false\n return Object.hasOwn(stored, projectId)\n } catch {\n return false\n }\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","hasLocalUnclaimedProject","stored","Object","hasOwn","readUnclaimedProjects","undefined","entries","map","toSorted","left","right","removeUnclaimedProject","expectedClaimToken","current","_","remaining","keys","delete"],"mappings":"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"}
package/oclif.config.js CHANGED
@@ -13,10 +13,7 @@ export default {
13
13
  './dist/hooks/prerun/warnings.js',
14
14
  ],
15
15
  },
16
- // Note: do not add '@sanity/migrate' here. The `migrations` commands now ship
17
- // natively (see commands/migrations/); re-adding the plugin would register
18
- // duplicate command ids.
19
- plugins: ['@oclif/plugin-help', '@sanity/runtime-cli', '@sanity/codegen'],
16
+ plugins: ['@oclif/plugin-help', '@sanity/runtime-cli'],
20
17
  topics: {
21
18
  backups: {description: 'Manage dataset backups'},
22
19
  cors: {description: 'Manage CORS origins for your project'},
@@ -36,6 +33,7 @@ export default {
36
33
  skills: {description: 'Install Sanity agent skills for AI agents'},
37
34
  telemetry: {description: 'Manage telemetry consent'},
38
35
  tokens: {description: 'Manage API tokens for your project'},
36
+ typegen: {description: 'Generate TypeScript types for schema and GROQ'},
39
37
  users: {description: 'Manage project users and invitations'},
40
38
  },
41
39
  topicSeparator: ' ',