@sanity/cli 8.22.0 → 8.22.1

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.
@@ -16,21 +16,12 @@ const debug = subdebug('deployStudioSchemasAndManifests.worker');
16
16
  */ export async function deployStudioSchemasAndManifestsWorker(port, workerData) {
17
17
  const parsedWorkerData = deployStudioSchemasAndManifestsWorkerData.parse(workerData);
18
18
  const options = parsedWorkerData;
19
- options.workspaceManifestsHandler = async (workspaceManifests)=>{
20
- if (!options.isExternal || parsedWorkerData.schemaRequired) {
21
- const schemaInputs = workspaceManifests.map((manifest)=>({
22
- dataset: manifest.dataset,
23
- manifestSchema: manifest.schema,
24
- name: manifest.name,
25
- projectId: manifest.projectId,
26
- title: manifest.title
27
- }));
28
- // Updates the workspaces schemas to /schemas endpoint
29
- await updateWorkspacesSchemas({
30
- verbose: options.verbose,
31
- workspaces: schemaInputs
32
- });
33
- }
19
+ options.workspaceSchemaHandler = async (schemaInputs)=>{
20
+ // Updates the workspaces schemas to /schemas endpoint
21
+ await updateWorkspacesSchemas({
22
+ verbose: options.verbose,
23
+ workspaces: schemaInputs
24
+ });
34
25
  };
35
26
  try {
36
27
  const result = await workerBuildStudioSchemasAndManifests(options);
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/actions/deploy/deployStudioSchemasAndManifestsWorker.ts"],"sourcesContent":["import {\n extractValidationFromSchemaError,\n workerBuildStudioSchemasAndManifests,\n} from '@sanity/cli-build/_internal/extract'\nimport {type CreateWorkspaceManifest} from '@sanity/cli-build/_internal/manifest'\nimport {subdebug} from '@sanity/cli-core'\n\nimport {\n updateWorkspacesSchemas,\n type WorkspaceSchemaInput,\n} from '../schema/updateWorkspaceSchema.js'\nimport {\n deployStudioSchemasAndManifestsWorkerData,\n type DeployStudioSchemasAndManifestsWorkerMessage,\n} from './types.js'\n\nconst debug = subdebug('deployStudioSchemasAndManifests.worker')\n\n/**\n * The subset of `MessagePort` this worker needs, so the body can be driven\n * without a real thread.\n */\nexport interface DeployStudioSchemasAndManifestsPort {\n postMessage: (message: DeployStudioSchemasAndManifestsWorkerMessage) => void\n}\n\n/**\n * Body of `deployStudioSchemasAndManifests.worker.ts`, kept out of the thread entry point so it\n * can be exercised directly in tests.\n *\n * 1. Validates the worker data\n * 2. Builds the studio schemas and manifests, updating the `/schemas` endpoint along the way\n * 3. Posts either the resulting studio manifest or a serialized error back to the parent\n *\n * @param port - The port to post the result to\n * @param workerData - The unvalidated worker data handed to the worker\n */\nexport async function deployStudioSchemasAndManifestsWorker(\n port: DeployStudioSchemasAndManifestsPort,\n workerData: unknown,\n): Promise<void> {\n const parsedWorkerData = deployStudioSchemasAndManifestsWorkerData.parse(workerData)\n\n const options: Parameters<typeof workerBuildStudioSchemasAndManifests>[0] = parsedWorkerData\n\n options.workspaceManifestsHandler = async (workspaceManifests: CreateWorkspaceManifest[]) => {\n if (!options.isExternal || parsedWorkerData.schemaRequired) {\n const schemaInputs: WorkspaceSchemaInput[] = workspaceManifests.map((manifest) => ({\n dataset: manifest.dataset,\n manifestSchema: manifest.schema,\n name: manifest.name,\n projectId: manifest.projectId,\n title: manifest.title,\n }))\n\n // Updates the workspaces schemas to /schemas endpoint\n await updateWorkspacesSchemas({verbose: options.verbose, workspaces: schemaInputs})\n }\n }\n\n try {\n const result = await workerBuildStudioSchemasAndManifests(options)\n\n port.postMessage({\n studioManifest: result.studioManifest,\n type: 'success',\n })\n } catch (error) {\n debug('Error deploying studio schemas and manifests', error)\n const validation = await extractValidationFromSchemaError(error, options.workDir)\n port.postMessage({\n error: error instanceof Error ? error.message : String(error),\n type: 'error',\n validation,\n })\n }\n}\n"],"names":["extractValidationFromSchemaError","workerBuildStudioSchemasAndManifests","subdebug","updateWorkspacesSchemas","deployStudioSchemasAndManifestsWorkerData","debug","deployStudioSchemasAndManifestsWorker","port","workerData","parsedWorkerData","parse","options","workspaceManifestsHandler","workspaceManifests","isExternal","schemaRequired","schemaInputs","map","manifest","dataset","manifestSchema","schema","name","projectId","title","verbose","workspaces","result","postMessage","studioManifest","type","error","validation","workDir","Error","message","String"],"mappings":"AAAA,SACEA,gCAAgC,EAChCC,oCAAoC,QAC/B,sCAAqC;AAE5C,SAAQC,QAAQ,QAAO,mBAAkB;AAEzC,SACEC,uBAAuB,QAElB,qCAAoC;AAC3C,SACEC,yCAAyC,QAEpC,aAAY;AAEnB,MAAMC,QAAQH,SAAS;AAUvB;;;;;;;;;;CAUC,GACD,OAAO,eAAeI,sCACpBC,IAAyC,EACzCC,UAAmB;IAEnB,MAAMC,mBAAmBL,0CAA0CM,KAAK,CAACF;IAEzE,MAAMG,UAAsEF;IAE5EE,QAAQC,yBAAyB,GAAG,OAAOC;QACzC,IAAI,CAACF,QAAQG,UAAU,IAAIL,iBAAiBM,cAAc,EAAE;YAC1D,MAAMC,eAAuCH,mBAAmBI,GAAG,CAAC,CAACC,WAAc,CAAA;oBACjFC,SAASD,SAASC,OAAO;oBACzBC,gBAAgBF,SAASG,MAAM;oBAC/BC,MAAMJ,SAASI,IAAI;oBACnBC,WAAWL,SAASK,SAAS;oBAC7BC,OAAON,SAASM,KAAK;gBACvB,CAAA;YAEA,sDAAsD;YACtD,MAAMrB,wBAAwB;gBAACsB,SAASd,QAAQc,OAAO;gBAAEC,YAAYV;YAAY;QACnF;IACF;IAEA,IAAI;QACF,MAAMW,SAAS,MAAM1B,qCAAqCU;QAE1DJ,KAAKqB,WAAW,CAAC;YACfC,gBAAgBF,OAAOE,cAAc;YACrCC,MAAM;QACR;IACF,EAAE,OAAOC,OAAO;QACd1B,MAAM,gDAAgD0B;QACtD,MAAMC,aAAa,MAAMhC,iCAAiC+B,OAAOpB,QAAQsB,OAAO;QAChF1B,KAAKqB,WAAW,CAAC;YACfG,OAAOA,iBAAiBG,QAAQH,MAAMI,OAAO,GAAGC,OAAOL;YACvDD,MAAM;YACNE;QACF;IACF;AACF"}
1
+ {"version":3,"sources":["../../../src/actions/deploy/deployStudioSchemasAndManifestsWorker.ts"],"sourcesContent":["import {\n extractValidationFromSchemaError,\n workerBuildStudioSchemasAndManifests,\n} from '@sanity/cli-build/_internal/extract'\nimport {subdebug} from '@sanity/cli-core'\n\nimport {updateWorkspacesSchemas} from '../schema/updateWorkspaceSchema.js'\nimport {\n deployStudioSchemasAndManifestsWorkerData,\n type DeployStudioSchemasAndManifestsWorkerMessage,\n} from './types.js'\n\nconst debug = subdebug('deployStudioSchemasAndManifests.worker')\n\n/**\n * The subset of `MessagePort` this worker needs, so the body can be driven\n * without a real thread.\n */\nexport interface DeployStudioSchemasAndManifestsPort {\n postMessage: (message: DeployStudioSchemasAndManifestsWorkerMessage) => void\n}\n\n/**\n * Body of `deployStudioSchemasAndManifests.worker.ts`, kept out of the thread entry point so it\n * can be exercised directly in tests.\n *\n * 1. Validates the worker data\n * 2. Builds the studio schemas and manifests, updating the `/schemas` endpoint along the way\n * 3. Posts either the resulting studio manifest or a serialized error back to the parent\n *\n * @param port - The port to post the result to\n * @param workerData - The unvalidated worker data handed to the worker\n */\nexport async function deployStudioSchemasAndManifestsWorker(\n port: DeployStudioSchemasAndManifestsPort,\n workerData: unknown,\n): Promise<void> {\n const parsedWorkerData = deployStudioSchemasAndManifestsWorkerData.parse(workerData)\n\n const options: Parameters<typeof workerBuildStudioSchemasAndManifests>[0] = parsedWorkerData\n\n options.workspaceSchemaHandler = async (schemaInputs) => {\n // Updates the workspaces schemas to /schemas endpoint\n await updateWorkspacesSchemas({verbose: options.verbose, workspaces: schemaInputs})\n }\n\n try {\n const result = await workerBuildStudioSchemasAndManifests(options)\n\n port.postMessage({\n studioManifest: result.studioManifest,\n type: 'success',\n })\n } catch (error) {\n debug('Error deploying studio schemas and manifests', error)\n const validation = await extractValidationFromSchemaError(error, options.workDir)\n port.postMessage({\n error: error instanceof Error ? error.message : String(error),\n type: 'error',\n validation,\n })\n }\n}\n"],"names":["extractValidationFromSchemaError","workerBuildStudioSchemasAndManifests","subdebug","updateWorkspacesSchemas","deployStudioSchemasAndManifestsWorkerData","debug","deployStudioSchemasAndManifestsWorker","port","workerData","parsedWorkerData","parse","options","workspaceSchemaHandler","schemaInputs","verbose","workspaces","result","postMessage","studioManifest","type","error","validation","workDir","Error","message","String"],"mappings":"AAAA,SACEA,gCAAgC,EAChCC,oCAAoC,QAC/B,sCAAqC;AAC5C,SAAQC,QAAQ,QAAO,mBAAkB;AAEzC,SAAQC,uBAAuB,QAAO,qCAAoC;AAC1E,SACEC,yCAAyC,QAEpC,aAAY;AAEnB,MAAMC,QAAQH,SAAS;AAUvB;;;;;;;;;;CAUC,GACD,OAAO,eAAeI,sCACpBC,IAAyC,EACzCC,UAAmB;IAEnB,MAAMC,mBAAmBL,0CAA0CM,KAAK,CAACF;IAEzE,MAAMG,UAAsEF;IAE5EE,QAAQC,sBAAsB,GAAG,OAAOC;QACtC,sDAAsD;QACtD,MAAMV,wBAAwB;YAACW,SAASH,QAAQG,OAAO;YAAEC,YAAYF;QAAY;IACnF;IAEA,IAAI;QACF,MAAMG,SAAS,MAAMf,qCAAqCU;QAE1DJ,KAAKU,WAAW,CAAC;YACfC,gBAAgBF,OAAOE,cAAc;YACrCC,MAAM;QACR;IACF,EAAE,OAAOC,OAAO;QACdf,MAAM,gDAAgDe;QACtD,MAAMC,aAAa,MAAMrB,iCAAiCoB,OAAOT,QAAQW,OAAO;QAChFf,KAAKU,WAAW,CAAC;YACfG,OAAOA,iBAAiBG,QAAQH,MAAMI,OAAO,GAAGC,OAAOL;YACvDD,MAAM;YACNE;QACF;IACF;AACF"}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/actions/schema/deploySchemas.ts"],"sourcesContent":["import {SchemaExtractionError} from '@sanity/cli-build/_internal/extract'\nimport {type ManifestSchemaType} from '@sanity/cli-build/_internal/manifest'\nimport {studioWorkerTask} from '@sanity/cli-core'\nimport {type SchemaValidationProblemGroup} from '@sanity/types'\nimport {type Workspace} from 'sanity'\n\nimport {type ExtractWorkspaceWorkerData} from './types.js'\nimport {updateWorkspacesSchemas, type WorkspaceSchemaInput} from './updateWorkspaceSchema.js'\n\ninterface DeploySchemasOptions {\n verbose: boolean\n workDir: string\n\n tag?: string\n workspaceName?: string\n}\n\ntype WorkspaceWithManifest = Workspace & {manifestSchema: ManifestSchemaType[]}\n\ntype ExtractWorkspaceWorkerMessage =\n | {\n error: string\n type: 'error'\n validation?: SchemaValidationProblemGroup[]\n }\n | {\n type: 'success'\n workspaces: WorkspaceWithManifest[]\n }\n\nexport async function deploySchemas(options: DeploySchemasOptions): Promise<void> {\n const {tag, verbose, workDir, workspaceName} = options\n\n const result = await studioWorkerTask<ExtractWorkspaceWorkerMessage>(\n new URL('extractSanityWorkspace.worker.js', import.meta.url),\n {\n name: 'extractSanityWorkspace',\n studioRootPath: workDir,\n workerData: {\n configPath: workDir,\n workDir,\n } satisfies ExtractWorkspaceWorkerData,\n },\n )\n\n if (result.type === 'error') {\n throw new SchemaExtractionError(result.error, result.validation)\n }\n\n const workspaces: WorkspaceSchemaInput[] = result.workspaces\n .filter((workspace) => !workspaceName || workspace.name === workspaceName)\n .map((workspace) => ({\n dataset: workspace.dataset,\n manifestSchema: workspace.manifestSchema,\n name: workspace.name,\n projectId: workspace.projectId,\n title: workspace.title,\n }))\n\n if (workspaces.length === 0) {\n const error = workspaceName\n ? new Error(`Found no workspaces named \"${workspaceName}\"`)\n : new Error('No workspaces found')\n throw error\n }\n\n await updateWorkspacesSchemas({\n tag,\n verbose,\n workspaces,\n })\n}\n"],"names":["SchemaExtractionError","studioWorkerTask","updateWorkspacesSchemas","deploySchemas","options","tag","verbose","workDir","workspaceName","result","URL","url","name","studioRootPath","workerData","configPath","type","error","validation","workspaces","filter","workspace","map","dataset","manifestSchema","projectId","title","length","Error"],"mappings":"AAAA,SAAQA,qBAAqB,QAAO,sCAAqC;AAEzE,SAAQC,gBAAgB,QAAO,mBAAkB;AAKjD,SAAQC,uBAAuB,QAAkC,6BAA4B;AAuB7F,OAAO,eAAeC,cAAcC,OAA6B;IAC/D,MAAM,EAACC,GAAG,EAAEC,OAAO,EAAEC,OAAO,EAAEC,aAAa,EAAC,GAAGJ;IAE/C,MAAMK,SAAS,MAAMR,iBACnB,IAAIS,IAAI,oCAAoC,YAAYC,GAAG,GAC3D;QACEC,MAAM;QACNC,gBAAgBN;QAChBO,YAAY;YACVC,YAAYR;YACZA;QACF;IACF;IAGF,IAAIE,OAAOO,IAAI,KAAK,SAAS;QAC3B,MAAM,IAAIhB,sBAAsBS,OAAOQ,KAAK,EAAER,OAAOS,UAAU;IACjE;IAEA,MAAMC,aAAqCV,OAAOU,UAAU,CACzDC,MAAM,CAAC,CAACC,YAAc,CAACb,iBAAiBa,UAAUT,IAAI,KAAKJ,eAC3Dc,GAAG,CAAC,CAACD,YAAe,CAAA;YACnBE,SAASF,UAAUE,OAAO;YAC1BC,gBAAgBH,UAAUG,cAAc;YACxCZ,MAAMS,UAAUT,IAAI;YACpBa,WAAWJ,UAAUI,SAAS;YAC9BC,OAAOL,UAAUK,KAAK;QACxB,CAAA;IAEF,IAAIP,WAAWQ,MAAM,KAAK,GAAG;QAC3B,MAAMV,QAAQT,gBACV,IAAIoB,MAAM,CAAC,2BAA2B,EAAEpB,cAAc,CAAC,CAAC,IACxD,IAAIoB,MAAM;QACd,MAAMX;IACR;IAEA,MAAMf,wBAAwB;QAC5BG;QACAC;QACAa;IACF;AACF"}
1
+ {"version":3,"sources":["../../../src/actions/schema/deploySchemas.ts"],"sourcesContent":["import {SchemaExtractionError} from '@sanity/cli-build/_internal/extract'\nimport {\n type ManifestSchemaType,\n type WorkspaceSchemaInput,\n} from '@sanity/cli-build/_internal/manifest'\nimport {studioWorkerTask} from '@sanity/cli-core'\nimport {type SchemaValidationProblemGroup} from '@sanity/types'\nimport {type Workspace} from 'sanity'\n\nimport {type ExtractWorkspaceWorkerData} from './types.js'\nimport {updateWorkspacesSchemas} from './updateWorkspaceSchema.js'\n\ninterface DeploySchemasOptions {\n verbose: boolean\n workDir: string\n\n tag?: string\n workspaceName?: string\n}\n\ntype WorkspaceWithManifest = Workspace & {manifestSchema: ManifestSchemaType[]}\n\ntype ExtractWorkspaceWorkerMessage =\n | {\n error: string\n type: 'error'\n validation?: SchemaValidationProblemGroup[]\n }\n | {\n type: 'success'\n workspaces: WorkspaceWithManifest[]\n }\n\nexport async function deploySchemas(options: DeploySchemasOptions): Promise<void> {\n const {tag, verbose, workDir, workspaceName} = options\n\n const result = await studioWorkerTask<ExtractWorkspaceWorkerMessage>(\n new URL('extractSanityWorkspace.worker.js', import.meta.url),\n {\n name: 'extractSanityWorkspace',\n studioRootPath: workDir,\n workerData: {\n configPath: workDir,\n workDir,\n } satisfies ExtractWorkspaceWorkerData,\n },\n )\n\n if (result.type === 'error') {\n throw new SchemaExtractionError(result.error, result.validation)\n }\n\n const workspaces: WorkspaceSchemaInput[] = result.workspaces\n .filter((workspace) => !workspaceName || workspace.name === workspaceName)\n .map((workspace) => ({\n dataset: workspace.dataset,\n manifestSchema: workspace.manifestSchema,\n name: workspace.name,\n projectId: workspace.projectId,\n title: workspace.title,\n }))\n\n if (workspaces.length === 0) {\n const error = workspaceName\n ? new Error(`Found no workspaces named \"${workspaceName}\"`)\n : new Error('No workspaces found')\n throw error\n }\n\n await updateWorkspacesSchemas({\n tag,\n verbose,\n workspaces,\n })\n}\n"],"names":["SchemaExtractionError","studioWorkerTask","updateWorkspacesSchemas","deploySchemas","options","tag","verbose","workDir","workspaceName","result","URL","url","name","studioRootPath","workerData","configPath","type","error","validation","workspaces","filter","workspace","map","dataset","manifestSchema","projectId","title","length","Error"],"mappings":"AAAA,SAAQA,qBAAqB,QAAO,sCAAqC;AAKzE,SAAQC,gBAAgB,QAAO,mBAAkB;AAKjD,SAAQC,uBAAuB,QAAO,6BAA4B;AAuBlE,OAAO,eAAeC,cAAcC,OAA6B;IAC/D,MAAM,EAACC,GAAG,EAAEC,OAAO,EAAEC,OAAO,EAAEC,aAAa,EAAC,GAAGJ;IAE/C,MAAMK,SAAS,MAAMR,iBACnB,IAAIS,IAAI,oCAAoC,YAAYC,GAAG,GAC3D;QACEC,MAAM;QACNC,gBAAgBN;QAChBO,YAAY;YACVC,YAAYR;YACZA;QACF;IACF;IAGF,IAAIE,OAAOO,IAAI,KAAK,SAAS;QAC3B,MAAM,IAAIhB,sBAAsBS,OAAOQ,KAAK,EAAER,OAAOS,UAAU;IACjE;IAEA,MAAMC,aAAqCV,OAAOU,UAAU,CACzDC,MAAM,CAAC,CAACC,YAAc,CAACb,iBAAiBa,UAAUT,IAAI,KAAKJ,eAC3Dc,GAAG,CAAC,CAACD,YAAe,CAAA;YACnBE,SAASF,UAAUE,OAAO;YAC1BC,gBAAgBH,UAAUG,cAAc;YACxCZ,MAAMS,UAAUT,IAAI;YACpBa,WAAWJ,UAAUI,SAAS;YAC9BC,OAAOL,UAAUK,KAAK;QACxB,CAAA;IAEF,IAAIP,WAAWQ,MAAM,KAAK,GAAG;QAC3B,MAAMV,QAAQT,gBACV,IAAIoB,MAAM,CAAC,2BAA2B,EAAEpB,cAAc,CAAC,CAAC,IACxD,IAAIoB,MAAM;QACd,MAAMX;IACR;IAEA,MAAMf,wBAAwB;QAC5BG;QACAC;QACAa;IACF;AACF"}
@@ -1,21 +1,64 @@
1
- import { dirname, isAbsolute, join, relative } from 'node:path';
1
+ import { basename, dirname, isAbsolute, relative, resolve } from 'node:path';
2
2
  import { createSchemaPatternMatcher, formatSchemaValidation, runSchemaExtraction, SchemaExtractionError } from '@sanity/cli-build/_internal/extract';
3
3
  import { exitCodes } from '@sanity/cli-core';
4
4
  import { spinner } from '@sanity/cli-core/ux';
5
5
  import { watch as chokidarWatch } from 'chokidar';
6
6
  import debounce from 'lodash-es/debounce.js';
7
+ import picomatch from 'picomatch';
7
8
  import { schemasExtractDebug } from './utils/debug.js';
8
9
  /** Default glob patterns to watch for schema changes */ export const DEFAULT_WATCH_PATTERNS = [
9
10
  'sanity.config.{js,jsx,ts,tsx,mjs}',
10
11
  'schema*/**/*.{js,jsx,ts,tsx,mjs}'
11
12
  ];
12
- /** Default patterns to ignore when watching */ const IGNORED_PATTERNS = [
13
- '**/node_modules/**',
14
- '**/.git/**',
15
- '**/dist/**',
16
- '**/lib/**',
17
- '**/.sanity/**'
18
- ];
13
+ /**
14
+ * Directory names never descended into, unless a watch pattern names one directly. chokidar 4 and
15
+ * later reject glob `ignored` patterns, so this matches on the directory name alone.
16
+ */ const IGNORED_DIRECTORIES = new Set([
17
+ '.astro',
18
+ '.cache',
19
+ '.git',
20
+ '.next',
21
+ '.nuxt',
22
+ '.output',
23
+ '.sanity',
24
+ '.svelte-kit',
25
+ '.turbo',
26
+ '.vercel',
27
+ 'build',
28
+ 'coverage',
29
+ 'dist',
30
+ 'lib',
31
+ 'node_modules',
32
+ 'out'
33
+ ]);
34
+ /**
35
+ * Returns `pattern` relative to `workDir` with forward slashes, so one string can feed both the
36
+ * base scan and the matcher. A pattern with no glob characters names a file or a directory, and a
37
+ * directory matches everything inside it.
38
+ */ function normalizeWatchPattern(pattern, workDir) {
39
+ const normalized = relative(workDir, resolve(workDir, pattern)).replaceAll('\\', '/');
40
+ if (!normalized) return [
41
+ '**'
42
+ ];
43
+ return picomatch.scan(normalized).isGlob ? [
44
+ normalized
45
+ ] : [
46
+ normalized,
47
+ `${normalized}/**`
48
+ ];
49
+ }
50
+ /**
51
+ * Returns the directories to hand chokidar for `patterns`, deduplicated.
52
+ *
53
+ * chokidar 4 and later do not expand globs, so a pattern cannot be watched directly: it has to
54
+ * be reduced to its static base directory, with `isMatch` filtering the events that base emits.
55
+ * Both default patterns begin with a glob segment, so both reduce to `workDir` itself.
56
+ */ function watchRootsFor(patterns, workDir) {
57
+ const bases = patterns.map((pattern)=>resolve(workDir, picomatch.scan(pattern).base));
58
+ return [
59
+ ...new Set(bases)
60
+ ];
61
+ }
19
62
  /**
20
63
  * Creates an extraction runner with concurrency control.
21
64
  * If extraction is already running, queues one more extraction to run after completion.
@@ -90,7 +133,6 @@ import { schemasExtractDebug } from './utils/debug.js';
90
133
  };
91
134
  // Run initial extraction
92
135
  await runExtraction();
93
- const absoluteWatchPatterns = watchPatterns.map((pattern)=>join(workDir, pattern));
94
136
  // Create extraction runner with concurrency control
95
137
  const { runExtraction: runConcurrentExtraction } = createExtractionRunner(async ()=>{
96
138
  await runExtraction();
@@ -99,14 +141,23 @@ import { schemasExtractDebug } from './utils/debug.js';
99
141
  const debouncedExtract = debounce(()=>{
100
142
  void runConcurrentExtraction();
101
143
  }, 1000);
102
- const { isMatch } = createSchemaPatternMatcher(watchPatterns);
103
- const watcher = chokidarWatch(absoluteWatchPatterns, {
144
+ const normalizedPatterns = watchPatterns.flatMap((pattern)=>normalizeWatchPattern(pattern, workDir));
145
+ const { isMatch } = createSchemaPatternMatcher(normalizedPatterns);
146
+ const watchRoots = watchRootsFor(normalizedPatterns, workDir);
147
+ // A pattern can name a directory this would otherwise skip, such as the documented
148
+ // `--watch-patterns "lib/**/*.ts"`. chokidar asks about each root before descending, so
149
+ // skipping one there would leave it unwatched and silently match nothing.
150
+ const watchRootSet = new Set(watchRoots);
151
+ // Every extraction rewrites this file. Watching it would make each run trigger the next.
152
+ const outputFile = resolve(workDir, outputPath).toLowerCase();
153
+ const isOutputFile = (path)=>resolve(workDir, path).toLowerCase() === outputFile;
154
+ const watcher = chokidarWatch(watchRoots, {
104
155
  cwd: workDir,
105
- ignored: IGNORED_PATTERNS,
156
+ ignored: (path)=>isOutputFile(path) || !watchRootSet.has(resolve(workDir, path)) && IGNORED_DIRECTORIES.has(basename(path)),
106
157
  ignoreInitial: true
107
158
  });
108
159
  watcher.on('all', (event, filePath)=>{
109
- if (!isMatch(filePath, workDir)) {
160
+ if (isOutputFile(filePath) || !isMatch(filePath, workDir)) {
110
161
  return;
111
162
  }
112
163
  const timestamp = new Date().toLocaleTimeString();
@@ -115,7 +166,11 @@ import { schemasExtractDebug } from './utils/debug.js';
115
166
  debouncedExtract();
116
167
  });
117
168
  watcher.on('error', (err)=>{
118
- output.error(`Watcher error: ${err instanceof Error ? err.message : String(err)}`);
169
+ // `output.error` throws unless told not to exit. A watch session should survive a transient
170
+ // fs error such as EMFILE or an inotify limit, the way the typegen watcher does.
171
+ output.error(`Watcher error: ${err instanceof Error ? err.message : String(err)}`, {
172
+ exit: false
173
+ });
119
174
  });
120
175
  return {
121
176
  close: ()=>watcher.close(),
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/actions/schema/extractSchemaWatcher.ts"],"sourcesContent":["import {dirname, isAbsolute, join, relative} from 'node:path'\n\nimport {\n createSchemaPatternMatcher,\n type ExtractOptions,\n formatSchemaValidation,\n runSchemaExtraction,\n SchemaExtractionError,\n} from '@sanity/cli-build/_internal/extract'\nimport {exitCodes, type Output} from '@sanity/cli-core'\nimport {spinner} from '@sanity/cli-core/ux'\nimport {watch as chokidarWatch, type FSWatcher} from 'chokidar'\nimport debounce from 'lodash-es/debounce.js'\n\nimport {schemasExtractDebug} from './utils/debug.js'\n\n/** Default glob patterns to watch for schema changes */\nexport const DEFAULT_WATCH_PATTERNS = [\n 'sanity.config.{js,jsx,ts,tsx,mjs}',\n 'schema*/**/*.{js,jsx,ts,tsx,mjs}',\n]\n\n/** Default patterns to ignore when watching */\nconst IGNORED_PATTERNS = [\n '**/node_modules/**',\n '**/.git/**',\n '**/dist/**',\n '**/lib/**',\n '**/.sanity/**',\n]\n\ninterface ExtractSchemaWatcherOptions {\n extractOptions: ExtractOptions\n output: Output\n watchPatterns: string[]\n\n onExtraction?: (result: {duration: number; success: boolean}) => void\n}\n\ninterface ExtractSchemaWatcher {\n close: () => Promise<void>\n watcher: FSWatcher\n}\n\n/** State for tracking extraction status */\ninterface WatchState {\n isExtracting: boolean\n pendingExtraction: boolean\n}\n\n/** Return type for createExtractionRunner */\ninterface ExtractionRunner {\n runExtraction: () => Promise<void>\n state: WatchState\n}\n\n/**\n * Creates an extraction runner with concurrency control.\n * If extraction is already running, queues one more extraction to run after completion.\n * Multiple queued requests are coalesced into a single pending extraction.\n */\nfunction createExtractionRunner(onExtract: () => Promise<void>): ExtractionRunner {\n const state: WatchState = {\n isExtracting: false,\n pendingExtraction: false,\n }\n\n async function runExtraction(): Promise<void> {\n if (state.isExtracting) {\n state.pendingExtraction = true\n return\n }\n\n state.isExtracting = true\n state.pendingExtraction = false\n\n try {\n await onExtract()\n } finally {\n state.isExtracting = false\n\n // If a change came in during extraction, run again\n if (state.pendingExtraction) {\n state.pendingExtraction = false\n await runExtraction()\n }\n }\n }\n\n return {runExtraction, state}\n}\n\n/**\n * Starts a schema watcher that extracts schema on file changes.\n * Returns a watcher instance and a stop function.\n */\nexport async function startExtractSchemaWatcher(\n options: ExtractSchemaWatcherOptions,\n): Promise<ExtractSchemaWatcher> {\n const {extractOptions, onExtraction, output, watchPatterns} = options\n\n const {configPath, enforceRequiredFields, outputPath} = extractOptions\n const workDir = dirname(configPath)\n\n // Helper function to run extraction with spinner and error handling\n const runExtraction = async (): Promise<boolean> => {\n const spin = spinner(\n enforceRequiredFields\n ? 'Extracting schema with enforced required fields'\n : 'Extracting schema...',\n ).start()\n const extractionStartTime = Date.now()\n\n try {\n await runSchemaExtraction(extractOptions)\n\n spin.succeed(\n enforceRequiredFields\n ? `Extracted schema to ${outputPath} with enforced required fields`\n : `Extracted schema to ${outputPath}`,\n )\n\n const duration = Date.now() - extractionStartTime\n onExtraction?.({duration, success: true})\n\n return true\n } catch (err) {\n const duration = Date.now() - extractionStartTime\n onExtraction?.({duration, success: false})\n\n schemasExtractDebug('Failed to extract schema', err)\n spin.fail('Extraction failed')\n\n // Display validation errors if available\n if (err instanceof SchemaExtractionError && err.validation && err.validation.length > 0) {\n output.log('')\n output.log(formatSchemaValidation(err.validation))\n } else if (err instanceof Error) {\n output.error(err.message, {exit: exitCodes.RUNTIME_ERROR})\n }\n\n return false\n }\n }\n\n // Run initial extraction\n await runExtraction()\n\n const absoluteWatchPatterns = watchPatterns.map((pattern) => join(workDir, pattern))\n\n // Create extraction runner with concurrency control\n const {runExtraction: runConcurrentExtraction} = createExtractionRunner(async () => {\n await runExtraction()\n })\n\n // Debounced extraction trigger (1 second delay)\n const debouncedExtract = debounce(() => {\n void runConcurrentExtraction()\n }, 1000)\n\n const {isMatch} = createSchemaPatternMatcher(watchPatterns)\n\n const watcher: FSWatcher = chokidarWatch(absoluteWatchPatterns, {\n cwd: workDir,\n ignored: IGNORED_PATTERNS,\n ignoreInitial: true,\n })\n\n watcher.on('all', (event, filePath) => {\n if (!isMatch(filePath, workDir)) {\n return\n }\n\n const timestamp = new Date().toLocaleTimeString()\n const relativePath = isAbsolute(filePath) ? relative(workDir, filePath) : filePath\n output.log(`[${timestamp}] ${event}: ${relativePath}`)\n debouncedExtract()\n })\n\n watcher.on('error', (err) => {\n output.error(`Watcher error: ${err instanceof Error ? err.message : String(err)}`)\n })\n\n return {\n close: () => watcher.close(),\n watcher,\n }\n}\n"],"names":["dirname","isAbsolute","join","relative","createSchemaPatternMatcher","formatSchemaValidation","runSchemaExtraction","SchemaExtractionError","exitCodes","spinner","watch","chokidarWatch","debounce","schemasExtractDebug","DEFAULT_WATCH_PATTERNS","IGNORED_PATTERNS","createExtractionRunner","onExtract","state","isExtracting","pendingExtraction","runExtraction","startExtractSchemaWatcher","options","extractOptions","onExtraction","output","watchPatterns","configPath","enforceRequiredFields","outputPath","workDir","spin","start","extractionStartTime","Date","now","succeed","duration","success","err","fail","validation","length","log","Error","error","message","exit","RUNTIME_ERROR","absoluteWatchPatterns","map","pattern","runConcurrentExtraction","debouncedExtract","isMatch","watcher","cwd","ignored","ignoreInitial","on","event","filePath","timestamp","toLocaleTimeString","relativePath","String","close"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../src/actions/schema/extractSchemaWatcher.ts"],"sourcesContent":["import {basename, dirname, isAbsolute, relative, resolve} from 'node:path'\n\nimport {\n createSchemaPatternMatcher,\n type ExtractOptions,\n formatSchemaValidation,\n runSchemaExtraction,\n SchemaExtractionError,\n} from '@sanity/cli-build/_internal/extract'\nimport {exitCodes, type Output} from '@sanity/cli-core'\nimport {spinner} from '@sanity/cli-core/ux'\nimport {watch as chokidarWatch, type FSWatcher} from 'chokidar'\nimport debounce from 'lodash-es/debounce.js'\nimport picomatch from 'picomatch'\n\nimport {schemasExtractDebug} from './utils/debug.js'\n\n/** Default glob patterns to watch for schema changes */\nexport const DEFAULT_WATCH_PATTERNS = [\n 'sanity.config.{js,jsx,ts,tsx,mjs}',\n 'schema*/**/*.{js,jsx,ts,tsx,mjs}',\n]\n\n/**\n * Directory names never descended into, unless a watch pattern names one directly. chokidar 4 and\n * later reject glob `ignored` patterns, so this matches on the directory name alone.\n */\nconst IGNORED_DIRECTORIES = new Set([\n '.astro',\n '.cache',\n '.git',\n '.next',\n '.nuxt',\n '.output',\n '.sanity',\n '.svelte-kit',\n '.turbo',\n '.vercel',\n 'build',\n 'coverage',\n 'dist',\n 'lib',\n 'node_modules',\n 'out',\n])\n\n/**\n * Returns `pattern` relative to `workDir` with forward slashes, so one string can feed both the\n * base scan and the matcher. A pattern with no glob characters names a file or a directory, and a\n * directory matches everything inside it.\n */\nfunction normalizeWatchPattern(pattern: string, workDir: string): string[] {\n const normalized = relative(workDir, resolve(workDir, pattern)).replaceAll('\\\\', '/')\n if (!normalized) return ['**']\n return picomatch.scan(normalized).isGlob ? [normalized] : [normalized, `${normalized}/**`]\n}\n\n/**\n * Returns the directories to hand chokidar for `patterns`, deduplicated.\n *\n * chokidar 4 and later do not expand globs, so a pattern cannot be watched directly: it has to\n * be reduced to its static base directory, with `isMatch` filtering the events that base emits.\n * Both default patterns begin with a glob segment, so both reduce to `workDir` itself.\n */\nfunction watchRootsFor(patterns: string[], workDir: string): string[] {\n const bases = patterns.map((pattern) => resolve(workDir, picomatch.scan(pattern).base))\n return [...new Set(bases)]\n}\n\ninterface ExtractSchemaWatcherOptions {\n extractOptions: ExtractOptions\n output: Output\n watchPatterns: string[]\n\n onExtraction?: (result: {duration: number; success: boolean}) => void\n}\n\ninterface ExtractSchemaWatcher {\n close: () => Promise<void>\n watcher: FSWatcher\n}\n\n/** State for tracking extraction status */\ninterface WatchState {\n isExtracting: boolean\n pendingExtraction: boolean\n}\n\n/** Return type for createExtractionRunner */\ninterface ExtractionRunner {\n runExtraction: () => Promise<void>\n state: WatchState\n}\n\n/**\n * Creates an extraction runner with concurrency control.\n * If extraction is already running, queues one more extraction to run after completion.\n * Multiple queued requests are coalesced into a single pending extraction.\n */\nfunction createExtractionRunner(onExtract: () => Promise<void>): ExtractionRunner {\n const state: WatchState = {\n isExtracting: false,\n pendingExtraction: false,\n }\n\n async function runExtraction(): Promise<void> {\n if (state.isExtracting) {\n state.pendingExtraction = true\n return\n }\n\n state.isExtracting = true\n state.pendingExtraction = false\n\n try {\n await onExtract()\n } finally {\n state.isExtracting = false\n\n // If a change came in during extraction, run again\n if (state.pendingExtraction) {\n state.pendingExtraction = false\n await runExtraction()\n }\n }\n }\n\n return {runExtraction, state}\n}\n\n/**\n * Starts a schema watcher that extracts schema on file changes.\n * Returns a watcher instance and a stop function.\n */\nexport async function startExtractSchemaWatcher(\n options: ExtractSchemaWatcherOptions,\n): Promise<ExtractSchemaWatcher> {\n const {extractOptions, onExtraction, output, watchPatterns} = options\n\n const {configPath, enforceRequiredFields, outputPath} = extractOptions\n const workDir = dirname(configPath)\n\n // Helper function to run extraction with spinner and error handling\n const runExtraction = async (): Promise<boolean> => {\n const spin = spinner(\n enforceRequiredFields\n ? 'Extracting schema with enforced required fields'\n : 'Extracting schema...',\n ).start()\n const extractionStartTime = Date.now()\n\n try {\n await runSchemaExtraction(extractOptions)\n\n spin.succeed(\n enforceRequiredFields\n ? `Extracted schema to ${outputPath} with enforced required fields`\n : `Extracted schema to ${outputPath}`,\n )\n\n const duration = Date.now() - extractionStartTime\n onExtraction?.({duration, success: true})\n\n return true\n } catch (err) {\n const duration = Date.now() - extractionStartTime\n onExtraction?.({duration, success: false})\n\n schemasExtractDebug('Failed to extract schema', err)\n spin.fail('Extraction failed')\n\n // Display validation errors if available\n if (err instanceof SchemaExtractionError && err.validation && err.validation.length > 0) {\n output.log('')\n output.log(formatSchemaValidation(err.validation))\n } else if (err instanceof Error) {\n output.error(err.message, {exit: exitCodes.RUNTIME_ERROR})\n }\n\n return false\n }\n }\n\n // Run initial extraction\n await runExtraction()\n\n // Create extraction runner with concurrency control\n const {runExtraction: runConcurrentExtraction} = createExtractionRunner(async () => {\n await runExtraction()\n })\n\n // Debounced extraction trigger (1 second delay)\n const debouncedExtract = debounce(() => {\n void runConcurrentExtraction()\n }, 1000)\n\n const normalizedPatterns = watchPatterns.flatMap((pattern) =>\n normalizeWatchPattern(pattern, workDir),\n )\n const {isMatch} = createSchemaPatternMatcher(normalizedPatterns)\n\n const watchRoots = watchRootsFor(normalizedPatterns, workDir)\n // A pattern can name a directory this would otherwise skip, such as the documented\n // `--watch-patterns \"lib/**/*.ts\"`. chokidar asks about each root before descending, so\n // skipping one there would leave it unwatched and silently match nothing.\n const watchRootSet = new Set(watchRoots)\n // Every extraction rewrites this file. Watching it would make each run trigger the next.\n const outputFile = resolve(workDir, outputPath).toLowerCase()\n const isOutputFile = (path: string) => resolve(workDir, path).toLowerCase() === outputFile\n\n const watcher: FSWatcher = chokidarWatch(watchRoots, {\n cwd: workDir,\n ignored: (path) =>\n isOutputFile(path) ||\n (!watchRootSet.has(resolve(workDir, path)) && IGNORED_DIRECTORIES.has(basename(path))),\n ignoreInitial: true,\n })\n\n watcher.on('all', (event, filePath) => {\n if (isOutputFile(filePath) || !isMatch(filePath, workDir)) {\n return\n }\n\n const timestamp = new Date().toLocaleTimeString()\n const relativePath = isAbsolute(filePath) ? relative(workDir, filePath) : filePath\n output.log(`[${timestamp}] ${event}: ${relativePath}`)\n debouncedExtract()\n })\n\n watcher.on('error', (err) => {\n // `output.error` throws unless told not to exit. A watch session should survive a transient\n // fs error such as EMFILE or an inotify limit, the way the typegen watcher does.\n output.error(`Watcher error: ${err instanceof Error ? err.message : String(err)}`, {\n exit: false,\n })\n })\n\n return {\n close: () => watcher.close(),\n watcher,\n }\n}\n"],"names":["basename","dirname","isAbsolute","relative","resolve","createSchemaPatternMatcher","formatSchemaValidation","runSchemaExtraction","SchemaExtractionError","exitCodes","spinner","watch","chokidarWatch","debounce","picomatch","schemasExtractDebug","DEFAULT_WATCH_PATTERNS","IGNORED_DIRECTORIES","Set","normalizeWatchPattern","pattern","workDir","normalized","replaceAll","scan","isGlob","watchRootsFor","patterns","bases","map","base","createExtractionRunner","onExtract","state","isExtracting","pendingExtraction","runExtraction","startExtractSchemaWatcher","options","extractOptions","onExtraction","output","watchPatterns","configPath","enforceRequiredFields","outputPath","spin","start","extractionStartTime","Date","now","succeed","duration","success","err","fail","validation","length","log","Error","error","message","exit","RUNTIME_ERROR","runConcurrentExtraction","debouncedExtract","normalizedPatterns","flatMap","isMatch","watchRoots","watchRootSet","outputFile","toLowerCase","isOutputFile","path","watcher","cwd","ignored","has","ignoreInitial","on","event","filePath","timestamp","toLocaleTimeString","relativePath","String","close"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/actions/schema/updateWorkspaceSchema.ts"],"sourcesContent":["import {styleText} from 'node:util'\n\nimport {ux} from '@oclif/core/ux'\nimport {\n CURRENT_WORKSPACE_SCHEMA_VERSION,\n type ManifestSchemaType,\n type StoredWorkspaceSchema,\n} from '@sanity/cli-build/_internal/manifest'\nimport {spinner} from '@sanity/cli-core/ux'\nimport partition from 'lodash-es/partition.js'\n\nimport {updateSchemas} from '../../services/schemas.js'\nimport {SCHEMA_PERMISSION_HELP_TEXT} from './utils/schemaStoreValidation.js'\nimport {getWorkspaceSchemaId} from './utils/workspaceSchemaId.js'\n\n/**\n * Workspace metadata + pre-extracted manifest schema for deployment.\n * The schema must already be in ManifestSchemaType[] format (extracted from\n * the live Schema object before any structured clone boundary).\n */\nexport interface WorkspaceSchemaInput {\n dataset: string\n manifestSchema: ManifestSchemaType[]\n name: string\n projectId: string\n\n title?: string\n}\n\n/**\n * Updates the schemas for a list of workspaces.\n */\nexport async function updateWorkspacesSchemas(args: {\n tag?: string\n verbose: boolean\n workspaces: WorkspaceSchemaInput[]\n}) {\n const {tag, verbose, workspaces} = args\n\n /* Known caveat: we _don't_ rollback failed operations or partial success */\n const results = await Promise.allSettled(\n workspaces.map(async (workspace): Promise<void> => {\n await updateWorkspaceSchema({\n tag,\n verbose,\n workspace,\n })\n }),\n )\n\n const [fulfilledUpdates, rejectedUpdates] = partition(\n results,\n (result) => result.status === 'fulfilled',\n )\n\n if (rejectedUpdates.length > 0) {\n throw new Error(\n `Failed to deploy ${rejectedUpdates.length}/${workspaces.length} schemas. Successfully deployed ${fulfilledUpdates.length}/${workspaces.length} schemas.`,\n )\n }\n\n spinner(`Deployed ${fulfilledUpdates.length}/${workspaces.length} schemas`).succeed()\n}\n\n/**\n * Updates a workspace schema in the dataset.\n */\nasync function updateWorkspaceSchema(args: {\n tag?: string\n verbose: boolean\n workspace: WorkspaceSchemaInput\n}) {\n const {tag, verbose, workspace} = args\n\n const {dataset, manifestSchema, projectId} = workspace\n\n const {idWarning, safeBaseId: id} = getWorkspaceSchemaId({\n tag,\n workspaceName: workspace.name,\n })\n\n if (idWarning) ux.warn(idWarning)\n\n try {\n await updateSchemas<Omit<StoredWorkspaceSchema, '_id' | '_type'>[]>(dataset, projectId, [\n {\n // the API will stringify the schema – we send as JSON\n schema: manifestSchema,\n tag,\n version: CURRENT_WORKSPACE_SCHEMA_VERSION,\n workspace: {\n name: workspace.name,\n title: workspace.title,\n },\n },\n ])\n\n if (verbose) {\n ux.stdout(\n styleText('gray', `↳ schemaId: ${id}, projectId: ${projectId}, dataset: ${dataset}`),\n )\n }\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err)\n if (\n err instanceof Error &&\n 'statusCode' in err &&\n (err as {statusCode: unknown}).statusCode === 401\n ) {\n ux.warn(\n `↳ No permissions to write schema for workspace \"${workspace.name}\" in dataset \"${workspace.dataset}\". ${\n SCHEMA_PERMISSION_HELP_TEXT\n }:\\n ${styleText('red', message)}`,\n )\n } else {\n ux.stdout(\n styleText(\n 'red',\n `↳ Error deploying schema for workspace \"${workspace.name}\":\\n ${styleText('red', message)}`,\n ),\n )\n }\n\n throw err\n }\n}\n"],"names":["styleText","ux","CURRENT_WORKSPACE_SCHEMA_VERSION","spinner","partition","updateSchemas","SCHEMA_PERMISSION_HELP_TEXT","getWorkspaceSchemaId","updateWorkspacesSchemas","args","tag","verbose","workspaces","results","Promise","allSettled","map","workspace","updateWorkspaceSchema","fulfilledUpdates","rejectedUpdates","result","status","length","Error","succeed","dataset","manifestSchema","projectId","idWarning","safeBaseId","id","workspaceName","name","warn","schema","version","title","stdout","err","message","String","statusCode"],"mappings":"AAAA,SAAQA,SAAS,QAAO,YAAW;AAEnC,SAAQC,EAAE,QAAO,iBAAgB;AACjC,SACEC,gCAAgC,QAG3B,uCAAsC;AAC7C,SAAQC,OAAO,QAAO,sBAAqB;AAC3C,OAAOC,eAAe,yBAAwB;AAE9C,SAAQC,aAAa,QAAO,4BAA2B;AACvD,SAAQC,2BAA2B,QAAO,mCAAkC;AAC5E,SAAQC,oBAAoB,QAAO,+BAA8B;AAgBjE;;CAEC,GACD,OAAO,eAAeC,wBAAwBC,IAI7C;IACC,MAAM,EAACC,GAAG,EAAEC,OAAO,EAAEC,UAAU,EAAC,GAAGH;IAEnC,0EAA0E,GAC1E,MAAMI,UAAU,MAAMC,QAAQC,UAAU,CACtCH,WAAWI,GAAG,CAAC,OAAOC;QACpB,MAAMC,sBAAsB;YAC1BR;YACAC;YACAM;QACF;IACF;IAGF,MAAM,CAACE,kBAAkBC,gBAAgB,GAAGhB,UAC1CS,SACA,CAACQ,SAAWA,OAAOC,MAAM,KAAK;IAGhC,IAAIF,gBAAgBG,MAAM,GAAG,GAAG;QAC9B,MAAM,IAAIC,MACR,CAAC,iBAAiB,EAAEJ,gBAAgBG,MAAM,CAAC,CAAC,EAAEX,WAAWW,MAAM,CAAC,gCAAgC,EAAEJ,iBAAiBI,MAAM,CAAC,CAAC,EAAEX,WAAWW,MAAM,CAAC,SAAS,CAAC;IAE7J;IAEApB,QAAQ,CAAC,SAAS,EAAEgB,iBAAiBI,MAAM,CAAC,CAAC,EAAEX,WAAWW,MAAM,CAAC,QAAQ,CAAC,EAAEE,OAAO;AACrF;AAEA;;CAEC,GACD,eAAeP,sBAAsBT,IAIpC;IACC,MAAM,EAACC,GAAG,EAAEC,OAAO,EAAEM,SAAS,EAAC,GAAGR;IAElC,MAAM,EAACiB,OAAO,EAAEC,cAAc,EAAEC,SAAS,EAAC,GAAGX;IAE7C,MAAM,EAACY,SAAS,EAAEC,YAAYC,EAAE,EAAC,GAAGxB,qBAAqB;QACvDG;QACAsB,eAAef,UAAUgB,IAAI;IAC/B;IAEA,IAAIJ,WAAW5B,GAAGiC,IAAI,CAACL;IAEvB,IAAI;QACF,MAAMxB,cAA8DqB,SAASE,WAAW;YACtF;gBACE,sDAAsD;gBACtDO,QAAQR;gBACRjB;gBACA0B,SAASlC;gBACTe,WAAW;oBACTgB,MAAMhB,UAAUgB,IAAI;oBACpBI,OAAOpB,UAAUoB,KAAK;gBACxB;YACF;SACD;QAED,IAAI1B,SAAS;YACXV,GAAGqC,MAAM,CACPtC,UAAU,QAAQ,CAAC,YAAY,EAAE+B,GAAG,aAAa,EAAEH,UAAU,WAAW,EAAEF,SAAS;QAEvF;IACF,EAAE,OAAOa,KAAK;QACZ,MAAMC,UAAUD,eAAef,QAAQe,IAAIC,OAAO,GAAGC,OAAOF;QAC5D,IACEA,eAAef,SACf,gBAAgBe,OAChB,AAACA,IAA8BG,UAAU,KAAK,KAC9C;YACAzC,GAAGiC,IAAI,CACL,CAAC,gDAAgD,EAAEjB,UAAUgB,IAAI,CAAC,cAAc,EAAEhB,UAAUS,OAAO,CAAC,GAAG,EACrGpB,4BACD,KAAK,EAAEN,UAAU,OAAOwC,UAAU;QAEvC,OAAO;YACLvC,GAAGqC,MAAM,CACPtC,UACE,OACA,CAAC,wCAAwC,EAAEiB,UAAUgB,IAAI,CAAC,MAAM,EAAEjC,UAAU,OAAOwC,UAAU;QAGnG;QAEA,MAAMD;IACR;AACF"}
1
+ {"version":3,"sources":["../../../src/actions/schema/updateWorkspaceSchema.ts"],"sourcesContent":["import {styleText} from 'node:util'\n\nimport {ux} from '@oclif/core/ux'\nimport {\n CURRENT_WORKSPACE_SCHEMA_VERSION,\n type StoredWorkspaceSchema,\n type WorkspaceSchemaInput,\n} from '@sanity/cli-build/_internal/manifest'\nimport {spinner} from '@sanity/cli-core/ux'\nimport partition from 'lodash-es/partition.js'\n\nimport {updateSchemas} from '../../services/schemas.js'\nimport {SCHEMA_PERMISSION_HELP_TEXT} from './utils/schemaStoreValidation.js'\nimport {getWorkspaceSchemaId} from './utils/workspaceSchemaId.js'\n\n/**\n * Updates the schemas for a list of workspaces.\n */\nexport async function updateWorkspacesSchemas(args: {\n tag?: string\n verbose: boolean\n workspaces: WorkspaceSchemaInput[]\n}) {\n const {tag, verbose, workspaces} = args\n\n /* Known caveat: we _don't_ rollback failed operations or partial success */\n const results = await Promise.allSettled(\n workspaces.map(async (workspace): Promise<void> => {\n await updateWorkspaceSchema({\n tag,\n verbose,\n workspace,\n })\n }),\n )\n\n const [fulfilledUpdates, rejectedUpdates] = partition(\n results,\n (result) => result.status === 'fulfilled',\n )\n\n if (rejectedUpdates.length > 0) {\n throw new Error(\n `Failed to deploy ${rejectedUpdates.length}/${workspaces.length} schemas. Successfully deployed ${fulfilledUpdates.length}/${workspaces.length} schemas.`,\n )\n }\n\n spinner(`Deployed ${fulfilledUpdates.length}/${workspaces.length} schemas`).succeed()\n}\n\n/**\n * Updates a workspace schema in the dataset.\n */\nasync function updateWorkspaceSchema(args: {\n tag?: string\n verbose: boolean\n workspace: WorkspaceSchemaInput\n}) {\n const {tag, verbose, workspace} = args\n\n const {dataset, manifestSchema, projectId} = workspace\n\n const {idWarning, safeBaseId: id} = getWorkspaceSchemaId({\n tag,\n workspaceName: workspace.name,\n })\n\n if (idWarning) ux.warn(idWarning)\n\n try {\n await updateSchemas<Omit<StoredWorkspaceSchema, '_id' | '_type'>[]>(dataset, projectId, [\n {\n // the API will stringify the schema – we send as JSON\n schema: manifestSchema,\n tag,\n version: CURRENT_WORKSPACE_SCHEMA_VERSION,\n workspace: {\n name: workspace.name,\n title: workspace.title,\n },\n },\n ])\n\n if (verbose) {\n ux.stdout(\n styleText('gray', `↳ schemaId: ${id}, projectId: ${projectId}, dataset: ${dataset}`),\n )\n }\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err)\n if (\n err instanceof Error &&\n 'statusCode' in err &&\n (err as {statusCode: unknown}).statusCode === 401\n ) {\n ux.warn(\n `↳ No permissions to write schema for workspace \"${workspace.name}\" in dataset \"${workspace.dataset}\". ${\n SCHEMA_PERMISSION_HELP_TEXT\n }:\\n ${styleText('red', message)}`,\n )\n } else {\n ux.stdout(\n styleText(\n 'red',\n `↳ Error deploying schema for workspace \"${workspace.name}\":\\n ${styleText('red', message)}`,\n ),\n )\n }\n\n throw err\n }\n}\n"],"names":["styleText","ux","CURRENT_WORKSPACE_SCHEMA_VERSION","spinner","partition","updateSchemas","SCHEMA_PERMISSION_HELP_TEXT","getWorkspaceSchemaId","updateWorkspacesSchemas","args","tag","verbose","workspaces","results","Promise","allSettled","map","workspace","updateWorkspaceSchema","fulfilledUpdates","rejectedUpdates","result","status","length","Error","succeed","dataset","manifestSchema","projectId","idWarning","safeBaseId","id","workspaceName","name","warn","schema","version","title","stdout","err","message","String","statusCode"],"mappings":"AAAA,SAAQA,SAAS,QAAO,YAAW;AAEnC,SAAQC,EAAE,QAAO,iBAAgB;AACjC,SACEC,gCAAgC,QAG3B,uCAAsC;AAC7C,SAAQC,OAAO,QAAO,sBAAqB;AAC3C,OAAOC,eAAe,yBAAwB;AAE9C,SAAQC,aAAa,QAAO,4BAA2B;AACvD,SAAQC,2BAA2B,QAAO,mCAAkC;AAC5E,SAAQC,oBAAoB,QAAO,+BAA8B;AAEjE;;CAEC,GACD,OAAO,eAAeC,wBAAwBC,IAI7C;IACC,MAAM,EAACC,GAAG,EAAEC,OAAO,EAAEC,UAAU,EAAC,GAAGH;IAEnC,0EAA0E,GAC1E,MAAMI,UAAU,MAAMC,QAAQC,UAAU,CACtCH,WAAWI,GAAG,CAAC,OAAOC;QACpB,MAAMC,sBAAsB;YAC1BR;YACAC;YACAM;QACF;IACF;IAGF,MAAM,CAACE,kBAAkBC,gBAAgB,GAAGhB,UAC1CS,SACA,CAACQ,SAAWA,OAAOC,MAAM,KAAK;IAGhC,IAAIF,gBAAgBG,MAAM,GAAG,GAAG;QAC9B,MAAM,IAAIC,MACR,CAAC,iBAAiB,EAAEJ,gBAAgBG,MAAM,CAAC,CAAC,EAAEX,WAAWW,MAAM,CAAC,gCAAgC,EAAEJ,iBAAiBI,MAAM,CAAC,CAAC,EAAEX,WAAWW,MAAM,CAAC,SAAS,CAAC;IAE7J;IAEApB,QAAQ,CAAC,SAAS,EAAEgB,iBAAiBI,MAAM,CAAC,CAAC,EAAEX,WAAWW,MAAM,CAAC,QAAQ,CAAC,EAAEE,OAAO;AACrF;AAEA;;CAEC,GACD,eAAeP,sBAAsBT,IAIpC;IACC,MAAM,EAACC,GAAG,EAAEC,OAAO,EAAEM,SAAS,EAAC,GAAGR;IAElC,MAAM,EAACiB,OAAO,EAAEC,cAAc,EAAEC,SAAS,EAAC,GAAGX;IAE7C,MAAM,EAACY,SAAS,EAAEC,YAAYC,EAAE,EAAC,GAAGxB,qBAAqB;QACvDG;QACAsB,eAAef,UAAUgB,IAAI;IAC/B;IAEA,IAAIJ,WAAW5B,GAAGiC,IAAI,CAACL;IAEvB,IAAI;QACF,MAAMxB,cAA8DqB,SAASE,WAAW;YACtF;gBACE,sDAAsD;gBACtDO,QAAQR;gBACRjB;gBACA0B,SAASlC;gBACTe,WAAW;oBACTgB,MAAMhB,UAAUgB,IAAI;oBACpBI,OAAOpB,UAAUoB,KAAK;gBACxB;YACF;SACD;QAED,IAAI1B,SAAS;YACXV,GAAGqC,MAAM,CACPtC,UAAU,QAAQ,CAAC,YAAY,EAAE+B,GAAG,aAAa,EAAEH,UAAU,WAAW,EAAEF,SAAS;QAEvF;IACF,EAAE,OAAOa,KAAK;QACZ,MAAMC,UAAUD,eAAef,QAAQe,IAAIC,OAAO,GAAGC,OAAOF;QAC5D,IACEA,eAAef,SACf,gBAAgBe,OAChB,AAACA,IAA8BG,UAAU,KAAK,KAC9C;YACAzC,GAAGiC,IAAI,CACL,CAAC,gDAAgD,EAAEjB,UAAUgB,IAAI,CAAC,cAAc,EAAEhB,UAAUS,OAAO,CAAC,GAAG,EACrGpB,4BACD,KAAK,EAAEN,UAAU,OAAOwC,UAAU;QAEvC,OAAO;YACLvC,GAAGqC,MAAM,CACPtC,UACE,OACA,CAAC,wCAAwC,EAAEiB,UAAUgB,IAAI,CAAC,MAAM,EAAEjC,UAAU,OAAOwC,UAAU;QAGnG;QAEA,MAAMD;IACR;AACF"}