@sanity/cli 8.6.0 → 8.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (103) hide show
  1. package/README.md +918 -40
  2. package/dist/actions/api/distillApiRoutes.js +1 -1
  3. package/dist/actions/api/distillApiRoutes.js.map +1 -1
  4. package/dist/actions/api/resolveEndpoint.js +1 -1
  5. package/dist/actions/api/resolveEndpoint.js.map +1 -1
  6. package/dist/actions/backup/archiveDir.js +7 -3
  7. package/dist/actions/backup/archiveDir.js.map +1 -1
  8. package/dist/actions/context/resolveOrganizationId.js +17 -0
  9. package/dist/actions/context/resolveOrganizationId.js.map +1 -0
  10. package/dist/actions/context/waitForJob.js +24 -0
  11. package/dist/actions/context/waitForJob.js.map +1 -0
  12. package/dist/actions/context/watchJob.js +32 -0
  13. package/dist/actions/context/watchJob.js.map +1 -0
  14. package/dist/actions/deploy/deployApp.js +6 -6
  15. package/dist/actions/deploy/deployApp.js.map +1 -1
  16. package/dist/actions/deploy/deployStudio.js +6 -6
  17. package/dist/actions/deploy/deployStudio.js.map +1 -1
  18. package/dist/actions/exec/execScript.js +6 -18
  19. package/dist/actions/exec/execScript.js.map +1 -1
  20. package/dist/actions/exec/runScript.worker.js +21 -0
  21. package/dist/actions/exec/runScript.worker.js.map +1 -0
  22. package/dist/actions/init/initAction.js +1 -1
  23. package/dist/actions/init/initAction.js.map +1 -1
  24. package/dist/actions/media/importMedia.js +4 -2
  25. package/dist/actions/media/importMedia.js.map +1 -1
  26. package/dist/commands/backups/download.js +8 -17
  27. package/dist/commands/backups/download.js.map +1 -1
  28. package/dist/commands/backups/list.js +1 -1
  29. package/dist/commands/backups/list.js.map +1 -1
  30. package/dist/commands/context/build.js +111 -0
  31. package/dist/commands/context/build.js.map +1 -0
  32. package/dist/commands/context/create.js +106 -0
  33. package/dist/commands/context/create.js.map +1 -0
  34. package/dist/commands/context/delete.js +68 -0
  35. package/dist/commands/context/delete.js.map +1 -0
  36. package/dist/commands/context/get.js +95 -0
  37. package/dist/commands/context/get.js.map +1 -0
  38. package/dist/commands/context/imports/create.js +270 -0
  39. package/dist/commands/context/imports/create.js.map +1 -0
  40. package/dist/commands/context/imports/delete.js +73 -0
  41. package/dist/commands/context/imports/delete.js.map +1 -0
  42. package/dist/commands/context/imports/download.js +65 -0
  43. package/dist/commands/context/imports/download.js.map +1 -0
  44. package/dist/commands/context/imports/get.js +93 -0
  45. package/dist/commands/context/imports/get.js.map +1 -0
  46. package/dist/commands/context/imports/list.js +105 -0
  47. package/dist/commands/context/imports/list.js.map +1 -0
  48. package/dist/commands/context/jobs/get.js +90 -0
  49. package/dist/commands/context/jobs/get.js.map +1 -0
  50. package/dist/commands/context/list.js +109 -0
  51. package/dist/commands/context/list.js.map +1 -0
  52. package/dist/commands/context/refresh.js +46 -0
  53. package/dist/commands/context/refresh.js.map +1 -0
  54. package/dist/commands/context/update.js +127 -0
  55. package/dist/commands/context/update.js.map +1 -0
  56. package/dist/commands/datasets/alias/delete.js +4 -9
  57. package/dist/commands/datasets/alias/delete.js.map +1 -1
  58. package/dist/commands/datasets/alias/unlink.js +4 -9
  59. package/dist/commands/datasets/alias/unlink.js.map +1 -1
  60. package/dist/commands/datasets/copy.js +1 -1
  61. package/dist/commands/datasets/copy.js.map +1 -1
  62. package/dist/commands/datasets/delete.js +4 -9
  63. package/dist/commands/datasets/delete.js.map +1 -1
  64. package/dist/commands/graphql/undeploy.js +4 -9
  65. package/dist/commands/graphql/undeploy.js.map +1 -1
  66. package/dist/commands/init.js +1 -1
  67. package/dist/commands/init.js.map +1 -1
  68. package/dist/commands/media/create-aspect.js +5 -6
  69. package/dist/commands/media/create-aspect.js.map +1 -1
  70. package/dist/commands/media/delete-aspect.js +7 -23
  71. package/dist/commands/media/delete-aspect.js.map +1 -1
  72. package/dist/commands/media/deploy-aspect.js +4 -9
  73. package/dist/commands/media/deploy-aspect.js.map +1 -1
  74. package/dist/commands/media/export.js +3 -7
  75. package/dist/commands/media/export.js.map +1 -1
  76. package/dist/commands/media/import.js +3 -7
  77. package/dist/commands/media/import.js.map +1 -1
  78. package/dist/commands/organizations/create.js +4 -9
  79. package/dist/commands/organizations/create.js.map +1 -1
  80. package/dist/commands/schemas/delete.js +3 -8
  81. package/dist/commands/schemas/delete.js.map +1 -1
  82. package/dist/commands/tokens/delete.js +4 -7
  83. package/dist/commands/tokens/delete.js.map +1 -1
  84. package/dist/commands/users/invite.js +8 -18
  85. package/dist/commands/users/invite.js.map +1 -1
  86. package/dist/exports/index.js +1 -1
  87. package/dist/exports/index.js.map +1 -1
  88. package/dist/exports/invokeSanityCli/commandPolicies/mcpPolicy.js +18 -0
  89. package/dist/exports/invokeSanityCli/commandPolicies/mcpPolicy.js.map +1 -1
  90. package/dist/generated/apiRoutes.js +11 -9
  91. package/dist/generated/apiRoutes.js.map +1 -1
  92. package/dist/prompts/promptForOrganization.js +19 -0
  93. package/dist/prompts/promptForOrganization.js.map +1 -0
  94. package/dist/services/context.js +132 -0
  95. package/dist/services/context.js.map +1 -0
  96. package/dist/util/extractDocumentsFromNdjsonOrTarball.js.map +1 -1
  97. package/dist/util/sharedFlags.js +24 -0
  98. package/dist/util/sharedFlags.js.map +1 -1
  99. package/oclif.config.js +1 -0
  100. package/oclif.manifest.json +1931 -1133
  101. package/package.json +20 -26
  102. package/dist/util/dates.js +0 -125
  103. package/dist/util/dates.js.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/commands/context/get.ts"],"sourcesContent":["import {Args, Flags} from '@oclif/core'\nimport {type FlagInput} from '@oclif/core/interfaces'\nimport {exitCodes, SanityCommand, subdebug} from '@sanity/cli-core'\nimport {getErrorMessage} from '@sanity/cli-core/errors'\nimport {isHttpError} from '@sanity/client'\n\nimport {formatKeyValue} from '../../actions/debug/output.js'\nimport {getKnowledgeBase} from '../../services/context.js'\n\nconst getContextDebug = subdebug('context:get')\n\nexport class GetKnowledgeBaseCommand extends SanityCommand<typeof GetKnowledgeBaseCommand> {\n static override args = {\n knowledgeBaseId: Args.string({\n description: 'Knowledge base ID',\n required: true,\n }),\n }\n\n static override description = 'Get details of a knowledge base'\n\n static override examples = [\n {\n command: '<%= config.bin %> <%= command.id %> kb-abc123',\n description: 'Get details of a specific knowledge base',\n },\n {\n command: '<%= config.bin %> <%= command.id %> kb-abc123 --json',\n description: 'Output the knowledge base as JSON',\n },\n ]\n\n static override flags = {\n json: Flags.boolean({\n default: false,\n description: 'Output the knowledge base in JSON format',\n }),\n } satisfies FlagInput\n\n public async run(): Promise<void> {\n const {knowledgeBaseId} = this.args\n const {json} = this.flags\n\n let knowledgeBase\n try {\n knowledgeBase = await getKnowledgeBase(knowledgeBaseId)\n } catch (error) {\n getContextDebug('Error getting knowledge base', error)\n if (isHttpError(error) && error.statusCode === 404) {\n this.error(`Knowledge base \"${knowledgeBaseId}\" not found`, {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n this.error(`Failed to get knowledge base: ${getErrorMessage(error)}`, {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n\n if (json) {\n this.log(JSON.stringify(knowledgeBase, null, 2))\n return\n }\n\n const pending = knowledgeBase.pendingChanges\n const padTo = 15 // \"Pending changes\" is the longest key\n this.log(formatKeyValue('ID', knowledgeBase.publicId, {padTo}))\n this.log(formatKeyValue('Title', knowledgeBase.title, {padTo}))\n this.log(formatKeyValue('Description', knowledgeBase.description, {padTo}))\n this.log(formatKeyValue('Organization', knowledgeBase.organizationId, {padTo}))\n this.log(formatKeyValue('State', knowledgeBase.state, {padTo}))\n this.log(formatKeyValue('Active job', knowledgeBase.activeJobId ?? '-', {padTo}))\n this.log(\n formatKeyValue(\n 'Pending changes',\n pending\n ? `${pending.added} added, ${pending.changed} changed, ${pending.removed} removed`\n : '-',\n {padTo},\n ),\n )\n this.log(\n formatKeyValue(\n 'Refresh',\n knowledgeBase.refreshEnabled ? `enabled (${knowledgeBase.refreshFrequency})` : 'disabled',\n {padTo},\n ),\n )\n this.log(formatKeyValue('Open issues', knowledgeBase.openIssueCount, {padTo}))\n this.log(formatKeyValue('Instructions', knowledgeBase.instructionCount, {padTo}))\n this.log(formatKeyValue('Created', knowledgeBase.createdAt, {padTo}))\n this.log(formatKeyValue('Updated', knowledgeBase.updatedAt, {padTo}))\n }\n}\n"],"names":["Args","Flags","exitCodes","SanityCommand","subdebug","getErrorMessage","isHttpError","formatKeyValue","getKnowledgeBase","getContextDebug","GetKnowledgeBaseCommand","args","knowledgeBaseId","string","description","required","examples","command","flags","json","boolean","default","run","knowledgeBase","error","statusCode","exit","RUNTIME_ERROR","log","JSON","stringify","pending","pendingChanges","padTo","publicId","title","organizationId","state","activeJobId","added","changed","removed","refreshEnabled","refreshFrequency","openIssueCount","instructionCount","createdAt","updatedAt"],"mappings":"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"}
@@ -0,0 +1,270 @@
1
+ import { readFile } from 'node:fs/promises';
2
+ import { basename, extname } from 'node:path';
3
+ import { Args, Flags } from '@oclif/core';
4
+ import { exitCodes, SanityCommand, subdebug } from '@sanity/cli-core';
5
+ import { getErrorMessage } from '@sanity/cli-core/errors';
6
+ import { spinner } from '@sanity/cli-core/ux';
7
+ import { isHttpError } from '@sanity/client';
8
+ import { formatKeyValue } from '../../../actions/debug/output.js';
9
+ import { createImport } from '../../../services/context.js';
10
+ import { defineCommandTelemetry } from '../../../util/telemetry/commandTelemetry.js';
11
+ const createImportDebug = subdebug('context:imports:create');
12
+ const TEXT_CONTENT_TYPES = [
13
+ 'text/markdown',
14
+ 'text/plain'
15
+ ];
16
+ function isTextContentType(value) {
17
+ const textContentTypes = TEXT_CONTENT_TYPES;
18
+ return textContentTypes.includes(value);
19
+ }
20
+ const FILE_CONTENT_TYPES = {
21
+ '.csv': 'text/csv',
22
+ '.docx': 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
23
+ '.htm': 'text/html',
24
+ '.html': 'text/html',
25
+ '.json': 'application/json',
26
+ '.markdown': 'text/markdown',
27
+ '.md': 'text/markdown',
28
+ '.pdf': 'application/pdf',
29
+ '.txt': 'text/plain'
30
+ };
31
+ const flags = {
32
+ 'content-type': Flags.string({
33
+ description: 'Content type of the import (--text: text/markdown or text/plain; --file: any MIME type, inferred from the file extension when omitted)',
34
+ helpValue: '<mime>',
35
+ parse: async (input)=>{
36
+ const trimmed = input.trim();
37
+ if (trimmed === '') {
38
+ throw new Error('`--content-type` cannot be empty if provided');
39
+ }
40
+ return trimmed;
41
+ },
42
+ required: false
43
+ }),
44
+ file: Flags.string({
45
+ description: 'Path to a local file to import',
46
+ exclusive: [
47
+ 'text',
48
+ 'url',
49
+ 'query'
50
+ ],
51
+ helpValue: '<path>',
52
+ required: false
53
+ }),
54
+ query: Flags.string({
55
+ description: 'GROQ query binding a Sanity dataset as a source',
56
+ exclusive: [
57
+ 'text',
58
+ 'url',
59
+ 'file'
60
+ ],
61
+ required: false
62
+ }),
63
+ 'sanity-dataset': Flags.string({
64
+ dependsOn: [
65
+ 'query'
66
+ ],
67
+ description: 'Sanity dataset for a dataset import',
68
+ helpValue: '<name>',
69
+ required: false
70
+ }),
71
+ 'sanity-project': Flags.string({
72
+ dependsOn: [
73
+ 'query'
74
+ ],
75
+ description: 'Sanity project ID for a dataset import',
76
+ helpValue: '<id>',
77
+ required: false
78
+ }),
79
+ text: Flags.string({
80
+ description: 'Inline text content to import (requires --title)',
81
+ exclusive: [
82
+ 'file',
83
+ 'url',
84
+ 'query'
85
+ ],
86
+ required: false
87
+ }),
88
+ title: Flags.string({
89
+ dependsOn: [
90
+ 'text'
91
+ ],
92
+ description: 'Title for an inline text import',
93
+ required: false
94
+ }),
95
+ url: Flags.string({
96
+ description: 'Website URL to crawl',
97
+ exclusive: [
98
+ 'text',
99
+ 'file',
100
+ 'query'
101
+ ],
102
+ helpValue: '<url>',
103
+ required: false
104
+ })
105
+ };
106
+ export class CreateImportCommand extends SanityCommand {
107
+ static args = {
108
+ knowledgeBaseId: Args.string({
109
+ description: 'Knowledge base ID',
110
+ required: true
111
+ })
112
+ };
113
+ static description = 'Import content into a knowledge base';
114
+ static examples = [
115
+ {
116
+ command: '<%= config.bin %> <%= command.id %> kb-abc123 --text "Refunds are processed within 5 days" --title "Refund policy"',
117
+ description: 'Import inline text'
118
+ },
119
+ {
120
+ command: '<%= config.bin %> <%= command.id %> kb-abc123 --file ./handbook.pdf',
121
+ description: 'Upload and import a local file'
122
+ },
123
+ {
124
+ command: '<%= config.bin %> <%= command.id %> kb-abc123 --url https://example.com/docs',
125
+ description: 'Crawl a website'
126
+ },
127
+ {
128
+ command: '<%= config.bin %> <%= command.id %> kb-abc123 --query \'*[_type == "article"]\' --sanity-project abc123 --sanity-dataset production',
129
+ description: 'Bind a Sanity dataset as a source'
130
+ }
131
+ ];
132
+ static flags = flags;
133
+ static telemetry = defineCommandTelemetry(flags, {
134
+ redact: [
135
+ 'text',
136
+ 'file',
137
+ 'url',
138
+ 'title',
139
+ 'query'
140
+ ]
141
+ });
142
+ async run() {
143
+ const { knowledgeBaseId } = this.args;
144
+ const params = await this.buildImportParams();
145
+ const spin = spinner('Creating import').start();
146
+ try {
147
+ const { jobId } = await createImport(knowledgeBaseId, params);
148
+ spin.succeed('Import created');
149
+ this.log(formatKeyValue('Job ID', jobId));
150
+ this.log(`Track it with: sanity context jobs get ${knowledgeBaseId} ${jobId}`);
151
+ } catch (error) {
152
+ spin.fail();
153
+ createImportDebug('Error creating import', error);
154
+ if (isHttpError(error) && error.statusCode === 404) {
155
+ this.error(`Knowledge base "${knowledgeBaseId}" not found`, {
156
+ exit: exitCodes.RUNTIME_ERROR
157
+ });
158
+ }
159
+ this.error(`Failed to create import: ${getErrorMessage(error)}`, {
160
+ exit: exitCodes.RUNTIME_ERROR
161
+ });
162
+ }
163
+ }
164
+ async buildFileImportParams(filePath) {
165
+ const { 'content-type': contentType } = this.flags;
166
+ let fileContent;
167
+ try {
168
+ fileContent = await readFile(filePath);
169
+ } catch (error) {
170
+ createImportDebug('Error reading import file', error);
171
+ this.error(`Failed to read file "${filePath}": ${getErrorMessage(error)}`, {
172
+ exit: exitCodes.RUNTIME_ERROR
173
+ });
174
+ }
175
+ // The Context API signs the upload URL for a content-type header, so one
176
+ // must always be sent or the upload fails (API quirk found in live testing).
177
+ const inferredContentType = FILE_CONTENT_TYPES[extname(filePath).toLowerCase()] ?? 'application/octet-stream';
178
+ return {
179
+ contentType: contentType ?? inferredContentType,
180
+ file: fileContent,
181
+ filename: basename(filePath),
182
+ type: 'file'
183
+ };
184
+ }
185
+ async buildImportParams() {
186
+ const { 'content-type': contentType, file, query, 'sanity-dataset': sanityDataset, 'sanity-project': sanityProject, text, url } = this.flags;
187
+ const sources = [
188
+ [
189
+ '--text',
190
+ text
191
+ ],
192
+ [
193
+ '--file',
194
+ file
195
+ ],
196
+ [
197
+ '--url',
198
+ url
199
+ ],
200
+ [
201
+ '--query',
202
+ query
203
+ ]
204
+ ];
205
+ const provided = sources.filter(([, value])=>value !== undefined);
206
+ if (provided.length !== 1) {
207
+ this.error('Provide exactly one of --text, --file, --url or --query.', {
208
+ exit: exitCodes.USAGE_ERROR
209
+ });
210
+ }
211
+ const [sourceFlag, sourceValue] = provided[0];
212
+ if (!sourceValue?.trim()) {
213
+ this.error(`${sourceFlag} cannot be empty`, {
214
+ exit: exitCodes.USAGE_ERROR
215
+ });
216
+ }
217
+ if (sourceFlag === '--text') {
218
+ return this.buildTextImportParams(sourceValue);
219
+ }
220
+ if (sourceFlag === '--file') {
221
+ return this.buildFileImportParams(sourceValue);
222
+ }
223
+ if (contentType !== undefined) {
224
+ this.error('The --content-type flag only applies to --text and --file imports.', {
225
+ exit: exitCodes.USAGE_ERROR
226
+ });
227
+ }
228
+ if (sourceFlag === '--url') {
229
+ return {
230
+ type: 'crawl',
231
+ url: sourceValue
232
+ };
233
+ }
234
+ // Only --query remains; the checks above narrow `sourceFlag` to '--query'.
235
+ if (!sanityProject || !sanityDataset) {
236
+ this.error('Dataset imports require --sanity-project and --sanity-dataset alongside --query.', {
237
+ exit: exitCodes.USAGE_ERROR
238
+ });
239
+ }
240
+ return {
241
+ query: sourceValue,
242
+ sanityDatasetId: sanityDataset,
243
+ sanityProjectId: sanityProject,
244
+ type: 'dataset'
245
+ };
246
+ }
247
+ buildTextImportParams(text) {
248
+ const { 'content-type': contentType, title } = this.flags;
249
+ if (!title?.trim()) {
250
+ this.error('Title is required for text imports. Provide it with the --title flag.', {
251
+ exit: exitCodes.USAGE_ERROR
252
+ });
253
+ }
254
+ if (contentType !== undefined && !isTextContentType(contentType)) {
255
+ this.error(`Text imports support content types ${TEXT_CONTENT_TYPES.join(' and ')}, got "${contentType}".`, {
256
+ exit: exitCodes.USAGE_ERROR
257
+ });
258
+ }
259
+ return {
260
+ content: text,
261
+ title: title.trim(),
262
+ type: 'text',
263
+ ...contentType === undefined ? {} : {
264
+ contentType
265
+ }
266
+ };
267
+ }
268
+ }
269
+
270
+ //# sourceMappingURL=create.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../src/commands/context/imports/create.ts"],"sourcesContent":["import {readFile} from 'node:fs/promises'\nimport {basename, extname} from 'node:path'\n\nimport {Args, Flags} from '@oclif/core'\nimport {type FlagInput} from '@oclif/core/interfaces'\nimport {exitCodes, SanityCommand, subdebug} from '@sanity/cli-core'\nimport {getErrorMessage} from '@sanity/cli-core/errors'\nimport {spinner} from '@sanity/cli-core/ux'\nimport {type Context, isHttpError} from '@sanity/client'\n\nimport {formatKeyValue} from '../../../actions/debug/output.js'\nimport {createImport} from '../../../services/context.js'\nimport {defineCommandTelemetry} from '../../../util/telemetry/commandTelemetry.js'\n\nconst createImportDebug = subdebug('context:imports:create')\n\nconst TEXT_CONTENT_TYPES = ['text/markdown', 'text/plain'] as const\n\nfunction isTextContentType(value: string): value is (typeof TEXT_CONTENT_TYPES)[number] {\n const textContentTypes: readonly string[] = TEXT_CONTENT_TYPES\n return textContentTypes.includes(value)\n}\n\nconst FILE_CONTENT_TYPES: Record<string, string> = {\n '.csv': 'text/csv',\n '.docx': 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',\n '.htm': 'text/html',\n '.html': 'text/html',\n '.json': 'application/json',\n '.markdown': 'text/markdown',\n '.md': 'text/markdown',\n '.pdf': 'application/pdf',\n '.txt': 'text/plain',\n}\n\nconst flags = {\n 'content-type': Flags.string({\n description:\n 'Content type of the import (--text: text/markdown or text/plain; --file: any MIME type, inferred from the file extension when omitted)',\n helpValue: '<mime>',\n parse: async (input: string) => {\n const trimmed = input.trim()\n if (trimmed === '') {\n throw new Error('`--content-type` cannot be empty if provided')\n }\n return trimmed\n },\n required: false,\n }),\n file: Flags.string({\n description: 'Path to a local file to import',\n exclusive: ['text', 'url', 'query'],\n helpValue: '<path>',\n required: false,\n }),\n query: Flags.string({\n description: 'GROQ query binding a Sanity dataset as a source',\n exclusive: ['text', 'url', 'file'],\n required: false,\n }),\n 'sanity-dataset': Flags.string({\n dependsOn: ['query'],\n description: 'Sanity dataset for a dataset import',\n helpValue: '<name>',\n required: false,\n }),\n 'sanity-project': Flags.string({\n dependsOn: ['query'],\n description: 'Sanity project ID for a dataset import',\n helpValue: '<id>',\n required: false,\n }),\n text: Flags.string({\n description: 'Inline text content to import (requires --title)',\n exclusive: ['file', 'url', 'query'],\n required: false,\n }),\n title: Flags.string({\n dependsOn: ['text'],\n description: 'Title for an inline text import',\n required: false,\n }),\n url: Flags.string({\n description: 'Website URL to crawl',\n exclusive: ['text', 'file', 'query'],\n helpValue: '<url>',\n required: false,\n }),\n} satisfies FlagInput\n\nexport class CreateImportCommand extends SanityCommand<typeof CreateImportCommand> {\n static override args = {\n knowledgeBaseId: Args.string({\n description: 'Knowledge base ID',\n required: true,\n }),\n }\n\n static override description = 'Import content into a knowledge base'\n\n static override examples = [\n {\n command:\n '<%= config.bin %> <%= command.id %> kb-abc123 --text \"Refunds are processed within 5 days\" --title \"Refund policy\"',\n description: 'Import inline text',\n },\n {\n command: '<%= config.bin %> <%= command.id %> kb-abc123 --file ./handbook.pdf',\n description: 'Upload and import a local file',\n },\n {\n command: '<%= config.bin %> <%= command.id %> kb-abc123 --url https://example.com/docs',\n description: 'Crawl a website',\n },\n {\n command:\n '<%= config.bin %> <%= command.id %> kb-abc123 --query \\'*[_type == \"article\"]\\' --sanity-project abc123 --sanity-dataset production',\n description: 'Bind a Sanity dataset as a source',\n },\n ]\n\n static override flags = flags\n\n static telemetry = defineCommandTelemetry(flags, {\n redact: ['text', 'file', 'url', 'title', 'query'],\n })\n\n public async run(): Promise<void> {\n const {knowledgeBaseId} = this.args\n\n const params = await this.buildImportParams()\n\n const spin = spinner('Creating import').start()\n try {\n const {jobId} = await createImport(knowledgeBaseId, params)\n spin.succeed('Import created')\n this.log(formatKeyValue('Job ID', jobId))\n this.log(`Track it with: sanity context jobs get ${knowledgeBaseId} ${jobId}`)\n } catch (error) {\n spin.fail()\n createImportDebug('Error creating import', error)\n if (isHttpError(error) && error.statusCode === 404) {\n this.error(`Knowledge base \"${knowledgeBaseId}\" not found`, {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n this.error(`Failed to create import: ${getErrorMessage(error)}`, {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n }\n\n private async buildFileImportParams(filePath: string): Promise<Context.CreateFileImportParams> {\n const {'content-type': contentType} = this.flags\n\n let fileContent: Buffer\n try {\n fileContent = await readFile(filePath)\n } catch (error) {\n createImportDebug('Error reading import file', error)\n this.error(`Failed to read file \"${filePath}\": ${getErrorMessage(error)}`, {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n\n // The Context API signs the upload URL for a content-type header, so one\n // must always be sent or the upload fails (API quirk found in live testing).\n const inferredContentType =\n FILE_CONTENT_TYPES[extname(filePath).toLowerCase()] ?? 'application/octet-stream'\n\n return {\n contentType: contentType ?? inferredContentType,\n file: fileContent,\n filename: basename(filePath),\n type: 'file',\n }\n }\n\n private async buildImportParams(): Promise<\n Context.CreateFileImportParams | Context.CreateImportParams\n > {\n const {\n 'content-type': contentType,\n file,\n query,\n 'sanity-dataset': sanityDataset,\n 'sanity-project': sanityProject,\n text,\n url,\n } = this.flags\n\n const sources: [flag: '--file' | '--query' | '--text' | '--url', value: string | undefined][] =\n [\n ['--text', text],\n ['--file', file],\n ['--url', url],\n ['--query', query],\n ]\n const provided = sources.filter(([, value]) => value !== undefined)\n if (provided.length !== 1) {\n this.error('Provide exactly one of --text, --file, --url or --query.', {\n exit: exitCodes.USAGE_ERROR,\n })\n }\n\n const [sourceFlag, sourceValue] = provided[0]\n if (!sourceValue?.trim()) {\n this.error(`${sourceFlag} cannot be empty`, {exit: exitCodes.USAGE_ERROR})\n }\n\n if (sourceFlag === '--text') {\n return this.buildTextImportParams(sourceValue)\n }\n\n if (sourceFlag === '--file') {\n return this.buildFileImportParams(sourceValue)\n }\n\n if (contentType !== undefined) {\n this.error('The --content-type flag only applies to --text and --file imports.', {\n exit: exitCodes.USAGE_ERROR,\n })\n }\n\n if (sourceFlag === '--url') {\n return {type: 'crawl', url: sourceValue}\n }\n\n // Only --query remains; the checks above narrow `sourceFlag` to '--query'.\n if (!sanityProject || !sanityDataset) {\n this.error(\n 'Dataset imports require --sanity-project and --sanity-dataset alongside --query.',\n {exit: exitCodes.USAGE_ERROR},\n )\n }\n\n return {\n query: sourceValue,\n sanityDatasetId: sanityDataset,\n sanityProjectId: sanityProject,\n type: 'dataset',\n }\n }\n\n private buildTextImportParams(text: string): Context.CreateImportParams {\n const {'content-type': contentType, title} = this.flags\n\n if (!title?.trim()) {\n this.error('Title is required for text imports. Provide it with the --title flag.', {\n exit: exitCodes.USAGE_ERROR,\n })\n }\n\n if (contentType !== undefined && !isTextContentType(contentType)) {\n this.error(\n `Text imports support content types ${TEXT_CONTENT_TYPES.join(' and ')}, got \"${contentType}\".`,\n {exit: exitCodes.USAGE_ERROR},\n )\n }\n\n return {\n content: text,\n title: title.trim(),\n type: 'text',\n ...(contentType === undefined ? {} : {contentType}),\n }\n }\n}\n"],"names":["readFile","basename","extname","Args","Flags","exitCodes","SanityCommand","subdebug","getErrorMessage","spinner","isHttpError","formatKeyValue","createImport","defineCommandTelemetry","createImportDebug","TEXT_CONTENT_TYPES","isTextContentType","value","textContentTypes","includes","FILE_CONTENT_TYPES","flags","string","description","helpValue","parse","input","trimmed","trim","Error","required","file","exclusive","query","dependsOn","text","title","url","CreateImportCommand","args","knowledgeBaseId","examples","command","telemetry","redact","run","params","buildImportParams","spin","start","jobId","succeed","log","error","fail","statusCode","exit","RUNTIME_ERROR","buildFileImportParams","filePath","contentType","fileContent","inferredContentType","toLowerCase","filename","type","sanityDataset","sanityProject","sources","provided","filter","undefined","length","USAGE_ERROR","sourceFlag","sourceValue","buildTextImportParams","sanityDatasetId","sanityProjectId","join","content"],"mappings":"AAAA,SAAQA,QAAQ,QAAO,mBAAkB;AACzC,SAAQC,QAAQ,EAAEC,OAAO,QAAO,YAAW;AAE3C,SAAQC,IAAI,EAAEC,KAAK,QAAO,cAAa;AAEvC,SAAQC,SAAS,EAAEC,aAAa,EAAEC,QAAQ,QAAO,mBAAkB;AACnE,SAAQC,eAAe,QAAO,0BAAyB;AACvD,SAAQC,OAAO,QAAO,sBAAqB;AAC3C,SAAsBC,WAAW,QAAO,iBAAgB;AAExD,SAAQC,cAAc,QAAO,mCAAkC;AAC/D,SAAQC,YAAY,QAAO,+BAA8B;AACzD,SAAQC,sBAAsB,QAAO,8CAA6C;AAElF,MAAMC,oBAAoBP,SAAS;AAEnC,MAAMQ,qBAAqB;IAAC;IAAiB;CAAa;AAE1D,SAASC,kBAAkBC,KAAa;IACtC,MAAMC,mBAAsCH;IAC5C,OAAOG,iBAAiBC,QAAQ,CAACF;AACnC;AAEA,MAAMG,qBAA6C;IACjD,QAAQ;IACR,SAAS;IACT,QAAQ;IACR,SAAS;IACT,SAAS;IACT,aAAa;IACb,OAAO;IACP,QAAQ;IACR,QAAQ;AACV;AAEA,MAAMC,QAAQ;IACZ,gBAAgBjB,MAAMkB,MAAM,CAAC;QAC3BC,aACE;QACFC,WAAW;QACXC,OAAO,OAAOC;YACZ,MAAMC,UAAUD,MAAME,IAAI;YAC1B,IAAID,YAAY,IAAI;gBAClB,MAAM,IAAIE,MAAM;YAClB;YACA,OAAOF;QACT;QACAG,UAAU;IACZ;IACAC,MAAM3B,MAAMkB,MAAM,CAAC;QACjBC,aAAa;QACbS,WAAW;YAAC;YAAQ;YAAO;SAAQ;QACnCR,WAAW;QACXM,UAAU;IACZ;IACAG,OAAO7B,MAAMkB,MAAM,CAAC;QAClBC,aAAa;QACbS,WAAW;YAAC;YAAQ;YAAO;SAAO;QAClCF,UAAU;IACZ;IACA,kBAAkB1B,MAAMkB,MAAM,CAAC;QAC7BY,WAAW;YAAC;SAAQ;QACpBX,aAAa;QACbC,WAAW;QACXM,UAAU;IACZ;IACA,kBAAkB1B,MAAMkB,MAAM,CAAC;QAC7BY,WAAW;YAAC;SAAQ;QACpBX,aAAa;QACbC,WAAW;QACXM,UAAU;IACZ;IACAK,MAAM/B,MAAMkB,MAAM,CAAC;QACjBC,aAAa;QACbS,WAAW;YAAC;YAAQ;YAAO;SAAQ;QACnCF,UAAU;IACZ;IACAM,OAAOhC,MAAMkB,MAAM,CAAC;QAClBY,WAAW;YAAC;SAAO;QACnBX,aAAa;QACbO,UAAU;IACZ;IACAO,KAAKjC,MAAMkB,MAAM,CAAC;QAChBC,aAAa;QACbS,WAAW;YAAC;YAAQ;YAAQ;SAAQ;QACpCR,WAAW;QACXM,UAAU;IACZ;AACF;AAEA,OAAO,MAAMQ,4BAA4BhC;IACvC,OAAgBiC,OAAO;QACrBC,iBAAiBrC,KAAKmB,MAAM,CAAC;YAC3BC,aAAa;YACbO,UAAU;QACZ;IACF,EAAC;IAED,OAAgBP,cAAc,uCAAsC;IAEpE,OAAgBkB,WAAW;QACzB;YACEC,SACE;YACFnB,aAAa;QACf;QACA;YACEmB,SAAS;YACTnB,aAAa;QACf;QACA;YACEmB,SAAS;YACTnB,aAAa;QACf;QACA;YACEmB,SACE;YACFnB,aAAa;QACf;KACD,CAAA;IAED,OAAgBF,QAAQA,MAAK;IAE7B,OAAOsB,YAAY9B,uBAAuBQ,OAAO;QAC/CuB,QAAQ;YAAC;YAAQ;YAAQ;YAAO;YAAS;SAAQ;IACnD,GAAE;IAEF,MAAaC,MAAqB;QAChC,MAAM,EAACL,eAAe,EAAC,GAAG,IAAI,CAACD,IAAI;QAEnC,MAAMO,SAAS,MAAM,IAAI,CAACC,iBAAiB;QAE3C,MAAMC,OAAOvC,QAAQ,mBAAmBwC,KAAK;QAC7C,IAAI;YACF,MAAM,EAACC,KAAK,EAAC,GAAG,MAAMtC,aAAa4B,iBAAiBM;YACpDE,KAAKG,OAAO,CAAC;YACb,IAAI,CAACC,GAAG,CAACzC,eAAe,UAAUuC;YAClC,IAAI,CAACE,GAAG,CAAC,CAAC,uCAAuC,EAAEZ,gBAAgB,CAAC,EAAEU,OAAO;QAC/E,EAAE,OAAOG,OAAO;YACdL,KAAKM,IAAI;YACTxC,kBAAkB,yBAAyBuC;YAC3C,IAAI3C,YAAY2C,UAAUA,MAAME,UAAU,KAAK,KAAK;gBAClD,IAAI,CAACF,KAAK,CAAC,CAAC,gBAAgB,EAAEb,gBAAgB,WAAW,CAAC,EAAE;oBAC1DgB,MAAMnD,UAAUoD,aAAa;gBAC/B;YACF;YACA,IAAI,CAACJ,KAAK,CAAC,CAAC,yBAAyB,EAAE7C,gBAAgB6C,QAAQ,EAAE;gBAC/DG,MAAMnD,UAAUoD,aAAa;YAC/B;QACF;IACF;IAEA,MAAcC,sBAAsBC,QAAgB,EAA2C;QAC7F,MAAM,EAAC,gBAAgBC,WAAW,EAAC,GAAG,IAAI,CAACvC,KAAK;QAEhD,IAAIwC;QACJ,IAAI;YACFA,cAAc,MAAM7D,SAAS2D;QAC/B,EAAE,OAAON,OAAO;YACdvC,kBAAkB,6BAA6BuC;YAC/C,IAAI,CAACA,KAAK,CAAC,CAAC,qBAAqB,EAAEM,SAAS,GAAG,EAAEnD,gBAAgB6C,QAAQ,EAAE;gBACzEG,MAAMnD,UAAUoD,aAAa;YAC/B;QACF;QAEA,yEAAyE;QACzE,6EAA6E;QAC7E,MAAMK,sBACJ1C,kBAAkB,CAAClB,QAAQyD,UAAUI,WAAW,GAAG,IAAI;QAEzD,OAAO;YACLH,aAAaA,eAAeE;YAC5B/B,MAAM8B;YACNG,UAAU/D,SAAS0D;YACnBM,MAAM;QACR;IACF;IAEA,MAAclB,oBAEZ;QACA,MAAM,EACJ,gBAAgBa,WAAW,EAC3B7B,IAAI,EACJE,KAAK,EACL,kBAAkBiC,aAAa,EAC/B,kBAAkBC,aAAa,EAC/BhC,IAAI,EACJE,GAAG,EACJ,GAAG,IAAI,CAAChB,KAAK;QAEd,MAAM+C,UACJ;YACE;gBAAC;gBAAUjC;aAAK;YAChB;gBAAC;gBAAUJ;aAAK;YAChB;gBAAC;gBAASM;aAAI;YACd;gBAAC;gBAAWJ;aAAM;SACnB;QACH,MAAMoC,WAAWD,QAAQE,MAAM,CAAC,CAAC,GAAGrD,MAAM,GAAKA,UAAUsD;QACzD,IAAIF,SAASG,MAAM,KAAK,GAAG;YACzB,IAAI,CAACnB,KAAK,CAAC,4DAA4D;gBACrEG,MAAMnD,UAAUoE,WAAW;YAC7B;QACF;QAEA,MAAM,CAACC,YAAYC,YAAY,GAAGN,QAAQ,CAAC,EAAE;QAC7C,IAAI,CAACM,aAAa/C,QAAQ;YACxB,IAAI,CAACyB,KAAK,CAAC,GAAGqB,WAAW,gBAAgB,CAAC,EAAE;gBAAClB,MAAMnD,UAAUoE,WAAW;YAAA;QAC1E;QAEA,IAAIC,eAAe,UAAU;YAC3B,OAAO,IAAI,CAACE,qBAAqB,CAACD;QACpC;QAEA,IAAID,eAAe,UAAU;YAC3B,OAAO,IAAI,CAAChB,qBAAqB,CAACiB;QACpC;QAEA,IAAIf,gBAAgBW,WAAW;YAC7B,IAAI,CAAClB,KAAK,CAAC,sEAAsE;gBAC/EG,MAAMnD,UAAUoE,WAAW;YAC7B;QACF;QAEA,IAAIC,eAAe,SAAS;YAC1B,OAAO;gBAACT,MAAM;gBAAS5B,KAAKsC;YAAW;QACzC;QAEA,2EAA2E;QAC3E,IAAI,CAACR,iBAAiB,CAACD,eAAe;YACpC,IAAI,CAACb,KAAK,CACR,oFACA;gBAACG,MAAMnD,UAAUoE,WAAW;YAAA;QAEhC;QAEA,OAAO;YACLxC,OAAO0C;YACPE,iBAAiBX;YACjBY,iBAAiBX;YACjBF,MAAM;QACR;IACF;IAEQW,sBAAsBzC,IAAY,EAA8B;QACtE,MAAM,EAAC,gBAAgByB,WAAW,EAAExB,KAAK,EAAC,GAAG,IAAI,CAACf,KAAK;QAEvD,IAAI,CAACe,OAAOR,QAAQ;YAClB,IAAI,CAACyB,KAAK,CAAC,yEAAyE;gBAClFG,MAAMnD,UAAUoE,WAAW;YAC7B;QACF;QAEA,IAAIb,gBAAgBW,aAAa,CAACvD,kBAAkB4C,cAAc;YAChE,IAAI,CAACP,KAAK,CACR,CAAC,mCAAmC,EAAEtC,mBAAmBgE,IAAI,CAAC,SAAS,OAAO,EAAEnB,YAAY,EAAE,CAAC,EAC/F;gBAACJ,MAAMnD,UAAUoE,WAAW;YAAA;QAEhC;QAEA,OAAO;YACLO,SAAS7C;YACTC,OAAOA,MAAMR,IAAI;YACjBqC,MAAM;YACN,GAAIL,gBAAgBW,YAAY,CAAC,IAAI;gBAACX;YAAW,CAAC;QACpD;IACF;AACF"}
@@ -0,0 +1,73 @@
1
+ import { Args, Flags } from '@oclif/core';
2
+ import { exitCodes, SanityCommand, subdebug } from '@sanity/cli-core';
3
+ import { getErrorMessage } from '@sanity/cli-core/errors';
4
+ import { confirm } from '@sanity/cli-core/ux';
5
+ import { isHttpError } from '@sanity/client';
6
+ import { deleteImport } from '../../../services/context.js';
7
+ const deleteImportDebug = subdebug('context:imports:delete');
8
+ export class DeleteImportCommand extends SanityCommand {
9
+ static args = {
10
+ knowledgeBaseId: Args.string({
11
+ description: 'Knowledge base ID',
12
+ required: true
13
+ }),
14
+ // eslint-disable-next-line perfectionist/sort-objects -- positional order: knowledge base first
15
+ importId: Args.string({
16
+ description: 'Import ID',
17
+ required: true
18
+ })
19
+ };
20
+ static description = 'Delete an import from a knowledge base';
21
+ static examples = [
22
+ {
23
+ command: '<%= config.bin %> <%= command.id %> kb-abc123 import-def456',
24
+ description: 'Delete an import after confirmation'
25
+ },
26
+ {
27
+ command: '<%= config.bin %> <%= command.id %> kb-abc123 import-def456 --yes',
28
+ description: 'Delete an import without confirmation prompt'
29
+ }
30
+ ];
31
+ static flags = {
32
+ yes: Flags.boolean({
33
+ char: 'y',
34
+ default: false,
35
+ description: 'Skip confirmation prompt (unattended mode)'
36
+ })
37
+ };
38
+ async run() {
39
+ const { importId, knowledgeBaseId } = this.args;
40
+ const { yes: skipConfirmation } = this.flags;
41
+ if (this.isUnattended() && !skipConfirmation) {
42
+ this.error('Deletion requires confirmation. Pass `--yes` to delete the import.', {
43
+ exit: exitCodes.USAGE_ERROR
44
+ });
45
+ }
46
+ if (!skipConfirmation) {
47
+ const confirmed = await confirm({
48
+ default: false,
49
+ message: `Delete import "${importId}"?`
50
+ });
51
+ if (!confirmed) {
52
+ this.log('Import not deleted');
53
+ this.exit(exitCodes.USER_ABORT);
54
+ }
55
+ }
56
+ try {
57
+ await deleteImport(knowledgeBaseId, importId);
58
+ this.log('Import deleted');
59
+ } catch (error) {
60
+ deleteImportDebug('Error deleting import', error);
61
+ if (isHttpError(error) && error.statusCode === 404) {
62
+ this.error(`Import "${importId}" not found on knowledge base "${knowledgeBaseId}"`, {
63
+ exit: exitCodes.RUNTIME_ERROR
64
+ });
65
+ }
66
+ this.error(`Failed to delete import: ${getErrorMessage(error)}`, {
67
+ exit: exitCodes.RUNTIME_ERROR
68
+ });
69
+ }
70
+ }
71
+ }
72
+
73
+ //# sourceMappingURL=delete.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../src/commands/context/imports/delete.ts"],"sourcesContent":["import {Args, Flags} from '@oclif/core'\nimport {type FlagInput} from '@oclif/core/interfaces'\nimport {exitCodes, SanityCommand, subdebug} from '@sanity/cli-core'\nimport {getErrorMessage} from '@sanity/cli-core/errors'\nimport {confirm} from '@sanity/cli-core/ux'\nimport {isHttpError} from '@sanity/client'\n\nimport {deleteImport} from '../../../services/context.js'\n\nconst deleteImportDebug = subdebug('context:imports:delete')\n\nexport class DeleteImportCommand extends SanityCommand<typeof DeleteImportCommand> {\n static override args = {\n knowledgeBaseId: Args.string({\n description: 'Knowledge base ID',\n required: true,\n }),\n // eslint-disable-next-line perfectionist/sort-objects -- positional order: knowledge base first\n importId: Args.string({\n description: 'Import ID',\n required: true,\n }),\n }\n\n static override description = 'Delete an import from a knowledge base'\n\n static override examples = [\n {\n command: '<%= config.bin %> <%= command.id %> kb-abc123 import-def456',\n description: 'Delete an import after confirmation',\n },\n {\n command: '<%= config.bin %> <%= command.id %> kb-abc123 import-def456 --yes',\n description: 'Delete an import without confirmation prompt',\n },\n ]\n\n static override flags = {\n yes: Flags.boolean({\n char: 'y',\n default: false,\n description: 'Skip confirmation prompt (unattended mode)',\n }),\n } satisfies FlagInput\n\n public async run(): Promise<void> {\n const {importId, knowledgeBaseId} = this.args\n const {yes: skipConfirmation} = this.flags\n\n if (this.isUnattended() && !skipConfirmation) {\n this.error('Deletion requires confirmation. Pass `--yes` to delete the import.', {\n exit: exitCodes.USAGE_ERROR,\n })\n }\n\n if (!skipConfirmation) {\n const confirmed = await confirm({\n default: false,\n message: `Delete import \"${importId}\"?`,\n })\n\n if (!confirmed) {\n this.log('Import not deleted')\n this.exit(exitCodes.USER_ABORT)\n }\n }\n\n try {\n await deleteImport(knowledgeBaseId, importId)\n this.log('Import deleted')\n } catch (error) {\n deleteImportDebug('Error deleting import', error)\n if (isHttpError(error) && error.statusCode === 404) {\n this.error(`Import \"${importId}\" not found on knowledge base \"${knowledgeBaseId}\"`, {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n this.error(`Failed to delete import: ${getErrorMessage(error)}`, {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n }\n}\n"],"names":["Args","Flags","exitCodes","SanityCommand","subdebug","getErrorMessage","confirm","isHttpError","deleteImport","deleteImportDebug","DeleteImportCommand","args","knowledgeBaseId","string","description","required","importId","examples","command","flags","yes","boolean","char","default","run","skipConfirmation","isUnattended","error","exit","USAGE_ERROR","confirmed","message","log","USER_ABORT","statusCode","RUNTIME_ERROR"],"mappings":"AAAA,SAAQA,IAAI,EAAEC,KAAK,QAAO,cAAa;AAEvC,SAAQC,SAAS,EAAEC,aAAa,EAAEC,QAAQ,QAAO,mBAAkB;AACnE,SAAQC,eAAe,QAAO,0BAAyB;AACvD,SAAQC,OAAO,QAAO,sBAAqB;AAC3C,SAAQC,WAAW,QAAO,iBAAgB;AAE1C,SAAQC,YAAY,QAAO,+BAA8B;AAEzD,MAAMC,oBAAoBL,SAAS;AAEnC,OAAO,MAAMM,4BAA4BP;IACvC,OAAgBQ,OAAO;QACrBC,iBAAiBZ,KAAKa,MAAM,CAAC;YAC3BC,aAAa;YACbC,UAAU;QACZ;QACA,gGAAgG;QAChGC,UAAUhB,KAAKa,MAAM,CAAC;YACpBC,aAAa;YACbC,UAAU;QACZ;IACF,EAAC;IAED,OAAgBD,cAAc,yCAAwC;IAEtE,OAAgBG,WAAW;QACzB;YACEC,SAAS;YACTJ,aAAa;QACf;QACA;YACEI,SAAS;YACTJ,aAAa;QACf;KACD,CAAA;IAED,OAAgBK,QAAQ;QACtBC,KAAKnB,MAAMoB,OAAO,CAAC;YACjBC,MAAM;YACNC,SAAS;YACTT,aAAa;QACf;IACF,EAAqB;IAErB,MAAaU,MAAqB;QAChC,MAAM,EAACR,QAAQ,EAAEJ,eAAe,EAAC,GAAG,IAAI,CAACD,IAAI;QAC7C,MAAM,EAACS,KAAKK,gBAAgB,EAAC,GAAG,IAAI,CAACN,KAAK;QAE1C,IAAI,IAAI,CAACO,YAAY,MAAM,CAACD,kBAAkB;YAC5C,IAAI,CAACE,KAAK,CAAC,sEAAsE;gBAC/EC,MAAM1B,UAAU2B,WAAW;YAC7B;QACF;QAEA,IAAI,CAACJ,kBAAkB;YACrB,MAAMK,YAAY,MAAMxB,QAAQ;gBAC9BiB,SAAS;gBACTQ,SAAS,CAAC,eAAe,EAAEf,SAAS,EAAE,CAAC;YACzC;YAEA,IAAI,CAACc,WAAW;gBACd,IAAI,CAACE,GAAG,CAAC;gBACT,IAAI,CAACJ,IAAI,CAAC1B,UAAU+B,UAAU;YAChC;QACF;QAEA,IAAI;YACF,MAAMzB,aAAaI,iBAAiBI;YACpC,IAAI,CAACgB,GAAG,CAAC;QACX,EAAE,OAAOL,OAAO;YACdlB,kBAAkB,yBAAyBkB;YAC3C,IAAIpB,YAAYoB,UAAUA,MAAMO,UAAU,KAAK,KAAK;gBAClD,IAAI,CAACP,KAAK,CAAC,CAAC,QAAQ,EAAEX,SAAS,+BAA+B,EAAEJ,gBAAgB,CAAC,CAAC,EAAE;oBAClFgB,MAAM1B,UAAUiC,aAAa;gBAC/B;YACF;YACA,IAAI,CAACR,KAAK,CAAC,CAAC,yBAAyB,EAAEtB,gBAAgBsB,QAAQ,EAAE;gBAC/DC,MAAM1B,UAAUiC,aAAa;YAC/B;QACF;IACF;AACF"}
@@ -0,0 +1,65 @@
1
+ import { Args, Flags } from '@oclif/core';
2
+ import { exitCodes, SanityCommand, subdebug } from '@sanity/cli-core';
3
+ import { getErrorMessage } from '@sanity/cli-core/errors';
4
+ import { isHttpError } from '@sanity/client';
5
+ import { formatKeyValue } from '../../../actions/debug/output.js';
6
+ import { downloadImport } from '../../../services/context.js';
7
+ const downloadImportDebug = subdebug('context:imports:download');
8
+ export class DownloadImportCommand extends SanityCommand {
9
+ static args = {
10
+ knowledgeBaseId: Args.string({
11
+ description: 'Knowledge base ID',
12
+ required: true
13
+ }),
14
+ // eslint-disable-next-line perfectionist/sort-objects -- positional order: knowledge base first
15
+ importId: Args.string({
16
+ description: 'Import ID',
17
+ required: true
18
+ })
19
+ };
20
+ static description = 'Get a short-lived signed URL for the original uploaded bytes of a file import';
21
+ static examples = [
22
+ {
23
+ command: '<%= config.bin %> <%= command.id %> kb-abc123 import-def456',
24
+ description: 'Get a download URL for an uploaded file'
25
+ }
26
+ ];
27
+ static flags = {
28
+ json: Flags.boolean({
29
+ default: false,
30
+ description: 'Output the download URL in JSON format'
31
+ })
32
+ };
33
+ async run() {
34
+ const { importId, knowledgeBaseId } = this.args;
35
+ const { json } = this.flags;
36
+ let download;
37
+ try {
38
+ download = await downloadImport(knowledgeBaseId, importId);
39
+ } catch (error) {
40
+ downloadImportDebug('Error getting import download URL', error);
41
+ if (isHttpError(error) && error.statusCode === 404) {
42
+ this.error(`Import "${importId}" not found on knowledge base "${knowledgeBaseId}"`, {
43
+ exit: exitCodes.RUNTIME_ERROR
44
+ });
45
+ }
46
+ this.error(`Failed to get import download URL: ${getErrorMessage(error)}`, {
47
+ exit: exitCodes.RUNTIME_ERROR
48
+ });
49
+ }
50
+ if (json) {
51
+ this.log(JSON.stringify(download, null, 2));
52
+ return;
53
+ }
54
+ const padTo = 7 // "Expires" is the longest key
55
+ ;
56
+ this.log(formatKeyValue('URL', download.url, {
57
+ padTo
58
+ }));
59
+ this.log(formatKeyValue('Expires', download.expiresAt, {
60
+ padTo
61
+ }));
62
+ }
63
+ }
64
+
65
+ //# sourceMappingURL=download.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../src/commands/context/imports/download.ts"],"sourcesContent":["import {Args, Flags} from '@oclif/core'\nimport {type FlagInput} from '@oclif/core/interfaces'\nimport {exitCodes, SanityCommand, subdebug} from '@sanity/cli-core'\nimport {getErrorMessage} from '@sanity/cli-core/errors'\nimport {isHttpError} from '@sanity/client'\n\nimport {formatKeyValue} from '../../../actions/debug/output.js'\nimport {downloadImport} from '../../../services/context.js'\n\nconst downloadImportDebug = subdebug('context:imports:download')\n\nexport class DownloadImportCommand extends SanityCommand<typeof DownloadImportCommand> {\n static override args = {\n knowledgeBaseId: Args.string({\n description: 'Knowledge base ID',\n required: true,\n }),\n // eslint-disable-next-line perfectionist/sort-objects -- positional order: knowledge base first\n importId: Args.string({\n description: 'Import ID',\n required: true,\n }),\n }\n\n static override description =\n 'Get a short-lived signed URL for the original uploaded bytes of a file import'\n\n static override examples = [\n {\n command: '<%= config.bin %> <%= command.id %> kb-abc123 import-def456',\n description: 'Get a download URL for an uploaded file',\n },\n ]\n\n static override flags = {\n json: Flags.boolean({\n default: false,\n description: 'Output the download URL in JSON format',\n }),\n } satisfies FlagInput\n\n public async run(): Promise<void> {\n const {importId, knowledgeBaseId} = this.args\n const {json} = this.flags\n\n let download\n try {\n download = await downloadImport(knowledgeBaseId, importId)\n } catch (error) {\n downloadImportDebug('Error getting import download URL', error)\n if (isHttpError(error) && error.statusCode === 404) {\n this.error(`Import \"${importId}\" not found on knowledge base \"${knowledgeBaseId}\"`, {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n this.error(`Failed to get import download URL: ${getErrorMessage(error)}`, {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n\n if (json) {\n this.log(JSON.stringify(download, null, 2))\n return\n }\n\n const padTo = 7 // \"Expires\" is the longest key\n this.log(formatKeyValue('URL', download.url, {padTo}))\n this.log(formatKeyValue('Expires', download.expiresAt, {padTo}))\n }\n}\n"],"names":["Args","Flags","exitCodes","SanityCommand","subdebug","getErrorMessage","isHttpError","formatKeyValue","downloadImport","downloadImportDebug","DownloadImportCommand","args","knowledgeBaseId","string","description","required","importId","examples","command","flags","json","boolean","default","run","download","error","statusCode","exit","RUNTIME_ERROR","log","JSON","stringify","padTo","url","expiresAt"],"mappings":"AAAA,SAAQA,IAAI,EAAEC,KAAK,QAAO,cAAa;AAEvC,SAAQC,SAAS,EAAEC,aAAa,EAAEC,QAAQ,QAAO,mBAAkB;AACnE,SAAQC,eAAe,QAAO,0BAAyB;AACvD,SAAQC,WAAW,QAAO,iBAAgB;AAE1C,SAAQC,cAAc,QAAO,mCAAkC;AAC/D,SAAQC,cAAc,QAAO,+BAA8B;AAE3D,MAAMC,sBAAsBL,SAAS;AAErC,OAAO,MAAMM,8BAA8BP;IACzC,OAAgBQ,OAAO;QACrBC,iBAAiBZ,KAAKa,MAAM,CAAC;YAC3BC,aAAa;YACbC,UAAU;QACZ;QACA,gGAAgG;QAChGC,UAAUhB,KAAKa,MAAM,CAAC;YACpBC,aAAa;YACbC,UAAU;QACZ;IACF,EAAC;IAED,OAAgBD,cACd,gFAA+E;IAEjF,OAAgBG,WAAW;QACzB;YACEC,SAAS;YACTJ,aAAa;QACf;KACD,CAAA;IAED,OAAgBK,QAAQ;QACtBC,MAAMnB,MAAMoB,OAAO,CAAC;YAClBC,SAAS;YACTR,aAAa;QACf;IACF,EAAqB;IAErB,MAAaS,MAAqB;QAChC,MAAM,EAACP,QAAQ,EAAEJ,eAAe,EAAC,GAAG,IAAI,CAACD,IAAI;QAC7C,MAAM,EAACS,IAAI,EAAC,GAAG,IAAI,CAACD,KAAK;QAEzB,IAAIK;QACJ,IAAI;YACFA,WAAW,MAAMhB,eAAeI,iBAAiBI;QACnD,EAAE,OAAOS,OAAO;YACdhB,oBAAoB,qCAAqCgB;YACzD,IAAInB,YAAYmB,UAAUA,MAAMC,UAAU,KAAK,KAAK;gBAClD,IAAI,CAACD,KAAK,CAAC,CAAC,QAAQ,EAAET,SAAS,+BAA+B,EAAEJ,gBAAgB,CAAC,CAAC,EAAE;oBAClFe,MAAMzB,UAAU0B,aAAa;gBAC/B;YACF;YACA,IAAI,CAACH,KAAK,CAAC,CAAC,mCAAmC,EAAEpB,gBAAgBoB,QAAQ,EAAE;gBACzEE,MAAMzB,UAAU0B,aAAa;YAC/B;QACF;QAEA,IAAIR,MAAM;YACR,IAAI,CAACS,GAAG,CAACC,KAAKC,SAAS,CAACP,UAAU,MAAM;YACxC;QACF;QAEA,MAAMQ,QAAQ,EAAE,+BAA+B;;QAC/C,IAAI,CAACH,GAAG,CAACtB,eAAe,OAAOiB,SAASS,GAAG,EAAE;YAACD;QAAK;QACnD,IAAI,CAACH,GAAG,CAACtB,eAAe,WAAWiB,SAASU,SAAS,EAAE;YAACF;QAAK;IAC/D;AACF"}
@@ -0,0 +1,93 @@
1
+ import { Args, Flags } from '@oclif/core';
2
+ import { exitCodes, SanityCommand, subdebug } from '@sanity/cli-core';
3
+ import { getErrorMessage } from '@sanity/cli-core/errors';
4
+ import { isHttpError } from '@sanity/client';
5
+ import { formatKeyValue } from '../../../actions/debug/output.js';
6
+ import { getImport } from '../../../services/context.js';
7
+ const getImportDebug = subdebug('context:imports:get');
8
+ export class GetImportCommand extends SanityCommand {
9
+ static args = {
10
+ knowledgeBaseId: Args.string({
11
+ description: 'Knowledge base ID',
12
+ required: true
13
+ }),
14
+ // eslint-disable-next-line perfectionist/sort-objects -- positional order: knowledge base first
15
+ importId: Args.string({
16
+ description: 'Import ID',
17
+ required: true
18
+ })
19
+ };
20
+ static description = 'Get details of an import';
21
+ static examples = [
22
+ {
23
+ command: '<%= config.bin %> <%= command.id %> kb-abc123 import-def456',
24
+ description: 'Get details of a specific import'
25
+ },
26
+ {
27
+ command: '<%= config.bin %> <%= command.id %> kb-abc123 import-def456 --json',
28
+ description: 'Output the import as JSON'
29
+ }
30
+ ];
31
+ static flags = {
32
+ json: Flags.boolean({
33
+ default: false,
34
+ description: 'Output the import in JSON format'
35
+ })
36
+ };
37
+ async run() {
38
+ const { importId, knowledgeBaseId } = this.args;
39
+ const { json } = this.flags;
40
+ let importDetail;
41
+ try {
42
+ importDetail = await getImport(knowledgeBaseId, importId);
43
+ } catch (error) {
44
+ getImportDebug('Error getting import', error);
45
+ if (isHttpError(error) && error.statusCode === 404) {
46
+ this.error(`Import "${importId}" not found on knowledge base "${knowledgeBaseId}"`, {
47
+ exit: exitCodes.RUNTIME_ERROR
48
+ });
49
+ }
50
+ this.error(`Failed to get import: ${getErrorMessage(error)}`, {
51
+ exit: exitCodes.RUNTIME_ERROR
52
+ });
53
+ }
54
+ if (json) {
55
+ this.log(JSON.stringify(importDetail, null, 2));
56
+ return;
57
+ }
58
+ const padTo = 9 // "Completed" is the longest key
59
+ ;
60
+ this.log(formatKeyValue('ID', importDetail.id, {
61
+ padTo
62
+ }));
63
+ this.log(formatKeyValue('Name', importDetail.name ?? '-', {
64
+ padTo
65
+ }));
66
+ this.log(formatKeyValue('Kind', importDetail.sourceKind, {
67
+ padTo
68
+ }));
69
+ this.log(formatKeyValue('Status', importDetail.status, {
70
+ padTo
71
+ }));
72
+ this.log(formatKeyValue('Detail', importDetail.statusDetail ?? '-', {
73
+ padTo
74
+ }));
75
+ this.log(formatKeyValue('Error', importDetail.error ?? '-', {
76
+ padTo
77
+ }));
78
+ this.log(formatKeyValue('Sources', importDetail.sourceCount, {
79
+ padTo
80
+ }));
81
+ this.log(formatKeyValue('Distilled', `${importDetail.distilledCount}/${importDetail.totalDistillableCount}`, {
82
+ padTo
83
+ }));
84
+ this.log(formatKeyValue('Created', importDetail.createdAt, {
85
+ padTo
86
+ }));
87
+ this.log(formatKeyValue('Completed', importDetail.completedAt ?? '-', {
88
+ padTo
89
+ }));
90
+ }
91
+ }
92
+
93
+ //# sourceMappingURL=get.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../src/commands/context/imports/get.ts"],"sourcesContent":["import {Args, Flags} from '@oclif/core'\nimport {type FlagInput} from '@oclif/core/interfaces'\nimport {exitCodes, SanityCommand, subdebug} from '@sanity/cli-core'\nimport {getErrorMessage} from '@sanity/cli-core/errors'\nimport {isHttpError} from '@sanity/client'\n\nimport {formatKeyValue} from '../../../actions/debug/output.js'\nimport {getImport} from '../../../services/context.js'\n\nconst getImportDebug = subdebug('context:imports:get')\n\nexport class GetImportCommand extends SanityCommand<typeof GetImportCommand> {\n static override args = {\n knowledgeBaseId: Args.string({\n description: 'Knowledge base ID',\n required: true,\n }),\n // eslint-disable-next-line perfectionist/sort-objects -- positional order: knowledge base first\n importId: Args.string({\n description: 'Import ID',\n required: true,\n }),\n }\n\n static override description = 'Get details of an import'\n\n static override examples = [\n {\n command: '<%= config.bin %> <%= command.id %> kb-abc123 import-def456',\n description: 'Get details of a specific import',\n },\n {\n command: '<%= config.bin %> <%= command.id %> kb-abc123 import-def456 --json',\n description: 'Output the import as JSON',\n },\n ]\n\n static override flags = {\n json: Flags.boolean({\n default: false,\n description: 'Output the import in JSON format',\n }),\n } satisfies FlagInput\n\n public async run(): Promise<void> {\n const {importId, knowledgeBaseId} = this.args\n const {json} = this.flags\n\n let importDetail\n try {\n importDetail = await getImport(knowledgeBaseId, importId)\n } catch (error) {\n getImportDebug('Error getting import', error)\n if (isHttpError(error) && error.statusCode === 404) {\n this.error(`Import \"${importId}\" not found on knowledge base \"${knowledgeBaseId}\"`, {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n this.error(`Failed to get import: ${getErrorMessage(error)}`, {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n\n if (json) {\n this.log(JSON.stringify(importDetail, null, 2))\n return\n }\n\n const padTo = 9 // \"Completed\" is the longest key\n this.log(formatKeyValue('ID', importDetail.id, {padTo}))\n this.log(formatKeyValue('Name', importDetail.name ?? '-', {padTo}))\n this.log(formatKeyValue('Kind', importDetail.sourceKind, {padTo}))\n this.log(formatKeyValue('Status', importDetail.status, {padTo}))\n this.log(formatKeyValue('Detail', importDetail.statusDetail ?? '-', {padTo}))\n this.log(formatKeyValue('Error', importDetail.error ?? '-', {padTo}))\n this.log(formatKeyValue('Sources', importDetail.sourceCount, {padTo}))\n this.log(\n formatKeyValue(\n 'Distilled',\n `${importDetail.distilledCount}/${importDetail.totalDistillableCount}`,\n {padTo},\n ),\n )\n this.log(formatKeyValue('Created', importDetail.createdAt, {padTo}))\n this.log(formatKeyValue('Completed', importDetail.completedAt ?? '-', {padTo}))\n }\n}\n"],"names":["Args","Flags","exitCodes","SanityCommand","subdebug","getErrorMessage","isHttpError","formatKeyValue","getImport","getImportDebug","GetImportCommand","args","knowledgeBaseId","string","description","required","importId","examples","command","flags","json","boolean","default","run","importDetail","error","statusCode","exit","RUNTIME_ERROR","log","JSON","stringify","padTo","id","name","sourceKind","status","statusDetail","sourceCount","distilledCount","totalDistillableCount","createdAt","completedAt"],"mappings":"AAAA,SAAQA,IAAI,EAAEC,KAAK,QAAO,cAAa;AAEvC,SAAQC,SAAS,EAAEC,aAAa,EAAEC,QAAQ,QAAO,mBAAkB;AACnE,SAAQC,eAAe,QAAO,0BAAyB;AACvD,SAAQC,WAAW,QAAO,iBAAgB;AAE1C,SAAQC,cAAc,QAAO,mCAAkC;AAC/D,SAAQC,SAAS,QAAO,+BAA8B;AAEtD,MAAMC,iBAAiBL,SAAS;AAEhC,OAAO,MAAMM,yBAAyBP;IACpC,OAAgBQ,OAAO;QACrBC,iBAAiBZ,KAAKa,MAAM,CAAC;YAC3BC,aAAa;YACbC,UAAU;QACZ;QACA,gGAAgG;QAChGC,UAAUhB,KAAKa,MAAM,CAAC;YACpBC,aAAa;YACbC,UAAU;QACZ;IACF,EAAC;IAED,OAAgBD,cAAc,2BAA0B;IAExD,OAAgBG,WAAW;QACzB;YACEC,SAAS;YACTJ,aAAa;QACf;QACA;YACEI,SAAS;YACTJ,aAAa;QACf;KACD,CAAA;IAED,OAAgBK,QAAQ;QACtBC,MAAMnB,MAAMoB,OAAO,CAAC;YAClBC,SAAS;YACTR,aAAa;QACf;IACF,EAAqB;IAErB,MAAaS,MAAqB;QAChC,MAAM,EAACP,QAAQ,EAAEJ,eAAe,EAAC,GAAG,IAAI,CAACD,IAAI;QAC7C,MAAM,EAACS,IAAI,EAAC,GAAG,IAAI,CAACD,KAAK;QAEzB,IAAIK;QACJ,IAAI;YACFA,eAAe,MAAMhB,UAAUI,iBAAiBI;QAClD,EAAE,OAAOS,OAAO;YACdhB,eAAe,wBAAwBgB;YACvC,IAAInB,YAAYmB,UAAUA,MAAMC,UAAU,KAAK,KAAK;gBAClD,IAAI,CAACD,KAAK,CAAC,CAAC,QAAQ,EAAET,SAAS,+BAA+B,EAAEJ,gBAAgB,CAAC,CAAC,EAAE;oBAClFe,MAAMzB,UAAU0B,aAAa;gBAC/B;YACF;YACA,IAAI,CAACH,KAAK,CAAC,CAAC,sBAAsB,EAAEpB,gBAAgBoB,QAAQ,EAAE;gBAC5DE,MAAMzB,UAAU0B,aAAa;YAC/B;QACF;QAEA,IAAIR,MAAM;YACR,IAAI,CAACS,GAAG,CAACC,KAAKC,SAAS,CAACP,cAAc,MAAM;YAC5C;QACF;QAEA,MAAMQ,QAAQ,EAAE,iCAAiC;;QACjD,IAAI,CAACH,GAAG,CAACtB,eAAe,MAAMiB,aAAaS,EAAE,EAAE;YAACD;QAAK;QACrD,IAAI,CAACH,GAAG,CAACtB,eAAe,QAAQiB,aAAaU,IAAI,IAAI,KAAK;YAACF;QAAK;QAChE,IAAI,CAACH,GAAG,CAACtB,eAAe,QAAQiB,aAAaW,UAAU,EAAE;YAACH;QAAK;QAC/D,IAAI,CAACH,GAAG,CAACtB,eAAe,UAAUiB,aAAaY,MAAM,EAAE;YAACJ;QAAK;QAC7D,IAAI,CAACH,GAAG,CAACtB,eAAe,UAAUiB,aAAaa,YAAY,IAAI,KAAK;YAACL;QAAK;QAC1E,IAAI,CAACH,GAAG,CAACtB,eAAe,SAASiB,aAAaC,KAAK,IAAI,KAAK;YAACO;QAAK;QAClE,IAAI,CAACH,GAAG,CAACtB,eAAe,WAAWiB,aAAac,WAAW,EAAE;YAACN;QAAK;QACnE,IAAI,CAACH,GAAG,CACNtB,eACE,aACA,GAAGiB,aAAae,cAAc,CAAC,CAAC,EAAEf,aAAagB,qBAAqB,EAAE,EACtE;YAACR;QAAK;QAGV,IAAI,CAACH,GAAG,CAACtB,eAAe,WAAWiB,aAAaiB,SAAS,EAAE;YAACT;QAAK;QACjE,IAAI,CAACH,GAAG,CAACtB,eAAe,aAAaiB,aAAakB,WAAW,IAAI,KAAK;YAACV;QAAK;IAC9E;AACF"}