@sanity/cli 8.0.1 → 8.0.2
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.
- package/dist/actions/backup/downloadAsset.js +3 -24
- package/dist/actions/backup/downloadAsset.js.map +1 -1
- package/dist/actions/backup/downloadDocument.js +11 -22
- package/dist/actions/backup/downloadDocument.js.map +1 -1
- package/dist/actions/backup/downloadStream.js +83 -0
- package/dist/actions/backup/downloadStream.js.map +1 -0
- package/dist/actions/documents/validate.js +0 -3
- package/dist/actions/documents/validate.js.map +1 -1
- package/dist/actions/documents/validateDocuments.worker.js +4 -1
- package/dist/actions/documents/validateDocuments.worker.js.map +1 -1
- package/dist/actions/schema/uploadSchemaToLexicon.js +3 -0
- package/dist/actions/schema/uploadSchemaToLexicon.js.map +1 -1
- package/dist/actions/telemetry/telemetryDebug.js +2 -2
- package/dist/actions/telemetry/telemetryDebug.js.map +1 -1
- package/dist/commands/datasets/import.js +7 -10
- package/dist/commands/datasets/import.js.map +1 -1
- package/dist/exports/_internal.d.ts +50 -82
- package/dist/exports/index.d.ts +48 -78
- package/dist/exports/invokeSanityCli/index.d.ts +108 -18
- package/dist/exports/invokeSanityCli/index.js +2 -1
- package/dist/exports/invokeSanityCli/index.js.map +1 -1
- package/dist/exports/runtime.d.ts +3 -65
- package/dist/services/api.js +23 -15
- package/dist/services/api.js.map +1 -1
- package/dist/services/auth.js +4 -4
- package/dist/services/auth.js.map +1 -1
- package/dist/services/backup.js +3 -3
- package/dist/services/backup.js.map +1 -1
- package/dist/services/cors.js +3 -3
- package/dist/services/cors.js.map +1 -1
- package/dist/services/datasetAliases.js +5 -5
- package/dist/services/datasetAliases.js.map +1 -1
- package/dist/services/datasets.js +3 -3
- package/dist/services/datasets.js.map +1 -1
- package/dist/services/documents.js +1 -1
- package/dist/services/documents.js.map +1 -1
- package/dist/services/getProjectFeatures.js +1 -1
- package/dist/services/getProjectFeatures.js.map +1 -1
- package/dist/services/getUrlHeaders.js +3 -9
- package/dist/services/getUrlHeaders.js.map +1 -1
- package/dist/services/grants.js +1 -1
- package/dist/services/grants.js.map +1 -1
- package/dist/services/graphql.js +4 -3
- package/dist/services/graphql.js.map +1 -1
- package/dist/services/hooks.js +6 -6
- package/dist/services/hooks.js.map +1 -1
- package/dist/services/mcp.js +4 -4
- package/dist/services/mcp.js.map +1 -1
- package/dist/services/mediaLibraries.js +3 -3
- package/dist/services/mediaLibraries.js.map +1 -1
- package/dist/services/mintProject.js +6 -11
- package/dist/services/mintProject.js.map +1 -1
- package/dist/services/organizations.js +6 -6
- package/dist/services/organizations.js.map +1 -1
- package/dist/services/plans.js +2 -2
- package/dist/services/plans.js.map +1 -1
- package/dist/services/projects.js +7 -7
- package/dist/services/projects.js.map +1 -1
- package/dist/services/schemas.js +2 -2
- package/dist/services/schemas.js.map +1 -1
- package/dist/services/telemetry.js +2 -2
- package/dist/services/telemetry.js.map +1 -1
- package/dist/services/tokens.js +5 -5
- package/dist/services/tokens.js.map +1 -1
- package/dist/services/user.js +1 -1
- package/dist/services/user.js.map +1 -1
- package/dist/services/userApplications.js +18 -18
- package/dist/services/userApplications.js.map +1 -1
- package/oclif.manifest.json +513 -513
- package/package.json +12 -12
|
@@ -1,19 +1,7 @@
|
|
|
1
1
|
import { createWriteStream } from 'node:fs';
|
|
2
2
|
import path from 'node:path';
|
|
3
|
-
import { pipeline } from 'node:stream/promises';
|
|
4
|
-
import { createRequester, keepAlive, retry } from '@sanity/cli-core/request';
|
|
5
3
|
import { backupDownloadDebug } from './backupDownloadDebug.js';
|
|
6
|
-
|
|
7
|
-
;
|
|
8
|
-
const READ_TIMEOUT = 3 * 60 * 1000 // 3 minutes
|
|
9
|
-
;
|
|
10
|
-
const request = createRequester({
|
|
11
|
-
middleware: {
|
|
12
|
-
promise: {
|
|
13
|
-
onlyBody: false
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
}).use(keepAlive()).use(retry());
|
|
4
|
+
import { downloadStream } from './downloadStream.js';
|
|
17
5
|
/**
|
|
18
6
|
* Downloads an asset (image or file) from a backup to the specified output directory
|
|
19
7
|
*
|
|
@@ -27,17 +15,8 @@ const request = createRequester({
|
|
|
27
15
|
// the base name as file name.
|
|
28
16
|
const normalizedFileName = path.basename(fileName);
|
|
29
17
|
const assetFilePath = getAssetFilePath(normalizedFileName, fileType, outDir);
|
|
30
|
-
const
|
|
31
|
-
|
|
32
|
-
stream: true,
|
|
33
|
-
timeout: {
|
|
34
|
-
connect: CONNECTION_TIMEOUT,
|
|
35
|
-
socket: READ_TIMEOUT
|
|
36
|
-
},
|
|
37
|
-
url
|
|
38
|
-
});
|
|
39
|
-
backupDownloadDebug('Received asset %s with status code %d', normalizedFileName, response.statusCode);
|
|
40
|
-
await pipeline(response.body, createWriteStream(assetFilePath));
|
|
18
|
+
const status = await downloadStream(url, ()=>createWriteStream(assetFilePath));
|
|
19
|
+
backupDownloadDebug('Received asset %s with status code %d', normalizedFileName, status);
|
|
41
20
|
}
|
|
42
21
|
function getAssetFilePath(fileName, fileType, outDir) {
|
|
43
22
|
// Set assetFilePath if we are downloading an asset file.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/actions/backup/downloadAsset.ts"],"sourcesContent":["import {createWriteStream} from 'node:fs'\nimport path from 'node:path'\
|
|
1
|
+
{"version":3,"sources":["../../../src/actions/backup/downloadAsset.ts"],"sourcesContent":["import {createWriteStream} from 'node:fs'\nimport path from 'node:path'\n\nimport {backupDownloadDebug} from './backupDownloadDebug.js'\nimport {downloadStream} from './downloadStream.js'\n\n/**\n * Downloads an asset (image or file) from a backup to the specified output directory\n *\n * @param url - The URL to download the asset from\n * @param fileName - The original file name of the asset\n * @param fileType - The type of asset ('image' or 'file')\n * @param outDir - The output directory to save the asset to\n */\nexport async function downloadAsset(\n url: string,\n fileName: string,\n fileType: string,\n outDir: string,\n): Promise<void> {\n // File names that contain a path to file (e.g. sanity-storage/assets/file-name.tar.gz) fail when archive is\n // created due to missing parent dir (e.g. sanity-storage/assets), so we want to handle them by taking\n // the base name as file name.\n const normalizedFileName = path.basename(fileName)\n\n const assetFilePath = getAssetFilePath(normalizedFileName, fileType, outDir)\n\n const status = await downloadStream(url, () => createWriteStream(assetFilePath))\n\n backupDownloadDebug('Received asset %s with status code %d', normalizedFileName, status)\n}\n\nfunction getAssetFilePath(fileName: string, fileType: string, outDir: string): string {\n // Set assetFilePath if we are downloading an asset file.\n // If it's a JSON document, assetFilePath will be an empty string.\n let assetFilePath = ''\n if (fileType === 'image') {\n assetFilePath = path.join(outDir, 'images', fileName)\n } else if (fileType === 'file') {\n assetFilePath = path.join(outDir, 'files', fileName)\n }\n\n return assetFilePath\n}\n"],"names":["createWriteStream","path","backupDownloadDebug","downloadStream","downloadAsset","url","fileName","fileType","outDir","normalizedFileName","basename","assetFilePath","getAssetFilePath","status","join"],"mappings":"AAAA,SAAQA,iBAAiB,QAAO,UAAS;AACzC,OAAOC,UAAU,YAAW;AAE5B,SAAQC,mBAAmB,QAAO,2BAA0B;AAC5D,SAAQC,cAAc,QAAO,sBAAqB;AAElD;;;;;;;CAOC,GACD,OAAO,eAAeC,cACpBC,GAAW,EACXC,QAAgB,EAChBC,QAAgB,EAChBC,MAAc;IAEd,4GAA4G;IAC5G,sGAAsG;IACtG,8BAA8B;IAC9B,MAAMC,qBAAqBR,KAAKS,QAAQ,CAACJ;IAEzC,MAAMK,gBAAgBC,iBAAiBH,oBAAoBF,UAAUC;IAErE,MAAMK,SAAS,MAAMV,eAAeE,KAAK,IAAML,kBAAkBW;IAEjET,oBAAoB,yCAAyCO,oBAAoBI;AACnF;AAEA,SAASD,iBAAiBN,QAAgB,EAAEC,QAAgB,EAAEC,MAAc;IAC1E,yDAAyD;IACzD,kEAAkE;IAClE,IAAIG,gBAAgB;IACpB,IAAIJ,aAAa,SAAS;QACxBI,gBAAgBV,KAAKa,IAAI,CAACN,QAAQ,UAAUF;IAC9C,OAAO,IAAIC,aAAa,QAAQ;QAC9BI,gBAAgBV,KAAKa,IAAI,CAACN,QAAQ,SAASF;IAC7C;IAEA,OAAOK;AACT"}
|
|
@@ -1,32 +1,21 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Writable } from 'node:stream';
|
|
2
2
|
import { backupDownloadDebug } from './backupDownloadDebug.js';
|
|
3
|
-
|
|
4
|
-
;
|
|
5
|
-
const READ_TIMEOUT = 3 * 60 * 1000 // 3 minutes
|
|
6
|
-
;
|
|
7
|
-
const request = createRequester({
|
|
8
|
-
middleware: {
|
|
9
|
-
promise: {
|
|
10
|
-
onlyBody: false
|
|
11
|
-
}
|
|
12
|
-
}
|
|
13
|
-
}).use(keepAlive()).use(retry());
|
|
3
|
+
import { downloadStream } from './downloadStream.js';
|
|
14
4
|
/**
|
|
15
5
|
* Downloads a document from a backup URL
|
|
16
6
|
*
|
|
17
7
|
* @param url - The URL to download the document from
|
|
18
8
|
* @returns The document content as received from the API
|
|
19
9
|
*/ export async function downloadDocument(url) {
|
|
20
|
-
const
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
return response.body;
|
|
10
|
+
const chunks = [];
|
|
11
|
+
const status = await downloadStream(url, ()=>new Writable({
|
|
12
|
+
write (chunk, _encoding, callback) {
|
|
13
|
+
chunks.push(Buffer.from(chunk));
|
|
14
|
+
callback();
|
|
15
|
+
}
|
|
16
|
+
}));
|
|
17
|
+
backupDownloadDebug('Received document from %s with status code %d', url, status);
|
|
18
|
+
return Buffer.concat(chunks).toString();
|
|
30
19
|
}
|
|
31
20
|
|
|
32
21
|
//# sourceMappingURL=downloadDocument.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/actions/backup/downloadDocument.ts"],"sourcesContent":["import {
|
|
1
|
+
{"version":3,"sources":["../../../src/actions/backup/downloadDocument.ts"],"sourcesContent":["import {Writable} from 'node:stream'\n\nimport {backupDownloadDebug} from './backupDownloadDebug.js'\nimport {downloadStream} from './downloadStream.js'\n\n/**\n * Downloads a document from a backup URL\n *\n * @param url - The URL to download the document from\n * @returns The document content as received from the API\n */\nexport async function downloadDocument(url: string): Promise<string> {\n const chunks: Buffer[] = []\n const status = await downloadStream(\n url,\n () =>\n new Writable({\n write(chunk: Buffer, _encoding, callback) {\n chunks.push(Buffer.from(chunk))\n callback()\n },\n }),\n )\n\n backupDownloadDebug('Received document from %s with status code %d', url, status)\n\n return Buffer.concat(chunks).toString()\n}\n"],"names":["Writable","backupDownloadDebug","downloadStream","downloadDocument","url","chunks","status","write","chunk","_encoding","callback","push","Buffer","from","concat","toString"],"mappings":"AAAA,SAAQA,QAAQ,QAAO,cAAa;AAEpC,SAAQC,mBAAmB,QAAO,2BAA0B;AAC5D,SAAQC,cAAc,QAAO,sBAAqB;AAElD;;;;;CAKC,GACD,OAAO,eAAeC,iBAAiBC,GAAW;IAChD,MAAMC,SAAmB,EAAE;IAC3B,MAAMC,SAAS,MAAMJ,eACnBE,KACA,IACE,IAAIJ,SAAS;YACXO,OAAMC,KAAa,EAAEC,SAAS,EAAEC,QAAQ;gBACtCL,OAAOM,IAAI,CAACC,OAAOC,IAAI,CAACL;gBACxBE;YACF;QACF;IAGJT,oBAAoB,iDAAiDG,KAAKE;IAE1E,OAAOM,OAAOE,MAAM,CAACT,QAAQU,QAAQ;AACvC"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { Transform } from 'node:stream';
|
|
2
|
+
import { pipeline } from 'node:stream/promises';
|
|
3
|
+
import { createRequester, isTimeoutError, nodeReadableFromWeb, retry } from '@sanity/cli-core/request';
|
|
4
|
+
const CONNECTION_TIMEOUT = 15 * 1000 // 15 seconds
|
|
5
|
+
;
|
|
6
|
+
const READ_TIMEOUT = 3 * 60 * 1000 // 3 minutes
|
|
7
|
+
;
|
|
8
|
+
const request = createRequester({
|
|
9
|
+
middleware: [
|
|
10
|
+
retry()
|
|
11
|
+
],
|
|
12
|
+
// Fresh 15s headers deadline per retry attempt (TimeoutError is retried for
|
|
13
|
+
// GET). No total deadline: the body phase is governed by the idle read
|
|
14
|
+
// timeout below, which resets on every received chunk.
|
|
15
|
+
timeout: {
|
|
16
|
+
headers: CONNECTION_TIMEOUT,
|
|
17
|
+
total: false
|
|
18
|
+
}
|
|
19
|
+
});
|
|
20
|
+
/**
|
|
21
|
+
* Downloads a backup response into a Node.js writable stream.
|
|
22
|
+
*
|
|
23
|
+
* The connection timeout only covers receiving the response headers. Once
|
|
24
|
+
* streaming starts, the read timeout is reset for every received chunk.
|
|
25
|
+
*
|
|
26
|
+
* @param url - Backup response URL
|
|
27
|
+
* @param createDestination - Creates the stream that receives the response body.
|
|
28
|
+
* Deferred so no destination (e.g. an empty file) exists when the request fails.
|
|
29
|
+
* @returns HTTP response status
|
|
30
|
+
* @internal
|
|
31
|
+
*/ export async function downloadStream(url, createDestination) {
|
|
32
|
+
const abortController = new AbortController();
|
|
33
|
+
let response;
|
|
34
|
+
try {
|
|
35
|
+
response = await request({
|
|
36
|
+
as: 'stream',
|
|
37
|
+
signal: abortController.signal,
|
|
38
|
+
url
|
|
39
|
+
});
|
|
40
|
+
} catch (error) {
|
|
41
|
+
if (isTimeoutError(error)) {
|
|
42
|
+
throw new Error('Backup download timed out before receiving a response. Try again.', {
|
|
43
|
+
cause: error
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
throw error;
|
|
47
|
+
}
|
|
48
|
+
let destination;
|
|
49
|
+
try {
|
|
50
|
+
destination = createDestination();
|
|
51
|
+
} catch (error) {
|
|
52
|
+
await response.body.cancel().catch(()=>{
|
|
53
|
+
// Surface the destination error, not the cancellation error.
|
|
54
|
+
});
|
|
55
|
+
throw error;
|
|
56
|
+
}
|
|
57
|
+
let readTimeout;
|
|
58
|
+
const resetReadTimeout = ()=>{
|
|
59
|
+
if (readTimeout) clearTimeout(readTimeout);
|
|
60
|
+
readTimeout = setTimeout(()=>{
|
|
61
|
+
const timeoutMinutes = READ_TIMEOUT / (60 * 1000);
|
|
62
|
+
const error = new Error(`Backup download stalled: no data received for ${timeoutMinutes} minutes. Try again.`);
|
|
63
|
+
abortController.abort(error);
|
|
64
|
+
timeoutStream.destroy(error);
|
|
65
|
+
}, READ_TIMEOUT);
|
|
66
|
+
readTimeout.unref();
|
|
67
|
+
};
|
|
68
|
+
const timeoutStream = new Transform({
|
|
69
|
+
transform (chunk, _encoding, callback) {
|
|
70
|
+
resetReadTimeout();
|
|
71
|
+
callback(null, chunk);
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
resetReadTimeout();
|
|
75
|
+
try {
|
|
76
|
+
await pipeline(nodeReadableFromWeb(response.body), timeoutStream, destination);
|
|
77
|
+
} finally{
|
|
78
|
+
if (readTimeout) clearTimeout(readTimeout);
|
|
79
|
+
}
|
|
80
|
+
return response.status;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
//# sourceMappingURL=downloadStream.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/actions/backup/downloadStream.ts"],"sourcesContent":["import {Transform, type TransformCallback, type Writable} from 'node:stream'\nimport {pipeline} from 'node:stream/promises'\n\nimport {\n createRequester,\n isTimeoutError,\n nodeReadableFromWeb,\n retry,\n type StreamResponse,\n} from '@sanity/cli-core/request'\n\nconst CONNECTION_TIMEOUT = 15 * 1000 // 15 seconds\nconst READ_TIMEOUT = 3 * 60 * 1000 // 3 minutes\n\nconst request = createRequester({\n middleware: [retry()],\n // Fresh 15s headers deadline per retry attempt (TimeoutError is retried for\n // GET). No total deadline: the body phase is governed by the idle read\n // timeout below, which resets on every received chunk.\n timeout: {headers: CONNECTION_TIMEOUT, total: false},\n})\n\n/**\n * Downloads a backup response into a Node.js writable stream.\n *\n * The connection timeout only covers receiving the response headers. Once\n * streaming starts, the read timeout is reset for every received chunk.\n *\n * @param url - Backup response URL\n * @param createDestination - Creates the stream that receives the response body.\n * Deferred so no destination (e.g. an empty file) exists when the request fails.\n * @returns HTTP response status\n * @internal\n */\nexport async function downloadStream(\n url: string,\n createDestination: () => Writable,\n): Promise<number> {\n const abortController = new AbortController()\n\n let response: StreamResponse\n try {\n response = await request({\n as: 'stream',\n signal: abortController.signal,\n url,\n })\n } catch (error) {\n if (isTimeoutError(error)) {\n throw new Error('Backup download timed out before receiving a response. Try again.', {\n cause: error,\n })\n }\n throw error\n }\n\n let destination: Writable\n try {\n destination = createDestination()\n } catch (error) {\n await response.body.cancel().catch(() => {\n // Surface the destination error, not the cancellation error.\n })\n throw error\n }\n\n let readTimeout: NodeJS.Timeout | undefined\n const resetReadTimeout = () => {\n if (readTimeout) clearTimeout(readTimeout)\n readTimeout = setTimeout(() => {\n const timeoutMinutes = READ_TIMEOUT / (60 * 1000)\n const error = new Error(\n `Backup download stalled: no data received for ${timeoutMinutes} minutes. Try again.`,\n )\n abortController.abort(error)\n timeoutStream.destroy(error)\n }, READ_TIMEOUT)\n readTimeout.unref()\n }\n const timeoutStream = new Transform({\n transform(chunk: Buffer, _encoding: BufferEncoding, callback: TransformCallback) {\n resetReadTimeout()\n callback(null, chunk)\n },\n })\n\n resetReadTimeout()\n try {\n await pipeline(nodeReadableFromWeb(response.body), timeoutStream, destination)\n } finally {\n if (readTimeout) clearTimeout(readTimeout)\n }\n\n return response.status\n}\n"],"names":["Transform","pipeline","createRequester","isTimeoutError","nodeReadableFromWeb","retry","CONNECTION_TIMEOUT","READ_TIMEOUT","request","middleware","timeout","headers","total","downloadStream","url","createDestination","abortController","AbortController","response","as","signal","error","Error","cause","destination","body","cancel","catch","readTimeout","resetReadTimeout","clearTimeout","setTimeout","timeoutMinutes","abort","timeoutStream","destroy","unref","transform","chunk","_encoding","callback","status"],"mappings":"AAAA,SAAQA,SAAS,QAA8C,cAAa;AAC5E,SAAQC,QAAQ,QAAO,uBAAsB;AAE7C,SACEC,eAAe,EACfC,cAAc,EACdC,mBAAmB,EACnBC,KAAK,QAEA,2BAA0B;AAEjC,MAAMC,qBAAqB,KAAK,KAAK,aAAa;;AAClD,MAAMC,eAAe,IAAI,KAAK,KAAK,YAAY;;AAE/C,MAAMC,UAAUN,gBAAgB;IAC9BO,YAAY;QAACJ;KAAQ;IACrB,4EAA4E;IAC5E,uEAAuE;IACvE,uDAAuD;IACvDK,SAAS;QAACC,SAASL;QAAoBM,OAAO;IAAK;AACrD;AAEA;;;;;;;;;;;CAWC,GACD,OAAO,eAAeC,eACpBC,GAAW,EACXC,iBAAiC;IAEjC,MAAMC,kBAAkB,IAAIC;IAE5B,IAAIC;IACJ,IAAI;QACFA,WAAW,MAAMV,QAAQ;YACvBW,IAAI;YACJC,QAAQJ,gBAAgBI,MAAM;YAC9BN;QACF;IACF,EAAE,OAAOO,OAAO;QACd,IAAIlB,eAAekB,QAAQ;YACzB,MAAM,IAAIC,MAAM,qEAAqE;gBACnFC,OAAOF;YACT;QACF;QACA,MAAMA;IACR;IAEA,IAAIG;IACJ,IAAI;QACFA,cAAcT;IAChB,EAAE,OAAOM,OAAO;QACd,MAAMH,SAASO,IAAI,CAACC,MAAM,GAAGC,KAAK,CAAC;QACjC,6DAA6D;QAC/D;QACA,MAAMN;IACR;IAEA,IAAIO;IACJ,MAAMC,mBAAmB;QACvB,IAAID,aAAaE,aAAaF;QAC9BA,cAAcG,WAAW;YACvB,MAAMC,iBAAiBzB,eAAgB,CAAA,KAAK,IAAG;YAC/C,MAAMc,QAAQ,IAAIC,MAChB,CAAC,8CAA8C,EAAEU,eAAe,oBAAoB,CAAC;YAEvFhB,gBAAgBiB,KAAK,CAACZ;YACtBa,cAAcC,OAAO,CAACd;QACxB,GAAGd;QACHqB,YAAYQ,KAAK;IACnB;IACA,MAAMF,gBAAgB,IAAIlC,UAAU;QAClCqC,WAAUC,KAAa,EAAEC,SAAyB,EAAEC,QAA2B;YAC7EX;YACAW,SAAS,MAAMF;QACjB;IACF;IAEAT;IACA,IAAI;QACF,MAAM5B,SAASG,oBAAoBc,SAASO,IAAI,GAAGS,eAAeV;IACpE,SAAU;QACR,IAAII,aAAaE,aAAaF;IAChC;IAEA,OAAOV,SAASuB,MAAM;AACxB"}
|
|
@@ -30,9 +30,6 @@ export async function validateDocuments(options) {
|
|
|
30
30
|
// `clientConfiguration` object and also mock a browser environment in
|
|
31
31
|
// this worker which triggers the browser warning
|
|
32
32
|
ignoreBrowserTokenWarning: true,
|
|
33
|
-
// Removing from object so config can be serialized
|
|
34
|
-
// before sent to validation worker
|
|
35
|
-
requester: undefined,
|
|
36
33
|
// we set this explictly to true because the default client configuration
|
|
37
34
|
// from the CLI comes configured with `useProjectHostname: false` when
|
|
38
35
|
// `requireProject` is set to false
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/actions/documents/validate.ts"],"sourcesContent":["import {getGlobalCliClient} from '@sanity/cli-core/apiClient'\nimport {createStudioWorker} from '@sanity/cli-core/tasks'\nimport {type ClientConfig} from '@sanity/client'\nimport {type ValidationMarker} from '@sanity/types'\nimport {WorkerChannelReceiver} from '@sanity/worker-channels'\n\nimport {DOCUMENTS_API_VERSION} from './constants.js'\nimport {\n Level,\n type ValidateDocumentsWorkerData,\n type ValidationReceiver,\n type ValidationWorkerChannel,\n} from './types.js'\n\ninterface ValidateDocumentsOptions<TReturn = unknown> {\n dataset?: string // override\n level?: Level\n maxCustomValidationConcurrency?: number\n maxFetchConcurrency?: number\n ndjsonFilePath?: string\n projectId?: string // override\n reporter?: (worker: ValidationReceiver) => TReturn\n studioHost?: string\n workDir?: string\n workspace?: string\n}\n\ninterface DocumentValidationResult {\n documentId: string\n documentType: string\n level: ValidationMarker['level']\n markers: ValidationMarker[]\n revision: string\n}\n\nconst defaultReporter = ({dispose, stream}: ValidationReceiver) => {\n async function* createValidationGenerator() {\n for await (const {documentId, documentType, level, markers, revision} of stream.validation()) {\n const result: DocumentValidationResult = {\n documentId,\n documentType,\n level,\n markers,\n revision,\n }\n\n yield result\n }\n\n await dispose()\n }\n\n return createValidationGenerator()\n}\n\nexport function validateDocuments<TReturn>(\n options: Required<Pick<ValidateDocumentsOptions<TReturn>, 'reporter'>> &\n ValidateDocumentsOptions<TReturn>,\n): Promise<TReturn>\nexport function validateDocuments(\n options: ValidateDocumentsOptions,\n): Promise<AsyncIterable<DocumentValidationResult>>\nexport async function validateDocuments(options: ValidateDocumentsOptions): Promise<unknown> {\n const {\n dataset,\n level,\n maxCustomValidationConcurrency,\n maxFetchConcurrency,\n ndjsonFilePath,\n projectId,\n reporter = defaultReporter,\n workDir = process.cwd(),\n workspace,\n } = options\n\n const apiClient = await getGlobalCliClient({\n apiVersion: DOCUMENTS_API_VERSION,\n requireUser: true,\n })\n\n const clientConfig: ClientConfig = {\n ...apiClient.config(),\n // we set this explictly to true because we pass in a token via the\n // `clientConfiguration` object and also mock a browser environment in\n // this worker which triggers the browser warning\n ignoreBrowserTokenWarning: true,\n //
|
|
1
|
+
{"version":3,"sources":["../../../src/actions/documents/validate.ts"],"sourcesContent":["import {getGlobalCliClient} from '@sanity/cli-core/apiClient'\nimport {createStudioWorker} from '@sanity/cli-core/tasks'\nimport {type ClientConfig} from '@sanity/client'\nimport {type ValidationMarker} from '@sanity/types'\nimport {WorkerChannelReceiver} from '@sanity/worker-channels'\n\nimport {DOCUMENTS_API_VERSION} from './constants.js'\nimport {\n Level,\n type ValidateDocumentsWorkerData,\n type ValidationReceiver,\n type ValidationWorkerChannel,\n} from './types.js'\n\ninterface ValidateDocumentsOptions<TReturn = unknown> {\n dataset?: string // override\n level?: Level\n maxCustomValidationConcurrency?: number\n maxFetchConcurrency?: number\n ndjsonFilePath?: string\n projectId?: string // override\n reporter?: (worker: ValidationReceiver) => TReturn\n studioHost?: string\n workDir?: string\n workspace?: string\n}\n\ninterface DocumentValidationResult {\n documentId: string\n documentType: string\n level: ValidationMarker['level']\n markers: ValidationMarker[]\n revision: string\n}\n\nconst defaultReporter = ({dispose, stream}: ValidationReceiver) => {\n async function* createValidationGenerator() {\n for await (const {documentId, documentType, level, markers, revision} of stream.validation()) {\n const result: DocumentValidationResult = {\n documentId,\n documentType,\n level,\n markers,\n revision,\n }\n\n yield result\n }\n\n await dispose()\n }\n\n return createValidationGenerator()\n}\n\nexport function validateDocuments<TReturn>(\n options: Required<Pick<ValidateDocumentsOptions<TReturn>, 'reporter'>> &\n ValidateDocumentsOptions<TReturn>,\n): Promise<TReturn>\nexport function validateDocuments(\n options: ValidateDocumentsOptions,\n): Promise<AsyncIterable<DocumentValidationResult>>\nexport async function validateDocuments(options: ValidateDocumentsOptions): Promise<unknown> {\n const {\n dataset,\n level,\n maxCustomValidationConcurrency,\n maxFetchConcurrency,\n ndjsonFilePath,\n projectId,\n reporter = defaultReporter,\n workDir = process.cwd(),\n workspace,\n } = options\n\n const apiClient = await getGlobalCliClient({\n apiVersion: DOCUMENTS_API_VERSION,\n requireUser: true,\n })\n\n const clientConfig: ClientConfig = {\n ...apiClient.config(),\n // we set this explictly to true because we pass in a token via the\n // `clientConfiguration` object and also mock a browser environment in\n // this worker which triggers the browser warning\n ignoreBrowserTokenWarning: true,\n // we set this explictly to true because the default client configuration\n // from the CLI comes configured with `useProjectHostname: false` when\n // `requireProject` is set to false\n useProjectHostname: true,\n }\n\n const worker = createStudioWorker(new URL('validateDocuments.worker.js', import.meta.url), {\n name: 'validateDocuments',\n studioRootPath: workDir,\n workerData: {\n // removes props in the config that make this object fail to serialize\n clientConfig: structuredClone(clientConfig),\n dataset,\n level,\n maxCustomValidationConcurrency,\n maxFetchConcurrency,\n ndjsonFilePath,\n projectId,\n studioHost: options.studioHost,\n workDir,\n workspace,\n } satisfies ValidateDocumentsWorkerData,\n })\n\n const receiver = WorkerChannelReceiver.from<ValidationWorkerChannel>(worker)\n const validationReceiver: ValidationReceiver = {\n dispose: async () => {\n receiver.unsubscribe()\n return worker.terminate()\n },\n event: receiver.event,\n stream: receiver.stream,\n }\n\n return reporter(validationReceiver)\n}\n"],"names":["getGlobalCliClient","createStudioWorker","WorkerChannelReceiver","DOCUMENTS_API_VERSION","defaultReporter","dispose","stream","createValidationGenerator","documentId","documentType","level","markers","revision","validation","result","validateDocuments","options","dataset","maxCustomValidationConcurrency","maxFetchConcurrency","ndjsonFilePath","projectId","reporter","workDir","process","cwd","workspace","apiClient","apiVersion","requireUser","clientConfig","config","ignoreBrowserTokenWarning","useProjectHostname","worker","URL","url","name","studioRootPath","workerData","structuredClone","studioHost","receiver","from","validationReceiver","unsubscribe","terminate","event"],"mappings":"AAAA,SAAQA,kBAAkB,QAAO,6BAA4B;AAC7D,SAAQC,kBAAkB,QAAO,yBAAwB;AAGzD,SAAQC,qBAAqB,QAAO,0BAAyB;AAE7D,SAAQC,qBAAqB,QAAO,iBAAgB;AA6BpD,MAAMC,kBAAkB,CAAC,EAACC,OAAO,EAAEC,MAAM,EAAqB;IAC5D,gBAAgBC;QACd,WAAW,MAAM,EAACC,UAAU,EAAEC,YAAY,EAAEC,KAAK,EAAEC,OAAO,EAAEC,QAAQ,EAAC,IAAIN,OAAOO,UAAU,GAAI;YAC5F,MAAMC,SAAmC;gBACvCN;gBACAC;gBACAC;gBACAC;gBACAC;YACF;YAEA,MAAME;QACR;QAEA,MAAMT;IACR;IAEA,OAAOE;AACT;AASA,OAAO,eAAeQ,kBAAkBC,OAAiC;IACvE,MAAM,EACJC,OAAO,EACPP,KAAK,EACLQ,8BAA8B,EAC9BC,mBAAmB,EACnBC,cAAc,EACdC,SAAS,EACTC,WAAWlB,eAAe,EAC1BmB,UAAUC,QAAQC,GAAG,EAAE,EACvBC,SAAS,EACV,GAAGV;IAEJ,MAAMW,YAAY,MAAM3B,mBAAmB;QACzC4B,YAAYzB;QACZ0B,aAAa;IACf;IAEA,MAAMC,eAA6B;QACjC,GAAGH,UAAUI,MAAM,EAAE;QACrB,mEAAmE;QACnE,sEAAsE;QACtE,iDAAiD;QACjDC,2BAA2B;QAC3B,yEAAyE;QACzE,sEAAsE;QACtE,mCAAmC;QACnCC,oBAAoB;IACtB;IAEA,MAAMC,SAASjC,mBAAmB,IAAIkC,IAAI,+BAA+B,YAAYC,GAAG,GAAG;QACzFC,MAAM;QACNC,gBAAgBf;QAChBgB,YAAY;YACV,sEAAsE;YACtET,cAAcU,gBAAgBV;YAC9Bb;YACAP;YACAQ;YACAC;YACAC;YACAC;YACAoB,YAAYzB,QAAQyB,UAAU;YAC9BlB;YACAG;QACF;IACF;IAEA,MAAMgB,WAAWxC,sBAAsByC,IAAI,CAA0BT;IACrE,MAAMU,qBAAyC;QAC7CvC,SAAS;YACPqC,SAASG,WAAW;YACpB,OAAOX,OAAOY,SAAS;QACzB;QACAC,OAAOL,SAASK,KAAK;QACrBzC,QAAQoC,SAASpC,MAAM;IACzB;IAEA,OAAOgB,SAASsB;AAClB"}
|
|
@@ -196,7 +196,10 @@ async function main() {
|
|
|
196
196
|
validateDocument({
|
|
197
197
|
document,
|
|
198
198
|
environment: 'cli',
|
|
199
|
-
|
|
199
|
+
// The local `sanity` package types its client against its own
|
|
200
|
+
// @sanity/client major; the runtime surface validation uses is
|
|
201
|
+
// compatible across v7/v8.
|
|
202
|
+
getClient: getClient,
|
|
200
203
|
getDocumentExists,
|
|
201
204
|
maxCustomValidationConcurrency,
|
|
202
205
|
maxFetchConcurrency,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/actions/documents/validateDocuments.worker.ts"],"sourcesContent":["import fs from 'node:fs'\nimport os from 'node:os'\nimport path from 'node:path'\nimport readline from 'node:readline'\nimport {Readable} from 'node:stream'\nimport {workerData as _workerData, isMainThread, parentPort} from 'node:worker_threads'\n\nimport {getStudioWorkspaces, getWorkspace, resolveLocalPackage} from '@sanity/cli-core'\nimport {type ClientConfig, createClient, type SanityDocument} from '@sanity/client'\nimport {type ValidationContext, type ValidationMarker} from '@sanity/types'\nimport {WorkerChannelReporter} from '@sanity/worker-channels'\nimport pMap from 'p-map'\n\nimport {\n type AvailabilityResponse,\n checkDocumentAvailability,\n exportDocuments,\n getDocumentCount,\n} from '../../services/documents.js'\nimport {extractDocumentsFromNdjsonOrTarball} from '../../util/extractDocumentsFromNdjsonOrTarball.js'\nimport {\n DOCUMENT_VALIDATION_TIMEOUT,\n getReferenceIds,\n isValidId,\n levelValues,\n MAX_VALIDATION_CONCURRENCY,\n REFERENCE_INTEGRITY_BATCH_SIZE,\n shouldIncludeDocument,\n} from '../../util/validation/validateDocumentsUtils.js'\nimport {type ValidateDocumentsWorkerData, type ValidationWorkerChannel} from './types.js'\n\nconst {\n clientConfig,\n dataset,\n level,\n maxCustomValidationConcurrency,\n maxFetchConcurrency,\n ndjsonFilePath,\n projectId,\n studioHost,\n workDir,\n workspace: workspaceName,\n} = _workerData as ValidateDocumentsWorkerData\n\nif (isMainThread || !parentPort) {\n throw new Error('This module must be run as a worker thread')\n}\n\nconst report = WorkerChannelReporter.from<ValidationWorkerChannel>(parentPort)\n\n// eslint-disable-next-line n/no-unsupported-features/node-builtins\nasync function* readerToGenerator(reader: ReadableStreamDefaultReader<Uint8Array>) {\n while (true) {\n const {done, value} = await reader.read()\n if (value) yield value\n if (done) return\n }\n}\n\nawait main()\nprocess.exit()\n\nasync function loadWorkspace() {\n const workspaces = await getStudioWorkspaces(workDir)\n const workspace = getWorkspace(workspaces, workspaceName)\n\n const resolvedDataset = dataset || workspace.dataset\n const resolvedProjectId = projectId || workspace.projectId\n\n const client = createClient({\n ...clientConfig,\n dataset: resolvedDataset,\n projectId: resolvedProjectId,\n requestTagPrefix: 'sanity.cli.validate',\n }).config({apiVersion: 'v2021-03-25'})\n\n report.event.loadedWorkspace({\n basePath: workspace.basePath,\n dataset: workspace.dataset,\n name: workspace.name,\n projectId: workspace.projectId,\n })\n\n return {client, dataset: resolvedDataset, projectId: resolvedProjectId, workspace}\n}\n\ninterface DownloadFromExportOptions {\n dataset: string\n projectId: string\n}\n\nasync function downloadFromExport({\n dataset: datasetName,\n projectId: projId,\n}: DownloadFromExportOptions) {\n const documentCount = await getDocumentCount({dataset: datasetName, projectId: projId})\n report.event.loadedDocumentCount({documentCount})\n\n const response = await exportDocuments({dataset: datasetName, projectId: projId})\n\n const reader = response.body?.getReader()\n if (!reader) throw new Error('Could not get reader from response body.')\n\n let downloadedCount = 0\n const referencedIds = new Set<string>()\n const documentIds = new Set<string>()\n const lines = readline.createInterface({input: Readable.from(readerToGenerator(reader))})\n\n // Note: we stream the export to a file and then re-read from that file to\n // make this less memory intensive.\n // this is a similar pattern to the import/export CLI commands\n const slugDate = new Date()\n .toISOString()\n .replaceAll(/[^a-z0-9]/gi, '-')\n .toLowerCase()\n const tempOutputFile = path.join(os.tmpdir(), `sanity-validate-${slugDate}.ndjson`)\n const outputStream = fs.createWriteStream(tempOutputFile)\n\n for await (const line of lines) {\n const document = JSON.parse(line) as SanityDocument\n\n if (shouldIncludeDocument(document)) {\n documentIds.add(document._id)\n for (const referenceId of getReferenceIds(document)) {\n referencedIds.add(referenceId)\n }\n\n outputStream.write(`${line}\\n`)\n }\n\n downloadedCount++\n report.stream.exportProgress.emit({documentCount, downloadedCount})\n }\n\n await new Promise<void>((resolve, reject) =>\n outputStream.close((err) => (err ? reject(err) : resolve())),\n )\n\n report.stream.exportProgress.end()\n report.event.exportFinished({totalDocumentsToValidate: documentIds.size})\n\n const getDocuments = () =>\n extractDocumentsFromNdjsonOrTarball(fs.createReadStream(tempOutputFile))\n\n return {cleanup: () => fs.promises.rm(tempOutputFile), documentIds, getDocuments, referencedIds}\n}\n\nasync function downloadFromFile(filePath: string) {\n const referencedIds = new Set<string>()\n const documentIds = new Set<string>()\n const getDocuments = () => extractDocumentsFromNdjsonOrTarball(fs.createReadStream(filePath))\n\n for await (const document of getDocuments()) {\n if (shouldIncludeDocument(document)) {\n documentIds.add(document._id)\n for (const referenceId of getReferenceIds(document)) {\n referencedIds.add(referenceId)\n }\n }\n }\n\n report.event.exportFinished({totalDocumentsToValidate: documentIds.size})\n\n return {cleanup: undefined, documentIds, getDocuments, referencedIds}\n}\n\ninterface CheckReferenceExistenceOptions {\n dataset: string\n documentIds: Set<string>\n projectId: string\n referencedIds: Set<string>\n}\n\nasync function checkReferenceExistence({\n dataset: datasetName,\n documentIds,\n projectId: projId,\n referencedIds: _referencedIds,\n}: CheckReferenceExistenceOptions) {\n const existingIds = new Set(documentIds)\n const idsToCheck = [..._referencedIds]\n .filter((id) => !existingIds.has(id) && isValidId(id))\n .toSorted()\n\n const batches: string[][] = []\n for (let i = 0; i < idsToCheck.length; i += REFERENCE_INTEGRITY_BATCH_SIZE) {\n batches.push(idsToCheck.slice(i, i + REFERENCE_INTEGRITY_BATCH_SIZE))\n }\n\n for (const batch of batches) {\n const {omitted} = await checkDocumentAvailability({\n dataset: datasetName,\n documentIds: batch,\n projectId: projId,\n })\n\n const omittedIds: Record<string, AvailabilityResponse['omitted'][number]['reason']> = {}\n for (const item of omitted) {\n omittedIds[item.id] = item.reason\n }\n\n for (const id of batch) {\n // unless the document ID is in the `omitted` object explictly due to\n // the reason `'existence'`, then it should exist\n if (omittedIds[id] !== 'existence') {\n existingIds.add(id)\n }\n }\n }\n report.event.loadedReferenceIntegrity()\n\n return {existingIds}\n}\n\nasync function main() {\n let cleanupDownloadedDocuments: (() => Promise<void>) | undefined\n\n try {\n const {client, dataset: datasetName, projectId: projId, workspace} = await loadWorkspace()\n const {cleanup, documentIds, getDocuments, referencedIds} = ndjsonFilePath\n ? await downloadFromFile(ndjsonFilePath)\n : await downloadFromExport({dataset: datasetName, projectId: projId})\n cleanupDownloadedDocuments = cleanup\n const {existingIds} = await checkReferenceExistence({\n dataset: datasetName,\n documentIds,\n projectId: projId,\n referencedIds,\n })\n\n const getClient = <TOptions extends Partial<ClientConfig>>(options: TOptions) =>\n client.withConfig(options)\n\n const getDocumentExists: ValidationContext['getDocumentExists'] = ({id}) =>\n Promise.resolve(existingIds.has(id))\n\n const getLevel = (markers: ValidationMarker[]) => {\n let foundWarning = false\n for (const marker of markers) {\n if (marker.level === 'error') return 'error'\n if (marker.level === 'warning') foundWarning = true\n }\n\n if (foundWarning) return 'warning'\n return 'info'\n }\n\n let validatedCount = 0\n\n const validate = async (document: SanityDocument) => {\n let markers: ValidationMarker[]\n\n try {\n const timeout = Symbol('timeout')\n\n const {validateDocument} = await resolveLocalPackage<typeof import('sanity')>(\n 'sanity',\n workDir,\n )\n\n const result = await Promise.race([\n validateDocument({\n document,\n environment: 'cli',\n getClient,\n getDocumentExists,\n maxCustomValidationConcurrency,\n maxFetchConcurrency,\n workspace,\n }),\n new Promise<typeof timeout>((resolve) =>\n setTimeout(() => resolve(timeout), DOCUMENT_VALIDATION_TIMEOUT),\n ),\n ])\n\n if (result === timeout) {\n throw new Error(\n `Document '${document._id}' failed to validate within ${DOCUMENT_VALIDATION_TIMEOUT}ms.`,\n )\n }\n\n markers = result\n // filter out unwanted levels\n .filter((marker) => {\n const markerValue = levelValues[marker.level]\n const flagLevelValue =\n levelValues[level as keyof typeof levelValues] ?? levelValues.info\n return markerValue <= flagLevelValue\n })\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : 'Unknown error'\n\n const message = `Exception occurred while validating value: ${errorMessage}`\n\n markers = [\n {\n level: 'error',\n message,\n path: [],\n },\n ]\n }\n\n validatedCount++\n\n const intentUrl =\n studioHost &&\n `${studioHost}${path.resolve(\n workspace.basePath,\n `/intent/edit/id=${encodeURIComponent(document._id)};type=${encodeURIComponent(\n document._type,\n )}`,\n )}`\n\n report.stream.validation.emit({\n documentId: document._id,\n documentType: document._type,\n ...(intentUrl && {intentUrl}),\n level: getLevel(markers),\n markers,\n revision: document._rev,\n validatedCount,\n })\n }\n\n await pMap(getDocuments(), validate, {concurrency: MAX_VALIDATION_CONCURRENCY})\n\n report.stream.validation.end()\n } finally {\n await cleanupDownloadedDocuments?.()\n }\n}\n"],"names":["fs","os","path","readline","Readable","workerData","_workerData","isMainThread","parentPort","getStudioWorkspaces","getWorkspace","resolveLocalPackage","createClient","WorkerChannelReporter","pMap","checkDocumentAvailability","exportDocuments","getDocumentCount","extractDocumentsFromNdjsonOrTarball","DOCUMENT_VALIDATION_TIMEOUT","getReferenceIds","isValidId","levelValues","MAX_VALIDATION_CONCURRENCY","REFERENCE_INTEGRITY_BATCH_SIZE","shouldIncludeDocument","clientConfig","dataset","level","maxCustomValidationConcurrency","maxFetchConcurrency","ndjsonFilePath","projectId","studioHost","workDir","workspace","workspaceName","Error","report","from","readerToGenerator","reader","done","value","read","main","process","exit","loadWorkspace","workspaces","resolvedDataset","resolvedProjectId","client","requestTagPrefix","config","apiVersion","event","loadedWorkspace","basePath","name","downloadFromExport","datasetName","projId","documentCount","loadedDocumentCount","response","body","getReader","downloadedCount","referencedIds","Set","documentIds","lines","createInterface","input","slugDate","Date","toISOString","replaceAll","toLowerCase","tempOutputFile","join","tmpdir","outputStream","createWriteStream","line","document","JSON","parse","add","_id","referenceId","write","stream","exportProgress","emit","Promise","resolve","reject","close","err","end","exportFinished","totalDocumentsToValidate","size","getDocuments","createReadStream","cleanup","promises","rm","downloadFromFile","filePath","undefined","checkReferenceExistence","_referencedIds","existingIds","idsToCheck","filter","id","has","toSorted","batches","i","length","push","slice","batch","omitted","omittedIds","item","reason","loadedReferenceIntegrity","cleanupDownloadedDocuments","getClient","options","withConfig","getDocumentExists","getLevel","markers","foundWarning","marker","validatedCount","validate","timeout","Symbol","validateDocument","result","race","environment","setTimeout","markerValue","flagLevelValue","info","errorMessage","message","intentUrl","encodeURIComponent","_type","validation","documentId","documentType","revision","_rev","concurrency"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../src/actions/documents/validateDocuments.worker.ts"],"sourcesContent":["import fs from 'node:fs'\nimport os from 'node:os'\nimport path from 'node:path'\nimport readline from 'node:readline'\nimport {Readable} from 'node:stream'\nimport {workerData as _workerData, isMainThread, parentPort} from 'node:worker_threads'\n\nimport {getStudioWorkspaces, getWorkspace, resolveLocalPackage} from '@sanity/cli-core'\nimport {type ClientConfig, createClient, type SanityDocument} from '@sanity/client'\nimport {type ValidationContext, type ValidationMarker} from '@sanity/types'\nimport {WorkerChannelReporter} from '@sanity/worker-channels'\nimport pMap from 'p-map'\n\nimport {\n type AvailabilityResponse,\n checkDocumentAvailability,\n exportDocuments,\n getDocumentCount,\n} from '../../services/documents.js'\nimport {extractDocumentsFromNdjsonOrTarball} from '../../util/extractDocumentsFromNdjsonOrTarball.js'\nimport {\n DOCUMENT_VALIDATION_TIMEOUT,\n getReferenceIds,\n isValidId,\n levelValues,\n MAX_VALIDATION_CONCURRENCY,\n REFERENCE_INTEGRITY_BATCH_SIZE,\n shouldIncludeDocument,\n} from '../../util/validation/validateDocumentsUtils.js'\nimport {type ValidateDocumentsWorkerData, type ValidationWorkerChannel} from './types.js'\n\nconst {\n clientConfig,\n dataset,\n level,\n maxCustomValidationConcurrency,\n maxFetchConcurrency,\n ndjsonFilePath,\n projectId,\n studioHost,\n workDir,\n workspace: workspaceName,\n} = _workerData as ValidateDocumentsWorkerData\n\nif (isMainThread || !parentPort) {\n throw new Error('This module must be run as a worker thread')\n}\n\nconst report = WorkerChannelReporter.from<ValidationWorkerChannel>(parentPort)\n\n// eslint-disable-next-line n/no-unsupported-features/node-builtins\nasync function* readerToGenerator(reader: ReadableStreamDefaultReader<Uint8Array>) {\n while (true) {\n const {done, value} = await reader.read()\n if (value) yield value\n if (done) return\n }\n}\n\nawait main()\nprocess.exit()\n\nasync function loadWorkspace() {\n const workspaces = await getStudioWorkspaces(workDir)\n const workspace = getWorkspace(workspaces, workspaceName)\n\n const resolvedDataset = dataset || workspace.dataset\n const resolvedProjectId = projectId || workspace.projectId\n\n const client = createClient({\n ...clientConfig,\n dataset: resolvedDataset,\n projectId: resolvedProjectId,\n requestTagPrefix: 'sanity.cli.validate',\n }).config({apiVersion: 'v2021-03-25'})\n\n report.event.loadedWorkspace({\n basePath: workspace.basePath,\n dataset: workspace.dataset,\n name: workspace.name,\n projectId: workspace.projectId,\n })\n\n return {client, dataset: resolvedDataset, projectId: resolvedProjectId, workspace}\n}\n\ninterface DownloadFromExportOptions {\n dataset: string\n projectId: string\n}\n\nasync function downloadFromExport({\n dataset: datasetName,\n projectId: projId,\n}: DownloadFromExportOptions) {\n const documentCount = await getDocumentCount({dataset: datasetName, projectId: projId})\n report.event.loadedDocumentCount({documentCount})\n\n const response = await exportDocuments({dataset: datasetName, projectId: projId})\n\n const reader = response.body?.getReader()\n if (!reader) throw new Error('Could not get reader from response body.')\n\n let downloadedCount = 0\n const referencedIds = new Set<string>()\n const documentIds = new Set<string>()\n const lines = readline.createInterface({input: Readable.from(readerToGenerator(reader))})\n\n // Note: we stream the export to a file and then re-read from that file to\n // make this less memory intensive.\n // this is a similar pattern to the import/export CLI commands\n const slugDate = new Date()\n .toISOString()\n .replaceAll(/[^a-z0-9]/gi, '-')\n .toLowerCase()\n const tempOutputFile = path.join(os.tmpdir(), `sanity-validate-${slugDate}.ndjson`)\n const outputStream = fs.createWriteStream(tempOutputFile)\n\n for await (const line of lines) {\n const document = JSON.parse(line) as SanityDocument\n\n if (shouldIncludeDocument(document)) {\n documentIds.add(document._id)\n for (const referenceId of getReferenceIds(document)) {\n referencedIds.add(referenceId)\n }\n\n outputStream.write(`${line}\\n`)\n }\n\n downloadedCount++\n report.stream.exportProgress.emit({documentCount, downloadedCount})\n }\n\n await new Promise<void>((resolve, reject) =>\n outputStream.close((err) => (err ? reject(err) : resolve())),\n )\n\n report.stream.exportProgress.end()\n report.event.exportFinished({totalDocumentsToValidate: documentIds.size})\n\n const getDocuments = () =>\n extractDocumentsFromNdjsonOrTarball(fs.createReadStream(tempOutputFile))\n\n return {cleanup: () => fs.promises.rm(tempOutputFile), documentIds, getDocuments, referencedIds}\n}\n\nasync function downloadFromFile(filePath: string) {\n const referencedIds = new Set<string>()\n const documentIds = new Set<string>()\n const getDocuments = () => extractDocumentsFromNdjsonOrTarball(fs.createReadStream(filePath))\n\n for await (const document of getDocuments()) {\n if (shouldIncludeDocument(document)) {\n documentIds.add(document._id)\n for (const referenceId of getReferenceIds(document)) {\n referencedIds.add(referenceId)\n }\n }\n }\n\n report.event.exportFinished({totalDocumentsToValidate: documentIds.size})\n\n return {cleanup: undefined, documentIds, getDocuments, referencedIds}\n}\n\ninterface CheckReferenceExistenceOptions {\n dataset: string\n documentIds: Set<string>\n projectId: string\n referencedIds: Set<string>\n}\n\nasync function checkReferenceExistence({\n dataset: datasetName,\n documentIds,\n projectId: projId,\n referencedIds: _referencedIds,\n}: CheckReferenceExistenceOptions) {\n const existingIds = new Set(documentIds)\n const idsToCheck = [..._referencedIds]\n .filter((id) => !existingIds.has(id) && isValidId(id))\n .toSorted()\n\n const batches: string[][] = []\n for (let i = 0; i < idsToCheck.length; i += REFERENCE_INTEGRITY_BATCH_SIZE) {\n batches.push(idsToCheck.slice(i, i + REFERENCE_INTEGRITY_BATCH_SIZE))\n }\n\n for (const batch of batches) {\n const {omitted} = await checkDocumentAvailability({\n dataset: datasetName,\n documentIds: batch,\n projectId: projId,\n })\n\n const omittedIds: Record<string, AvailabilityResponse['omitted'][number]['reason']> = {}\n for (const item of omitted) {\n omittedIds[item.id] = item.reason\n }\n\n for (const id of batch) {\n // unless the document ID is in the `omitted` object explictly due to\n // the reason `'existence'`, then it should exist\n if (omittedIds[id] !== 'existence') {\n existingIds.add(id)\n }\n }\n }\n report.event.loadedReferenceIntegrity()\n\n return {existingIds}\n}\n\nasync function main() {\n let cleanupDownloadedDocuments: (() => Promise<void>) | undefined\n\n try {\n const {client, dataset: datasetName, projectId: projId, workspace} = await loadWorkspace()\n const {cleanup, documentIds, getDocuments, referencedIds} = ndjsonFilePath\n ? await downloadFromFile(ndjsonFilePath)\n : await downloadFromExport({dataset: datasetName, projectId: projId})\n cleanupDownloadedDocuments = cleanup\n const {existingIds} = await checkReferenceExistence({\n dataset: datasetName,\n documentIds,\n projectId: projId,\n referencedIds,\n })\n\n const getClient = <TOptions extends Partial<ClientConfig>>(options: TOptions) =>\n client.withConfig(options)\n\n const getDocumentExists: ValidationContext['getDocumentExists'] = ({id}) =>\n Promise.resolve(existingIds.has(id))\n\n const getLevel = (markers: ValidationMarker[]) => {\n let foundWarning = false\n for (const marker of markers) {\n if (marker.level === 'error') return 'error'\n if (marker.level === 'warning') foundWarning = true\n }\n\n if (foundWarning) return 'warning'\n return 'info'\n }\n\n let validatedCount = 0\n\n const validate = async (document: SanityDocument) => {\n let markers: ValidationMarker[]\n\n try {\n const timeout = Symbol('timeout')\n\n const {validateDocument} = await resolveLocalPackage<typeof import('sanity')>(\n 'sanity',\n workDir,\n )\n\n const result = await Promise.race([\n validateDocument({\n document,\n environment: 'cli',\n // The local `sanity` package types its client against its own\n // @sanity/client major; the runtime surface validation uses is\n // compatible across v7/v8.\n getClient: getClient as unknown as Parameters<typeof validateDocument>[0]['getClient'],\n getDocumentExists,\n maxCustomValidationConcurrency,\n maxFetchConcurrency,\n workspace,\n }),\n new Promise<typeof timeout>((resolve) =>\n setTimeout(() => resolve(timeout), DOCUMENT_VALIDATION_TIMEOUT),\n ),\n ])\n\n if (result === timeout) {\n throw new Error(\n `Document '${document._id}' failed to validate within ${DOCUMENT_VALIDATION_TIMEOUT}ms.`,\n )\n }\n\n markers = result\n // filter out unwanted levels\n .filter((marker) => {\n const markerValue = levelValues[marker.level]\n const flagLevelValue =\n levelValues[level as keyof typeof levelValues] ?? levelValues.info\n return markerValue <= flagLevelValue\n })\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : 'Unknown error'\n\n const message = `Exception occurred while validating value: ${errorMessage}`\n\n markers = [\n {\n level: 'error',\n message,\n path: [],\n },\n ]\n }\n\n validatedCount++\n\n const intentUrl =\n studioHost &&\n `${studioHost}${path.resolve(\n workspace.basePath,\n `/intent/edit/id=${encodeURIComponent(document._id)};type=${encodeURIComponent(\n document._type,\n )}`,\n )}`\n\n report.stream.validation.emit({\n documentId: document._id,\n documentType: document._type,\n ...(intentUrl && {intentUrl}),\n level: getLevel(markers),\n markers,\n revision: document._rev,\n validatedCount,\n })\n }\n\n await pMap(getDocuments(), validate, {concurrency: MAX_VALIDATION_CONCURRENCY})\n\n report.stream.validation.end()\n } finally {\n await cleanupDownloadedDocuments?.()\n }\n}\n"],"names":["fs","os","path","readline","Readable","workerData","_workerData","isMainThread","parentPort","getStudioWorkspaces","getWorkspace","resolveLocalPackage","createClient","WorkerChannelReporter","pMap","checkDocumentAvailability","exportDocuments","getDocumentCount","extractDocumentsFromNdjsonOrTarball","DOCUMENT_VALIDATION_TIMEOUT","getReferenceIds","isValidId","levelValues","MAX_VALIDATION_CONCURRENCY","REFERENCE_INTEGRITY_BATCH_SIZE","shouldIncludeDocument","clientConfig","dataset","level","maxCustomValidationConcurrency","maxFetchConcurrency","ndjsonFilePath","projectId","studioHost","workDir","workspace","workspaceName","Error","report","from","readerToGenerator","reader","done","value","read","main","process","exit","loadWorkspace","workspaces","resolvedDataset","resolvedProjectId","client","requestTagPrefix","config","apiVersion","event","loadedWorkspace","basePath","name","downloadFromExport","datasetName","projId","documentCount","loadedDocumentCount","response","body","getReader","downloadedCount","referencedIds","Set","documentIds","lines","createInterface","input","slugDate","Date","toISOString","replaceAll","toLowerCase","tempOutputFile","join","tmpdir","outputStream","createWriteStream","line","document","JSON","parse","add","_id","referenceId","write","stream","exportProgress","emit","Promise","resolve","reject","close","err","end","exportFinished","totalDocumentsToValidate","size","getDocuments","createReadStream","cleanup","promises","rm","downloadFromFile","filePath","undefined","checkReferenceExistence","_referencedIds","existingIds","idsToCheck","filter","id","has","toSorted","batches","i","length","push","slice","batch","omitted","omittedIds","item","reason","loadedReferenceIntegrity","cleanupDownloadedDocuments","getClient","options","withConfig","getDocumentExists","getLevel","markers","foundWarning","marker","validatedCount","validate","timeout","Symbol","validateDocument","result","race","environment","setTimeout","markerValue","flagLevelValue","info","errorMessage","message","intentUrl","encodeURIComponent","_type","validation","documentId","documentType","revision","_rev","concurrency"],"mappings":"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"}
|
|
@@ -37,6 +37,9 @@ const debug = subdebug('uploadSchemaToLexicon');
|
|
|
37
37
|
dataset: workspace.dataset,
|
|
38
38
|
projectId: workspace.projectId
|
|
39
39
|
});
|
|
40
|
+
// The local `sanity` package types its client against its own
|
|
41
|
+
// @sanity/client major; the runtime surface uploadSchema uses is
|
|
42
|
+
// compatible across v7/v8.
|
|
40
43
|
const descriptorId = await uploadSchema(workspace.schema, workspaceClient);
|
|
41
44
|
if (!descriptorId) {
|
|
42
45
|
throw new Error(`Failed to get schema descriptor ID for workspace "${workspace.name}": upload returned empty result`);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/actions/schema/uploadSchemaToLexicon.ts"],"sourcesContent":["import {styleText} from 'node:util'\n\nimport {ux} from '@oclif/core/ux'\nimport {\n doImport,\n getLocalPackageVersion,\n getProjectCliClient,\n resolveLocalPackage,\n subdebug,\n} from '@sanity/cli-core'\nimport {spinner} from '@sanity/cli-core/ux'\nimport {type StudioManifest, type Workspace} from 'sanity'\n\nimport {SCHEMA_API_VERSION} from '../../services/schemas.js'\n\nconst iconResolverPath = new URL('../manifest/iconResolver.js', import.meta.url).href\n\ninterface UploadSchemaToLexiconOptions {\n projectId: string\n workDir: string\n workspaces: Workspace[]\n\n verbose?: boolean\n}\n\nconst debug = subdebug('uploadSchemaToLexicon')\n\n/**\n * Uploads the schemas to Lexicon and returns the studio manifest\n * @param options - The options for the uploadSchemaToLexicon function\n * @returns The studio manifest\n */\nexport async function uploadSchemaToLexicon(\n options: UploadSchemaToLexiconOptions,\n): Promise<StudioManifest | null> {\n const {projectId, verbose, workDir, workspaces} = options\n const spin = spinner('Generating studio manifest').start()\n\n try {\n const schemaDescriptors = new Map<string, string>()\n\n const client = await getProjectCliClient({\n apiVersion: SCHEMA_API_VERSION,\n projectId,\n requestTagPrefix: 'sanity.cli.deploy',\n requireUser: true,\n })\n\n const [bundleVersion, {generateStudioManifest, uploadSchema}] = await Promise.all([\n getLocalPackageVersion('sanity', workDir),\n resolveLocalPackage<typeof import('sanity')>('sanity', workDir),\n ])\n\n if (!bundleVersion) {\n throw new Error('Failed to find sanity version')\n }\n\n for (const workspace of workspaces) {\n const workspaceClient = client.withConfig({\n dataset: workspace.dataset,\n projectId: workspace.projectId,\n })\n\n try {\n debug('Uploading schema to lexicon for workspace %o', {\n dataset: workspace.dataset,\n projectId: workspace.projectId,\n })\n const descriptorId = await uploadSchema(workspace.schema
|
|
1
|
+
{"version":3,"sources":["../../../src/actions/schema/uploadSchemaToLexicon.ts"],"sourcesContent":["import {styleText} from 'node:util'\n\nimport {ux} from '@oclif/core/ux'\nimport {\n doImport,\n getLocalPackageVersion,\n getProjectCliClient,\n resolveLocalPackage,\n subdebug,\n} from '@sanity/cli-core'\nimport {spinner} from '@sanity/cli-core/ux'\nimport {type StudioManifest, type Workspace} from 'sanity'\n\nimport {SCHEMA_API_VERSION} from '../../services/schemas.js'\n\nconst iconResolverPath = new URL('../manifest/iconResolver.js', import.meta.url).href\n\ninterface UploadSchemaToLexiconOptions {\n projectId: string\n workDir: string\n workspaces: Workspace[]\n\n verbose?: boolean\n}\n\nconst debug = subdebug('uploadSchemaToLexicon')\n\n/**\n * Uploads the schemas to Lexicon and returns the studio manifest\n * @param options - The options for the uploadSchemaToLexicon function\n * @returns The studio manifest\n */\nexport async function uploadSchemaToLexicon(\n options: UploadSchemaToLexiconOptions,\n): Promise<StudioManifest | null> {\n const {projectId, verbose, workDir, workspaces} = options\n const spin = spinner('Generating studio manifest').start()\n\n try {\n const schemaDescriptors = new Map<string, string>()\n\n const client = await getProjectCliClient({\n apiVersion: SCHEMA_API_VERSION,\n projectId,\n requestTagPrefix: 'sanity.cli.deploy',\n requireUser: true,\n })\n\n const [bundleVersion, {generateStudioManifest, uploadSchema}] = await Promise.all([\n getLocalPackageVersion('sanity', workDir),\n resolveLocalPackage<typeof import('sanity')>('sanity', workDir),\n ])\n\n if (!bundleVersion) {\n throw new Error('Failed to find sanity version')\n }\n\n for (const workspace of workspaces) {\n const workspaceClient = client.withConfig({\n dataset: workspace.dataset,\n projectId: workspace.projectId,\n })\n\n try {\n debug('Uploading schema to lexicon for workspace %o', {\n dataset: workspace.dataset,\n projectId: workspace.projectId,\n })\n // The local `sanity` package types its client against its own\n // @sanity/client major; the runtime surface uploadSchema uses is\n // compatible across v7/v8.\n const descriptorId = await uploadSchema(\n workspace.schema,\n workspaceClient as unknown as Parameters<typeof uploadSchema>[1],\n )\n\n if (!descriptorId) {\n throw new Error(\n `Failed to get schema descriptor ID for workspace \"${workspace.name}\": upload returned empty result`,\n )\n }\n\n schemaDescriptors.set(workspace.name, descriptorId)\n debug(\n `Uploaded schema for workspace \"${workspace.name}\" to Lexicon with descriptor ID: ${descriptorId}`,\n )\n } catch (error) {\n debug('Error uploading schema to lexicon for workspace %o', error)\n const errorMessage = error instanceof Error ? error.message : 'Unknown error'\n throw new Error(\n `Failed to upload schema for workspace \"${workspace.name}\": ${errorMessage}`,\n {cause: error},\n )\n }\n }\n\n // Lazy import to avoid pulling in @sanity/ui at module load time\n const {resolveIcon} = await doImport(iconResolverPath)\n\n // Generate studio manifest using the shared utility\n const manifest = await generateStudioManifest({\n buildId: JSON.stringify(Date.now()),\n bundleVersion,\n // @todo replace with import from @sanity/schema/_internal in future\n resolveIcon: async (workspace) =>\n (await resolveIcon({\n icon: workspace.icon,\n subtitle: workspace.subtitle,\n title: workspace.title || workspace.name || 'default',\n workDir,\n })) ?? undefined,\n resolveSchemaDescriptorId: (workspace) => schemaDescriptors.get(workspace.name),\n workspaces,\n })\n\n spin.succeed('Generated studio manifest')\n\n const studioManifest = manifest.workspaces.length === 0 ? null : manifest\n\n if (verbose) {\n if (studioManifest) {\n for (const workspace of studioManifest.workspaces) {\n ux.stdout(\n styleText(\n 'gray',\n `↳ projectId: ${workspace.projectId}, dataset: ${workspace.dataset}, schemaDescriptorId: ${workspace.schemaDescriptorId}`,\n ),\n )\n }\n } else {\n ux.stdout(`${styleText('gray', '↳ No workspaces found')}`)\n }\n }\n\n return studioManifest\n } catch (error) {\n spin.fail(error instanceof Error ? error.message : 'Unknown error')\n throw error\n }\n}\n"],"names":["styleText","ux","doImport","getLocalPackageVersion","getProjectCliClient","resolveLocalPackage","subdebug","spinner","SCHEMA_API_VERSION","iconResolverPath","URL","url","href","debug","uploadSchemaToLexicon","options","projectId","verbose","workDir","workspaces","spin","start","schemaDescriptors","Map","client","apiVersion","requestTagPrefix","requireUser","bundleVersion","generateStudioManifest","uploadSchema","Promise","all","Error","workspace","workspaceClient","withConfig","dataset","descriptorId","schema","name","set","error","errorMessage","message","cause","resolveIcon","manifest","buildId","JSON","stringify","Date","now","icon","subtitle","title","undefined","resolveSchemaDescriptorId","get","succeed","studioManifest","length","stdout","schemaDescriptorId","fail"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/actions/telemetry/telemetryDebug.ts"],"sourcesContent":["import
|
|
1
|
+
{"version":3,"sources":["../../../src/actions/telemetry/telemetryDebug.ts"],"sourcesContent":["import {createDebug} from 'obug'\n\nexport const telemetryDebug = createDebug('telemetry:sanity:cli')\n"],"names":["createDebug","telemetryDebug"],"mappings":"AAAA,SAAQA,WAAW,QAAO,OAAM;AAEhC,OAAO,MAAMC,iBAAiBD,YAAY,wBAAuB"}
|
|
@@ -2,7 +2,7 @@ import fs from 'node:fs';
|
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import { Args, Flags } from '@oclif/core';
|
|
4
4
|
import { exitCodes, getProjectCliClient, SanityCommand, subdebug } from '@sanity/cli-core';
|
|
5
|
-
import { createRequester } from '@sanity/cli-core/request';
|
|
5
|
+
import { createRequester, nodeReadableFromWeb } from '@sanity/cli-core/request';
|
|
6
6
|
import { spinner } from '@sanity/cli-core/ux';
|
|
7
7
|
import { sanityImport } from '@sanity/import';
|
|
8
8
|
import prettyMs from 'pretty-ms';
|
|
@@ -25,19 +25,16 @@ function getAssetsBase(source) {
|
|
|
25
25
|
}
|
|
26
26
|
}
|
|
27
27
|
async function getUriStream(uri) {
|
|
28
|
-
const request = createRequester(
|
|
29
|
-
middleware: {
|
|
30
|
-
promise: {
|
|
31
|
-
onlyBody: false
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
});
|
|
28
|
+
const request = createRequester();
|
|
35
29
|
try {
|
|
30
|
+
// No timeout: large dataset exports may stream for longer than get-it's
|
|
31
|
+
// default request timeout, which would abort the body mid-transfer.
|
|
36
32
|
const response = await request({
|
|
37
|
-
|
|
33
|
+
as: 'stream',
|
|
34
|
+
timeout: false,
|
|
38
35
|
url: uri
|
|
39
36
|
});
|
|
40
|
-
return response.body;
|
|
37
|
+
return nodeReadableFromWeb(response.body);
|
|
41
38
|
} catch (err) {
|
|
42
39
|
throw new Error(`Error fetching source:\n${err.message}`, {
|
|
43
40
|
cause: err
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/commands/datasets/import.ts"],"sourcesContent":["import fs from 'node:fs'\nimport path from 'node:path'\n\nimport {Args, Flags} from '@oclif/core'\nimport {exitCodes, getProjectCliClient, SanityCommand, subdebug} from '@sanity/cli-core'\nimport {createRequester} from '@sanity/cli-core/request'\nimport {spinner} from '@sanity/cli-core/ux'\nimport {sanityImport} from '@sanity/import'\nimport prettyMs from 'pretty-ms'\n\nimport {NEW_DATASET_VALUE, promptForDataset} from '../../prompts/promptForDataset.js'\nimport {promptForDatasetName} from '../../prompts/promptForDatasetName.js'\nimport {promptForProject} from '../../prompts/promptForProject.js'\nimport {createDataset, listDatasets} from '../../services/datasets.js'\nimport {getDatasetFlag, getProjectIdFlag} from '../../util/sharedFlags.js'\n\nconst importDebug = subdebug('dataset:import')\n\ninterface ProgressEvent {\n step: string\n\n current?: number\n total?: number\n update?: string\n}\n\nfunction getAssetsBase(source: string): string | undefined {\n if (/^https?:\\/\\//i.test(source) || source === '-') {\n return undefined\n }\n\n try {\n const fileStats = fs.statSync(source)\n const sourceIsFolder = fileStats.isDirectory()\n return sourceIsFolder ? source : path.dirname(source)\n } catch {\n return undefined\n }\n}\n\nasync function getUriStream(uri: string): Promise<NodeJS.ReadableStream> {\n const request = createRequester({\n middleware: {promise: {onlyBody: false}},\n })\n\n try {\n const response = (await request({stream: true, url: uri})) as {body: NodeJS.ReadableStream}\n return response.body\n } catch (err) {\n throw new Error(`Error fetching source:\\n${(err as Error).message}`, {cause: err})\n }\n}\n\nfunction getPercentage(opts: ProgressEvent): string {\n if (!opts.total) {\n return ''\n }\n\n const percent = Math.floor(((opts.current || 0) / opts.total) * 100)\n return `[${percent}%] `\n}\n\nexport class ImportDatasetCommand extends SanityCommand<typeof ImportDatasetCommand> {\n static override args = {\n source: Args.string({\n description: 'Source file (use \"-\" for stdin)',\n required: true,\n }),\n targetDataset: Args.string({\n description: 'Target dataset (prefer --dataset flag instead)',\n required: false,\n }),\n }\n\n static override description = 'Import documents to a Sanity dataset'\n\n static override examples = [\n {\n command: '<%= config.bin %> <%= command.id %> -d staging my-dataset.ndjson',\n description: 'Import \"./my-dataset.ndjson\" into dataset \"staging\"',\n },\n {\n command: 'cat my-dataset.ndjson | <%= config.bin %> <%= command.id %> -d test -',\n description: 'Import into dataset \"test\" from stdin',\n },\n {\n command: '<%= config.bin %> <%= command.id %> -p projectId -d staging my-dataset.ndjson',\n description: 'Import with explicit project ID (overrides CLI configuration)',\n },\n {\n command:\n '<%= config.bin %> <%= command.id %> -d staging -t someSecretToken my-dataset.ndjson',\n description: 'Import with an explicit token (e.g. for CI/CD)',\n },\n ]\n\n static override flags = {\n 'allow-assets-in-different-dataset': Flags.boolean({\n default: false,\n description: 'Allow asset documents to reference different project/dataset',\n }),\n 'allow-failing-assets': Flags.boolean({\n default: false,\n description: 'Skip assets that cannot be fetched/uploaded',\n }),\n 'allow-replacement-characters': Flags.boolean({\n default: false,\n description: 'Allow unicode replacement characters in imported documents',\n }),\n 'allow-system-documents': Flags.boolean({\n default: false,\n description: 'Imports system documents',\n }),\n 'asset-concurrency': Flags.integer({\n description: 'Number of parallel asset imports',\n }),\n ...getDatasetFlag({\n description: 'Dataset to import to',\n semantics: 'specify',\n }),\n missing: Flags.boolean({\n default: false,\n description: 'Skip documents that already exist',\n exclusive: ['replace'],\n }),\n ...getProjectIdFlag({\n description: 'Project ID to import to',\n semantics: 'override',\n }),\n project: Flags.string({\n deprecated: {to: 'project-id'},\n description: 'Project ID to import to',\n hidden: true,\n }),\n replace: Flags.boolean({\n default: false,\n description: 'Replace documents with the same IDs',\n exclusive: ['missing'],\n }),\n 'replace-assets': Flags.boolean({\n default: false,\n description: 'Skip reuse of existing assets',\n }),\n 'skip-cross-dataset-references': Flags.boolean({\n default: false,\n description: 'Skips references to other datasets',\n }),\n token: Flags.string({\n char: 't',\n description: 'Token to authenticate with',\n env: 'SANITY_IMPORT_TOKEN',\n required: false,\n }),\n }\n\n static override hiddenAliases: string[] = ['dataset:import']\n\n private currentProgress?: ReturnType<typeof spinner>\n private currentStep?: string\n private spinInterval?: NodeJS.Timeout | null\n private stepStart?: number\n\n private static async getStream(source: string): Promise<NodeJS.ReadableStream> {\n if (/^https?:\\/\\//i.test(source)) {\n return getUriStream(source)\n }\n\n return source === '-' ? process.stdin : fs.createReadStream(source)\n }\n\n public async run(): Promise<void> {\n const {args, flags} = await this.parse(ImportDatasetCommand)\n\n const {\n 'allow-assets-in-different-dataset': allowAssetsInDifferentDataset,\n 'allow-failing-assets': allowFailingAssets,\n 'allow-replacement-characters': allowReplacementCharacters,\n 'allow-system-documents': allowSystemDocuments,\n 'asset-concurrency': assetConcurrency,\n dataset: datasetFlag,\n missing,\n replace,\n 'replace-assets': replaceAssets,\n 'skip-cross-dataset-references': skipCrossDatasetReferences,\n token,\n } = flags\n\n const projectId = await this.getProjectId({\n deprecatedFlagName: 'project',\n fallback: () => promptForProject({}),\n })\n\n const {source, targetDataset: targetDatasetArg} = args\n\n if (targetDatasetArg && !datasetFlag) {\n this.output.warn(\n 'Positional dataset argument is deprecated. Use the --dataset flag instead: --dataset <name>',\n )\n }\n\n let dataset = datasetFlag ?? targetDatasetArg\n if (!dataset) {\n if (this.isUnattended()) {\n return this.output.error('Dataset is required. Pass it with `--dataset <name>`.', {\n exit: exitCodes.USAGE_ERROR,\n })\n }\n\n const datasets = await listDatasets(projectId)\n dataset = await promptForDataset({allowCreation: true, datasets})\n\n if (dataset === NEW_DATASET_VALUE) {\n const newDatasetName = await promptForDatasetName()\n\n try {\n await createDataset({datasetName: newDatasetName, projectId})\n dataset = newDatasetName\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error)\n importDebug(`Failed to create dataset ${newDatasetName}: ${message}`, error)\n return this.output.error(`Failed to create dataset ${newDatasetName}: ${message}`, {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n }\n }\n\n let operation: 'create' | 'createIfNotExists' | 'createOrReplace' = 'create'\n let releasesOperation: 'fail' | 'ignore' | 'replace' = 'fail'\n\n if (replace || missing) {\n operation = replace ? 'createOrReplace' : 'createIfNotExists'\n releasesOperation = replace ? 'replace' : 'ignore'\n }\n\n const client = await getProjectCliClient({\n apiVersion: 'v2025-02-19',\n dataset,\n projectId,\n requireUser: true,\n ...(token ? {token} : {}),\n })\n\n try {\n const stream = await ImportDatasetCommand.getStream(source)\n const assetsBase = getAssetsBase(source)\n\n const importOptions = {\n allowAssetsInDifferentDataset,\n allowFailingAssets,\n allowReplacementCharacters,\n allowSystemDocuments,\n client,\n onProgress: this.onProgress.bind(this),\n operation,\n releasesOperation,\n replaceAssets,\n skipCrossDatasetReferences,\n tag: 'sanity.import',\n targetDataset: dataset,\n targetProjectId: projectId,\n ...(assetsBase ? {assetsBase} : {}),\n ...(assetConcurrency === undefined ? {} : {assetConcurrency}),\n }\n\n const {numDocs, warnings} = await sanityImport(stream, importOptions)\n\n if (this.stepStart) {\n const timeSpent = prettyMs(Date.now() - this.stepStart, {secondsDecimalDigits: 2})\n if (this.currentProgress) {\n if (this.spinInterval) {\n clearInterval(this.spinInterval)\n this.spinInterval = null\n }\n this.currentProgress.text = `[100%] ${this.currentStep} (${timeSpent})`\n this.currentProgress.succeed()\n }\n }\n\n this.output.log('Done! Imported %d documents to dataset \"%s\"\\n', numDocs, dataset)\n this.printWarnings(warnings)\n } catch (err) {\n if (this.spinInterval) {\n clearInterval(this.spinInterval)\n this.spinInterval = null\n }\n\n if (this.currentProgress) {\n this.currentProgress.fail()\n }\n\n return (err as Error).name === 'ReplacementCharError'\n ? this.output.error(\n `Import failed due to unicode replacement characters in the data.\\n${(err as Error).message}\\n\\nIf you are certain you want to proceed with the import despite potentially corrupt data, re-run the import with the \\`--allow-replacement-characters\\` flag set.`,\n {exit: exitCodes.RUNTIME_ERROR},\n )\n : this.output.error((err as Error).stack || (err as Error).message, {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n }\n\n private onProgress(opts: ProgressEvent): void {\n const lengthComputable = opts.total\n const sameStep = opts.step === this.currentStep\n const percent = getPercentage(opts)\n\n if (lengthComputable && opts.total === opts.current && this.spinInterval) {\n clearInterval(this.spinInterval)\n this.spinInterval = null\n }\n\n if (sameStep && !lengthComputable) {\n return\n }\n\n if (sameStep) {\n if (this.stepStart) {\n const timeSpent = prettyMs(Date.now() - this.stepStart, {secondsDecimalDigits: 2})\n if (this.currentProgress) {\n this.currentProgress.text = `${percent}${opts.step} (${timeSpent})`\n this.currentProgress.render()\n }\n }\n return\n }\n\n // Moved to a new step\n const prevStep = this.currentStep\n const prevStepStart = this.stepStart\n this.stepStart = Date.now()\n this.currentStep = opts.step\n\n if (this.spinInterval) {\n clearInterval(this.spinInterval)\n this.spinInterval = null\n }\n\n if (this.currentProgress && this.currentProgress.succeed && prevStepStart) {\n const timeSpent = prettyMs(Date.now() - prevStepStart, {\n secondsDecimalDigits: 2,\n })\n this.currentProgress.text = `[100%] ${prevStep} (${timeSpent})`\n this.currentProgress.succeed()\n }\n\n this.currentProgress = spinner(`[0%] ${opts.step} (0.00s)`).start()\n\n if (!lengthComputable) {\n this.spinInterval = setInterval(() => {\n if (this.stepStart && this.currentProgress) {\n const timeSpent = prettyMs(Date.now() - this.stepStart, {\n secondsDecimalDigits: 2,\n })\n this.currentProgress.text = `${percent}${opts.step} (${timeSpent})`\n this.currentProgress.render()\n }\n }, 60)\n }\n }\n\n private printWarnings(warnings: Array<{message: string; type?: string; url?: string}>): void {\n const assetFails = warnings.filter((warn) => warn.type === 'asset')\n\n if (assetFails.length === 0) {\n return\n }\n\n this.output.warn(\n `Failed to import the following ${assetFails.length > 1 ? 'assets' : 'asset'}:`,\n )\n\n for (const warning of assetFails) {\n if (warning.url) {\n this.output.warn(` ${warning.url}`)\n }\n }\n }\n}\n"],"names":["fs","path","Args","Flags","exitCodes","getProjectCliClient","SanityCommand","subdebug","createRequester","spinner","sanityImport","prettyMs","NEW_DATASET_VALUE","promptForDataset","promptForDatasetName","promptForProject","createDataset","listDatasets","getDatasetFlag","getProjectIdFlag","importDebug","getAssetsBase","source","test","undefined","fileStats","statSync","sourceIsFolder","isDirectory","dirname","getUriStream","uri","request","middleware","promise","onlyBody","response","stream","url","body","err","Error","message","cause","getPercentage","opts","total","percent","Math","floor","current","ImportDatasetCommand","args","string","description","required","targetDataset","examples","command","flags","boolean","default","integer","semantics","missing","exclusive","project","deprecated","to","hidden","replace","token","char","env","hiddenAliases","currentProgress","currentStep","spinInterval","stepStart","getStream","process","stdin","createReadStream","run","parse","allowAssetsInDifferentDataset","allowFailingAssets","allowReplacementCharacters","allowSystemDocuments","assetConcurrency","dataset","datasetFlag","replaceAssets","skipCrossDatasetReferences","projectId","getProjectId","deprecatedFlagName","fallback","targetDatasetArg","output","warn","isUnattended","error","exit","USAGE_ERROR","datasets","allowCreation","newDatasetName","datasetName","String","RUNTIME_ERROR","operation","releasesOperation","client","apiVersion","requireUser","assetsBase","importOptions","onProgress","bind","tag","targetProjectId","numDocs","warnings","timeSpent","Date","now","secondsDecimalDigits","clearInterval","text","succeed","log","printWarnings","fail","name","stack","lengthComputable","sameStep","step","render","prevStep","prevStepStart","start","setInterval","assetFails","filter","type","length","warning"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../src/commands/datasets/import.ts"],"sourcesContent":["import fs from 'node:fs'\nimport path from 'node:path'\n\nimport {Args, Flags} from '@oclif/core'\nimport {exitCodes, getProjectCliClient, SanityCommand, subdebug} from '@sanity/cli-core'\nimport {createRequester, nodeReadableFromWeb} from '@sanity/cli-core/request'\nimport {spinner} from '@sanity/cli-core/ux'\nimport {sanityImport} from '@sanity/import'\nimport prettyMs from 'pretty-ms'\n\nimport {NEW_DATASET_VALUE, promptForDataset} from '../../prompts/promptForDataset.js'\nimport {promptForDatasetName} from '../../prompts/promptForDatasetName.js'\nimport {promptForProject} from '../../prompts/promptForProject.js'\nimport {createDataset, listDatasets} from '../../services/datasets.js'\nimport {getDatasetFlag, getProjectIdFlag} from '../../util/sharedFlags.js'\n\nconst importDebug = subdebug('dataset:import')\n\ninterface ProgressEvent {\n step: string\n\n current?: number\n total?: number\n update?: string\n}\n\nfunction getAssetsBase(source: string): string | undefined {\n if (/^https?:\\/\\//i.test(source) || source === '-') {\n return undefined\n }\n\n try {\n const fileStats = fs.statSync(source)\n const sourceIsFolder = fileStats.isDirectory()\n return sourceIsFolder ? source : path.dirname(source)\n } catch {\n return undefined\n }\n}\n\nasync function getUriStream(uri: string): Promise<NodeJS.ReadableStream> {\n const request = createRequester()\n\n try {\n // No timeout: large dataset exports may stream for longer than get-it's\n // default request timeout, which would abort the body mid-transfer.\n const response = await request({as: 'stream', timeout: false, url: uri})\n return nodeReadableFromWeb(response.body)\n } catch (err) {\n throw new Error(`Error fetching source:\\n${(err as Error).message}`, {cause: err})\n }\n}\n\nfunction getPercentage(opts: ProgressEvent): string {\n if (!opts.total) {\n return ''\n }\n\n const percent = Math.floor(((opts.current || 0) / opts.total) * 100)\n return `[${percent}%] `\n}\n\nexport class ImportDatasetCommand extends SanityCommand<typeof ImportDatasetCommand> {\n static override args = {\n source: Args.string({\n description: 'Source file (use \"-\" for stdin)',\n required: true,\n }),\n targetDataset: Args.string({\n description: 'Target dataset (prefer --dataset flag instead)',\n required: false,\n }),\n }\n\n static override description = 'Import documents to a Sanity dataset'\n\n static override examples = [\n {\n command: '<%= config.bin %> <%= command.id %> -d staging my-dataset.ndjson',\n description: 'Import \"./my-dataset.ndjson\" into dataset \"staging\"',\n },\n {\n command: 'cat my-dataset.ndjson | <%= config.bin %> <%= command.id %> -d test -',\n description: 'Import into dataset \"test\" from stdin',\n },\n {\n command: '<%= config.bin %> <%= command.id %> -p projectId -d staging my-dataset.ndjson',\n description: 'Import with explicit project ID (overrides CLI configuration)',\n },\n {\n command:\n '<%= config.bin %> <%= command.id %> -d staging -t someSecretToken my-dataset.ndjson',\n description: 'Import with an explicit token (e.g. for CI/CD)',\n },\n ]\n\n static override flags = {\n 'allow-assets-in-different-dataset': Flags.boolean({\n default: false,\n description: 'Allow asset documents to reference different project/dataset',\n }),\n 'allow-failing-assets': Flags.boolean({\n default: false,\n description: 'Skip assets that cannot be fetched/uploaded',\n }),\n 'allow-replacement-characters': Flags.boolean({\n default: false,\n description: 'Allow unicode replacement characters in imported documents',\n }),\n 'allow-system-documents': Flags.boolean({\n default: false,\n description: 'Imports system documents',\n }),\n 'asset-concurrency': Flags.integer({\n description: 'Number of parallel asset imports',\n }),\n ...getDatasetFlag({\n description: 'Dataset to import to',\n semantics: 'specify',\n }),\n missing: Flags.boolean({\n default: false,\n description: 'Skip documents that already exist',\n exclusive: ['replace'],\n }),\n ...getProjectIdFlag({\n description: 'Project ID to import to',\n semantics: 'override',\n }),\n project: Flags.string({\n deprecated: {to: 'project-id'},\n description: 'Project ID to import to',\n hidden: true,\n }),\n replace: Flags.boolean({\n default: false,\n description: 'Replace documents with the same IDs',\n exclusive: ['missing'],\n }),\n 'replace-assets': Flags.boolean({\n default: false,\n description: 'Skip reuse of existing assets',\n }),\n 'skip-cross-dataset-references': Flags.boolean({\n default: false,\n description: 'Skips references to other datasets',\n }),\n token: Flags.string({\n char: 't',\n description: 'Token to authenticate with',\n env: 'SANITY_IMPORT_TOKEN',\n required: false,\n }),\n }\n\n static override hiddenAliases: string[] = ['dataset:import']\n\n private currentProgress?: ReturnType<typeof spinner>\n private currentStep?: string\n private spinInterval?: NodeJS.Timeout | null\n private stepStart?: number\n\n private static async getStream(source: string): Promise<NodeJS.ReadableStream> {\n if (/^https?:\\/\\//i.test(source)) {\n return getUriStream(source)\n }\n\n return source === '-' ? process.stdin : fs.createReadStream(source)\n }\n\n public async run(): Promise<void> {\n const {args, flags} = await this.parse(ImportDatasetCommand)\n\n const {\n 'allow-assets-in-different-dataset': allowAssetsInDifferentDataset,\n 'allow-failing-assets': allowFailingAssets,\n 'allow-replacement-characters': allowReplacementCharacters,\n 'allow-system-documents': allowSystemDocuments,\n 'asset-concurrency': assetConcurrency,\n dataset: datasetFlag,\n missing,\n replace,\n 'replace-assets': replaceAssets,\n 'skip-cross-dataset-references': skipCrossDatasetReferences,\n token,\n } = flags\n\n const projectId = await this.getProjectId({\n deprecatedFlagName: 'project',\n fallback: () => promptForProject({}),\n })\n\n const {source, targetDataset: targetDatasetArg} = args\n\n if (targetDatasetArg && !datasetFlag) {\n this.output.warn(\n 'Positional dataset argument is deprecated. Use the --dataset flag instead: --dataset <name>',\n )\n }\n\n let dataset = datasetFlag ?? targetDatasetArg\n if (!dataset) {\n if (this.isUnattended()) {\n return this.output.error('Dataset is required. Pass it with `--dataset <name>`.', {\n exit: exitCodes.USAGE_ERROR,\n })\n }\n\n const datasets = await listDatasets(projectId)\n dataset = await promptForDataset({allowCreation: true, datasets})\n\n if (dataset === NEW_DATASET_VALUE) {\n const newDatasetName = await promptForDatasetName()\n\n try {\n await createDataset({datasetName: newDatasetName, projectId})\n dataset = newDatasetName\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error)\n importDebug(`Failed to create dataset ${newDatasetName}: ${message}`, error)\n return this.output.error(`Failed to create dataset ${newDatasetName}: ${message}`, {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n }\n }\n\n let operation: 'create' | 'createIfNotExists' | 'createOrReplace' = 'create'\n let releasesOperation: 'fail' | 'ignore' | 'replace' = 'fail'\n\n if (replace || missing) {\n operation = replace ? 'createOrReplace' : 'createIfNotExists'\n releasesOperation = replace ? 'replace' : 'ignore'\n }\n\n const client = await getProjectCliClient({\n apiVersion: 'v2025-02-19',\n dataset,\n projectId,\n requireUser: true,\n ...(token ? {token} : {}),\n })\n\n try {\n const stream = await ImportDatasetCommand.getStream(source)\n const assetsBase = getAssetsBase(source)\n\n const importOptions = {\n allowAssetsInDifferentDataset,\n allowFailingAssets,\n allowReplacementCharacters,\n allowSystemDocuments,\n client,\n onProgress: this.onProgress.bind(this),\n operation,\n releasesOperation,\n replaceAssets,\n skipCrossDatasetReferences,\n tag: 'sanity.import',\n targetDataset: dataset,\n targetProjectId: projectId,\n ...(assetsBase ? {assetsBase} : {}),\n ...(assetConcurrency === undefined ? {} : {assetConcurrency}),\n }\n\n const {numDocs, warnings} = await sanityImport(stream, importOptions)\n\n if (this.stepStart) {\n const timeSpent = prettyMs(Date.now() - this.stepStart, {secondsDecimalDigits: 2})\n if (this.currentProgress) {\n if (this.spinInterval) {\n clearInterval(this.spinInterval)\n this.spinInterval = null\n }\n this.currentProgress.text = `[100%] ${this.currentStep} (${timeSpent})`\n this.currentProgress.succeed()\n }\n }\n\n this.output.log('Done! Imported %d documents to dataset \"%s\"\\n', numDocs, dataset)\n this.printWarnings(warnings)\n } catch (err) {\n if (this.spinInterval) {\n clearInterval(this.spinInterval)\n this.spinInterval = null\n }\n\n if (this.currentProgress) {\n this.currentProgress.fail()\n }\n\n return (err as Error).name === 'ReplacementCharError'\n ? this.output.error(\n `Import failed due to unicode replacement characters in the data.\\n${(err as Error).message}\\n\\nIf you are certain you want to proceed with the import despite potentially corrupt data, re-run the import with the \\`--allow-replacement-characters\\` flag set.`,\n {exit: exitCodes.RUNTIME_ERROR},\n )\n : this.output.error((err as Error).stack || (err as Error).message, {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n }\n\n private onProgress(opts: ProgressEvent): void {\n const lengthComputable = opts.total\n const sameStep = opts.step === this.currentStep\n const percent = getPercentage(opts)\n\n if (lengthComputable && opts.total === opts.current && this.spinInterval) {\n clearInterval(this.spinInterval)\n this.spinInterval = null\n }\n\n if (sameStep && !lengthComputable) {\n return\n }\n\n if (sameStep) {\n if (this.stepStart) {\n const timeSpent = prettyMs(Date.now() - this.stepStart, {secondsDecimalDigits: 2})\n if (this.currentProgress) {\n this.currentProgress.text = `${percent}${opts.step} (${timeSpent})`\n this.currentProgress.render()\n }\n }\n return\n }\n\n // Moved to a new step\n const prevStep = this.currentStep\n const prevStepStart = this.stepStart\n this.stepStart = Date.now()\n this.currentStep = opts.step\n\n if (this.spinInterval) {\n clearInterval(this.spinInterval)\n this.spinInterval = null\n }\n\n if (this.currentProgress && this.currentProgress.succeed && prevStepStart) {\n const timeSpent = prettyMs(Date.now() - prevStepStart, {\n secondsDecimalDigits: 2,\n })\n this.currentProgress.text = `[100%] ${prevStep} (${timeSpent})`\n this.currentProgress.succeed()\n }\n\n this.currentProgress = spinner(`[0%] ${opts.step} (0.00s)`).start()\n\n if (!lengthComputable) {\n this.spinInterval = setInterval(() => {\n if (this.stepStart && this.currentProgress) {\n const timeSpent = prettyMs(Date.now() - this.stepStart, {\n secondsDecimalDigits: 2,\n })\n this.currentProgress.text = `${percent}${opts.step} (${timeSpent})`\n this.currentProgress.render()\n }\n }, 60)\n }\n }\n\n private printWarnings(warnings: Array<{message: string; type?: string; url?: string}>): void {\n const assetFails = warnings.filter((warn) => warn.type === 'asset')\n\n if (assetFails.length === 0) {\n return\n }\n\n this.output.warn(\n `Failed to import the following ${assetFails.length > 1 ? 'assets' : 'asset'}:`,\n )\n\n for (const warning of assetFails) {\n if (warning.url) {\n this.output.warn(` ${warning.url}`)\n }\n }\n }\n}\n"],"names":["fs","path","Args","Flags","exitCodes","getProjectCliClient","SanityCommand","subdebug","createRequester","nodeReadableFromWeb","spinner","sanityImport","prettyMs","NEW_DATASET_VALUE","promptForDataset","promptForDatasetName","promptForProject","createDataset","listDatasets","getDatasetFlag","getProjectIdFlag","importDebug","getAssetsBase","source","test","undefined","fileStats","statSync","sourceIsFolder","isDirectory","dirname","getUriStream","uri","request","response","as","timeout","url","body","err","Error","message","cause","getPercentage","opts","total","percent","Math","floor","current","ImportDatasetCommand","args","string","description","required","targetDataset","examples","command","flags","boolean","default","integer","semantics","missing","exclusive","project","deprecated","to","hidden","replace","token","char","env","hiddenAliases","currentProgress","currentStep","spinInterval","stepStart","getStream","process","stdin","createReadStream","run","parse","allowAssetsInDifferentDataset","allowFailingAssets","allowReplacementCharacters","allowSystemDocuments","assetConcurrency","dataset","datasetFlag","replaceAssets","skipCrossDatasetReferences","projectId","getProjectId","deprecatedFlagName","fallback","targetDatasetArg","output","warn","isUnattended","error","exit","USAGE_ERROR","datasets","allowCreation","newDatasetName","datasetName","String","RUNTIME_ERROR","operation","releasesOperation","client","apiVersion","requireUser","stream","assetsBase","importOptions","onProgress","bind","tag","targetProjectId","numDocs","warnings","timeSpent","Date","now","secondsDecimalDigits","clearInterval","text","succeed","log","printWarnings","fail","name","stack","lengthComputable","sameStep","step","render","prevStep","prevStepStart","start","setInterval","assetFails","filter","type","length","warning"],"mappings":"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"}
|