@sanity/cli 6.3.0 → 6.3.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/README.md +295 -442
- package/dist/actions/build/decorateIndexWithStagingScript.js +16 -0
- package/dist/actions/build/decorateIndexWithStagingScript.js.map +1 -0
- package/dist/actions/build/writeSanityRuntime.js +3 -2
- package/dist/actions/build/writeSanityRuntime.js.map +1 -1
- package/dist/actions/dataset/create.js +4 -0
- package/dist/actions/dataset/create.js.map +1 -1
- package/dist/actions/deploy/findUserApplicationForApp.js +1 -0
- package/dist/actions/deploy/findUserApplicationForApp.js.map +1 -1
- package/dist/actions/deploy/types.js +1 -1
- package/dist/actions/deploy/types.js.map +1 -1
- package/dist/actions/init/templates/nextjs/index.js +1 -2
- package/dist/actions/init/templates/nextjs/index.js.map +1 -1
- package/dist/actions/manifest/types.js +1 -1
- package/dist/actions/manifest/types.js.map +1 -1
- package/dist/actions/schema/types.js +3 -3
- package/dist/actions/schema/types.js.map +1 -1
- package/dist/actions/users/validateEmail.js +2 -2
- package/dist/actions/users/validateEmail.js.map +1 -1
- package/dist/commands/backups/disable.js +1 -1
- package/dist/commands/backups/disable.js.map +1 -1
- package/dist/commands/backups/download.js +1 -1
- package/dist/commands/backups/download.js.map +1 -1
- package/dist/commands/backups/enable.js +1 -1
- package/dist/commands/backups/enable.js.map +1 -1
- package/dist/commands/backups/list.js +1 -1
- package/dist/commands/backups/list.js.map +1 -1
- package/dist/commands/build.js +1 -1
- package/dist/commands/build.js.map +1 -1
- package/dist/commands/cors/add.js +1 -1
- package/dist/commands/cors/add.js.map +1 -1
- package/dist/commands/cors/delete.js +1 -1
- package/dist/commands/cors/delete.js.map +1 -1
- package/dist/commands/cors/list.js +2 -2
- package/dist/commands/cors/list.js.map +1 -1
- package/dist/commands/datasets/alias/create.js +1 -1
- package/dist/commands/datasets/alias/create.js.map +1 -1
- package/dist/commands/datasets/alias/delete.js +1 -1
- package/dist/commands/datasets/alias/delete.js.map +1 -1
- package/dist/commands/datasets/alias/link.js +1 -1
- package/dist/commands/datasets/alias/link.js.map +1 -1
- package/dist/commands/datasets/alias/unlink.js +1 -1
- package/dist/commands/datasets/alias/unlink.js.map +1 -1
- package/dist/commands/datasets/copy.js +1 -1
- package/dist/commands/datasets/copy.js.map +1 -1
- package/dist/commands/datasets/create.js +1 -1
- package/dist/commands/datasets/create.js.map +1 -1
- package/dist/commands/datasets/delete.js +1 -1
- package/dist/commands/datasets/delete.js.map +1 -1
- package/dist/commands/datasets/embeddings/enable.js +11 -0
- package/dist/commands/datasets/embeddings/enable.js.map +1 -1
- package/dist/commands/datasets/export.js +2 -2
- package/dist/commands/datasets/export.js.map +1 -1
- package/dist/commands/datasets/list.js +2 -2
- package/dist/commands/datasets/list.js.map +1 -1
- package/dist/commands/debug.js +1 -1
- package/dist/commands/debug.js.map +1 -1
- package/dist/commands/deploy.js +3 -3
- package/dist/commands/deploy.js.map +1 -1
- package/dist/commands/dev.js +5 -5
- package/dist/commands/dev.js.map +1 -1
- package/dist/commands/docs/browse.js +1 -1
- package/dist/commands/docs/browse.js.map +1 -1
- package/dist/commands/documents/delete.js +1 -1
- package/dist/commands/documents/delete.js.map +1 -1
- package/dist/commands/exec.js +2 -2
- package/dist/commands/exec.js.map +1 -1
- package/dist/commands/graphql/deploy.js +2 -2
- package/dist/commands/graphql/deploy.js.map +1 -1
- package/dist/commands/graphql/list.js +2 -2
- package/dist/commands/graphql/list.js.map +1 -1
- package/dist/commands/hooks/create.js +2 -2
- package/dist/commands/hooks/create.js.map +1 -1
- package/dist/commands/hooks/delete.js +5 -5
- package/dist/commands/hooks/delete.js.map +1 -1
- package/dist/commands/hooks/list.js +3 -3
- package/dist/commands/hooks/list.js.map +1 -1
- package/dist/commands/hooks/logs.js +5 -5
- package/dist/commands/hooks/logs.js.map +1 -1
- package/dist/commands/init.js +30 -12
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/install.js +1 -1
- package/dist/commands/install.js.map +1 -1
- package/dist/commands/learn.js +1 -1
- package/dist/commands/learn.js.map +1 -1
- package/dist/commands/login.js +1 -1
- package/dist/commands/login.js.map +1 -1
- package/dist/commands/logout.js +1 -1
- package/dist/commands/logout.js.map +1 -1
- package/dist/commands/manage.js +1 -1
- package/dist/commands/manage.js.map +1 -1
- package/dist/commands/manifest/extract.js +2 -2
- package/dist/commands/manifest/extract.js.map +1 -1
- package/dist/commands/media/delete-aspect.js +1 -1
- package/dist/commands/media/delete-aspect.js.map +1 -1
- package/dist/commands/media/export.js +1 -1
- package/dist/commands/media/export.js.map +1 -1
- package/dist/commands/preview.js +3 -3
- package/dist/commands/preview.js.map +1 -1
- package/dist/commands/projects/list.js +4 -2
- package/dist/commands/projects/list.js.map +1 -1
- package/dist/commands/schemas/deploy.js +3 -4
- package/dist/commands/schemas/deploy.js.map +1 -1
- package/dist/commands/schemas/extract.js +3 -3
- package/dist/commands/schemas/extract.js.map +1 -1
- package/dist/commands/schemas/list.js +4 -5
- package/dist/commands/schemas/list.js.map +1 -1
- package/dist/commands/telemetry/disable.js +2 -2
- package/dist/commands/telemetry/disable.js.map +1 -1
- package/dist/commands/telemetry/enable.js +2 -2
- package/dist/commands/telemetry/enable.js.map +1 -1
- package/dist/commands/telemetry/status.js +2 -2
- package/dist/commands/telemetry/status.js.map +1 -1
- package/dist/commands/tokens/add.js +1 -1
- package/dist/commands/tokens/add.js.map +1 -1
- package/dist/commands/tokens/delete.js +1 -1
- package/dist/commands/tokens/delete.js.map +1 -1
- package/dist/commands/tokens/list.js +2 -2
- package/dist/commands/tokens/list.js.map +1 -1
- package/dist/commands/users/list.js +1 -1
- package/dist/commands/users/list.js.map +1 -1
- package/dist/commands/versions.js +1 -1
- package/dist/commands/versions.js.map +1 -1
- package/dist/server/vite/plugin-sanity-build-entries.js +3 -2
- package/dist/server/vite/plugin-sanity-build-entries.js.map +1 -1
- package/dist/util/telemetry/createTelemetryStore.js +27 -12
- package/dist/util/telemetry/createTelemetryStore.js.map +1 -1
- package/dist/util/validateProjection.js +121 -0
- package/dist/util/validateProjection.js.map +1 -0
- package/oclif.manifest.json +317 -315
- package/package.json +27 -26
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { isStaging } from '@sanity/cli-core';
|
|
2
|
+
/**
|
|
3
|
+
* Decorates the given HTML template with a script tag that sets
|
|
4
|
+
* `globalThis.__SANITY_STAGING__` to `true` when building in a
|
|
5
|
+
* staging environment. The script is injected as the first child
|
|
6
|
+
* of `<head>` so it runs before any module scripts.
|
|
7
|
+
*
|
|
8
|
+
* @internal
|
|
9
|
+
*/ export function decorateIndexWithStagingScript(template) {
|
|
10
|
+
if (!isStaging()) {
|
|
11
|
+
return template;
|
|
12
|
+
}
|
|
13
|
+
return template.replace(/<head([^>]*)>/, '<head$1>\n<script>globalThis.__SANITY_STAGING__ = true</script>');
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
//# sourceMappingURL=decorateIndexWithStagingScript.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/actions/build/decorateIndexWithStagingScript.ts"],"sourcesContent":["import {isStaging} from '@sanity/cli-core'\n\n/**\n * Decorates the given HTML template with a script tag that sets\n * `globalThis.__SANITY_STAGING__` to `true` when building in a\n * staging environment. The script is injected as the first child\n * of `<head>` so it runs before any module scripts.\n *\n * @internal\n */\nexport function decorateIndexWithStagingScript(template: string): string {\n if (!isStaging()) {\n return template\n }\n\n return template.replace(\n /<head([^>]*)>/,\n '<head$1>\\n<script>globalThis.__SANITY_STAGING__ = true</script>',\n )\n}\n"],"names":["isStaging","decorateIndexWithStagingScript","template","replace"],"mappings":"AAAA,SAAQA,SAAS,QAAO,mBAAkB;AAE1C;;;;;;;CAOC,GACD,OAAO,SAASC,+BAA+BC,QAAgB;IAC7D,IAAI,CAACF,aAAa;QAChB,OAAOE;IACT;IAEA,OAAOA,SAASC,OAAO,CACrB,iBACA;AAEJ"}
|
|
@@ -6,6 +6,7 @@ import { toForwardSlashes } from '../../util/toForwardSlashes.js';
|
|
|
6
6
|
import { buildDebug } from './buildDebug.js';
|
|
7
7
|
import { decorateIndexWithAutoGeneratedWarning } from './decorateIndexWithAutoGeneratedWarning.js';
|
|
8
8
|
import { decorateIndexWithBridgeScript } from './decorateIndexWithBridgeScript.js';
|
|
9
|
+
import { decorateIndexWithStagingScript } from './decorateIndexWithStagingScript.js';
|
|
9
10
|
import { getEntryModule } from './getEntryModule.js';
|
|
10
11
|
import { getPossibleDocumentComponentLocations } from './getPossibleDocumentComponentLocations.js';
|
|
11
12
|
import { renderDocument } from './renderDocument.js';
|
|
@@ -25,7 +26,7 @@ import { renderDocument } from './renderDocument.js';
|
|
|
25
26
|
});
|
|
26
27
|
async function renderAndWriteDocument() {
|
|
27
28
|
buildDebug('Rendering document template');
|
|
28
|
-
const indexHtml = decorateIndexWithBridgeScript(decorateIndexWithAutoGeneratedWarning(await renderDocument({
|
|
29
|
+
const indexHtml = decorateIndexWithStagingScript(decorateIndexWithBridgeScript(decorateIndexWithAutoGeneratedWarning(await renderDocument({
|
|
29
30
|
isApp,
|
|
30
31
|
props: {
|
|
31
32
|
basePath: basePath || '/',
|
|
@@ -33,7 +34,7 @@ import { renderDocument } from './renderDocument.js';
|
|
|
33
34
|
title: appTitle
|
|
34
35
|
},
|
|
35
36
|
studioRootPath: cwd
|
|
36
|
-
})));
|
|
37
|
+
}))));
|
|
37
38
|
buildDebug('Writing index.html to runtime directory');
|
|
38
39
|
await fs.writeFile(path.join(runtimeDir, 'index.html'), indexHtml);
|
|
39
40
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/actions/build/writeSanityRuntime.ts"],"sourcesContent":["import fs from 'node:fs/promises'\nimport path from 'node:path'\n\nimport {tryFindStudioConfigPath} from '@sanity/cli-core'\nimport {watch as chokidarWatch, type FSWatcher} from 'chokidar'\n\nimport {toForwardSlashes} from '../../util/toForwardSlashes.js'\nimport {buildDebug} from './buildDebug.js'\nimport {decorateIndexWithAutoGeneratedWarning} from './decorateIndexWithAutoGeneratedWarning.js'\nimport {decorateIndexWithBridgeScript} from './decorateIndexWithBridgeScript.js'\nimport {getEntryModule} from './getEntryModule.js'\nimport {getPossibleDocumentComponentLocations} from './getPossibleDocumentComponentLocations.js'\nimport {renderDocument} from './renderDocument.js'\n\ninterface RuntimeOptions {\n cwd: string\n reactStrictMode: boolean\n watch: boolean\n\n appTitle?: string\n basePath?: string\n entry?: string\n isApp?: boolean\n}\n\n/**\n * Generates the `.sanity/runtime` directory, and optionally watches for custom\n * document files, rebuilding when they change\n *\n * @param options - Current working directory (Sanity root dir), and whether or not to watch\n * @returns A watcher instance if watch is enabled, undefined otherwise\n * @internal\n */\nexport async function writeSanityRuntime(options: RuntimeOptions): Promise<FSWatcher | undefined> {\n const {appTitle, basePath, cwd, entry, isApp, reactStrictMode, watch} = options\n const runtimeDir = path.join(cwd, '.sanity', 'runtime')\n\n buildDebug('Making runtime directory')\n await fs.mkdir(runtimeDir, {recursive: true})\n\n async function renderAndWriteDocument() {\n buildDebug('Rendering document template')\n const indexHtml = decorateIndexWithBridgeScript(\n
|
|
1
|
+
{"version":3,"sources":["../../../src/actions/build/writeSanityRuntime.ts"],"sourcesContent":["import fs from 'node:fs/promises'\nimport path from 'node:path'\n\nimport {tryFindStudioConfigPath} from '@sanity/cli-core'\nimport {watch as chokidarWatch, type FSWatcher} from 'chokidar'\n\nimport {toForwardSlashes} from '../../util/toForwardSlashes.js'\nimport {buildDebug} from './buildDebug.js'\nimport {decorateIndexWithAutoGeneratedWarning} from './decorateIndexWithAutoGeneratedWarning.js'\nimport {decorateIndexWithBridgeScript} from './decorateIndexWithBridgeScript.js'\nimport {decorateIndexWithStagingScript} from './decorateIndexWithStagingScript.js'\nimport {getEntryModule} from './getEntryModule.js'\nimport {getPossibleDocumentComponentLocations} from './getPossibleDocumentComponentLocations.js'\nimport {renderDocument} from './renderDocument.js'\n\ninterface RuntimeOptions {\n cwd: string\n reactStrictMode: boolean\n watch: boolean\n\n appTitle?: string\n basePath?: string\n entry?: string\n isApp?: boolean\n}\n\n/**\n * Generates the `.sanity/runtime` directory, and optionally watches for custom\n * document files, rebuilding when they change\n *\n * @param options - Current working directory (Sanity root dir), and whether or not to watch\n * @returns A watcher instance if watch is enabled, undefined otherwise\n * @internal\n */\nexport async function writeSanityRuntime(options: RuntimeOptions): Promise<FSWatcher | undefined> {\n const {appTitle, basePath, cwd, entry, isApp, reactStrictMode, watch} = options\n const runtimeDir = path.join(cwd, '.sanity', 'runtime')\n\n buildDebug('Making runtime directory')\n await fs.mkdir(runtimeDir, {recursive: true})\n\n async function renderAndWriteDocument() {\n buildDebug('Rendering document template')\n const indexHtml = decorateIndexWithStagingScript(\n decorateIndexWithBridgeScript(\n decorateIndexWithAutoGeneratedWarning(\n await renderDocument({\n isApp,\n props: {\n basePath: basePath || '/',\n entryPath: `/${toForwardSlashes(path.relative(cwd, path.join(runtimeDir, 'app.js')))}`,\n title: appTitle,\n },\n studioRootPath: cwd,\n }),\n ),\n ),\n )\n\n buildDebug('Writing index.html to runtime directory')\n await fs.writeFile(path.join(runtimeDir, 'index.html'), indexHtml)\n }\n\n let watcher: FSWatcher | undefined\n\n if (watch) {\n watcher = chokidarWatch(getPossibleDocumentComponentLocations(cwd)).on('all', () =>\n renderAndWriteDocument(),\n )\n }\n\n await renderAndWriteDocument()\n\n buildDebug('Writing app.js to runtime directory')\n let relativeConfigLocation: string | null = null\n if (!isApp) {\n const studioConfigPath = await tryFindStudioConfigPath(cwd)\n relativeConfigLocation = studioConfigPath\n ? toForwardSlashes(path.relative(runtimeDir, studioConfigPath))\n : null\n }\n\n const relativeEntry = toForwardSlashes(\n path.relative(runtimeDir, path.resolve(cwd, entry || './src/App')),\n )\n const appJsContent = getEntryModule({\n basePath,\n entry: relativeEntry,\n isApp,\n reactStrictMode,\n relativeConfigLocation,\n })\n await fs.writeFile(path.join(runtimeDir, 'app.js'), appJsContent)\n\n return watcher\n}\n"],"names":["fs","path","tryFindStudioConfigPath","watch","chokidarWatch","toForwardSlashes","buildDebug","decorateIndexWithAutoGeneratedWarning","decorateIndexWithBridgeScript","decorateIndexWithStagingScript","getEntryModule","getPossibleDocumentComponentLocations","renderDocument","writeSanityRuntime","options","appTitle","basePath","cwd","entry","isApp","reactStrictMode","runtimeDir","join","mkdir","recursive","renderAndWriteDocument","indexHtml","props","entryPath","relative","title","studioRootPath","writeFile","watcher","on","relativeConfigLocation","studioConfigPath","relativeEntry","resolve","appJsContent"],"mappings":"AAAA,OAAOA,QAAQ,mBAAkB;AACjC,OAAOC,UAAU,YAAW;AAE5B,SAAQC,uBAAuB,QAAO,mBAAkB;AACxD,SAAQC,SAASC,aAAa,QAAuB,WAAU;AAE/D,SAAQC,gBAAgB,QAAO,iCAAgC;AAC/D,SAAQC,UAAU,QAAO,kBAAiB;AAC1C,SAAQC,qCAAqC,QAAO,6CAA4C;AAChG,SAAQC,6BAA6B,QAAO,qCAAoC;AAChF,SAAQC,8BAA8B,QAAO,sCAAqC;AAClF,SAAQC,cAAc,QAAO,sBAAqB;AAClD,SAAQC,qCAAqC,QAAO,6CAA4C;AAChG,SAAQC,cAAc,QAAO,sBAAqB;AAalD;;;;;;;CAOC,GACD,OAAO,eAAeC,mBAAmBC,OAAuB;IAC9D,MAAM,EAACC,QAAQ,EAAEC,QAAQ,EAAEC,GAAG,EAAEC,KAAK,EAAEC,KAAK,EAAEC,eAAe,EAAEjB,KAAK,EAAC,GAAGW;IACxE,MAAMO,aAAapB,KAAKqB,IAAI,CAACL,KAAK,WAAW;IAE7CX,WAAW;IACX,MAAMN,GAAGuB,KAAK,CAACF,YAAY;QAACG,WAAW;IAAI;IAE3C,eAAeC;QACbnB,WAAW;QACX,MAAMoB,YAAYjB,+BAChBD,8BACED,sCACE,MAAMK,eAAe;YACnBO;YACAQ,OAAO;gBACLX,UAAUA,YAAY;gBACtBY,WAAW,CAAC,CAAC,EAAEvB,iBAAiBJ,KAAK4B,QAAQ,CAACZ,KAAKhB,KAAKqB,IAAI,CAACD,YAAY,aAAa;gBACtFS,OAAOf;YACT;YACAgB,gBAAgBd;QAClB;QAKNX,WAAW;QACX,MAAMN,GAAGgC,SAAS,CAAC/B,KAAKqB,IAAI,CAACD,YAAY,eAAeK;IAC1D;IAEA,IAAIO;IAEJ,IAAI9B,OAAO;QACT8B,UAAU7B,cAAcO,sCAAsCM,MAAMiB,EAAE,CAAC,OAAO,IAC5ET;IAEJ;IAEA,MAAMA;IAENnB,WAAW;IACX,IAAI6B,yBAAwC;IAC5C,IAAI,CAAChB,OAAO;QACV,MAAMiB,mBAAmB,MAAMlC,wBAAwBe;QACvDkB,yBAAyBC,mBACrB/B,iBAAiBJ,KAAK4B,QAAQ,CAACR,YAAYe,qBAC3C;IACN;IAEA,MAAMC,gBAAgBhC,iBACpBJ,KAAK4B,QAAQ,CAACR,YAAYpB,KAAKqC,OAAO,CAACrB,KAAKC,SAAS;IAEvD,MAAMqB,eAAe7B,eAAe;QAClCM;QACAE,OAAOmB;QACPlB;QACAC;QACAe;IACF;IACA,MAAMnC,GAAGgC,SAAS,CAAC/B,KAAKqB,IAAI,CAACD,YAAY,WAAWkB;IAEpD,OAAON;AACT"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { subdebug } from '@sanity/cli-core';
|
|
2
2
|
import { spinner } from '@sanity/cli-core/ux';
|
|
3
3
|
import { createDataset as createDatasetService } from '../../services/datasets.js';
|
|
4
|
+
import { validateProjection } from '../../util/validateProjection.js';
|
|
4
5
|
import { determineDatasetAclMode } from './determineDatasetAclMode.js';
|
|
5
6
|
const debug = subdebug('dataset:create');
|
|
6
7
|
/**
|
|
@@ -24,6 +25,9 @@ const debug = subdebug('dataset:create');
|
|
|
24
25
|
output,
|
|
25
26
|
visibility
|
|
26
27
|
});
|
|
28
|
+
if (embeddingsProjection) {
|
|
29
|
+
validateProjection(embeddingsProjection);
|
|
30
|
+
}
|
|
27
31
|
try {
|
|
28
32
|
const spin = spinner('Creating dataset').start();
|
|
29
33
|
const newDataset = await createDatasetService({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/actions/dataset/create.ts"],"sourcesContent":["import {type Output, subdebug} from '@sanity/cli-core'\nimport {spinner} from '@sanity/cli-core/ux'\nimport {type DatasetAclMode, DatasetResponse} from '@sanity/client'\n\nimport {createDataset as createDatasetService} from '../../services/datasets.js'\nimport {determineDatasetAclMode} from './determineDatasetAclMode.js'\n\nconst debug = subdebug('dataset:create')\n\n/**\n * Options for creating a dataset\n */\ninterface CreateDatasetOptions {\n /**\n * Name of the dataset to create\n */\n datasetName: string\n\n /**\n * Output instance for logging\n */\n output: Output\n\n /**\n * Array of project features to determine capabilities\n * Used to check if private datasets are available\n */\n projectFeatures: string[]\n\n /**\n * Project ID where the dataset will be created\n */\n projectId: string\n\n /**\n * Whether to enable embeddings for the new dataset\n */\n embeddings?: boolean\n\n /**\n * GROQ projection for embeddings indexing (e.g. \"\\{ title, body \\}\")\n * Only used when embeddings is true\n */\n embeddingsProjection?: string\n\n /**\n * Whether to force disable private dataset creation\n * Used when default config is selected (which forces public datasets)\n */\n forcePublic?: boolean\n\n /**\n * Whether to run in unattended mode (no prompts)\n */\n isUnattended?: boolean\n\n /**\n * Requested visibility mode from flags/options\n */\n visibility?: string\n}\n\n/**\n * Creates a new dataset with the appropriate ACL mode.\n *\n * This action handles the business logic for:\n * - Determining the appropriate ACL mode based on project capabilities\n * - Creating the dataset via the service layer\n * - Handling errors and providing user feedback\n *\n * @param options - Configuration options\n * @returns Promise resolving when dataset is created\n * @throws Error if dataset creation fails\n */\nexport async function createDataset(options: CreateDatasetOptions): Promise<DatasetResponse> {\n const {\n datasetName,\n embeddings,\n embeddingsProjection,\n forcePublic = false,\n isUnattended = false,\n output,\n projectFeatures,\n projectId,\n visibility,\n } = options\n\n const canCreatePrivate = projectFeatures.includes('privateDataset') && !forcePublic\n\n // Determine the appropriate ACL mode\n const aclMode: DatasetAclMode = await determineDatasetAclMode({\n canCreatePrivate,\n isUnattended,\n output,\n visibility,\n })\n\n try {\n const spin = spinner('Creating dataset').start()\n const newDataset = await createDatasetService({\n aclMode,\n datasetName,\n embeddings: embeddings\n ? {enabled: true, ...(embeddingsProjection ? {projection: embeddingsProjection} : {})}\n : undefined,\n projectId,\n })\n spin.succeed()\n output.log(`Dataset created successfully`)\n return newDataset\n } catch (error) {\n debug('Error creating dataset', {datasetName, error})\n throw error\n }\n}\n"],"names":["subdebug","spinner","createDataset","createDatasetService","determineDatasetAclMode","debug","options","datasetName","embeddings","embeddingsProjection","forcePublic","isUnattended","output","projectFeatures","projectId","visibility","canCreatePrivate","includes","aclMode","spin","start","newDataset","enabled","projection","undefined","succeed","log","error"],"mappings":"AAAA,SAAqBA,QAAQ,QAAO,mBAAkB;AACtD,SAAQC,OAAO,QAAO,sBAAqB;AAG3C,SAAQC,iBAAiBC,oBAAoB,QAAO,6BAA4B;AAChF,SAAQC,uBAAuB,QAAO,+BAA8B;AAEpE,MAAMC,
|
|
1
|
+
{"version":3,"sources":["../../../src/actions/dataset/create.ts"],"sourcesContent":["import {type Output, subdebug} from '@sanity/cli-core'\nimport {spinner} from '@sanity/cli-core/ux'\nimport {type DatasetAclMode, DatasetResponse} from '@sanity/client'\n\nimport {createDataset as createDatasetService} from '../../services/datasets.js'\nimport {validateProjection} from '../../util/validateProjection.js'\nimport {determineDatasetAclMode} from './determineDatasetAclMode.js'\n\nconst debug = subdebug('dataset:create')\n\n/**\n * Options for creating a dataset\n */\ninterface CreateDatasetOptions {\n /**\n * Name of the dataset to create\n */\n datasetName: string\n\n /**\n * Output instance for logging\n */\n output: Output\n\n /**\n * Array of project features to determine capabilities\n * Used to check if private datasets are available\n */\n projectFeatures: string[]\n\n /**\n * Project ID where the dataset will be created\n */\n projectId: string\n\n /**\n * Whether to enable embeddings for the new dataset\n */\n embeddings?: boolean\n\n /**\n * GROQ projection for embeddings indexing (e.g. \"\\{ title, body \\}\")\n * Only used when embeddings is true\n */\n embeddingsProjection?: string\n\n /**\n * Whether to force disable private dataset creation\n * Used when default config is selected (which forces public datasets)\n */\n forcePublic?: boolean\n\n /**\n * Whether to run in unattended mode (no prompts)\n */\n isUnattended?: boolean\n\n /**\n * Requested visibility mode from flags/options\n */\n visibility?: string\n}\n\n/**\n * Creates a new dataset with the appropriate ACL mode.\n *\n * This action handles the business logic for:\n * - Determining the appropriate ACL mode based on project capabilities\n * - Creating the dataset via the service layer\n * - Handling errors and providing user feedback\n *\n * @param options - Configuration options\n * @returns Promise resolving when dataset is created\n * @throws Error if dataset creation fails\n */\nexport async function createDataset(options: CreateDatasetOptions): Promise<DatasetResponse> {\n const {\n datasetName,\n embeddings,\n embeddingsProjection,\n forcePublic = false,\n isUnattended = false,\n output,\n projectFeatures,\n projectId,\n visibility,\n } = options\n\n const canCreatePrivate = projectFeatures.includes('privateDataset') && !forcePublic\n\n // Determine the appropriate ACL mode\n const aclMode: DatasetAclMode = await determineDatasetAclMode({\n canCreatePrivate,\n isUnattended,\n output,\n visibility,\n })\n\n if (embeddingsProjection) {\n validateProjection(embeddingsProjection)\n }\n\n try {\n const spin = spinner('Creating dataset').start()\n const newDataset = await createDatasetService({\n aclMode,\n datasetName,\n embeddings: embeddings\n ? {enabled: true, ...(embeddingsProjection ? {projection: embeddingsProjection} : {})}\n : undefined,\n projectId,\n })\n spin.succeed()\n output.log(`Dataset created successfully`)\n return newDataset\n } catch (error) {\n debug('Error creating dataset', {datasetName, error})\n throw error\n }\n}\n"],"names":["subdebug","spinner","createDataset","createDatasetService","validateProjection","determineDatasetAclMode","debug","options","datasetName","embeddings","embeddingsProjection","forcePublic","isUnattended","output","projectFeatures","projectId","visibility","canCreatePrivate","includes","aclMode","spin","start","newDataset","enabled","projection","undefined","succeed","log","error"],"mappings":"AAAA,SAAqBA,QAAQ,QAAO,mBAAkB;AACtD,SAAQC,OAAO,QAAO,sBAAqB;AAG3C,SAAQC,iBAAiBC,oBAAoB,QAAO,6BAA4B;AAChF,SAAQC,kBAAkB,QAAO,mCAAkC;AACnE,SAAQC,uBAAuB,QAAO,+BAA8B;AAEpE,MAAMC,QAAQN,SAAS;AAuDvB;;;;;;;;;;;CAWC,GACD,OAAO,eAAeE,cAAcK,OAA6B;IAC/D,MAAM,EACJC,WAAW,EACXC,UAAU,EACVC,oBAAoB,EACpBC,cAAc,KAAK,EACnBC,eAAe,KAAK,EACpBC,MAAM,EACNC,eAAe,EACfC,SAAS,EACTC,UAAU,EACX,GAAGT;IAEJ,MAAMU,mBAAmBH,gBAAgBI,QAAQ,CAAC,qBAAqB,CAACP;IAExE,qCAAqC;IACrC,MAAMQ,UAA0B,MAAMd,wBAAwB;QAC5DY;QACAL;QACAC;QACAG;IACF;IAEA,IAAIN,sBAAsB;QACxBN,mBAAmBM;IACrB;IAEA,IAAI;QACF,MAAMU,OAAOnB,QAAQ,oBAAoBoB,KAAK;QAC9C,MAAMC,aAAa,MAAMnB,qBAAqB;YAC5CgB;YACAX;YACAC,YAAYA,aACR;gBAACc,SAAS;gBAAM,GAAIb,uBAAuB;oBAACc,YAAYd;gBAAoB,IAAI,CAAC,CAAC;YAAC,IACnFe;YACJV;QACF;QACAK,KAAKM,OAAO;QACZb,OAAOc,GAAG,CAAC,CAAC,4BAA4B,CAAC;QACzC,OAAOL;IACT,EAAE,OAAOM,OAAO;QACdtB,MAAM,0BAA0B;YAACE;YAAaoB;QAAK;QACnD,MAAMA;IACR;AACF"}
|
|
@@ -45,6 +45,7 @@ import { deployDebug } from './deployDebug.js';
|
|
|
45
45
|
});
|
|
46
46
|
// If no applications are found, return null
|
|
47
47
|
if (!userApplications?.length) {
|
|
48
|
+
spin.info('No application ID configured');
|
|
48
49
|
return null;
|
|
49
50
|
}
|
|
50
51
|
// No app ID configured, done checking for existing applications;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/actions/deploy/findUserApplicationForApp.ts"],"sourcesContent":["/**\n * Helper functions to find a user application for a Sanity application.\n */\n\nimport {type CliConfig, type Output} from '@sanity/cli-core'\nimport {select, Separator, spinner} from '@sanity/cli-core/ux'\n\nimport {\n getUserApplication,\n getUserApplications,\n type UserApplication,\n} from '../../services/userApplications.js'\nimport {checkForDeprecatedAppId, getAppId} from '../../util/appId.js'\nimport {deployDebug} from './deployDebug.js'\n\ninterface FindUserApplicationForAppOptions {\n cliConfig: CliConfig\n organizationId: string\n output: Output\n}\n\n/**\n * Find a user application for a Sanity application.\n */\nexport async function findUserApplicationForApp(\n options: FindUserApplicationForAppOptions,\n): Promise<UserApplication | null> {\n const {cliConfig, organizationId, output} = options\n\n const spin = spinner('Checking application info...').start()\n\n try {\n checkForDeprecatedAppId({cliConfig, output})\n\n deployDebug('Checking for a user application as specified in the local app config')\n const userApplication = await findUserApplication(options)\n\n if (userApplication) {\n deployDebug('Found a user application as configured')\n spin.succeed()\n return userApplication\n }\n\n const appId = getAppId(cliConfig)\n\n // If there's an appId in the application config but there's no userApplication,\n // then the provided application ID doesn’t exist in the org\n if (appId) {\n spin.clear()\n output.error(\n 'The `appId` provided in your configuration’s `deployment` object cannot be found in your organization',\n {\n exit: 1,\n suggestions: ['Verify the appId in your configuration matches an existing application'],\n },\n )\n return null\n }\n\n // Done checking local application info\n // Update the spinner text to indicate the next operation\n spin.text = 'No application ID configured; checking for existing applications...'\n\n // Get a list of existing applications to select from.\n // This will fail if the org ID is malformed or the user doesn’t have access to the org ID\n const userApplications = await getUserApplications({\n appType: 'coreApp',\n organizationId,\n })\n\n // If no applications are found, return null\n if (!userApplications?.length) {\n return null\n }\n\n // No app ID configured, done checking for existing applications;\n // retain this spinner text for clarity\n spin.info('No application ID configured')\n\n // Enumerate the available applications\n const choices = userApplications.map((app) => ({\n name: app.title ?? app.appHost,\n value: app.appHost,\n }))\n\n // Ask the user to select an existing app or create a new one\n const selected = await select({\n choices: [\n {name: 'New application deployment', value: 'NEW_APP'},\n new Separator(' ════ Existing applications: ════ '),\n ...choices,\n ],\n loop: false,\n message:\n 'Would you like to create a new application deployment, or deploy to an existing one?',\n pageSize: 10,\n })\n\n // If the user wants to create a new deployed application, return null\n if (selected === 'NEW_APP') {\n return null\n }\n\n return userApplications.find((app) => app.appHost === selected)!\n } catch (error) {\n // User can't access applications for the org\n if (error?.statusCode === 403) {\n spin.clear()\n deployDebug(\n 'User does not have permission to get applications for the org, or the org ID is malformed/doesn’t exist',\n error,\n )\n output.error(\n `You don’t have permission to view applications for the configured organization ID (\"${organizationId}\")`,\n {\n exit: 1,\n suggestions: [\n 'Verify that you’ve entered the correct organization ID',\n 'Ask your Sanity organization’s admin to provide you with the proper permissions',\n ],\n },\n )\n return null\n }\n\n // We've failed for some other reason\n spin.clear()\n deployDebug('Error finding user application for app', error)\n output.error(error)\n return null\n }\n}\n\nfunction findUserApplication(\n options: FindUserApplicationForAppOptions,\n): Promise<UserApplication | null> | null {\n const {cliConfig} = options\n\n const appId = getAppId(cliConfig)\n\n if (!appId) {\n return null\n }\n\n return getUserApplication({appId, isSdkApp: true})\n}\n"],"names":["select","Separator","spinner","getUserApplication","getUserApplications","checkForDeprecatedAppId","getAppId","deployDebug","findUserApplicationForApp","options","cliConfig","organizationId","output","spin","start","userApplication","findUserApplication","succeed","appId","clear","error","exit","suggestions","text","userApplications","appType","length","info","choices","map","app","name","title","appHost","value","selected","loop","message","pageSize","find","statusCode","isSdkApp"],"mappings":"AAAA;;CAEC,GAGD,SAAQA,MAAM,EAAEC,SAAS,EAAEC,OAAO,QAAO,sBAAqB;AAE9D,SACEC,kBAAkB,EAClBC,mBAAmB,QAEd,qCAAoC;AAC3C,SAAQC,uBAAuB,EAAEC,QAAQ,QAAO,sBAAqB;AACrE,SAAQC,WAAW,QAAO,mBAAkB;AAQ5C;;CAEC,GACD,OAAO,eAAeC,0BACpBC,OAAyC;IAEzC,MAAM,EAACC,SAAS,EAAEC,cAAc,EAAEC,MAAM,EAAC,GAAGH;IAE5C,MAAMI,OAAOX,QAAQ,gCAAgCY,KAAK;IAE1D,IAAI;QACFT,wBAAwB;YAACK;YAAWE;QAAM;QAE1CL,YAAY;QACZ,MAAMQ,kBAAkB,MAAMC,oBAAoBP;QAElD,IAAIM,iBAAiB;YACnBR,YAAY;YACZM,KAAKI,OAAO;YACZ,OAAOF;QACT;QAEA,MAAMG,QAAQZ,SAASI;QAEvB,gFAAgF;QAChF,4DAA4D;QAC5D,IAAIQ,OAAO;YACTL,KAAKM,KAAK;YACVP,OAAOQ,KAAK,CACV,yGACA;gBACEC,MAAM;gBACNC,aAAa;oBAAC;iBAAyE;YACzF;YAEF,OAAO;QACT;QAEA,uCAAuC;QACvC,yDAAyD;QACzDT,KAAKU,IAAI,GAAG;QAEZ,sDAAsD;QACtD,0FAA0F;QAC1F,MAAMC,mBAAmB,MAAMpB,oBAAoB;YACjDqB,SAAS;YACTd;QACF;QAEA,4CAA4C;QAC5C,IAAI,CAACa,kBAAkBE,QAAQ;
|
|
1
|
+
{"version":3,"sources":["../../../src/actions/deploy/findUserApplicationForApp.ts"],"sourcesContent":["/**\n * Helper functions to find a user application for a Sanity application.\n */\n\nimport {type CliConfig, type Output} from '@sanity/cli-core'\nimport {select, Separator, spinner} from '@sanity/cli-core/ux'\n\nimport {\n getUserApplication,\n getUserApplications,\n type UserApplication,\n} from '../../services/userApplications.js'\nimport {checkForDeprecatedAppId, getAppId} from '../../util/appId.js'\nimport {deployDebug} from './deployDebug.js'\n\ninterface FindUserApplicationForAppOptions {\n cliConfig: CliConfig\n organizationId: string\n output: Output\n}\n\n/**\n * Find a user application for a Sanity application.\n */\nexport async function findUserApplicationForApp(\n options: FindUserApplicationForAppOptions,\n): Promise<UserApplication | null> {\n const {cliConfig, organizationId, output} = options\n\n const spin = spinner('Checking application info...').start()\n\n try {\n checkForDeprecatedAppId({cliConfig, output})\n\n deployDebug('Checking for a user application as specified in the local app config')\n const userApplication = await findUserApplication(options)\n\n if (userApplication) {\n deployDebug('Found a user application as configured')\n spin.succeed()\n return userApplication\n }\n\n const appId = getAppId(cliConfig)\n\n // If there's an appId in the application config but there's no userApplication,\n // then the provided application ID doesn’t exist in the org\n if (appId) {\n spin.clear()\n output.error(\n 'The `appId` provided in your configuration’s `deployment` object cannot be found in your organization',\n {\n exit: 1,\n suggestions: ['Verify the appId in your configuration matches an existing application'],\n },\n )\n return null\n }\n\n // Done checking local application info\n // Update the spinner text to indicate the next operation\n spin.text = 'No application ID configured; checking for existing applications...'\n\n // Get a list of existing applications to select from.\n // This will fail if the org ID is malformed or the user doesn’t have access to the org ID\n const userApplications = await getUserApplications({\n appType: 'coreApp',\n organizationId,\n })\n\n // If no applications are found, return null\n if (!userApplications?.length) {\n spin.info('No application ID configured')\n return null\n }\n\n // No app ID configured, done checking for existing applications;\n // retain this spinner text for clarity\n spin.info('No application ID configured')\n\n // Enumerate the available applications\n const choices = userApplications.map((app) => ({\n name: app.title ?? app.appHost,\n value: app.appHost,\n }))\n\n // Ask the user to select an existing app or create a new one\n const selected = await select({\n choices: [\n {name: 'New application deployment', value: 'NEW_APP'},\n new Separator(' ════ Existing applications: ════ '),\n ...choices,\n ],\n loop: false,\n message:\n 'Would you like to create a new application deployment, or deploy to an existing one?',\n pageSize: 10,\n })\n\n // If the user wants to create a new deployed application, return null\n if (selected === 'NEW_APP') {\n return null\n }\n\n return userApplications.find((app) => app.appHost === selected)!\n } catch (error) {\n // User can't access applications for the org\n if (error?.statusCode === 403) {\n spin.clear()\n deployDebug(\n 'User does not have permission to get applications for the org, or the org ID is malformed/doesn’t exist',\n error,\n )\n output.error(\n `You don’t have permission to view applications for the configured organization ID (\"${organizationId}\")`,\n {\n exit: 1,\n suggestions: [\n 'Verify that you’ve entered the correct organization ID',\n 'Ask your Sanity organization’s admin to provide you with the proper permissions',\n ],\n },\n )\n return null\n }\n\n // We've failed for some other reason\n spin.clear()\n deployDebug('Error finding user application for app', error)\n output.error(error)\n return null\n }\n}\n\nfunction findUserApplication(\n options: FindUserApplicationForAppOptions,\n): Promise<UserApplication | null> | null {\n const {cliConfig} = options\n\n const appId = getAppId(cliConfig)\n\n if (!appId) {\n return null\n }\n\n return getUserApplication({appId, isSdkApp: true})\n}\n"],"names":["select","Separator","spinner","getUserApplication","getUserApplications","checkForDeprecatedAppId","getAppId","deployDebug","findUserApplicationForApp","options","cliConfig","organizationId","output","spin","start","userApplication","findUserApplication","succeed","appId","clear","error","exit","suggestions","text","userApplications","appType","length","info","choices","map","app","name","title","appHost","value","selected","loop","message","pageSize","find","statusCode","isSdkApp"],"mappings":"AAAA;;CAEC,GAGD,SAAQA,MAAM,EAAEC,SAAS,EAAEC,OAAO,QAAO,sBAAqB;AAE9D,SACEC,kBAAkB,EAClBC,mBAAmB,QAEd,qCAAoC;AAC3C,SAAQC,uBAAuB,EAAEC,QAAQ,QAAO,sBAAqB;AACrE,SAAQC,WAAW,QAAO,mBAAkB;AAQ5C;;CAEC,GACD,OAAO,eAAeC,0BACpBC,OAAyC;IAEzC,MAAM,EAACC,SAAS,EAAEC,cAAc,EAAEC,MAAM,EAAC,GAAGH;IAE5C,MAAMI,OAAOX,QAAQ,gCAAgCY,KAAK;IAE1D,IAAI;QACFT,wBAAwB;YAACK;YAAWE;QAAM;QAE1CL,YAAY;QACZ,MAAMQ,kBAAkB,MAAMC,oBAAoBP;QAElD,IAAIM,iBAAiB;YACnBR,YAAY;YACZM,KAAKI,OAAO;YACZ,OAAOF;QACT;QAEA,MAAMG,QAAQZ,SAASI;QAEvB,gFAAgF;QAChF,4DAA4D;QAC5D,IAAIQ,OAAO;YACTL,KAAKM,KAAK;YACVP,OAAOQ,KAAK,CACV,yGACA;gBACEC,MAAM;gBACNC,aAAa;oBAAC;iBAAyE;YACzF;YAEF,OAAO;QACT;QAEA,uCAAuC;QACvC,yDAAyD;QACzDT,KAAKU,IAAI,GAAG;QAEZ,sDAAsD;QACtD,0FAA0F;QAC1F,MAAMC,mBAAmB,MAAMpB,oBAAoB;YACjDqB,SAAS;YACTd;QACF;QAEA,4CAA4C;QAC5C,IAAI,CAACa,kBAAkBE,QAAQ;YAC7Bb,KAAKc,IAAI,CAAC;YACV,OAAO;QACT;QAEA,iEAAiE;QACjE,uCAAuC;QACvCd,KAAKc,IAAI,CAAC;QAEV,uCAAuC;QACvC,MAAMC,UAAUJ,iBAAiBK,GAAG,CAAC,CAACC,MAAS,CAAA;gBAC7CC,MAAMD,IAAIE,KAAK,IAAIF,IAAIG,OAAO;gBAC9BC,OAAOJ,IAAIG,OAAO;YACpB,CAAA;QAEA,6DAA6D;QAC7D,MAAME,WAAW,MAAMnC,OAAO;YAC5B4B,SAAS;gBACP;oBAACG,MAAM;oBAA8BG,OAAO;gBAAS;gBACrD,IAAIjC,UAAU;mBACX2B;aACJ;YACDQ,MAAM;YACNC,SACE;YACFC,UAAU;QACZ;QAEA,sEAAsE;QACtE,IAAIH,aAAa,WAAW;YAC1B,OAAO;QACT;QAEA,OAAOX,iBAAiBe,IAAI,CAAC,CAACT,MAAQA,IAAIG,OAAO,KAAKE;IACxD,EAAE,OAAOf,OAAO;QACd,6CAA6C;QAC7C,IAAIA,OAAOoB,eAAe,KAAK;YAC7B3B,KAAKM,KAAK;YACVZ,YACE,2GACAa;YAEFR,OAAOQ,KAAK,CACV,CAAC,oFAAoF,EAAET,eAAe,EAAE,CAAC,EACzG;gBACEU,MAAM;gBACNC,aAAa;oBACX;oBACA;iBACD;YACH;YAEF,OAAO;QACT;QAEA,qCAAqC;QACrCT,KAAKM,KAAK;QACVZ,YAAY,0CAA0Ca;QACtDR,OAAOQ,KAAK,CAACA;QACb,OAAO;IACT;AACF;AAEA,SAASJ,oBACPP,OAAyC;IAEzC,MAAM,EAACC,SAAS,EAAC,GAAGD;IAEpB,MAAMS,QAAQZ,SAASI;IAEvB,IAAI,CAACQ,OAAO;QACV,OAAO;IACT;IAEA,OAAOf,mBAAmB;QAACe;QAAOuB,UAAU;IAAI;AAClD"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/actions/deploy/types.ts"],"sourcesContent":["import {type CliConfig, type Output, type ProjectRootResult} from '@sanity/cli-core'\nimport {z} from 'zod'\n\nimport {DeployCommand} from '../../commands/deploy.js'\n\nexport type DeployFlags = DeployCommand['flags']\n\nexport interface DeployAppOptions {\n cliConfig: CliConfig\n flags: DeployFlags\n output: Output\n projectRoot: ProjectRootResult\n sourceDir: string\n}\n\nexport const deployStudioSchemasAndManifestsWorkerData = z.object({\n configPath: z.string(),\n isExternal: z.boolean(),\n outPath: z.string(),\n projectId: z.string(),\n schemaRequired: z.boolean(),\n verbose: z.boolean(),\n workDir: z.string(),\n})\n\nexport type DeployStudioSchemasAndManifestsWorkerData = z.infer<\n typeof deployStudioSchemasAndManifestsWorkerData\n>\n"],"names":["z","deployStudioSchemasAndManifestsWorkerData","object","configPath","string","isExternal","boolean","outPath","projectId","schemaRequired","verbose","workDir"],"mappings":"AACA,SAAQA,CAAC,QAAO,
|
|
1
|
+
{"version":3,"sources":["../../../src/actions/deploy/types.ts"],"sourcesContent":["import {type CliConfig, type Output, type ProjectRootResult} from '@sanity/cli-core'\nimport {z} from 'zod/mini'\n\nimport {DeployCommand} from '../../commands/deploy.js'\n\nexport type DeployFlags = DeployCommand['flags']\n\nexport interface DeployAppOptions {\n cliConfig: CliConfig\n flags: DeployFlags\n output: Output\n projectRoot: ProjectRootResult\n sourceDir: string\n}\n\nexport const deployStudioSchemasAndManifestsWorkerData = z.object({\n configPath: z.string(),\n isExternal: z.boolean(),\n outPath: z.string(),\n projectId: z.string(),\n schemaRequired: z.boolean(),\n verbose: z.boolean(),\n workDir: z.string(),\n})\n\nexport type DeployStudioSchemasAndManifestsWorkerData = z.infer<\n typeof deployStudioSchemasAndManifestsWorkerData\n>\n"],"names":["z","deployStudioSchemasAndManifestsWorkerData","object","configPath","string","isExternal","boolean","outPath","projectId","schemaRequired","verbose","workDir"],"mappings":"AACA,SAAQA,CAAC,QAAO,WAAU;AAc1B,OAAO,MAAMC,4CAA4CD,EAAEE,MAAM,CAAC;IAChEC,YAAYH,EAAEI,MAAM;IACpBC,YAAYL,EAAEM,OAAO;IACrBC,SAASP,EAAEI,MAAM;IACjBI,WAAWR,EAAEI,MAAM;IACnBK,gBAAgBT,EAAEM,OAAO;IACzBI,SAASV,EAAEM,OAAO;IAClBK,SAASX,EAAEI,MAAM;AACnB,GAAE"}
|
|
@@ -162,8 +162,7 @@ export const { sanityFetch, SanityLive } = defineLive({
|
|
|
162
162
|
client,
|
|
163
163
|
});
|
|
164
164
|
`;
|
|
165
|
-
const imageTS = `import createImageUrlBuilder from '@sanity/image-url'
|
|
166
|
-
import type { SanityImageSource } from "@sanity/image-url";
|
|
165
|
+
const imageTS = `import { createImageUrlBuilder, type SanityImageSource } from '@sanity/image-url'
|
|
167
166
|
|
|
168
167
|
import { dataset, projectId } from '../env'
|
|
169
168
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../src/actions/init/templates/nextjs/index.ts"],"sourcesContent":["import {blogSchemaFolder, blogSchemaJS, blogSchemaTS} from './schemaTypes/blog.js'\n\nexport const sanityConfigTemplate = (hasSrcFolder = false): string => `'use client'\n\n/**\n * This configuration is used to for the Sanity Studio that’s mounted on the \\`:route:\\` route\n */\n\nimport {visionTool} from '@sanity/vision'\nimport {defineConfig} from 'sanity'\nimport {structureTool} from 'sanity/structure'\n\n// Go to https://www.sanity.io/docs/api-versioning to learn how API versioning works\nimport {apiVersion, dataset, projectId} from ${hasSrcFolder ? \"'./src/sanity/env'\" : \"'./sanity/env'\"}\nimport {schema} from ${hasSrcFolder ? \"'./src/sanity/schemaTypes'\" : \"'./sanity/schemaTypes'\"}\nimport {structure} from ${hasSrcFolder ? \"'./src/sanity/structure'\" : \"'./sanity/structure'\"}\n\nexport default defineConfig({\n basePath: ':basePath:',\n projectId,\n dataset,\n // Add and edit the content schema in the './sanity/schemaTypes' folder\n schema,\n plugins: [\n structureTool({structure}),\n // Vision is for querying with GROQ from inside the Studio\n // https://www.sanity.io/docs/the-vision-plugin\n visionTool({defaultApiVersion: apiVersion}),\n ],\n})\n`\n\nexport const sanityCliTemplate = `/**\n* This configuration file lets you run \\`$ sanity [command]\\` in this folder\n* Go to https://www.sanity.io/docs/cli to learn more.\n**/\nimport { defineCliConfig } from 'sanity/cli'\n\nconst projectId = process.env.NEXT_PUBLIC_SANITY_PROJECT_ID\nconst dataset = process.env.NEXT_PUBLIC_SANITY_DATASET\n\nexport default defineCliConfig({ api: { projectId, dataset } })\n`\n\nexport const sanityStudioTemplate = `/**\n * This route is responsible for the built-in authoring environment using Sanity Studio.\n * All routes under your studio path is handled by this file using Next.js' catch-all routes:\n * https://nextjs.org/docs/routing/dynamic-routes#catch-all-routes\n *\n * You can learn more about the next-sanity package here:\n * https://github.com/sanity-io/next-sanity\n */\n\nimport { NextStudio } from 'next-sanity/studio'\nimport config from ':configPath:'\n\nexport const dynamic = 'force-static'\n\nexport { metadata, viewport } from 'next-sanity/studio'\n\nexport default function StudioPage() {\n return <NextStudio config={config} />\n}\n`\n\n// Format today's date like YYYY-MM-DD\nconst envTS = `export const apiVersion =\n process.env.NEXT_PUBLIC_SANITY_API_VERSION || '${new Date().toISOString().split('T')[0]}'\n\nexport const dataset = assertValue(\n process.env.NEXT_PUBLIC_SANITY_DATASET,\n 'Missing environment variable: NEXT_PUBLIC_SANITY_DATASET'\n)\n\nexport const projectId = assertValue(\n process.env.NEXT_PUBLIC_SANITY_PROJECT_ID,\n 'Missing environment variable: NEXT_PUBLIC_SANITY_PROJECT_ID'\n)\n\nfunction assertValue<T>(v: T | undefined, errorMessage: string): T {\n if (v === undefined) {\n throw new Error(errorMessage)\n }\n\n return v\n}\n`\n\nconst envJS = `export const apiVersion =\n process.env.NEXT_PUBLIC_SANITY_API_VERSION || '${new Date().toISOString().split('T')[0]}'\n\nexport const dataset = process.env.NEXT_PUBLIC_SANITY_DATASET;\nexport const projectId = process.env.NEXT_PUBLIC_SANITY_PROJECT_ID;\n`\n\nconst schemaTS = `import { type SchemaTypeDefinition } from 'sanity'\n\nexport const schema: { types: SchemaTypeDefinition[] } = {\n types: [],\n}\n`\n\nconst schemaJS = `export const schema = {\n types: [],\n}\n`\n\nconst blogStructureTS = `import type {StructureResolver} from 'sanity/structure'\n\n// https://www.sanity.io/docs/structure-builder-cheat-sheet\nexport const structure: StructureResolver = (S) =>\n S.list()\n .title('Blog')\n .items([\n S.documentTypeListItem('post').title('Posts'),\n S.documentTypeListItem('category').title('Categories'),\n S.documentTypeListItem('author').title('Authors'),\n S.divider(),\n ...S.documentTypeListItems().filter(\n (item) => item.getId() && !['post', 'category', 'author'].includes(item.getId()!),\n ),\n ])\n`\n\nconst blogStructureJS = `// https://www.sanity.io/docs/structure-builder-cheat-sheet\nexport const structure = (S) =>\n S.list()\n .title('Blog')\n .items([\n S.documentTypeListItem('post').title('Posts'),\n S.documentTypeListItem('category').title('Categories'),\n S.documentTypeListItem('author').title('Authors'),\n S.divider(),\n ...S.documentTypeListItems().filter(\n (item) => item.getId() && !['post', 'category', 'author'].includes(item.getId()),\n ),\n ])\n`\n\nconst structureTS = `import type {StructureResolver} from 'sanity/structure'\n\n// https://www.sanity.io/docs/structure-builder-cheat-sheet\nexport const structure: StructureResolver = (S) =>\n S.list()\n .title('Content')\n .items(S.documentTypeListItems())\n`\n\nconst structureJS = `// https://www.sanity.io/docs/structure-builder-cheat-sheet\nexport const structure = (S) =>\n S.list()\n .title('Content')\n .items(S.documentTypeListItems())\n`\n\nconst client = `import { createClient } from 'next-sanity'\n\nimport { apiVersion, dataset, projectId } from '../env'\n\nexport const client = createClient({\n projectId,\n dataset,\n apiVersion,\n useCdn: true, // Set to false if statically generating pages, using ISR or tag-based revalidation\n})\n`\n\nconst live = `// Querying with \"sanityFetch\" will keep content automatically updated\n// Before using it, import and render \"<SanityLive />\" in your layout, see\n// https://github.com/sanity-io/next-sanity#live-content-api for more information.\nimport { defineLive } from \"next-sanity/live\";\nimport { client } from './client'\n\nexport const { sanityFetch, SanityLive } = defineLive({\n client,\n});\n`\n\nconst imageTS = `import createImageUrlBuilder
|
|
1
|
+
{"version":3,"sources":["../../../../../src/actions/init/templates/nextjs/index.ts"],"sourcesContent":["import {blogSchemaFolder, blogSchemaJS, blogSchemaTS} from './schemaTypes/blog.js'\n\nexport const sanityConfigTemplate = (hasSrcFolder = false): string => `'use client'\n\n/**\n * This configuration is used to for the Sanity Studio that’s mounted on the \\`:route:\\` route\n */\n\nimport {visionTool} from '@sanity/vision'\nimport {defineConfig} from 'sanity'\nimport {structureTool} from 'sanity/structure'\n\n// Go to https://www.sanity.io/docs/api-versioning to learn how API versioning works\nimport {apiVersion, dataset, projectId} from ${hasSrcFolder ? \"'./src/sanity/env'\" : \"'./sanity/env'\"}\nimport {schema} from ${hasSrcFolder ? \"'./src/sanity/schemaTypes'\" : \"'./sanity/schemaTypes'\"}\nimport {structure} from ${hasSrcFolder ? \"'./src/sanity/structure'\" : \"'./sanity/structure'\"}\n\nexport default defineConfig({\n basePath: ':basePath:',\n projectId,\n dataset,\n // Add and edit the content schema in the './sanity/schemaTypes' folder\n schema,\n plugins: [\n structureTool({structure}),\n // Vision is for querying with GROQ from inside the Studio\n // https://www.sanity.io/docs/the-vision-plugin\n visionTool({defaultApiVersion: apiVersion}),\n ],\n})\n`\n\nexport const sanityCliTemplate = `/**\n* This configuration file lets you run \\`$ sanity [command]\\` in this folder\n* Go to https://www.sanity.io/docs/cli to learn more.\n**/\nimport { defineCliConfig } from 'sanity/cli'\n\nconst projectId = process.env.NEXT_PUBLIC_SANITY_PROJECT_ID\nconst dataset = process.env.NEXT_PUBLIC_SANITY_DATASET\n\nexport default defineCliConfig({ api: { projectId, dataset } })\n`\n\nexport const sanityStudioTemplate = `/**\n * This route is responsible for the built-in authoring environment using Sanity Studio.\n * All routes under your studio path is handled by this file using Next.js' catch-all routes:\n * https://nextjs.org/docs/routing/dynamic-routes#catch-all-routes\n *\n * You can learn more about the next-sanity package here:\n * https://github.com/sanity-io/next-sanity\n */\n\nimport { NextStudio } from 'next-sanity/studio'\nimport config from ':configPath:'\n\nexport const dynamic = 'force-static'\n\nexport { metadata, viewport } from 'next-sanity/studio'\n\nexport default function StudioPage() {\n return <NextStudio config={config} />\n}\n`\n\n// Format today's date like YYYY-MM-DD\nconst envTS = `export const apiVersion =\n process.env.NEXT_PUBLIC_SANITY_API_VERSION || '${new Date().toISOString().split('T')[0]}'\n\nexport const dataset = assertValue(\n process.env.NEXT_PUBLIC_SANITY_DATASET,\n 'Missing environment variable: NEXT_PUBLIC_SANITY_DATASET'\n)\n\nexport const projectId = assertValue(\n process.env.NEXT_PUBLIC_SANITY_PROJECT_ID,\n 'Missing environment variable: NEXT_PUBLIC_SANITY_PROJECT_ID'\n)\n\nfunction assertValue<T>(v: T | undefined, errorMessage: string): T {\n if (v === undefined) {\n throw new Error(errorMessage)\n }\n\n return v\n}\n`\n\nconst envJS = `export const apiVersion =\n process.env.NEXT_PUBLIC_SANITY_API_VERSION || '${new Date().toISOString().split('T')[0]}'\n\nexport const dataset = process.env.NEXT_PUBLIC_SANITY_DATASET;\nexport const projectId = process.env.NEXT_PUBLIC_SANITY_PROJECT_ID;\n`\n\nconst schemaTS = `import { type SchemaTypeDefinition } from 'sanity'\n\nexport const schema: { types: SchemaTypeDefinition[] } = {\n types: [],\n}\n`\n\nconst schemaJS = `export const schema = {\n types: [],\n}\n`\n\nconst blogStructureTS = `import type {StructureResolver} from 'sanity/structure'\n\n// https://www.sanity.io/docs/structure-builder-cheat-sheet\nexport const structure: StructureResolver = (S) =>\n S.list()\n .title('Blog')\n .items([\n S.documentTypeListItem('post').title('Posts'),\n S.documentTypeListItem('category').title('Categories'),\n S.documentTypeListItem('author').title('Authors'),\n S.divider(),\n ...S.documentTypeListItems().filter(\n (item) => item.getId() && !['post', 'category', 'author'].includes(item.getId()!),\n ),\n ])\n`\n\nconst blogStructureJS = `// https://www.sanity.io/docs/structure-builder-cheat-sheet\nexport const structure = (S) =>\n S.list()\n .title('Blog')\n .items([\n S.documentTypeListItem('post').title('Posts'),\n S.documentTypeListItem('category').title('Categories'),\n S.documentTypeListItem('author').title('Authors'),\n S.divider(),\n ...S.documentTypeListItems().filter(\n (item) => item.getId() && !['post', 'category', 'author'].includes(item.getId()),\n ),\n ])\n`\n\nconst structureTS = `import type {StructureResolver} from 'sanity/structure'\n\n// https://www.sanity.io/docs/structure-builder-cheat-sheet\nexport const structure: StructureResolver = (S) =>\n S.list()\n .title('Content')\n .items(S.documentTypeListItems())\n`\n\nconst structureJS = `// https://www.sanity.io/docs/structure-builder-cheat-sheet\nexport const structure = (S) =>\n S.list()\n .title('Content')\n .items(S.documentTypeListItems())\n`\n\nconst client = `import { createClient } from 'next-sanity'\n\nimport { apiVersion, dataset, projectId } from '../env'\n\nexport const client = createClient({\n projectId,\n dataset,\n apiVersion,\n useCdn: true, // Set to false if statically generating pages, using ISR or tag-based revalidation\n})\n`\n\nconst live = `// Querying with \"sanityFetch\" will keep content automatically updated\n// Before using it, import and render \"<SanityLive />\" in your layout, see\n// https://github.com/sanity-io/next-sanity#live-content-api for more information.\nimport { defineLive } from \"next-sanity/live\";\nimport { client } from './client'\n\nexport const { sanityFetch, SanityLive } = defineLive({\n client,\n});\n`\n\nconst imageTS = `import { createImageUrlBuilder, type SanityImageSource } from '@sanity/image-url'\n\nimport { dataset, projectId } from '../env'\n\n// https://www.sanity.io/docs/image-url\nconst builder = createImageUrlBuilder({ projectId, dataset })\n\nexport const urlFor = (source: SanityImageSource) => {\n return builder.image(source)\n}\n`\n\nconst imageJS = `import createImageUrlBuilder from '@sanity/image-url'\n\nimport { dataset, projectId } from '../env'\n\n// https://www.sanity.io/docs/image-url\nconst builder = createImageUrlBuilder({ projectId, dataset })\n\nexport const urlFor = (source) => {\n return builder.image(source)\n}\n`\n\ntype FolderStructure = Record<string, Record<string, string> | string>\n\nexport const sanityFolder = (\n useTypeScript: boolean,\n template?: 'blog' | 'clean',\n): FolderStructure => {\n // Files used in both templates\n const structure: FolderStructure = {\n 'env.': useTypeScript ? envTS : envJS,\n lib: {\n 'client.': client,\n 'image.': useTypeScript ? imageTS : imageJS,\n 'live.': live,\n },\n }\n\n if (template === 'blog') {\n structure.schemaTypes = {\n ...blogSchemaFolder,\n 'index.': useTypeScript ? blogSchemaTS : blogSchemaJS,\n }\n structure['structure.'] = useTypeScript ? blogStructureTS : blogStructureJS\n } else {\n structure.schemaTypes = {\n 'index.': useTypeScript ? schemaTS : schemaJS,\n }\n structure['structure.'] = useTypeScript ? structureTS : structureJS\n }\n\n return structure\n}\n"],"names":["blogSchemaFolder","blogSchemaJS","blogSchemaTS","sanityConfigTemplate","hasSrcFolder","sanityCliTemplate","sanityStudioTemplate","envTS","Date","toISOString","split","envJS","schemaTS","schemaJS","blogStructureTS","blogStructureJS","structureTS","structureJS","client","live","imageTS","imageJS","sanityFolder","useTypeScript","template","structure","lib","schemaTypes"],"mappings":"AAAA,SAAQA,gBAAgB,EAAEC,YAAY,EAAEC,YAAY,QAAO,wBAAuB;AAElF,OAAO,MAAMC,uBAAuB,CAACC,eAAe,KAAK,GAAa,CAAC;;;;;;;;;;;6CAW1B,EAAEA,eAAe,uBAAuB,iBAAiB;qBACjF,EAAEA,eAAe,+BAA+B,yBAAyB;wBACtE,EAAEA,eAAe,6BAA6B,uBAAuB;;;;;;;;;;;;;;;AAe7F,CAAC,CAAA;AAED,OAAO,MAAMC,oBAAoB,CAAC;;;;;;;;;;AAUlC,CAAC,CAAA;AAED,OAAO,MAAMC,uBAAuB,CAAC;;;;;;;;;;;;;;;;;;;AAmBrC,CAAC,CAAA;AAED,sCAAsC;AACtC,MAAMC,QAAQ,CAAC;iDACkC,EAAE,IAAIC,OAAOC,WAAW,GAAGC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;;;;;;;;;;;;;;;;;;;AAmB1F,CAAC;AAED,MAAMC,QAAQ,CAAC;iDACkC,EAAE,IAAIH,OAAOC,WAAW,GAAGC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;;;;AAI1F,CAAC;AAED,MAAME,WAAW,CAAC;;;;;AAKlB,CAAC;AAED,MAAMC,WAAW,CAAC;;;AAGlB,CAAC;AAED,MAAMC,kBAAkB,CAAC;;;;;;;;;;;;;;;AAezB,CAAC;AAED,MAAMC,kBAAkB,CAAC;;;;;;;;;;;;;AAazB,CAAC;AAED,MAAMC,cAAc,CAAC;;;;;;;AAOrB,CAAC;AAED,MAAMC,cAAc,CAAC;;;;;AAKrB,CAAC;AAED,MAAMC,SAAS,CAAC;;;;;;;;;;AAUhB,CAAC;AAED,MAAMC,OAAO,CAAC;;;;;;;;;AASd,CAAC;AAED,MAAMC,UAAU,CAAC;;;;;;;;;;AAUjB,CAAC;AAED,MAAMC,UAAU,CAAC;;;;;;;;;;AAUjB,CAAC;AAID,OAAO,MAAMC,eAAe,CAC1BC,eACAC;IAEA,+BAA+B;IAC/B,MAAMC,YAA6B;QACjC,QAAQF,gBAAgBhB,QAAQI;QAChCe,KAAK;YACH,WAAWR;YACX,UAAUK,gBAAgBH,UAAUC;YACpC,SAASF;QACX;IACF;IAEA,IAAIK,aAAa,QAAQ;QACvBC,UAAUE,WAAW,GAAG;YACtB,GAAG3B,gBAAgB;YACnB,UAAUuB,gBAAgBrB,eAAeD;QAC3C;QACAwB,SAAS,CAAC,aAAa,GAAGF,gBAAgBT,kBAAkBC;IAC9D,OAAO;QACLU,UAAUE,WAAW,GAAG;YACtB,UAAUJ,gBAAgBX,WAAWC;QACvC;QACAY,SAAS,CAAC,aAAa,GAAGF,gBAAgBP,cAAcC;IAC1D;IAEA,OAAOQ;AACT,EAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/actions/manifest/types.ts"],"sourcesContent":["import {type SanityDocumentLike} from '@sanity/types'\nimport {type MediaLibraryConfig} from 'sanity'\nimport {z} from 'zod'\n\nexport const SANITY_WORKSPACE_SCHEMA_ID_PREFIX = '_.schemas'\nexport const SANITY_WORKSPACE_SCHEMA_TYPE = 'system.schema'\nexport const CURRENT_WORKSPACE_SCHEMA_VERSION = '2025-05-01'\n\nexport type ManifestSerializable =\n | boolean\n | ManifestSerializable[]\n | number\n | string\n | {[k: string]: ManifestSerializable}\n\nexport interface CreateManifest {\n createdAt: string\n studioVersion: string | null\n version: number\n workspaces: ManifestWorkspaceFile[]\n}\n\nexport interface AppManifest {\n version: '1'\n\n icon?: string\n title?: string\n}\n\nexport interface ManifestWorkspaceFile extends Omit<CreateWorkspaceManifest, 'schema' | 'tools'> {\n schema: string // filename\n tools: string // filename\n}\n\nexport interface CreateWorkspaceManifest {\n basePath: string\n dataset: string\n /**\n * returns null in the case of the icon not being able to be stringified\n */\n icon: string | null\n name: string\n projectId: string\n schema: ManifestSchemaType[]\n tools: ManifestTool[]\n\n mediaLibrary?: MediaLibraryConfig\n subtitle?: string\n title?: string\n}\n\nexport interface ManifestSchemaType {\n name: string\n type: string\n\n deprecated?: {\n reason: string\n }\n fields?: ManifestField[]\n fieldsets?: ManifestFieldset[]\n hidden?: 'conditional' | boolean\n lists?: ManifestTitledValue[]\n //portable text\n marks?: {\n annotations?: ManifestArrayMember[]\n decorators?: ManifestTitledValue[]\n }\n of?: ManifestArrayMember[]\n options?: Record<string, ManifestSerializable>\n preview?: {\n select: Record<string, string>\n }\n readOnly?: 'conditional' | boolean\n styles?: ManifestTitledValue[]\n title?: string\n to?: ManifestReferenceMember[]\n validation?: ManifestValidationGroup[]\n\n // userland (assignable to ManifestSerializable | undefined)\n // not included to add some typesafty to extractManifest\n // [index: string]: unknown\n}\n\nexport interface ManifestFieldset {\n [index: string]: ManifestSerializable | undefined\n name: string\n\n title?: string\n}\n\nexport interface ManifestTitledValue {\n value: string\n\n title?: string\n}\n\ntype ManifestArrayMember = Omit<ManifestSchemaType, 'name'> & {name?: string}\ntype ManifestReferenceMember = Omit<ManifestSchemaType, 'name'> & {name?: string}\nexport type ManifestField = ManifestSchemaType & {fieldset?: string}\n\nexport interface ManifestValidationGroup {\n rules: ManifestValidationRule[]\n\n level?: 'error' | 'info' | 'warning'\n message?: string\n}\n\nexport type ManifestValidationRule = {\n [index: string]: ManifestSerializable | undefined\n constraint?: ManifestSerializable\n flag: string\n}\n\nexport interface ManifestTool {\n /**\n * returns null in the case of the icon not being able to be stringified\n */\n icon: string | null\n name: string\n title: string\n type: string | null\n}\n\nexport type DefaultWorkspaceSchemaId = `${typeof SANITY_WORKSPACE_SCHEMA_ID_PREFIX}.${string}`\ntype PrefixedWorkspaceSchemaId = `${DefaultWorkspaceSchemaId}.${string}`\nexport type WorkspaceSchemaId = DefaultWorkspaceSchemaId | PrefixedWorkspaceSchemaId\n\nexport interface StoredWorkspaceSchema extends SanityDocumentLike {\n _id: WorkspaceSchemaId\n _type: typeof SANITY_WORKSPACE_SCHEMA_TYPE\n /**\n * The API expects JSON coming in, but will store a string to save on attribute paths.\n * Consumers must use JSON.parse on the value, but we deploy to the API using ManifestSchemaType[]\n */\n schema: ManifestSchemaType[] | string\n /* api-like version string: date at which the format had a meaningful change */\n version: typeof CURRENT_WORKSPACE_SCHEMA_VERSION | undefined\n workspace: {\n name: string\n title?: string\n }\n\n tag?: string\n}\n\nexport const extractManifestWorkerData = z.object({configPath: z.string(), workDir: z.string()})\n\nexport type ExtractManifestWorkerData = z.infer<typeof extractManifestWorkerData>\n"],"names":["z","SANITY_WORKSPACE_SCHEMA_ID_PREFIX","SANITY_WORKSPACE_SCHEMA_TYPE","CURRENT_WORKSPACE_SCHEMA_VERSION","extractManifestWorkerData","object","configPath","string","workDir"],"mappings":"AAEA,SAAQA,CAAC,QAAO,
|
|
1
|
+
{"version":3,"sources":["../../../src/actions/manifest/types.ts"],"sourcesContent":["import {type SanityDocumentLike} from '@sanity/types'\nimport {type MediaLibraryConfig} from 'sanity'\nimport {z} from 'zod/mini'\n\nexport const SANITY_WORKSPACE_SCHEMA_ID_PREFIX = '_.schemas'\nexport const SANITY_WORKSPACE_SCHEMA_TYPE = 'system.schema'\nexport const CURRENT_WORKSPACE_SCHEMA_VERSION = '2025-05-01'\n\nexport type ManifestSerializable =\n | boolean\n | ManifestSerializable[]\n | number\n | string\n | {[k: string]: ManifestSerializable}\n\nexport interface CreateManifest {\n createdAt: string\n studioVersion: string | null\n version: number\n workspaces: ManifestWorkspaceFile[]\n}\n\nexport interface AppManifest {\n version: '1'\n\n icon?: string\n title?: string\n}\n\nexport interface ManifestWorkspaceFile extends Omit<CreateWorkspaceManifest, 'schema' | 'tools'> {\n schema: string // filename\n tools: string // filename\n}\n\nexport interface CreateWorkspaceManifest {\n basePath: string\n dataset: string\n /**\n * returns null in the case of the icon not being able to be stringified\n */\n icon: string | null\n name: string\n projectId: string\n schema: ManifestSchemaType[]\n tools: ManifestTool[]\n\n mediaLibrary?: MediaLibraryConfig\n subtitle?: string\n title?: string\n}\n\nexport interface ManifestSchemaType {\n name: string\n type: string\n\n deprecated?: {\n reason: string\n }\n fields?: ManifestField[]\n fieldsets?: ManifestFieldset[]\n hidden?: 'conditional' | boolean\n lists?: ManifestTitledValue[]\n //portable text\n marks?: {\n annotations?: ManifestArrayMember[]\n decorators?: ManifestTitledValue[]\n }\n of?: ManifestArrayMember[]\n options?: Record<string, ManifestSerializable>\n preview?: {\n select: Record<string, string>\n }\n readOnly?: 'conditional' | boolean\n styles?: ManifestTitledValue[]\n title?: string\n to?: ManifestReferenceMember[]\n validation?: ManifestValidationGroup[]\n\n // userland (assignable to ManifestSerializable | undefined)\n // not included to add some typesafty to extractManifest\n // [index: string]: unknown\n}\n\nexport interface ManifestFieldset {\n [index: string]: ManifestSerializable | undefined\n name: string\n\n title?: string\n}\n\nexport interface ManifestTitledValue {\n value: string\n\n title?: string\n}\n\ntype ManifestArrayMember = Omit<ManifestSchemaType, 'name'> & {name?: string}\ntype ManifestReferenceMember = Omit<ManifestSchemaType, 'name'> & {name?: string}\nexport type ManifestField = ManifestSchemaType & {fieldset?: string}\n\nexport interface ManifestValidationGroup {\n rules: ManifestValidationRule[]\n\n level?: 'error' | 'info' | 'warning'\n message?: string\n}\n\nexport type ManifestValidationRule = {\n [index: string]: ManifestSerializable | undefined\n constraint?: ManifestSerializable\n flag: string\n}\n\nexport interface ManifestTool {\n /**\n * returns null in the case of the icon not being able to be stringified\n */\n icon: string | null\n name: string\n title: string\n type: string | null\n}\n\nexport type DefaultWorkspaceSchemaId = `${typeof SANITY_WORKSPACE_SCHEMA_ID_PREFIX}.${string}`\ntype PrefixedWorkspaceSchemaId = `${DefaultWorkspaceSchemaId}.${string}`\nexport type WorkspaceSchemaId = DefaultWorkspaceSchemaId | PrefixedWorkspaceSchemaId\n\nexport interface StoredWorkspaceSchema extends SanityDocumentLike {\n _id: WorkspaceSchemaId\n _type: typeof SANITY_WORKSPACE_SCHEMA_TYPE\n /**\n * The API expects JSON coming in, but will store a string to save on attribute paths.\n * Consumers must use JSON.parse on the value, but we deploy to the API using ManifestSchemaType[]\n */\n schema: ManifestSchemaType[] | string\n /* api-like version string: date at which the format had a meaningful change */\n version: typeof CURRENT_WORKSPACE_SCHEMA_VERSION | undefined\n workspace: {\n name: string\n title?: string\n }\n\n tag?: string\n}\n\nexport const extractManifestWorkerData = z.object({configPath: z.string(), workDir: z.string()})\n\nexport type ExtractManifestWorkerData = z.infer<typeof extractManifestWorkerData>\n"],"names":["z","SANITY_WORKSPACE_SCHEMA_ID_PREFIX","SANITY_WORKSPACE_SCHEMA_TYPE","CURRENT_WORKSPACE_SCHEMA_VERSION","extractManifestWorkerData","object","configPath","string","workDir"],"mappings":"AAEA,SAAQA,CAAC,QAAO,WAAU;AAE1B,OAAO,MAAMC,oCAAoC,YAAW;AAC5D,OAAO,MAAMC,+BAA+B,gBAAe;AAC3D,OAAO,MAAMC,mCAAmC,aAAY;AA2I5D,OAAO,MAAMC,4BAA4BJ,EAAEK,MAAM,CAAC;IAACC,YAAYN,EAAEO,MAAM;IAAIC,SAASR,EAAEO,MAAM;AAAE,GAAE"}
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import { z } from 'zod';
|
|
1
|
+
import { z } from 'zod/mini';
|
|
2
2
|
export const extractSchemaWorkerData = z.object({
|
|
3
3
|
configPath: z.string(),
|
|
4
4
|
enforceRequiredFields: z.boolean(),
|
|
5
5
|
workDir: z.string(),
|
|
6
|
-
workspaceName: z.
|
|
6
|
+
workspaceName: z.optional(z.string())
|
|
7
7
|
});
|
|
8
8
|
export const uniqWorkspaceWorkerDataSchema = z.object({
|
|
9
9
|
configPath: z.string(),
|
|
10
|
-
dataset: z.
|
|
10
|
+
dataset: z.optional(z.string())
|
|
11
11
|
});
|
|
12
12
|
export const extractWorkspaceWorkerData = z.object({
|
|
13
13
|
configPath: z.string(),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/actions/schema/types.ts"],"sourcesContent":["import {type SchemaValidationProblemGroup} from '@sanity/types'\nimport {z} from 'zod'\n\nexport const extractSchemaWorkerData = z.object({\n configPath: z.string(),\n enforceRequiredFields: z.boolean(),\n workDir: z.string(),\n workspaceName: z.
|
|
1
|
+
{"version":3,"sources":["../../../src/actions/schema/types.ts"],"sourcesContent":["import {type SchemaValidationProblemGroup} from '@sanity/types'\nimport {z} from 'zod/mini'\n\nexport const extractSchemaWorkerData = z.object({\n configPath: z.string(),\n enforceRequiredFields: z.boolean(),\n workDir: z.string(),\n workspaceName: z.optional(z.string()),\n})\n\nexport type ExtractSchemaWorkerData = z.infer<typeof extractSchemaWorkerData>\n\n/**\n * Contains debug information about the serialized schema.\n *\n * @internal\n **/\nexport type SerializedSchemaDebug = {\n hoisted: Record<string, SerializedTypeDebug>\n parent?: SerializedSchemaDebug\n size: number\n types: Record<string, SerializedTypeDebug>\n}\n\n/**\n * Contains debug information about a serialized type.\n *\n * @internal\n **/\nexport type SerializedTypeDebug = {\n extends: string\n fields?: Record<string, SerializedTypeDebug>\n of?: Record<string, SerializedTypeDebug>\n size: number\n}\n\n/** @internal */\nexport interface ExtractSchemaWorkerError {\n error: string\n type: 'error'\n\n validation?: SchemaValidationProblemGroup[]\n}\n\nexport const uniqWorkspaceWorkerDataSchema = z.object({\n configPath: z.string(),\n dataset: z.optional(z.string()),\n})\n\nexport type UniqWorkspaceWorkerData = z.infer<typeof uniqWorkspaceWorkerDataSchema>\n\nexport const extractWorkspaceWorkerData = z.object({\n configPath: z.string(),\n workDir: z.string(),\n})\n\nexport type ExtractWorkspaceWorkerData = z.infer<typeof extractWorkspaceWorkerData>\n"],"names":["z","extractSchemaWorkerData","object","configPath","string","enforceRequiredFields","boolean","workDir","workspaceName","optional","uniqWorkspaceWorkerDataSchema","dataset","extractWorkspaceWorkerData"],"mappings":"AACA,SAAQA,CAAC,QAAO,WAAU;AAE1B,OAAO,MAAMC,0BAA0BD,EAAEE,MAAM,CAAC;IAC9CC,YAAYH,EAAEI,MAAM;IACpBC,uBAAuBL,EAAEM,OAAO;IAChCC,SAASP,EAAEI,MAAM;IACjBI,eAAeR,EAAES,QAAQ,CAACT,EAAEI,MAAM;AACpC,GAAE;AAoCF,OAAO,MAAMM,gCAAgCV,EAAEE,MAAM,CAAC;IACpDC,YAAYH,EAAEI,MAAM;IACpBO,SAASX,EAAES,QAAQ,CAACT,EAAEI,MAAM;AAC9B,GAAE;AAIF,OAAO,MAAMQ,6BAA6BZ,EAAEE,MAAM,CAAC;IACjDC,YAAYH,EAAEI,MAAM;IACpBG,SAASP,EAAEI,MAAM;AACnB,GAAE"}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { z } from 'zod';
|
|
1
|
+
import { z } from 'zod/mini';
|
|
2
2
|
export function validateEmail(email) {
|
|
3
3
|
const trimmedEmail = email.trim();
|
|
4
4
|
if (!trimmedEmail) {
|
|
5
5
|
return 'Email is required';
|
|
6
6
|
}
|
|
7
|
-
const validatedEmail = z.
|
|
7
|
+
const validatedEmail = z.email().safeParse(trimmedEmail);
|
|
8
8
|
if (!validatedEmail.success) {
|
|
9
9
|
return 'Please enter a valid email address';
|
|
10
10
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/actions/users/validateEmail.ts"],"sourcesContent":["import {z} from 'zod'\n\nexport function validateEmail(email: string): string | true {\n const trimmedEmail = email.trim()\n if (!trimmedEmail) {\n return 'Email is required'\n }\n\n const validatedEmail = z.
|
|
1
|
+
{"version":3,"sources":["../../../src/actions/users/validateEmail.ts"],"sourcesContent":["import {z} from 'zod/mini'\n\nexport function validateEmail(email: string): string | true {\n const trimmedEmail = email.trim()\n if (!trimmedEmail) {\n return 'Email is required'\n }\n\n const validatedEmail = z.email().safeParse(trimmedEmail)\n if (!validatedEmail.success) {\n return 'Please enter a valid email address'\n }\n\n return true\n}\n"],"names":["z","validateEmail","email","trimmedEmail","trim","validatedEmail","safeParse","success"],"mappings":"AAAA,SAAQA,CAAC,QAAO,WAAU;AAE1B,OAAO,SAASC,cAAcC,KAAa;IACzC,MAAMC,eAAeD,MAAME,IAAI;IAC/B,IAAI,CAACD,cAAc;QACjB,OAAO;IACT;IAEA,MAAME,iBAAiBL,EAAEE,KAAK,GAAGI,SAAS,CAACH;IAC3C,IAAI,CAACE,eAAeE,OAAO,EAAE;QAC3B,OAAO;IACT;IAEA,OAAO;AACT"}
|
|
@@ -15,7 +15,7 @@ export class DisableBackupCommand extends SanityCommand {
|
|
|
15
15
|
required: false
|
|
16
16
|
})
|
|
17
17
|
};
|
|
18
|
-
static description = 'Disable backup for a dataset
|
|
18
|
+
static description = 'Disable backup for a dataset';
|
|
19
19
|
static examples = [
|
|
20
20
|
{
|
|
21
21
|
command: '<%= config.bin %> <%= command.id %>',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/commands/backups/disable.ts"],"sourcesContent":["import {styleText} from 'node:util'\n\nimport {Args} from '@oclif/core'\nimport {SanityCommand, subdebug} from '@sanity/cli-core'\nimport {select} from '@sanity/cli-core/ux'\nimport {type DatasetsResponse} from '@sanity/client'\n\nimport {assertDatasetExists} from '../../actions/backup/assertDatasetExist.js'\nimport {promptForProject} from '../../prompts/promptForProject.js'\nimport {setBackup} from '../../services/backup.js'\nimport {listDatasets} from '../../services/datasets.js'\nimport {getProjectIdFlag} from '../../util/sharedFlags.js'\n\nconst disableBackupDebug = subdebug('backup:disable')\n\nexport class DisableBackupCommand extends SanityCommand<typeof DisableBackupCommand> {\n static override args = {\n dataset: Args.string({\n description: 'Dataset name to disable backup for',\n required: false,\n }),\n }\n\n static override description = 'Disable backup for a dataset
|
|
1
|
+
{"version":3,"sources":["../../../src/commands/backups/disable.ts"],"sourcesContent":["import {styleText} from 'node:util'\n\nimport {Args} from '@oclif/core'\nimport {SanityCommand, subdebug} from '@sanity/cli-core'\nimport {select} from '@sanity/cli-core/ux'\nimport {type DatasetsResponse} from '@sanity/client'\n\nimport {assertDatasetExists} from '../../actions/backup/assertDatasetExist.js'\nimport {promptForProject} from '../../prompts/promptForProject.js'\nimport {setBackup} from '../../services/backup.js'\nimport {listDatasets} from '../../services/datasets.js'\nimport {getProjectIdFlag} from '../../util/sharedFlags.js'\n\nconst disableBackupDebug = subdebug('backup:disable')\n\nexport class DisableBackupCommand extends SanityCommand<typeof DisableBackupCommand> {\n static override args = {\n dataset: Args.string({\n description: 'Dataset name to disable backup for',\n required: false,\n }),\n }\n\n static override description = 'Disable backup for a dataset'\n\n static override examples = [\n {\n command: '<%= config.bin %> <%= command.id %>',\n description: 'Interactively disable backup for a dataset',\n },\n {\n command: '<%= config.bin %> <%= command.id %> production',\n description: 'Disable backup for the production dataset',\n },\n ]\n\n static override flags = {\n ...getProjectIdFlag({\n description: 'Project ID to disable backups for',\n semantics: 'override',\n }),\n }\n\n static override hiddenAliases: string[] = ['backup:disable']\n\n public async run(): Promise<void> {\n const {args} = await this.parse(DisableBackupCommand)\n let {dataset} = args\n\n const projectId = await this.getProjectId({\n fallback: () =>\n promptForProject({\n requiredPermissions: [\n {grant: 'read', permission: 'sanity.project.datasets'},\n {grant: 'update', permission: 'sanity.project.datasets'},\n ],\n }),\n })\n\n let datasets: DatasetsResponse\n\n try {\n datasets = await listDatasets(projectId)\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error)\n disableBackupDebug(`Failed to list datasets: ${message}`, error)\n this.error(`Failed to list datasets: ${message}`, {exit: 1})\n }\n\n if (datasets.length === 0) {\n this.error('No datasets found in this project.', {exit: 1})\n }\n\n if (dataset) {\n assertDatasetExists(datasets, dataset)\n } else {\n dataset = await this.promptForDataset(datasets)\n }\n\n try {\n await setBackup({dataset, projectId, status: false})\n\n this.log(`${styleText('green', `Disabled daily backups for dataset ${dataset}.\\n`)}`)\n this.log(\n `${styleText('yellow', 'Note: Existing backups will be retained according to your retention policy.\\n')}`,\n )\n\n disableBackupDebug(`Successfully disabled backup for dataset ${dataset}`)\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error)\n disableBackupDebug(`Failed to disable backup for dataset`, error)\n this.error(`Disabling dataset backup failed: ${message}`, {exit: 1})\n }\n }\n\n private async promptForDataset(datasets: DatasetsResponse): Promise<string> {\n try {\n const choices = datasets.map((dataset) => ({\n name: dataset.name,\n value: dataset.name,\n }))\n\n return select({\n choices,\n message: 'Select the dataset name:',\n })\n } catch (error) {\n const err = error as Error\n disableBackupDebug(`Error fetching datasets`, err)\n this.error(`Failed to fetch datasets:\\n${err.message}`, {exit: 1})\n }\n }\n}\n"],"names":["styleText","Args","SanityCommand","subdebug","select","assertDatasetExists","promptForProject","setBackup","listDatasets","getProjectIdFlag","disableBackupDebug","DisableBackupCommand","args","dataset","string","description","required","examples","command","flags","semantics","hiddenAliases","run","parse","projectId","getProjectId","fallback","requiredPermissions","grant","permission","datasets","error","message","Error","String","exit","length","promptForDataset","status","log","choices","map","name","value","err"],"mappings":"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"}
|
|
@@ -34,7 +34,7 @@ export class DownloadBackupCommand extends SanityCommand {
|
|
|
34
34
|
required: false
|
|
35
35
|
})
|
|
36
36
|
};
|
|
37
|
-
static description = 'Download a dataset backup to a local file
|
|
37
|
+
static description = 'Download a dataset backup to a local file';
|
|
38
38
|
static examples = [
|
|
39
39
|
{
|
|
40
40
|
command: '<%= config.bin %> <%= command.id %>',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/commands/backups/download.ts"],"sourcesContent":["import {createWriteStream} from 'node:fs'\nimport {access, mkdir, mkdtemp} from 'node:fs/promises'\nimport {tmpdir} from 'node:os'\nimport path from 'node:path'\nimport {finished} from 'node:stream/promises'\nimport {styleText} from 'node:util'\n\nimport {Args, Flags} from '@oclif/core'\nimport {SanityCommand} from '@sanity/cli-core'\nimport {boxen, confirm, input, select} from '@sanity/cli-core/ux'\nimport {type DatasetsResponse} from '@sanity/client'\nimport pMap from 'p-map'\nimport prettyMs from 'pretty-ms'\n\nimport {archiveDir} from '../../actions/backup/archiveDir.js'\nimport {assertDatasetExists} from '../../actions/backup/assertDatasetExist.js'\nimport {backupDownloadDebug} from '../../actions/backup/backupDownloadDebug.js'\nimport {cleanupTmpDir} from '../../actions/backup/cleanupTmpDir.js'\nimport {downloadAsset} from '../../actions/backup/downloadAsset.js'\nimport {downloadDocument} from '../../actions/backup/downloadDocument.js'\nimport {type File, PaginatedGetBackupStream} from '../../actions/backup/fetchNextBackupPage.js'\nimport {newProgress} from '../../actions/backup/progressSpinner.js'\nimport {validateDatasetName} from '../../actions/dataset/validateDatasetName.js'\nimport {promptForDataset} from '../../prompts/promptForDataset.js'\nimport {promptForProject} from '../../prompts/promptForProject.js'\nimport {type BackupItem, listBackups} from '../../services/backup.js'\nimport {listDatasets} from '../../services/datasets.js'\nimport {humanFileSize} from '../../util/humanFileSize.js'\nimport {isPathDirName} from '../../util/isPathDirName.js'\nimport {getProjectIdFlag} from '../../util/sharedFlags.js'\n\nconst DEFAULT_DOWNLOAD_CONCURRENCY = 10\nconst MAX_DOWNLOAD_CONCURRENCY = 24\n\ninterface DownloadBackupOptions {\n backupId: string\n concurrency: number\n datasetName: string\n outDir: string\n outFileName: string\n overwrite: boolean\n projectId: string\n}\n\nexport class DownloadBackupCommand extends SanityCommand<typeof DownloadBackupCommand> {\n static override args = {\n dataset: Args.string({\n description: 'Dataset name to download backup from',\n required: false,\n }),\n }\n\n static override description = 'Download a dataset backup to a local file.'\n\n static override examples = [\n {\n command: '<%= config.bin %> <%= command.id %>',\n description: 'Interactively download a backup',\n },\n {\n command: '<%= config.bin %> <%= command.id %> production --backup-id 2024-01-01-backup-1',\n description: 'Download a specific backup for the production dataset',\n },\n {\n command:\n '<%= config.bin %> <%= command.id %> production --backup-id 2024-01-01-backup-2 --out /path/to/file',\n description: 'Download backup to a specific file',\n },\n {\n command:\n '<%= config.bin %> <%= command.id %> production --backup-id 2024-01-01-backup-3 --out /path/to/file --overwrite',\n description: 'Download backup and overwrite existing file',\n },\n ]\n\n static override flags = {\n ...getProjectIdFlag({\n description: 'Project ID to download backup from',\n semantics: 'override',\n }),\n 'backup-id': Flags.string({\n description: 'The backup ID to download',\n }),\n concurrency: Flags.integer({\n default: DEFAULT_DOWNLOAD_CONCURRENCY,\n description: `Concurrent number of backup item downloads (max: ${MAX_DOWNLOAD_CONCURRENCY})`,\n }),\n out: Flags.string({\n description: 'The file or directory path the backup should download to',\n }),\n overwrite: Flags.boolean({\n default: false,\n description: 'Allows overwriting of existing backup file',\n }),\n }\n\n static override hiddenAliases: string[] = ['backup:download']\n\n public async run(): Promise<void> {\n const {args} = await this.parse(DownloadBackupCommand)\n let {dataset} = args\n\n const projectId = await this.getProjectId({\n fallback: () =>\n promptForProject({\n requiredPermissions: [{grant: 'read', permission: 'sanity.project.datasets'}],\n }),\n })\n\n let datasets: DatasetsResponse\n\n try {\n datasets = await listDatasets(projectId)\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error)\n backupDownloadDebug(`Failed to list datasets: ${message}`, error)\n this.error(`Failed to list datasets: ${message}`, {exit: 1})\n }\n\n if (datasets.length === 0) {\n this.error('No datasets found in this project.', {exit: 1})\n }\n\n if (dataset) {\n assertDatasetExists(datasets, dataset)\n } else {\n dataset = await promptForDataset({allowCreation: false, datasets})\n }\n\n const opts = await this.prepareBackupOptions(projectId, dataset)\n const outFilePath = path.join(opts.outDir, opts.outFileName)\n\n this.log(\n boxen(\n `Downloading backup for:\n\n${styleText('bold', 'projectId')}: ${styleText('cyan', opts.projectId)}\n${styleText('bold', 'dataset')}: ${styleText('cyan', opts.datasetName)}\n${styleText('bold', 'backupId')}: ${styleText('cyan', opts.backupId)}`,\n {\n borderColor: 'cyan',\n borderStyle: 'round',\n padding: 1,\n },\n ),\n )\n this.log('')\n this.log(`Downloading backup to \"${styleText('cyan', outFilePath)}\"`)\n\n const start = Date.now()\n const progressSpinner = newProgress('Setting up backup environment...')\n\n // Create a unique temporary directory to store files before bundling them into the archive at outputPath.\n // Temporary directories are normally deleted at the end of backup process, any unexpected exit may leave them\n // behind, hence it is important to create a unique directory for each attempt.\n const tmpOutDir = await mkdtemp(path.join(tmpdir(), `sanity-backup-`))\n\n // Create required directories if they don't exist.\n for (const dir of [\n opts.outDir,\n path.join(tmpOutDir, 'images'),\n path.join(tmpOutDir, 'files'),\n ]) {\n await mkdir(dir, {recursive: true})\n }\n\n backupDownloadDebug('Writing to temporary directory %s', tmpOutDir)\n const tmpOutDocumentsFile = path.join(tmpOutDir, 'data.ndjson')\n\n const docOutStream = createWriteStream(tmpOutDocumentsFile)\n\n try {\n const backupFileStream = new PaginatedGetBackupStream(\n opts.projectId,\n opts.datasetName,\n opts.backupId,\n )\n\n const files: File[] = []\n let i = 0\n for await (const file of backupFileStream) {\n files.push(file)\n i++\n progressSpinner.set({\n current: i,\n step: `Reading backup files...`,\n total: backupFileStream.totalFiles,\n update: true,\n })\n }\n\n let totalItemsDownloaded = 0\n await pMap(\n files,\n async (file: File) => {\n if (file.type === 'file' || file.type === 'image') {\n await downloadAsset(file.url, file.name, file.type, tmpOutDir)\n } else {\n const doc = await downloadDocument(file.url)\n docOutStream.write(`${doc}\\n`)\n }\n\n totalItemsDownloaded += 1\n progressSpinner.set({\n current: totalItemsDownloaded,\n step: `Downloading documents and assets...`,\n total: backupFileStream.totalFiles,\n update: true,\n })\n },\n {concurrency: opts.concurrency},\n )\n } catch (error) {\n progressSpinner.fail()\n const message = error instanceof Error ? error.message : String(error)\n backupDownloadDebug(`Downloading dataset backup failed: ${message}`, error)\n this.error(`Downloading dataset backup failed: ${message}`, {exit: 1})\n }\n\n docOutStream.end()\n await finished(docOutStream)\n\n progressSpinner.set({step: `Archiving files into a tarball...`, update: true})\n try {\n await archiveDir(tmpOutDir, outFilePath, (processedBytes: number) => {\n progressSpinner.update({\n step: `Archiving files into a tarball, ${humanFileSize(processedBytes)} bytes written...`,\n })\n })\n } catch (err) {\n progressSpinner.fail()\n const message = err instanceof Error ? err.message : String(err)\n backupDownloadDebug(`Archiving backup failed: ${message}`, err)\n this.error(`Archiving backup failed: ${message}`, {exit: 1})\n }\n\n progressSpinner.set({\n step: `Cleaning up temporary files at ${styleText('cyan', `${tmpOutDir}`)}`,\n })\n await cleanupTmpDir(tmpOutDir)\n\n progressSpinner.set({\n step: `Backup download complete [${prettyMs(Date.now() - start)}]`,\n })\n progressSpinner.succeed()\n }\n\n private async getOutputPath(defaultOutFileName: string): Promise<string> {\n if (this.flags.out !== undefined) {\n // Rewrite the output path to an absolute path, if it is not already.\n return path.resolve(this.flags.out)\n }\n\n const workDir = process.cwd()\n const inputResult = await input({\n default: path.join(workDir, defaultOutFileName),\n message: 'Output path:',\n })\n return path.resolve(inputResult)\n }\n\n private async prepareBackupOptions(\n projectId: string,\n datasetName: string,\n ): Promise<DownloadBackupOptions> {\n const err = validateDatasetName(datasetName)\n if (err) {\n this.error(err, {exit: 1})\n }\n\n const backupId = String(\n this.flags['backup-id'] || (await this.promptForBackupId(projectId, datasetName)),\n )\n\n if (\n 'concurrency' in this.flags &&\n (this.flags.concurrency < 1 || this.flags.concurrency > MAX_DOWNLOAD_CONCURRENCY)\n ) {\n this.error(`concurrency should be in 1 to ${MAX_DOWNLOAD_CONCURRENCY} range`, {exit: 1})\n }\n\n const defaultOutFileName = `${datasetName}-backup-${backupId}.tar.gz`\n let out = await this.getOutputPath(defaultOutFileName)\n\n // If path is a directory name, then add a default file name to the path.\n if (isPathDirName(out)) {\n out = path.join(out, defaultOutFileName)\n }\n\n const exists = await access(out).then(\n () => true,\n () => false,\n )\n // If the file already exists, ask for confirmation if it should be overwritten.\n if (!this.flags.overwrite && exists) {\n const shouldOverwrite = await confirm({\n default: false,\n message: `File \"${out}\" already exists, would you like to overwrite it?`,\n })\n\n // If the user does not want to overwrite the file, cancel the operation.\n if (!shouldOverwrite) {\n this.error('Operation cancelled.', {exit: 1})\n }\n }\n\n return {\n backupId,\n concurrency: this.flags.concurrency || DEFAULT_DOWNLOAD_CONCURRENCY,\n datasetName,\n outDir: path.dirname(out),\n outFileName: path.basename(out),\n overwrite: this.flags.overwrite,\n projectId,\n }\n }\n\n private async promptForBackupId(projectId: string, datasetName: string): Promise<string> {\n const maxBackupIdsShown = 100\n\n try {\n const response = await listBackups({\n datasetName,\n limit: maxBackupIdsShown,\n projectId,\n })\n\n if (!response?.backups?.length) {\n this.error('No backups found', {exit: 1})\n }\n\n const backupIdChoices = response.backups.map((backup: BackupItem) => ({\n name: backup.id,\n value: backup.id,\n }))\n\n const hint =\n backupIdChoices.length === maxBackupIdsShown\n ? ` (only last ${maxBackupIdsShown} shown)`\n : ''\n\n return select({\n choices: backupIdChoices,\n message: `Select backup ID to use${hint}`,\n })\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err)\n backupDownloadDebug(`Failed to fetch backups for dataset ${datasetName}: ${message}`, err)\n this.error(`Failed to fetch backups for dataset ${datasetName}: ${message}`, {exit: 1})\n }\n }\n}\n"],"names":["createWriteStream","access","mkdir","mkdtemp","tmpdir","path","finished","styleText","Args","Flags","SanityCommand","boxen","confirm","input","select","pMap","prettyMs","archiveDir","assertDatasetExists","backupDownloadDebug","cleanupTmpDir","downloadAsset","downloadDocument","PaginatedGetBackupStream","newProgress","validateDatasetName","promptForDataset","promptForProject","listBackups","listDatasets","humanFileSize","isPathDirName","getProjectIdFlag","DEFAULT_DOWNLOAD_CONCURRENCY","MAX_DOWNLOAD_CONCURRENCY","DownloadBackupCommand","args","dataset","string","description","required","examples","command","flags","semantics","concurrency","integer","default","out","overwrite","boolean","hiddenAliases","run","parse","projectId","getProjectId","fallback","requiredPermissions","grant","permission","datasets","error","message","Error","String","exit","length","allowCreation","opts","prepareBackupOptions","outFilePath","join","outDir","outFileName","log","datasetName","backupId","borderColor","borderStyle","padding","start","Date","now","progressSpinner","tmpOutDir","dir","recursive","tmpOutDocumentsFile","docOutStream","backupFileStream","files","i","file","push","set","current","step","total","totalFiles","update","totalItemsDownloaded","type","url","name","doc","write","fail","end","processedBytes","err","succeed","getOutputPath","defaultOutFileName","undefined","resolve","workDir","process","cwd","inputResult","promptForBackupId","exists","then","shouldOverwrite","dirname","basename","maxBackupIdsShown","response","limit","backups","backupIdChoices","map","backup","id","value","hint","choices"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../src/commands/backups/download.ts"],"sourcesContent":["import {createWriteStream} from 'node:fs'\nimport {access, mkdir, mkdtemp} from 'node:fs/promises'\nimport {tmpdir} from 'node:os'\nimport path from 'node:path'\nimport {finished} from 'node:stream/promises'\nimport {styleText} from 'node:util'\n\nimport {Args, Flags} from '@oclif/core'\nimport {SanityCommand} from '@sanity/cli-core'\nimport {boxen, confirm, input, select} from '@sanity/cli-core/ux'\nimport {type DatasetsResponse} from '@sanity/client'\nimport pMap from 'p-map'\nimport prettyMs from 'pretty-ms'\n\nimport {archiveDir} from '../../actions/backup/archiveDir.js'\nimport {assertDatasetExists} from '../../actions/backup/assertDatasetExist.js'\nimport {backupDownloadDebug} from '../../actions/backup/backupDownloadDebug.js'\nimport {cleanupTmpDir} from '../../actions/backup/cleanupTmpDir.js'\nimport {downloadAsset} from '../../actions/backup/downloadAsset.js'\nimport {downloadDocument} from '../../actions/backup/downloadDocument.js'\nimport {type File, PaginatedGetBackupStream} from '../../actions/backup/fetchNextBackupPage.js'\nimport {newProgress} from '../../actions/backup/progressSpinner.js'\nimport {validateDatasetName} from '../../actions/dataset/validateDatasetName.js'\nimport {promptForDataset} from '../../prompts/promptForDataset.js'\nimport {promptForProject} from '../../prompts/promptForProject.js'\nimport {type BackupItem, listBackups} from '../../services/backup.js'\nimport {listDatasets} from '../../services/datasets.js'\nimport {humanFileSize} from '../../util/humanFileSize.js'\nimport {isPathDirName} from '../../util/isPathDirName.js'\nimport {getProjectIdFlag} from '../../util/sharedFlags.js'\n\nconst DEFAULT_DOWNLOAD_CONCURRENCY = 10\nconst MAX_DOWNLOAD_CONCURRENCY = 24\n\ninterface DownloadBackupOptions {\n backupId: string\n concurrency: number\n datasetName: string\n outDir: string\n outFileName: string\n overwrite: boolean\n projectId: string\n}\n\nexport class DownloadBackupCommand extends SanityCommand<typeof DownloadBackupCommand> {\n static override args = {\n dataset: Args.string({\n description: 'Dataset name to download backup from',\n required: false,\n }),\n }\n\n static override description = 'Download a dataset backup to a local file'\n\n static override examples = [\n {\n command: '<%= config.bin %> <%= command.id %>',\n description: 'Interactively download a backup',\n },\n {\n command: '<%= config.bin %> <%= command.id %> production --backup-id 2024-01-01-backup-1',\n description: 'Download a specific backup for the production dataset',\n },\n {\n command:\n '<%= config.bin %> <%= command.id %> production --backup-id 2024-01-01-backup-2 --out /path/to/file',\n description: 'Download backup to a specific file',\n },\n {\n command:\n '<%= config.bin %> <%= command.id %> production --backup-id 2024-01-01-backup-3 --out /path/to/file --overwrite',\n description: 'Download backup and overwrite existing file',\n },\n ]\n\n static override flags = {\n ...getProjectIdFlag({\n description: 'Project ID to download backup from',\n semantics: 'override',\n }),\n 'backup-id': Flags.string({\n description: 'The backup ID to download',\n }),\n concurrency: Flags.integer({\n default: DEFAULT_DOWNLOAD_CONCURRENCY,\n description: `Concurrent number of backup item downloads (max: ${MAX_DOWNLOAD_CONCURRENCY})`,\n }),\n out: Flags.string({\n description: 'The file or directory path the backup should download to',\n }),\n overwrite: Flags.boolean({\n default: false,\n description: 'Allows overwriting of existing backup file',\n }),\n }\n\n static override hiddenAliases: string[] = ['backup:download']\n\n public async run(): Promise<void> {\n const {args} = await this.parse(DownloadBackupCommand)\n let {dataset} = args\n\n const projectId = await this.getProjectId({\n fallback: () =>\n promptForProject({\n requiredPermissions: [{grant: 'read', permission: 'sanity.project.datasets'}],\n }),\n })\n\n let datasets: DatasetsResponse\n\n try {\n datasets = await listDatasets(projectId)\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error)\n backupDownloadDebug(`Failed to list datasets: ${message}`, error)\n this.error(`Failed to list datasets: ${message}`, {exit: 1})\n }\n\n if (datasets.length === 0) {\n this.error('No datasets found in this project.', {exit: 1})\n }\n\n if (dataset) {\n assertDatasetExists(datasets, dataset)\n } else {\n dataset = await promptForDataset({allowCreation: false, datasets})\n }\n\n const opts = await this.prepareBackupOptions(projectId, dataset)\n const outFilePath = path.join(opts.outDir, opts.outFileName)\n\n this.log(\n boxen(\n `Downloading backup for:\n\n${styleText('bold', 'projectId')}: ${styleText('cyan', opts.projectId)}\n${styleText('bold', 'dataset')}: ${styleText('cyan', opts.datasetName)}\n${styleText('bold', 'backupId')}: ${styleText('cyan', opts.backupId)}`,\n {\n borderColor: 'cyan',\n borderStyle: 'round',\n padding: 1,\n },\n ),\n )\n this.log('')\n this.log(`Downloading backup to \"${styleText('cyan', outFilePath)}\"`)\n\n const start = Date.now()\n const progressSpinner = newProgress('Setting up backup environment...')\n\n // Create a unique temporary directory to store files before bundling them into the archive at outputPath.\n // Temporary directories are normally deleted at the end of backup process, any unexpected exit may leave them\n // behind, hence it is important to create a unique directory for each attempt.\n const tmpOutDir = await mkdtemp(path.join(tmpdir(), `sanity-backup-`))\n\n // Create required directories if they don't exist.\n for (const dir of [\n opts.outDir,\n path.join(tmpOutDir, 'images'),\n path.join(tmpOutDir, 'files'),\n ]) {\n await mkdir(dir, {recursive: true})\n }\n\n backupDownloadDebug('Writing to temporary directory %s', tmpOutDir)\n const tmpOutDocumentsFile = path.join(tmpOutDir, 'data.ndjson')\n\n const docOutStream = createWriteStream(tmpOutDocumentsFile)\n\n try {\n const backupFileStream = new PaginatedGetBackupStream(\n opts.projectId,\n opts.datasetName,\n opts.backupId,\n )\n\n const files: File[] = []\n let i = 0\n for await (const file of backupFileStream) {\n files.push(file)\n i++\n progressSpinner.set({\n current: i,\n step: `Reading backup files...`,\n total: backupFileStream.totalFiles,\n update: true,\n })\n }\n\n let totalItemsDownloaded = 0\n await pMap(\n files,\n async (file: File) => {\n if (file.type === 'file' || file.type === 'image') {\n await downloadAsset(file.url, file.name, file.type, tmpOutDir)\n } else {\n const doc = await downloadDocument(file.url)\n docOutStream.write(`${doc}\\n`)\n }\n\n totalItemsDownloaded += 1\n progressSpinner.set({\n current: totalItemsDownloaded,\n step: `Downloading documents and assets...`,\n total: backupFileStream.totalFiles,\n update: true,\n })\n },\n {concurrency: opts.concurrency},\n )\n } catch (error) {\n progressSpinner.fail()\n const message = error instanceof Error ? error.message : String(error)\n backupDownloadDebug(`Downloading dataset backup failed: ${message}`, error)\n this.error(`Downloading dataset backup failed: ${message}`, {exit: 1})\n }\n\n docOutStream.end()\n await finished(docOutStream)\n\n progressSpinner.set({step: `Archiving files into a tarball...`, update: true})\n try {\n await archiveDir(tmpOutDir, outFilePath, (processedBytes: number) => {\n progressSpinner.update({\n step: `Archiving files into a tarball, ${humanFileSize(processedBytes)} bytes written...`,\n })\n })\n } catch (err) {\n progressSpinner.fail()\n const message = err instanceof Error ? err.message : String(err)\n backupDownloadDebug(`Archiving backup failed: ${message}`, err)\n this.error(`Archiving backup failed: ${message}`, {exit: 1})\n }\n\n progressSpinner.set({\n step: `Cleaning up temporary files at ${styleText('cyan', `${tmpOutDir}`)}`,\n })\n await cleanupTmpDir(tmpOutDir)\n\n progressSpinner.set({\n step: `Backup download complete [${prettyMs(Date.now() - start)}]`,\n })\n progressSpinner.succeed()\n }\n\n private async getOutputPath(defaultOutFileName: string): Promise<string> {\n if (this.flags.out !== undefined) {\n // Rewrite the output path to an absolute path, if it is not already.\n return path.resolve(this.flags.out)\n }\n\n const workDir = process.cwd()\n const inputResult = await input({\n default: path.join(workDir, defaultOutFileName),\n message: 'Output path:',\n })\n return path.resolve(inputResult)\n }\n\n private async prepareBackupOptions(\n projectId: string,\n datasetName: string,\n ): Promise<DownloadBackupOptions> {\n const err = validateDatasetName(datasetName)\n if (err) {\n this.error(err, {exit: 1})\n }\n\n const backupId = String(\n this.flags['backup-id'] || (await this.promptForBackupId(projectId, datasetName)),\n )\n\n if (\n 'concurrency' in this.flags &&\n (this.flags.concurrency < 1 || this.flags.concurrency > MAX_DOWNLOAD_CONCURRENCY)\n ) {\n this.error(`concurrency should be in 1 to ${MAX_DOWNLOAD_CONCURRENCY} range`, {exit: 1})\n }\n\n const defaultOutFileName = `${datasetName}-backup-${backupId}.tar.gz`\n let out = await this.getOutputPath(defaultOutFileName)\n\n // If path is a directory name, then add a default file name to the path.\n if (isPathDirName(out)) {\n out = path.join(out, defaultOutFileName)\n }\n\n const exists = await access(out).then(\n () => true,\n () => false,\n )\n // If the file already exists, ask for confirmation if it should be overwritten.\n if (!this.flags.overwrite && exists) {\n const shouldOverwrite = await confirm({\n default: false,\n message: `File \"${out}\" already exists, would you like to overwrite it?`,\n })\n\n // If the user does not want to overwrite the file, cancel the operation.\n if (!shouldOverwrite) {\n this.error('Operation cancelled.', {exit: 1})\n }\n }\n\n return {\n backupId,\n concurrency: this.flags.concurrency || DEFAULT_DOWNLOAD_CONCURRENCY,\n datasetName,\n outDir: path.dirname(out),\n outFileName: path.basename(out),\n overwrite: this.flags.overwrite,\n projectId,\n }\n }\n\n private async promptForBackupId(projectId: string, datasetName: string): Promise<string> {\n const maxBackupIdsShown = 100\n\n try {\n const response = await listBackups({\n datasetName,\n limit: maxBackupIdsShown,\n projectId,\n })\n\n if (!response?.backups?.length) {\n this.error('No backups found', {exit: 1})\n }\n\n const backupIdChoices = response.backups.map((backup: BackupItem) => ({\n name: backup.id,\n value: backup.id,\n }))\n\n const hint =\n backupIdChoices.length === maxBackupIdsShown\n ? ` (only last ${maxBackupIdsShown} shown)`\n : ''\n\n return select({\n choices: backupIdChoices,\n message: `Select backup ID to use${hint}`,\n })\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err)\n backupDownloadDebug(`Failed to fetch backups for dataset ${datasetName}: ${message}`, err)\n this.error(`Failed to fetch backups for dataset ${datasetName}: ${message}`, {exit: 1})\n }\n }\n}\n"],"names":["createWriteStream","access","mkdir","mkdtemp","tmpdir","path","finished","styleText","Args","Flags","SanityCommand","boxen","confirm","input","select","pMap","prettyMs","archiveDir","assertDatasetExists","backupDownloadDebug","cleanupTmpDir","downloadAsset","downloadDocument","PaginatedGetBackupStream","newProgress","validateDatasetName","promptForDataset","promptForProject","listBackups","listDatasets","humanFileSize","isPathDirName","getProjectIdFlag","DEFAULT_DOWNLOAD_CONCURRENCY","MAX_DOWNLOAD_CONCURRENCY","DownloadBackupCommand","args","dataset","string","description","required","examples","command","flags","semantics","concurrency","integer","default","out","overwrite","boolean","hiddenAliases","run","parse","projectId","getProjectId","fallback","requiredPermissions","grant","permission","datasets","error","message","Error","String","exit","length","allowCreation","opts","prepareBackupOptions","outFilePath","join","outDir","outFileName","log","datasetName","backupId","borderColor","borderStyle","padding","start","Date","now","progressSpinner","tmpOutDir","dir","recursive","tmpOutDocumentsFile","docOutStream","backupFileStream","files","i","file","push","set","current","step","total","totalFiles","update","totalItemsDownloaded","type","url","name","doc","write","fail","end","processedBytes","err","succeed","getOutputPath","defaultOutFileName","undefined","resolve","workDir","process","cwd","inputResult","promptForBackupId","exists","then","shouldOverwrite","dirname","basename","maxBackupIdsShown","response","limit","backups","backupIdChoices","map","backup","id","value","hint","choices"],"mappings":"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"}
|
|
@@ -16,7 +16,7 @@ export class EnableBackupCommand extends SanityCommand {
|
|
|
16
16
|
required: false
|
|
17
17
|
})
|
|
18
18
|
};
|
|
19
|
-
static description = 'Enable backup for a dataset
|
|
19
|
+
static description = 'Enable backup for a dataset';
|
|
20
20
|
static examples = [
|
|
21
21
|
{
|
|
22
22
|
command: '<%= config.bin %> <%= command.id %>',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/commands/backups/enable.ts"],"sourcesContent":["import {styleText} from 'node:util'\n\nimport {Args} from '@oclif/core'\nimport {SanityCommand, subdebug} from '@sanity/cli-core'\nimport {type DatasetsResponse} from '@sanity/client'\n\nimport {assertDatasetExists} from '../../actions/backup/assertDatasetExist.js'\nimport {NEW_DATASET_VALUE, promptForDataset} from '../../prompts/promptForDataset.js'\nimport {promptForDatasetName} from '../../prompts/promptForDatasetName.js'\nimport {promptForProject} from '../../prompts/promptForProject.js'\nimport {setBackup} from '../../services/backup.js'\nimport {createDataset, listDatasets} from '../../services/datasets.js'\nimport {getProjectIdFlag} from '../../util/sharedFlags.js'\n\nconst enableBackupDebug = subdebug('backup:enable')\n\nexport class EnableBackupCommand extends SanityCommand<typeof EnableBackupCommand> {\n static override args = {\n dataset: Args.string({\n description: 'Dataset name to enable backup for',\n required: false,\n }),\n }\n\n static override description = 'Enable backup for a dataset
|
|
1
|
+
{"version":3,"sources":["../../../src/commands/backups/enable.ts"],"sourcesContent":["import {styleText} from 'node:util'\n\nimport {Args} from '@oclif/core'\nimport {SanityCommand, subdebug} from '@sanity/cli-core'\nimport {type DatasetsResponse} from '@sanity/client'\n\nimport {assertDatasetExists} from '../../actions/backup/assertDatasetExist.js'\nimport {NEW_DATASET_VALUE, promptForDataset} from '../../prompts/promptForDataset.js'\nimport {promptForDatasetName} from '../../prompts/promptForDatasetName.js'\nimport {promptForProject} from '../../prompts/promptForProject.js'\nimport {setBackup} from '../../services/backup.js'\nimport {createDataset, listDatasets} from '../../services/datasets.js'\nimport {getProjectIdFlag} from '../../util/sharedFlags.js'\n\nconst enableBackupDebug = subdebug('backup:enable')\n\nexport class EnableBackupCommand extends SanityCommand<typeof EnableBackupCommand> {\n static override args = {\n dataset: Args.string({\n description: 'Dataset name to enable backup for',\n required: false,\n }),\n }\n\n static override description = 'Enable backup for a dataset'\n\n static override examples = [\n {\n command: '<%= config.bin %> <%= command.id %>',\n description: 'Interactively enable backup for a dataset',\n },\n {\n command: '<%= config.bin %> <%= command.id %> production',\n description: 'Enable backup for the production dataset',\n },\n ]\n\n static override flags = {\n ...getProjectIdFlag({\n description: 'Project ID to enable backups for',\n semantics: 'override',\n }),\n }\n\n static override hiddenAliases: string[] = ['backup:enable']\n\n public async run(): Promise<void> {\n const {args} = await this.parse(EnableBackupCommand)\n let {dataset} = args\n\n const projectId = await this.getProjectId({\n fallback: () =>\n promptForProject({\n requiredPermissions: [\n {grant: 'read', permission: 'sanity.project.datasets'},\n {grant: 'update', permission: 'sanity.project.datasets'},\n ],\n }),\n })\n\n let datasets: DatasetsResponse\n\n try {\n datasets = await listDatasets(projectId)\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error)\n enableBackupDebug(`Failed to list datasets: ${message}`, error)\n this.error(`Failed to list datasets: ${message}`, {exit: 1})\n }\n\n const hasProduction = datasets.some((dataset) => dataset.name === 'production')\n\n if (datasets.length === 0) {\n this.error('No datasets found in this project.', {exit: 1})\n }\n\n if (dataset) {\n assertDatasetExists(datasets, dataset)\n } else {\n dataset = await promptForDataset({allowCreation: true, datasets})\n\n if (dataset === NEW_DATASET_VALUE) {\n const newDatasetName = await promptForDatasetName({\n default: hasProduction ? undefined : 'production',\n })\n\n try {\n await createDataset({\n datasetName: newDatasetName,\n projectId,\n })\n dataset = newDatasetName\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error)\n enableBackupDebug(`Failed to create dataset ${newDatasetName}: ${message}`, error)\n this.error(`Failed to create dataset ${newDatasetName}: ${message}`, {exit: 1})\n }\n }\n }\n\n try {\n await setBackup({dataset, projectId, status: true})\n\n this.log(\n `${styleText(\n 'green',\n `Enabled backups for dataset ${dataset}.\\nPlease note that it may take up to 24 hours before the first backup is created.\\n`,\n )}`,\n )\n\n this.log(\n `${styleText('bold', `Retention policies may apply depending on your plan and agreement.\\n`)}`,\n )\n\n enableBackupDebug(`Successfully enabled backup for dataset ${dataset}`)\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error)\n enableBackupDebug(`Failed to enable backup for dataset`, error)\n this.error(`Enabling dataset backup failed: ${message}`, {exit: 1})\n }\n }\n}\n"],"names":["styleText","Args","SanityCommand","subdebug","assertDatasetExists","NEW_DATASET_VALUE","promptForDataset","promptForDatasetName","promptForProject","setBackup","createDataset","listDatasets","getProjectIdFlag","enableBackupDebug","EnableBackupCommand","args","dataset","string","description","required","examples","command","flags","semantics","hiddenAliases","run","parse","projectId","getProjectId","fallback","requiredPermissions","grant","permission","datasets","error","message","Error","String","exit","hasProduction","some","name","length","allowCreation","newDatasetName","default","undefined","datasetName","status","log"],"mappings":"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"}
|
|
@@ -20,7 +20,7 @@ export class ListBackupCommand extends SanityCommand {
|
|
|
20
20
|
required: false
|
|
21
21
|
})
|
|
22
22
|
};
|
|
23
|
-
static description = 'List available backups for a dataset
|
|
23
|
+
static description = 'List available backups for a dataset';
|
|
24
24
|
static examples = [
|
|
25
25
|
{
|
|
26
26
|
command: '<%= config.bin %> <%= command.id %>',
|