@sanity/cli-core 0.1.0-alpha.15 → 0.1.0-alpha.17

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.
@@ -2,7 +2,9 @@ import {default as boxen} from 'boxen'
2
2
  import {Options as BoxenOptions} from 'boxen'
3
3
  import {Boxes} from 'boxen'
4
4
  import {CustomBorderStyle} from 'boxen'
5
+ import * as inquirer from '@inquirer/prompts'
5
6
  import {default as logSymbols} from 'log-symbols'
7
+ import {Separator} from '@inquirer/prompts'
6
8
  import {Spacing} from 'boxen'
7
9
  import {Spinner} from 'ora'
8
10
  import {default as spinner} from 'ora'
@@ -17,10 +19,42 @@ export {BoxenOptions}
17
19
 
18
20
  export {Boxes}
19
21
 
22
+ export declare const checkbox: typeof inquirer.checkbox
23
+
24
+ declare const confirm_2: typeof inquirer.confirm
25
+ export {confirm_2 as confirm}
26
+
20
27
  export {CustomBorderStyle}
21
28
 
29
+ export declare const editor: typeof inquirer.editor
30
+
31
+ export declare const expand: typeof inquirer.expand
32
+
33
+ export declare const input: typeof inquirer.input
34
+
22
35
  export {logSymbols}
23
36
 
37
+ /**
38
+ * Error thrown when a prompt is attempted in a non-interactive environment
39
+ * (e.g., CI, non-TTY, piped stdin). Callers can catch this specific error
40
+ * to provide appropriate fallback behavior.
41
+ */
42
+ export declare class NonInteractiveError extends Error {
43
+ constructor(promptName: string)
44
+ }
45
+
46
+ export declare const number: typeof inquirer.number
47
+
48
+ export declare const password: typeof inquirer.password
49
+
50
+ export declare const rawlist: typeof inquirer.rawlist
51
+
52
+ export declare const search: typeof inquirer.search
53
+
54
+ export declare const select: typeof inquirer.select
55
+
56
+ export {Separator}
57
+
24
58
  export {Spacing}
25
59
 
26
60
  export {Spinner}
@@ -35,6 +69,4 @@ export {spinnerPromise}
35
69
 
36
70
  export {SpinnerPromiseOptions}
37
71
 
38
- export * from '@inquirer/prompts'
39
-
40
72
  export {}
@@ -1,3 +1,4 @@
1
+ export { NonInteractiveError } from '../util/NonInteractiveError.js';
1
2
  export * from '../ux/boxen.js';
2
3
  export * from '../ux/logSymbols.js';
3
4
  export * from '../ux/prompts.js';
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/_exports/ux.ts"],"sourcesContent":["export * from '../ux/boxen.js'\nexport * from '../ux/logSymbols.js'\nexport * from '../ux/prompts.js'\nexport * from '../ux/spinner.js'\n"],"names":[],"mappings":"AAAA,cAAc,iBAAgB;AAC9B,cAAc,sBAAqB;AACnC,cAAc,mBAAkB;AAChC,cAAc,mBAAkB"}
1
+ {"version":3,"sources":["../../src/_exports/ux.ts"],"sourcesContent":["export {NonInteractiveError} from '../util/NonInteractiveError.js'\nexport * from '../ux/boxen.js'\nexport * from '../ux/logSymbols.js'\nexport * from '../ux/prompts.js'\nexport * from '../ux/spinner.js'\n"],"names":["NonInteractiveError"],"mappings":"AAAA,SAAQA,mBAAmB,QAAO,iCAAgC;AAClE,cAAc,iBAAgB;AAC9B,cAAc,sBAAqB;AACnC,cAAc,mBAAkB;AAChC,cAAc,mBAAkB"}
@@ -2,11 +2,13 @@ import { stat } from 'node:fs/promises';
2
2
  import { dirname } from 'node:path';
3
3
  import { isMainThread } from 'node:worker_threads';
4
4
  import { firstValueFrom, of } from 'rxjs';
5
+ import { subdebug } from '../../debug.js';
5
6
  import { doImport } from '../../util/doImport.js';
6
7
  import { getEmptyAuth } from '../../util/getEmptyAuth.js';
7
8
  import { resolveLocalPackage } from '../../util/resolveLocalPackage.js';
8
9
  import { findStudioConfigPath } from '../util/findStudioConfigPath.js';
9
10
  import { isStudioConfig } from './isStudioConfig.js';
11
+ const debug = subdebug('worker:getStudioWorkspaces');
10
12
  /**
11
13
  * Resolves the workspaces from the studio config.
12
14
  *
@@ -23,14 +25,18 @@ import { isStudioConfig } from './isStudioConfig.js';
23
25
  if (isDirectory) {
24
26
  configPath = await findStudioConfigPath(configPath);
25
27
  }
28
+ debug('Finding studio config path %s', configPath);
26
29
  let config = await doImport(configPath);
30
+ debug('Imported config %o', config);
27
31
  if (!isStudioConfig(config)) {
28
32
  if (!('default' in config) || !isStudioConfig(config.default)) {
33
+ debug('Invalid studio config format in "%s"', configPath);
29
34
  throw new TypeError(`Invalid studio config format in "${configPath}"`);
30
35
  }
31
36
  config = config.default;
32
37
  }
33
38
  const workDir = dirname(configPath);
39
+ debug('Work dir %s', workDir);
34
40
  const { resolveConfig } = await resolveLocalPackage('sanity', workDir);
35
41
  if (typeof resolveConfig !== 'function') {
36
42
  throw new TypeError('Expected `resolveConfig` from `sanity` to be a function');
@@ -50,6 +56,7 @@ import { isStudioConfig } from './isStudioConfig.js';
50
56
  state: of(getEmptyAuth())
51
57
  }
52
58
  }));
59
+ debug('Unauthed workspaces %o', unauthedWorkspaces);
53
60
  return firstValueFrom(resolveConfig(unauthedWorkspaces));
54
61
  }
55
62
 
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/config/studio/getStudioWorkspaces.ts"],"sourcesContent":["import {stat} from 'node:fs/promises'\nimport {dirname} from 'node:path'\nimport {isMainThread} from 'node:worker_threads'\n\nimport {firstValueFrom, of} from 'rxjs'\nimport {type Workspace} from 'sanity'\n\nimport {doImport} from '../../util/doImport.js'\nimport {getEmptyAuth} from '../../util/getEmptyAuth.js'\nimport {resolveLocalPackage} from '../../util/resolveLocalPackage.js'\nimport {findStudioConfigPath} from '../util/findStudioConfigPath.js'\nimport {isStudioConfig} from './isStudioConfig.js'\n\n/**\n * Resolves the workspaces from the studio config.\n *\n * NOTE: This function should only be called from a worker thread.\n *\n * @param configPath - The path to the studio config\n * @returns The workspaces\n * @internal\n */\nexport async function getStudioWorkspaces(configPath: string): Promise<Workspace[]> {\n if (isMainThread) {\n throw new Error('getStudioWorkspaces should only be called from a worker thread')\n }\n const isDirectory = (await stat(configPath)).isDirectory()\n if (isDirectory) {\n configPath = await findStudioConfigPath(configPath)\n }\n let config = await doImport(configPath)\n if (!isStudioConfig(config)) {\n if (!('default' in config) || !isStudioConfig(config.default)) {\n throw new TypeError(`Invalid studio config format in \"${configPath}\"`)\n }\n\n config = config.default\n }\n\n const workDir = dirname(configPath)\n const {resolveConfig} = await resolveLocalPackage<typeof import('sanity')>('sanity', workDir)\n if (typeof resolveConfig !== 'function') {\n throw new TypeError('Expected `resolveConfig` from `sanity` to be a function')\n }\n\n // We will also want to stub out some configuration - we don't need to resolve the\n // users' logged in state, for instance - so let's disable the auth implementation.\n const rawWorkspaces = Array.isArray(config)\n ? config\n : [{...config, basePath: config.basePath || '/', name: config.name || 'default'}]\n\n const unauthedWorkspaces = rawWorkspaces.map((workspace) => ({\n ...workspace,\n auth: {state: of(getEmptyAuth())},\n }))\n\n return firstValueFrom(resolveConfig(unauthedWorkspaces))\n}\n"],"names":["stat","dirname","isMainThread","firstValueFrom","of","doImport","getEmptyAuth","resolveLocalPackage","findStudioConfigPath","isStudioConfig","getStudioWorkspaces","configPath","Error","isDirectory","config","default","TypeError","workDir","resolveConfig","rawWorkspaces","Array","isArray","basePath","name","unauthedWorkspaces","map","workspace","auth","state"],"mappings":"AAAA,SAAQA,IAAI,QAAO,mBAAkB;AACrC,SAAQC,OAAO,QAAO,YAAW;AACjC,SAAQC,YAAY,QAAO,sBAAqB;AAEhD,SAAQC,cAAc,EAAEC,EAAE,QAAO,OAAM;AAGvC,SAAQC,QAAQ,QAAO,yBAAwB;AAC/C,SAAQC,YAAY,QAAO,6BAA4B;AACvD,SAAQC,mBAAmB,QAAO,oCAAmC;AACrE,SAAQC,oBAAoB,QAAO,kCAAiC;AACpE,SAAQC,cAAc,QAAO,sBAAqB;AAElD;;;;;;;;CAQC,GACD,OAAO,eAAeC,oBAAoBC,UAAkB;IAC1D,IAAIT,cAAc;QAChB,MAAM,IAAIU,MAAM;IAClB;IACA,MAAMC,cAAc,AAAC,CAAA,MAAMb,KAAKW,WAAU,EAAGE,WAAW;IACxD,IAAIA,aAAa;QACfF,aAAa,MAAMH,qBAAqBG;IAC1C;IACA,IAAIG,SAAS,MAAMT,SAASM;IAC5B,IAAI,CAACF,eAAeK,SAAS;QAC3B,IAAI,CAAE,CAAA,aAAaA,MAAK,KAAM,CAACL,eAAeK,OAAOC,OAAO,GAAG;YAC7D,MAAM,IAAIC,UAAU,CAAC,iCAAiC,EAAEL,WAAW,CAAC,CAAC;QACvE;QAEAG,SAASA,OAAOC,OAAO;IACzB;IAEA,MAAME,UAAUhB,QAAQU;IACxB,MAAM,EAACO,aAAa,EAAC,GAAG,MAAMX,oBAA6C,UAAUU;IACrF,IAAI,OAAOC,kBAAkB,YAAY;QACvC,MAAM,IAAIF,UAAU;IACtB;IAEA,kFAAkF;IAClF,mFAAmF;IACnF,MAAMG,gBAAgBC,MAAMC,OAAO,CAACP,UAChCA,SACA;QAAC;YAAC,GAAGA,MAAM;YAAEQ,UAAUR,OAAOQ,QAAQ,IAAI;YAAKC,MAAMT,OAAOS,IAAI,IAAI;QAAS;KAAE;IAEnF,MAAMC,qBAAqBL,cAAcM,GAAG,CAAC,CAACC,YAAe,CAAA;YAC3D,GAAGA,SAAS;YACZC,MAAM;gBAACC,OAAOxB,GAAGE;YAAe;QAClC,CAAA;IAEA,OAAOH,eAAee,cAAcM;AACtC"}
1
+ {"version":3,"sources":["../../../src/config/studio/getStudioWorkspaces.ts"],"sourcesContent":["import {stat} from 'node:fs/promises'\nimport {dirname} from 'node:path'\nimport {isMainThread} from 'node:worker_threads'\n\nimport {firstValueFrom, of} from 'rxjs'\nimport {type Workspace} from 'sanity'\n\nimport {subdebug} from '../../debug.js'\nimport {doImport} from '../../util/doImport.js'\nimport {getEmptyAuth} from '../../util/getEmptyAuth.js'\nimport {resolveLocalPackage} from '../../util/resolveLocalPackage.js'\nimport {findStudioConfigPath} from '../util/findStudioConfigPath.js'\nimport {isStudioConfig} from './isStudioConfig.js'\n\nconst debug = subdebug('worker:getStudioWorkspaces')\n\n/**\n * Resolves the workspaces from the studio config.\n *\n * NOTE: This function should only be called from a worker thread.\n *\n * @param configPath - The path to the studio config\n * @returns The workspaces\n * @internal\n */\nexport async function getStudioWorkspaces(configPath: string): Promise<Workspace[]> {\n if (isMainThread) {\n throw new Error('getStudioWorkspaces should only be called from a worker thread')\n }\n const isDirectory = (await stat(configPath)).isDirectory()\n if (isDirectory) {\n configPath = await findStudioConfigPath(configPath)\n }\n debug('Finding studio config path %s', configPath)\n let config = await doImport(configPath)\n\n debug('Imported config %o', config)\n if (!isStudioConfig(config)) {\n if (!('default' in config) || !isStudioConfig(config.default)) {\n debug('Invalid studio config format in \"%s\"', configPath)\n throw new TypeError(`Invalid studio config format in \"${configPath}\"`)\n }\n\n config = config.default\n }\n\n const workDir = dirname(configPath)\n debug('Work dir %s', workDir)\n const {resolveConfig} = await resolveLocalPackage<typeof import('sanity')>('sanity', workDir)\n if (typeof resolveConfig !== 'function') {\n throw new TypeError('Expected `resolveConfig` from `sanity` to be a function')\n }\n\n // We will also want to stub out some configuration - we don't need to resolve the\n // users' logged in state, for instance - so let's disable the auth implementation.\n const rawWorkspaces = Array.isArray(config)\n ? config\n : [{...config, basePath: config.basePath || '/', name: config.name || 'default'}]\n\n const unauthedWorkspaces = rawWorkspaces.map((workspace) => ({\n ...workspace,\n auth: {state: of(getEmptyAuth())},\n }))\n\n debug('Unauthed workspaces %o', unauthedWorkspaces)\n\n return firstValueFrom(resolveConfig(unauthedWorkspaces))\n}\n"],"names":["stat","dirname","isMainThread","firstValueFrom","of","subdebug","doImport","getEmptyAuth","resolveLocalPackage","findStudioConfigPath","isStudioConfig","debug","getStudioWorkspaces","configPath","Error","isDirectory","config","default","TypeError","workDir","resolveConfig","rawWorkspaces","Array","isArray","basePath","name","unauthedWorkspaces","map","workspace","auth","state"],"mappings":"AAAA,SAAQA,IAAI,QAAO,mBAAkB;AACrC,SAAQC,OAAO,QAAO,YAAW;AACjC,SAAQC,YAAY,QAAO,sBAAqB;AAEhD,SAAQC,cAAc,EAAEC,EAAE,QAAO,OAAM;AAGvC,SAAQC,QAAQ,QAAO,iBAAgB;AACvC,SAAQC,QAAQ,QAAO,yBAAwB;AAC/C,SAAQC,YAAY,QAAO,6BAA4B;AACvD,SAAQC,mBAAmB,QAAO,oCAAmC;AACrE,SAAQC,oBAAoB,QAAO,kCAAiC;AACpE,SAAQC,cAAc,QAAO,sBAAqB;AAElD,MAAMC,QAAQN,SAAS;AAEvB;;;;;;;;CAQC,GACD,OAAO,eAAeO,oBAAoBC,UAAkB;IAC1D,IAAIX,cAAc;QAChB,MAAM,IAAIY,MAAM;IAClB;IACA,MAAMC,cAAc,AAAC,CAAA,MAAMf,KAAKa,WAAU,EAAGE,WAAW;IACxD,IAAIA,aAAa;QACfF,aAAa,MAAMJ,qBAAqBI;IAC1C;IACAF,MAAM,iCAAiCE;IACvC,IAAIG,SAAS,MAAMV,SAASO;IAE5BF,MAAM,sBAAsBK;IAC5B,IAAI,CAACN,eAAeM,SAAS;QAC3B,IAAI,CAAE,CAAA,aAAaA,MAAK,KAAM,CAACN,eAAeM,OAAOC,OAAO,GAAG;YAC7DN,MAAM,wCAAwCE;YAC9C,MAAM,IAAIK,UAAU,CAAC,iCAAiC,EAAEL,WAAW,CAAC,CAAC;QACvE;QAEAG,SAASA,OAAOC,OAAO;IACzB;IAEA,MAAME,UAAUlB,QAAQY;IACxBF,MAAM,eAAeQ;IACrB,MAAM,EAACC,aAAa,EAAC,GAAG,MAAMZ,oBAA6C,UAAUW;IACrF,IAAI,OAAOC,kBAAkB,YAAY;QACvC,MAAM,IAAIF,UAAU;IACtB;IAEA,kFAAkF;IAClF,mFAAmF;IACnF,MAAMG,gBAAgBC,MAAMC,OAAO,CAACP,UAChCA,SACA;QAAC;YAAC,GAAGA,MAAM;YAAEQ,UAAUR,OAAOQ,QAAQ,IAAI;YAAKC,MAAMT,OAAOS,IAAI,IAAI;QAAS;KAAE;IAEnF,MAAMC,qBAAqBL,cAAcM,GAAG,CAAC,CAACC,YAAe,CAAA;YAC3D,GAAGA,SAAS;YACZC,MAAM;gBAACC,OAAO1B,GAAGG;YAAe;QAClC,CAAA;IAEAI,MAAM,0BAA0Be;IAEhC,OAAOvB,eAAeiB,cAAcM;AACtC"}
@@ -1,18 +1,24 @@
1
1
  import { isMainThread, parentPort, workerData } from 'node:worker_threads';
2
2
  import { z } from 'zod';
3
+ import { subdebug } from '../../debug.js';
3
4
  import { doImport } from '../../util/doImport.js';
4
5
  import { safeStructuredClone } from '../../util/safeStructuredClone.js';
5
6
  import { getStudioWorkspaces } from './getStudioWorkspaces.js';
6
7
  if (isMainThread || !parentPort) {
7
8
  throw new Error('Should only be run in a worker!');
8
9
  }
10
+ const debug = subdebug('readStudioConfig.worker');
9
11
  const { configPath, resolvePlugins } = z.object({
10
12
  configPath: z.string(),
11
13
  resolvePlugins: z.boolean()
12
14
  }).parse(workerData);
15
+ debug('Parsing config path %s', configPath);
13
16
  let { default: config } = await doImport(configPath);
17
+ debug('Imported config %o', config);
14
18
  if (resolvePlugins) {
19
+ debug('Resolving workspaces');
15
20
  config = await getStudioWorkspaces(configPath);
21
+ debug('Resolved workspaces %o', config);
16
22
  }
17
23
  parentPort.postMessage(safeStructuredClone(config));
18
24
 
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/config/studio/readStudioConfig.worker.ts"],"sourcesContent":["import {isMainThread, parentPort, workerData} from 'node:worker_threads'\n\nimport {z} from 'zod'\n\nimport {doImport} from '../../util/doImport.js'\nimport {safeStructuredClone} from '../../util/safeStructuredClone.js'\nimport {getStudioWorkspaces} from './getStudioWorkspaces.js'\n\nif (isMainThread || !parentPort) {\n throw new Error('Should only be run in a worker!')\n}\n\nconst {configPath, resolvePlugins} = z\n .object({configPath: z.string(), resolvePlugins: z.boolean()})\n .parse(workerData)\n\nlet {default: config} = await doImport(configPath)\n\nif (resolvePlugins) {\n config = await getStudioWorkspaces(configPath)\n}\n\nparentPort.postMessage(safeStructuredClone(config))\n"],"names":["isMainThread","parentPort","workerData","z","doImport","safeStructuredClone","getStudioWorkspaces","Error","configPath","resolvePlugins","object","string","boolean","parse","default","config","postMessage"],"mappings":"AAAA,SAAQA,YAAY,EAAEC,UAAU,EAAEC,UAAU,QAAO,sBAAqB;AAExE,SAAQC,CAAC,QAAO,MAAK;AAErB,SAAQC,QAAQ,QAAO,yBAAwB;AAC/C,SAAQC,mBAAmB,QAAO,oCAAmC;AACrE,SAAQC,mBAAmB,QAAO,2BAA0B;AAE5D,IAAIN,gBAAgB,CAACC,YAAY;IAC/B,MAAM,IAAIM,MAAM;AAClB;AAEA,MAAM,EAACC,UAAU,EAAEC,cAAc,EAAC,GAAGN,EAClCO,MAAM,CAAC;IAACF,YAAYL,EAAEQ,MAAM;IAAIF,gBAAgBN,EAAES,OAAO;AAAE,GAC3DC,KAAK,CAACX;AAET,IAAI,EAACY,SAASC,MAAM,EAAC,GAAG,MAAMX,SAASI;AAEvC,IAAIC,gBAAgB;IAClBM,SAAS,MAAMT,oBAAoBE;AACrC;AAEAP,WAAWe,WAAW,CAACX,oBAAoBU"}
1
+ {"version":3,"sources":["../../../src/config/studio/readStudioConfig.worker.ts"],"sourcesContent":["import {isMainThread, parentPort, workerData} from 'node:worker_threads'\n\nimport {z} from 'zod'\n\nimport {subdebug} from '../../debug.js'\nimport {doImport} from '../../util/doImport.js'\nimport {safeStructuredClone} from '../../util/safeStructuredClone.js'\nimport {getStudioWorkspaces} from './getStudioWorkspaces.js'\n\nif (isMainThread || !parentPort) {\n throw new Error('Should only be run in a worker!')\n}\n\nconst debug = subdebug('readStudioConfig.worker')\n\nconst {configPath, resolvePlugins} = z\n .object({configPath: z.string(), resolvePlugins: z.boolean()})\n .parse(workerData)\n\ndebug('Parsing config path %s', configPath)\n\nlet {default: config} = await doImport(configPath)\n\ndebug('Imported config %o', config)\n\nif (resolvePlugins) {\n debug('Resolving workspaces')\n config = await getStudioWorkspaces(configPath)\n debug('Resolved workspaces %o', config)\n}\n\nparentPort.postMessage(safeStructuredClone(config))\n"],"names":["isMainThread","parentPort","workerData","z","subdebug","doImport","safeStructuredClone","getStudioWorkspaces","Error","debug","configPath","resolvePlugins","object","string","boolean","parse","default","config","postMessage"],"mappings":"AAAA,SAAQA,YAAY,EAAEC,UAAU,EAAEC,UAAU,QAAO,sBAAqB;AAExE,SAAQC,CAAC,QAAO,MAAK;AAErB,SAAQC,QAAQ,QAAO,iBAAgB;AACvC,SAAQC,QAAQ,QAAO,yBAAwB;AAC/C,SAAQC,mBAAmB,QAAO,oCAAmC;AACrE,SAAQC,mBAAmB,QAAO,2BAA0B;AAE5D,IAAIP,gBAAgB,CAACC,YAAY;IAC/B,MAAM,IAAIO,MAAM;AAClB;AAEA,MAAMC,QAAQL,SAAS;AAEvB,MAAM,EAACM,UAAU,EAAEC,cAAc,EAAC,GAAGR,EAClCS,MAAM,CAAC;IAACF,YAAYP,EAAEU,MAAM;IAAIF,gBAAgBR,EAAEW,OAAO;AAAE,GAC3DC,KAAK,CAACb;AAETO,MAAM,0BAA0BC;AAEhC,IAAI,EAACM,SAASC,MAAM,EAAC,GAAG,MAAMZ,SAASK;AAEvCD,MAAM,sBAAsBQ;AAE5B,IAAIN,gBAAgB;IAClBF,MAAM;IACNQ,SAAS,MAAMV,oBAAoBG;IACnCD,MAAM,0BAA0BQ;AAClC;AAEAhB,WAAWiB,WAAW,CAACZ,oBAAoBW"}
package/dist/index.d.ts CHANGED
@@ -683,6 +683,15 @@ export declare function isTrueish(value: string | undefined): boolean
683
683
  */
684
684
  export declare function mockBrowserEnvironment(basePath: string): Promise<() => void>
685
685
 
686
+ /**
687
+ * Error thrown when a prompt is attempted in a non-interactive environment
688
+ * (e.g., CI, non-TTY, piped stdin). Callers can catch this specific error
689
+ * to provide appropriate fallback behavior.
690
+ */
691
+ export declare class NonInteractiveError extends Error {
692
+ constructor(promptName: string)
693
+ }
694
+
686
695
  /**
687
696
  * Normalizes a path for cross-platform comparison by converting backslashes to forward slashes.
688
697
  * Useful for converting windows paths to unix paths.
@@ -809,17 +818,21 @@ export declare interface ProjectRootResult {
809
818
  }
810
819
 
811
820
  /**
812
- * Wraps a Node.js Worker in a Promise that resolves with the first message
813
- * the worker sends, and rejects on error, message deserialization failure,
814
- * or non-zero exit code. The worker is terminated after a message or error
815
- * is received.
821
+ * Creates a Node.js Worker from the given file path and options, and wraps it
822
+ * in a Promise that resolves with the first message the worker sends, and
823
+ * rejects on error, message deserialization failure, or non-zero exit code.
824
+ * The worker is terminated after a message or error is received.
816
825
  *
817
- * @param worker - The Worker instance to promisify
826
+ * @param filePath - URL to the worker file
827
+ * @param options - Options to pass to the Worker constructor
818
828
  * @returns A promise that resolves with the first message from the worker
819
829
  * @throws If the worker emits an error, a message deserialization error, or exits with a non-zero code
820
830
  * @internal
821
831
  */
822
- export declare function promisifyWorker<T = unknown>(worker: Worker_2): Promise<T>
832
+ export declare function promisifyWorker<T = unknown>(
833
+ filePath: URL,
834
+ options?: WorkerOptions_2,
835
+ ): Promise<T>
823
836
 
824
837
  declare const rawConfigSchema: z_2.ZodUnion<
825
838
  readonly [
@@ -1306,4 +1319,6 @@ export declare type UserViteConfig =
1306
1319
  | ((config: InlineConfig, env: ConfigEnv) => InlineConfig | Promise<InlineConfig>)
1307
1320
  | InlineConfig
1308
1321
 
1322
+ export declare const waitForAsync: (ms?: number) => Promise<void>
1323
+
1309
1324
  export {}
package/dist/index.js CHANGED
@@ -32,6 +32,7 @@ export * from './util/isInteractive.js';
32
32
  export * from './util/isRecord.js';
33
33
  export * from './util/isStaging.js';
34
34
  export * from './util/isTrueish.js';
35
+ export * from './util/NonInteractiveError.js';
35
36
  export * from './util/normalizePath.js';
36
37
  export * from './util/parseStringFlag.js';
37
38
  export * from './util/promisifyWorker.js';
@@ -40,6 +41,7 @@ export * from './util/readPackageJson.js';
40
41
  export * from './util/resolveLocalPackage.js';
41
42
  export * from './util/safeStructuredClone.js';
42
43
  export * from './util/tryGetDefaultExport.js';
44
+ export * from './util/waitForAsync.js';
43
45
  export * from './ux/colorizeJson.js';
44
46
  export * from './ux/formatObject.js';
45
47
  export * from './ux/printKeyValue.js';
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["export * from './config/cli/getCliConfig.js'\nexport * from './config/cli/getCliConfigSync.js'\nexport {type CliConfig} from './config/cli/types/cliConfig.js'\nexport {type UserViteConfig} from './config/cli/types/userViteConfig.js'\nexport * from './config/findProjectRoot.js'\nexport * from './config/findProjectRootSync.js'\nexport * from './config/studio/getStudioConfig.js'\nexport * from './config/studio/getStudioWorkspaces.js'\nexport * from './config/util/findConfigsPaths.js'\nexport * from './config/util/findStudioConfigPath.js'\nexport {type ProjectRootResult} from './config/util/recursivelyResolveProjectRoot.js'\nexport * from './debug.js'\nexport * from './loaders/studio/studioWorkerTask.js'\nexport * from './loaders/tsx/tsxWorkerTask.js'\nexport * from './SanityCommand.js'\nexport * from './services/apiClient.js'\nexport * from './services/cliUserConfig.js'\nexport * from './services/getCliToken.js'\nexport * from './telemetry/createTelemetryStore.js'\nexport * from './telemetry/flushTelemetryFiles.js'\nexport * from './telemetry/getTelemetryBaseInfo.js'\nexport * from './telemetry/telemetryStoreDebug.js'\nexport {\n type CLITelemetryStore,\n type ConsentInformation,\n type TelemetryUserProperties,\n} from './telemetry/types.js'\nexport {type Output, type SanityOrgUser} from './types.js'\nexport * from './util/createExpiringConfig.js'\nexport {doImport} from './util/doImport.js'\nexport * from './util/environment/mockBrowserEnvironment.js'\nexport * from './util/fileExists.js'\nexport {\n clearCliTelemetry,\n CLI_TELEMETRY_SYMBOL,\n getCliTelemetry,\n setCliTelemetry,\n} from './util/getCliTelemetry.js'\nexport * from './util/getEmptyAuth.js'\nexport * from './util/getSanityEnvVar.js'\nexport * from './util/getSanityUrl.js'\nexport * from './util/getUserConfig.js'\nexport * from './util/importModule.js'\nexport * from './util/isCi.js'\nexport * from './util/isInteractive.js'\nexport * from './util/isRecord.js'\nexport * from './util/isStaging.js'\nexport * from './util/isTrueish.js'\nexport * from './util/normalizePath.js'\nexport * from './util/parseStringFlag.js'\nexport * from './util/promisifyWorker.js'\nexport * from './util/readNDJSON.js'\nexport * from './util/readPackageJson.js'\nexport * from './util/resolveLocalPackage.js'\nexport * from './util/safeStructuredClone.js'\nexport * from './util/tryGetDefaultExport.js'\nexport * from './ux/colorizeJson.js'\nexport * from './ux/formatObject.js'\nexport * from './ux/printKeyValue.js'\nexport * from './ux/timer.js'\n"],"names":["doImport","clearCliTelemetry","CLI_TELEMETRY_SYMBOL","getCliTelemetry","setCliTelemetry"],"mappings":"AAAA,cAAc,+BAA8B;AAC5C,cAAc,mCAAkC;AAGhD,cAAc,8BAA6B;AAC3C,cAAc,kCAAiC;AAC/C,cAAc,qCAAoC;AAClD,cAAc,yCAAwC;AACtD,cAAc,oCAAmC;AACjD,cAAc,wCAAuC;AAErD,cAAc,aAAY;AAC1B,cAAc,uCAAsC;AACpD,cAAc,iCAAgC;AAC9C,cAAc,qBAAoB;AAClC,cAAc,0BAAyB;AACvC,cAAc,8BAA6B;AAC3C,cAAc,4BAA2B;AACzC,cAAc,sCAAqC;AACnD,cAAc,qCAAoC;AAClD,cAAc,sCAAqC;AACnD,cAAc,qCAAoC;AAOlD,cAAc,iCAAgC;AAC9C,SAAQA,QAAQ,QAAO,qBAAoB;AAC3C,cAAc,+CAA8C;AAC5D,cAAc,uBAAsB;AACpC,SACEC,iBAAiB,EACjBC,oBAAoB,EACpBC,eAAe,EACfC,eAAe,QACV,4BAA2B;AAClC,cAAc,yBAAwB;AACtC,cAAc,4BAA2B;AACzC,cAAc,yBAAwB;AACtC,cAAc,0BAAyB;AACvC,cAAc,yBAAwB;AACtC,cAAc,iBAAgB;AAC9B,cAAc,0BAAyB;AACvC,cAAc,qBAAoB;AAClC,cAAc,sBAAqB;AACnC,cAAc,sBAAqB;AACnC,cAAc,0BAAyB;AACvC,cAAc,4BAA2B;AACzC,cAAc,4BAA2B;AACzC,cAAc,uBAAsB;AACpC,cAAc,4BAA2B;AACzC,cAAc,gCAA+B;AAC7C,cAAc,gCAA+B;AAC7C,cAAc,gCAA+B;AAC7C,cAAc,uBAAsB;AACpC,cAAc,uBAAsB;AACpC,cAAc,wBAAuB;AACrC,cAAc,gBAAe"}
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["export * from './config/cli/getCliConfig.js'\nexport * from './config/cli/getCliConfigSync.js'\nexport {type CliConfig} from './config/cli/types/cliConfig.js'\nexport {type UserViteConfig} from './config/cli/types/userViteConfig.js'\nexport * from './config/findProjectRoot.js'\nexport * from './config/findProjectRootSync.js'\nexport * from './config/studio/getStudioConfig.js'\nexport * from './config/studio/getStudioWorkspaces.js'\nexport * from './config/util/findConfigsPaths.js'\nexport * from './config/util/findStudioConfigPath.js'\nexport {type ProjectRootResult} from './config/util/recursivelyResolveProjectRoot.js'\nexport * from './debug.js'\nexport * from './loaders/studio/studioWorkerTask.js'\nexport * from './loaders/tsx/tsxWorkerTask.js'\nexport * from './SanityCommand.js'\nexport * from './services/apiClient.js'\nexport * from './services/cliUserConfig.js'\nexport * from './services/getCliToken.js'\nexport * from './telemetry/createTelemetryStore.js'\nexport * from './telemetry/flushTelemetryFiles.js'\nexport * from './telemetry/getTelemetryBaseInfo.js'\nexport * from './telemetry/telemetryStoreDebug.js'\nexport {\n type CLITelemetryStore,\n type ConsentInformation,\n type TelemetryUserProperties,\n} from './telemetry/types.js'\nexport {type Output, type SanityOrgUser} from './types.js'\nexport * from './util/createExpiringConfig.js'\nexport {doImport} from './util/doImport.js'\nexport * from './util/environment/mockBrowserEnvironment.js'\nexport * from './util/fileExists.js'\nexport {\n clearCliTelemetry,\n CLI_TELEMETRY_SYMBOL,\n getCliTelemetry,\n setCliTelemetry,\n} from './util/getCliTelemetry.js'\nexport * from './util/getEmptyAuth.js'\nexport * from './util/getSanityEnvVar.js'\nexport * from './util/getSanityUrl.js'\nexport * from './util/getUserConfig.js'\nexport * from './util/importModule.js'\nexport * from './util/isCi.js'\nexport * from './util/isInteractive.js'\nexport * from './util/isRecord.js'\nexport * from './util/isStaging.js'\nexport * from './util/isTrueish.js'\nexport * from './util/NonInteractiveError.js'\nexport * from './util/normalizePath.js'\nexport * from './util/parseStringFlag.js'\nexport * from './util/promisifyWorker.js'\nexport * from './util/readNDJSON.js'\nexport * from './util/readPackageJson.js'\nexport * from './util/resolveLocalPackage.js'\nexport * from './util/safeStructuredClone.js'\nexport * from './util/tryGetDefaultExport.js'\nexport * from './util/waitForAsync.js'\nexport * from './ux/colorizeJson.js'\nexport * from './ux/formatObject.js'\nexport * from './ux/printKeyValue.js'\nexport * from './ux/timer.js'\n"],"names":["doImport","clearCliTelemetry","CLI_TELEMETRY_SYMBOL","getCliTelemetry","setCliTelemetry"],"mappings":"AAAA,cAAc,+BAA8B;AAC5C,cAAc,mCAAkC;AAGhD,cAAc,8BAA6B;AAC3C,cAAc,kCAAiC;AAC/C,cAAc,qCAAoC;AAClD,cAAc,yCAAwC;AACtD,cAAc,oCAAmC;AACjD,cAAc,wCAAuC;AAErD,cAAc,aAAY;AAC1B,cAAc,uCAAsC;AACpD,cAAc,iCAAgC;AAC9C,cAAc,qBAAoB;AAClC,cAAc,0BAAyB;AACvC,cAAc,8BAA6B;AAC3C,cAAc,4BAA2B;AACzC,cAAc,sCAAqC;AACnD,cAAc,qCAAoC;AAClD,cAAc,sCAAqC;AACnD,cAAc,qCAAoC;AAOlD,cAAc,iCAAgC;AAC9C,SAAQA,QAAQ,QAAO,qBAAoB;AAC3C,cAAc,+CAA8C;AAC5D,cAAc,uBAAsB;AACpC,SACEC,iBAAiB,EACjBC,oBAAoB,EACpBC,eAAe,EACfC,eAAe,QACV,4BAA2B;AAClC,cAAc,yBAAwB;AACtC,cAAc,4BAA2B;AACzC,cAAc,yBAAwB;AACtC,cAAc,0BAAyB;AACvC,cAAc,yBAAwB;AACtC,cAAc,iBAAgB;AAC9B,cAAc,0BAAyB;AACvC,cAAc,qBAAoB;AAClC,cAAc,sBAAqB;AACnC,cAAc,sBAAqB;AACnC,cAAc,gCAA+B;AAC7C,cAAc,0BAAyB;AACvC,cAAc,4BAA2B;AACzC,cAAc,4BAA2B;AACzC,cAAc,uBAAsB;AACpC,cAAc,4BAA2B;AACzC,cAAc,gCAA+B;AAC7C,cAAc,gCAA+B;AAC7C,cAAc,gCAA+B;AAC7C,cAAc,yBAAwB;AACtC,cAAc,uBAAsB;AACpC,cAAc,uBAAsB;AACpC,cAAc,wBAAuB;AACrC,cAAc,gBAAe"}
@@ -1,6 +1,10 @@
1
1
  import { isMainThread } from 'node:worker_threads';
2
- import { createServer, createServerModuleRunner, loadEnv, mergeConfig } from 'vite';
2
+ import { createServer, loadEnv, mergeConfig } from 'vite';
3
+ import { ViteNodeRunner } from 'vite-node/client';
4
+ import { ViteNodeServer } from 'vite-node/server';
5
+ import { installSourcemapsSupport } from 'vite-node/source-map';
3
6
  import { getCliConfig } from '../../config/cli/getCliConfig.js';
7
+ import { subdebug } from '../../debug.js';
4
8
  import { getStudioEnvironmentVariables } from '../../util/environment/getStudioEnvironmentVariables.js';
5
9
  import { setupBrowserStubs } from '../../util/environment/setupBrowserStubs.js';
6
10
  import { isRecord } from '../../util/isRecord.js';
@@ -12,12 +16,51 @@ const rootPath = process.env.STUDIO_WORKER_STUDIO_ROOT_PATH;
12
16
  if (!rootPath) {
13
17
  throw new Error('Missing `STUDIO_WORKER_STUDIO_ROOT_PATH` environment variable');
14
18
  }
19
+ const debug = subdebug('studio:worker');
15
20
  const workerScriptPath = process.env.STUDIO_WORKER_TASK_FILE;
16
21
  if (!workerScriptPath) {
17
22
  throw new Error('Missing `STUDIO_WORKER_TASK_FILE` environment variable');
18
23
  }
19
24
  await setupBrowserStubs();
20
25
  const studioEnvVars = await getStudioEnvironmentVariables(rootPath);
26
+ // Allow the CLI config (`sanity.cli.(js|ts)`) to define a `vite` property which can
27
+ // extend/modify the default vite configuration for the studio.
28
+ let cliConfig;
29
+ try {
30
+ cliConfig = await getCliConfig(rootPath);
31
+ } catch (err) {
32
+ debug('Failed to load CLI config: %o', err);
33
+ if (!isNotFoundError(err)) {
34
+ // eslint-disable-next-line no-console
35
+ console.warn('[warn] Failed to load CLI config:', err);
36
+ }
37
+ }
38
+ /**
39
+ * Fetches and caches modules from HTTP/HTTPS URLs.
40
+ * Vite's SSR transform treats `https://` imports as external and bypasses the plugin
41
+ * resolve pipeline entirely, so we intercept them at the ViteNodeRunner level instead.
42
+ */ const httpModuleCache = new Map();
43
+ async function fetchHttpModule(url) {
44
+ const cached = httpModuleCache.get(url);
45
+ if (cached) return {
46
+ code: cached
47
+ };
48
+ debug('Fetching HTTP import: %s', url);
49
+ const response = await fetch(url, {
50
+ signal: AbortSignal.timeout(30_000)
51
+ });
52
+ if (!response.ok) {
53
+ throw new Error(`Failed to fetch module from ${url}: ${response.status} ${response.statusText}`);
54
+ }
55
+ const code = await response.text();
56
+ httpModuleCache.set(url, code);
57
+ return {
58
+ code
59
+ };
60
+ }
61
+ function isHttpsUrl(id) {
62
+ return id.startsWith('https://');
63
+ }
21
64
  const defaultViteConfig = {
22
65
  build: {
23
66
  target: 'node'
@@ -28,27 +71,28 @@ const defaultViteConfig = {
28
71
  `process.env.${key}`,
29
72
  JSON.stringify(value)
30
73
  ])),
74
+ envPrefix: cliConfig && 'app' in cliConfig ? 'SANITY_APP_' : 'SANITY_STUDIO_',
75
+ esbuild: {
76
+ jsx: 'automatic'
77
+ },
31
78
  logLevel: 'error',
32
79
  optimizeDeps: {
33
- disabled: true
80
+ include: undefined,
81
+ noDiscovery: true
34
82
  },
35
83
  root: rootPath,
36
84
  server: {
37
85
  hmr: false,
38
86
  watch: null
87
+ },
88
+ ssr: {
89
+ /**
90
+ * We don't want to externalize any dependencies, we want everything to run thru vite.
91
+ * Especially for CJS compatibility, etc.
92
+ */ noExternal: true
39
93
  }
40
94
  };
41
- // Allow the CLI config (`sanity.cli.(js|ts)`) to define a `vite` property which can
42
- // extend/modify the default vite configuration for the studio.
43
- let cliConfig;
44
- try {
45
- cliConfig = await getCliConfig(rootPath);
46
- } catch (err) {
47
- if (!isNotFoundError(err)) {
48
- // eslint-disable-next-line no-console
49
- console.warn('[warn] Failed to load CLI config:', err);
50
- }
51
- }
95
+ // Merge the CLI config's Vite config with the default Vite config
52
96
  let viteConfig = defaultViteConfig;
53
97
  if (typeof cliConfig?.vite === 'function') {
54
98
  viteConfig = await cliConfig.vite(viteConfig, {
@@ -59,6 +103,7 @@ if (typeof cliConfig?.vite === 'function') {
59
103
  } else if (isRecord(cliConfig?.vite)) {
60
104
  viteConfig = mergeConfig(viteConfig, cliConfig.vite);
61
105
  }
106
+ debug('Creating Vite server with config: %o', viteConfig);
62
107
  // Vite will build the files we give it - targetting Node.js instead of the browser.
63
108
  // We include the inject plugin in order to provide the stubs for the undefined global APIs.
64
109
  const server = await createServer(viteConfig);
@@ -67,19 +112,52 @@ await server.pluginContainer.buildStart({});
67
112
  // Load environment variables from `.env` files in the same way as Vite does.
68
113
  // Note that Sanity also provides environment variables through `process.env.*` for compat reasons,
69
114
  // and so we need to do the same here.
70
- // @todo is this in line with sanity?
71
- const env = loadEnv(server.config.mode, server.config.envDir, '');
115
+ const env = loadEnv(server.config.mode, server.config.envDir, viteConfig.envPrefix ?? '');
72
116
  for(const key in env){
73
117
  process.env[key] ??= env[key];
74
118
  }
75
- // Now we're using Vite's Module Runner (replaces vite-node in Vite 4+)
76
- const runner = await createServerModuleRunner(server.environments.ssr, {
77
- hmr: false,
78
- sourcemapInterceptor: 'prepareStackTrace'
119
+ // Now we're providing the glue that ensures node-specific loading and execution works.
120
+ const node = new ViteNodeServer(server);
121
+ // Should make it easier to debug any crashes in the imported code…
122
+ installSourcemapsSupport({
123
+ getSourceMap: (source)=>node.getSourceMap(source)
124
+ });
125
+ const runner = new ViteNodeRunner({
126
+ base: server.config.base,
127
+ async fetchModule (id) {
128
+ // Vite's SSR transform externalizes https:// imports, so Node's ESM loader
129
+ // would reject them. We fetch the module over HTTP and run it through Vite's
130
+ // SSR transform to rewrite ESM export/import syntax to the __vite_ssr_*
131
+ // format that ViteNodeRunner expects.
132
+ if (isHttpsUrl(id)) {
133
+ const { code: rawCode } = await fetchHttpModule(id);
134
+ const result = await server.ssrTransform(rawCode, null, id);
135
+ return {
136
+ code: result?.code || rawCode
137
+ };
138
+ }
139
+ return node.fetchModule(id);
140
+ },
141
+ resolveId (id, importer) {
142
+ // Prevent vite-node from trying to resolve HTTP URLs through Node's resolver
143
+ if (isHttpsUrl(id)) return {
144
+ id
145
+ };
146
+ // Resolve any import from an HTTP-fetched module against the remote origin
147
+ // (e.g. esm.sh returns `export * from '/pkg@1.0/es2022/pkg.mjs'`)
148
+ if (importer && isHttpsUrl(importer)) {
149
+ return {
150
+ id: new URL(id, importer).href
151
+ };
152
+ }
153
+ return node.resolveId(id, importer);
154
+ },
155
+ root: server.config.root
79
156
  });
80
- // Apply the `define` config from vite - imports environment variables
81
- await runner.import('/@vite/env');
82
- // Execute the worker script
83
- await runner.import(workerScriptPath);
157
+ // Copied from `vite-node` - it appears that this applies the `define` config from
158
+ // vite, but it also takes a surprisingly long time to execute. Not clear at this
159
+ // point why this is, so we should investigate whether it's necessary or not.
160
+ await runner.executeId('/@vite/env');
161
+ await runner.executeId(workerScriptPath);
84
162
 
85
163
  //# sourceMappingURL=studioWorkerLoader.worker.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/loaders/studio/studioWorkerLoader.worker.ts"],"sourcesContent":["import {isMainThread} from 'node:worker_threads'\n\nimport {createServer, createServerModuleRunner, type InlineConfig, loadEnv, mergeConfig} from 'vite'\n\nimport {getCliConfig} from '../../config/cli/getCliConfig.js'\nimport {type CliConfig} from '../../config/cli/types/cliConfig.js'\nimport {getStudioEnvironmentVariables} from '../../util/environment/getStudioEnvironmentVariables.js'\nimport {setupBrowserStubs} from '../../util/environment/setupBrowserStubs.js'\nimport {isRecord} from '../../util/isRecord.js'\nimport {isNotFoundError} from '../../util/NotFoundError.js'\n\nif (isMainThread) {\n throw new Error('Should be child of thread, not the main thread')\n}\n\nconst rootPath = process.env.STUDIO_WORKER_STUDIO_ROOT_PATH\nif (!rootPath) {\n throw new Error('Missing `STUDIO_WORKER_STUDIO_ROOT_PATH` environment variable')\n}\n\nconst workerScriptPath = process.env.STUDIO_WORKER_TASK_FILE\nif (!workerScriptPath) {\n throw new Error('Missing `STUDIO_WORKER_TASK_FILE` environment variable')\n}\n\nawait setupBrowserStubs()\n\nconst studioEnvVars = await getStudioEnvironmentVariables(rootPath)\n\nconst defaultViteConfig: InlineConfig = {\n build: {target: 'node'},\n configFile: false, // @todo Should use `vite` prop from `sanity.cli.ts` (if any)\n // Inject environment variables as compile-time constants for Vite\n define: Object.fromEntries(\n Object.entries(studioEnvVars).map(([key, value]) => [\n `process.env.${key}`,\n JSON.stringify(value),\n ]),\n ),\n logLevel: 'error',\n optimizeDeps: {disabled: true}, // @todo is this necessary? cant remember why was added\n root: rootPath,\n server: {\n hmr: false,\n watch: null,\n },\n}\n\n// Allow the CLI config (`sanity.cli.(js|ts)`) to define a `vite` property which can\n// extend/modify the default vite configuration for the studio.\nlet cliConfig: CliConfig | undefined\ntry {\n cliConfig = await getCliConfig(rootPath)\n} catch (err) {\n if (!isNotFoundError(err)) {\n // eslint-disable-next-line no-console\n console.warn('[warn] Failed to load CLI config:', err)\n }\n}\n\nlet viteConfig = defaultViteConfig\nif (typeof cliConfig?.vite === 'function') {\n viteConfig = (await cliConfig.vite(viteConfig, {\n command: 'build',\n isSsrBuild: true,\n mode: 'production',\n })) as InlineConfig\n} else if (isRecord(cliConfig?.vite)) {\n viteConfig = mergeConfig(viteConfig, cliConfig.vite)\n}\n\n// Vite will build the files we give it - targetting Node.js instead of the browser.\n// We include the inject plugin in order to provide the stubs for the undefined global APIs.\nconst server = await createServer(viteConfig)\n\n// Bit of a hack, but seems necessary based on the `node-vite` binary implementation\nawait server.pluginContainer.buildStart({})\n\n// Load environment variables from `.env` files in the same way as Vite does.\n// Note that Sanity also provides environment variables through `process.env.*` for compat reasons,\n// and so we need to do the same here.\n// @todo is this in line with sanity?\nconst env = loadEnv(server.config.mode, server.config.envDir, '')\nfor (const key in env) {\n process.env[key] ??= env[key]\n}\n\n// Now we're using Vite's Module Runner (replaces vite-node in Vite 4+)\nconst runner = await createServerModuleRunner(server.environments.ssr, {\n hmr: false,\n sourcemapInterceptor: 'prepareStackTrace',\n})\n\n// Apply the `define` config from vite - imports environment variables\nawait runner.import('/@vite/env')\n\n// Execute the worker script\nawait runner.import(workerScriptPath)\n"],"names":["isMainThread","createServer","createServerModuleRunner","loadEnv","mergeConfig","getCliConfig","getStudioEnvironmentVariables","setupBrowserStubs","isRecord","isNotFoundError","Error","rootPath","process","env","STUDIO_WORKER_STUDIO_ROOT_PATH","workerScriptPath","STUDIO_WORKER_TASK_FILE","studioEnvVars","defaultViteConfig","build","target","configFile","define","Object","fromEntries","entries","map","key","value","JSON","stringify","logLevel","optimizeDeps","disabled","root","server","hmr","watch","cliConfig","err","console","warn","viteConfig","vite","command","isSsrBuild","mode","pluginContainer","buildStart","config","envDir","runner","environments","ssr","sourcemapInterceptor","import"],"mappings":"AAAA,SAAQA,YAAY,QAAO,sBAAqB;AAEhD,SAAQC,YAAY,EAAEC,wBAAwB,EAAqBC,OAAO,EAAEC,WAAW,QAAO,OAAM;AAEpG,SAAQC,YAAY,QAAO,mCAAkC;AAE7D,SAAQC,6BAA6B,QAAO,0DAAyD;AACrG,SAAQC,iBAAiB,QAAO,8CAA6C;AAC7E,SAAQC,QAAQ,QAAO,yBAAwB;AAC/C,SAAQC,eAAe,QAAO,8BAA6B;AAE3D,IAAIT,cAAc;IAChB,MAAM,IAAIU,MAAM;AAClB;AAEA,MAAMC,WAAWC,QAAQC,GAAG,CAACC,8BAA8B;AAC3D,IAAI,CAACH,UAAU;IACb,MAAM,IAAID,MAAM;AAClB;AAEA,MAAMK,mBAAmBH,QAAQC,GAAG,CAACG,uBAAuB;AAC5D,IAAI,CAACD,kBAAkB;IACrB,MAAM,IAAIL,MAAM;AAClB;AAEA,MAAMH;AAEN,MAAMU,gBAAgB,MAAMX,8BAA8BK;AAE1D,MAAMO,oBAAkC;IACtCC,OAAO;QAACC,QAAQ;IAAM;IACtBC,YAAY;IACZ,kEAAkE;IAClEC,QAAQC,OAAOC,WAAW,CACxBD,OAAOE,OAAO,CAACR,eAAeS,GAAG,CAAC,CAAC,CAACC,KAAKC,MAAM,GAAK;YAClD,CAAC,YAAY,EAAED,KAAK;YACpBE,KAAKC,SAAS,CAACF;SAChB;IAEHG,UAAU;IACVC,cAAc;QAACC,UAAU;IAAI;IAC7BC,MAAMvB;IACNwB,QAAQ;QACNC,KAAK;QACLC,OAAO;IACT;AACF;AAEA,oFAAoF;AACpF,+DAA+D;AAC/D,IAAIC;AACJ,IAAI;IACFA,YAAY,MAAMjC,aAAaM;AACjC,EAAE,OAAO4B,KAAK;IACZ,IAAI,CAAC9B,gBAAgB8B,MAAM;QACzB,sCAAsC;QACtCC,QAAQC,IAAI,CAAC,qCAAqCF;IACpD;AACF;AAEA,IAAIG,aAAaxB;AACjB,IAAI,OAAOoB,WAAWK,SAAS,YAAY;IACzCD,aAAc,MAAMJ,UAAUK,IAAI,CAACD,YAAY;QAC7CE,SAAS;QACTC,YAAY;QACZC,MAAM;IACR;AACF,OAAO,IAAItC,SAAS8B,WAAWK,OAAO;IACpCD,aAAatC,YAAYsC,YAAYJ,UAAUK,IAAI;AACrD;AAEA,oFAAoF;AACpF,4FAA4F;AAC5F,MAAMR,SAAS,MAAMlC,aAAayC;AAElC,oFAAoF;AACpF,MAAMP,OAAOY,eAAe,CAACC,UAAU,CAAC,CAAC;AAEzC,6EAA6E;AAC7E,mGAAmG;AACnG,sCAAsC;AACtC,qCAAqC;AACrC,MAAMnC,MAAMV,QAAQgC,OAAOc,MAAM,CAACH,IAAI,EAAEX,OAAOc,MAAM,CAACC,MAAM,EAAE;AAC9D,IAAK,MAAMvB,OAAOd,IAAK;IACrBD,QAAQC,GAAG,CAACc,IAAI,KAAKd,GAAG,CAACc,IAAI;AAC/B;AAEA,uEAAuE;AACvE,MAAMwB,SAAS,MAAMjD,yBAAyBiC,OAAOiB,YAAY,CAACC,GAAG,EAAE;IACrEjB,KAAK;IACLkB,sBAAsB;AACxB;AAEA,sEAAsE;AACtE,MAAMH,OAAOI,MAAM,CAAC;AAEpB,4BAA4B;AAC5B,MAAMJ,OAAOI,MAAM,CAACxC"}
1
+ {"version":3,"sources":["../../../src/loaders/studio/studioWorkerLoader.worker.ts"],"sourcesContent":["import {isMainThread} from 'node:worker_threads'\n\nimport {createServer, type InlineConfig, loadEnv, mergeConfig} from 'vite'\nimport {ViteNodeRunner} from 'vite-node/client'\nimport {ViteNodeServer} from 'vite-node/server'\nimport {installSourcemapsSupport} from 'vite-node/source-map'\n\nimport {getCliConfig} from '../../config/cli/getCliConfig.js'\nimport {type CliConfig} from '../../config/cli/types/cliConfig.js'\nimport {subdebug} from '../../debug.js'\nimport {getStudioEnvironmentVariables} from '../../util/environment/getStudioEnvironmentVariables.js'\nimport {setupBrowserStubs} from '../../util/environment/setupBrowserStubs.js'\nimport {isRecord} from '../../util/isRecord.js'\nimport {isNotFoundError} from '../../util/NotFoundError.js'\n\nif (isMainThread) {\n throw new Error('Should be child of thread, not the main thread')\n}\n\nconst rootPath = process.env.STUDIO_WORKER_STUDIO_ROOT_PATH\nif (!rootPath) {\n throw new Error('Missing `STUDIO_WORKER_STUDIO_ROOT_PATH` environment variable')\n}\n\nconst debug = subdebug('studio:worker')\n\nconst workerScriptPath = process.env.STUDIO_WORKER_TASK_FILE\nif (!workerScriptPath) {\n throw new Error('Missing `STUDIO_WORKER_TASK_FILE` environment variable')\n}\n\nawait setupBrowserStubs()\n\nconst studioEnvVars = await getStudioEnvironmentVariables(rootPath)\n\n// Allow the CLI config (`sanity.cli.(js|ts)`) to define a `vite` property which can\n// extend/modify the default vite configuration for the studio.\nlet cliConfig: CliConfig | undefined\ntry {\n cliConfig = await getCliConfig(rootPath)\n} catch (err) {\n debug('Failed to load CLI config: %o', err)\n if (!isNotFoundError(err)) {\n // eslint-disable-next-line no-console\n console.warn('[warn] Failed to load CLI config:', err)\n }\n}\n\n/**\n * Fetches and caches modules from HTTP/HTTPS URLs.\n * Vite's SSR transform treats `https://` imports as external and bypasses the plugin\n * resolve pipeline entirely, so we intercept them at the ViteNodeRunner level instead.\n */\nconst httpModuleCache = new Map<string, string>()\nasync function fetchHttpModule(url: string): Promise<{code: string}> {\n const cached = httpModuleCache.get(url)\n if (cached) return {code: cached}\n\n debug('Fetching HTTP import: %s', url)\n const response = await fetch(url, {signal: AbortSignal.timeout(30_000)})\n if (!response.ok) {\n throw new Error(`Failed to fetch module from ${url}: ${response.status} ${response.statusText}`)\n }\n\n const code = await response.text()\n httpModuleCache.set(url, code)\n return {code}\n}\n\nfunction isHttpsUrl(id: string): boolean {\n return id.startsWith('https://')\n}\n\nconst defaultViteConfig: InlineConfig = {\n build: {target: 'node'},\n configFile: false,\n // Inject environment variables as compile-time constants for Vite\n define: Object.fromEntries(\n Object.entries(studioEnvVars).map(([key, value]) => [\n `process.env.${key}`,\n JSON.stringify(value),\n ]),\n ),\n envPrefix: cliConfig && 'app' in cliConfig ? 'SANITY_APP_' : 'SANITY_STUDIO_',\n esbuild: {\n jsx: 'automatic',\n },\n logLevel: 'error',\n optimizeDeps: {\n include: undefined,\n noDiscovery: true,\n },\n root: rootPath,\n server: {\n hmr: false,\n watch: null,\n },\n ssr: {\n /**\n * We don't want to externalize any dependencies, we want everything to run thru vite.\n * Especially for CJS compatibility, etc.\n */\n noExternal: true,\n },\n}\n\n// Merge the CLI config's Vite config with the default Vite config\nlet viteConfig = defaultViteConfig\nif (typeof cliConfig?.vite === 'function') {\n viteConfig = (await cliConfig.vite(viteConfig, {\n command: 'build',\n isSsrBuild: true,\n mode: 'production',\n })) as InlineConfig\n} else if (isRecord(cliConfig?.vite)) {\n viteConfig = mergeConfig(viteConfig, cliConfig.vite)\n}\n\ndebug('Creating Vite server with config: %o', viteConfig)\n// Vite will build the files we give it - targetting Node.js instead of the browser.\n// We include the inject plugin in order to provide the stubs for the undefined global APIs.\nconst server = await createServer(viteConfig)\n\n// Bit of a hack, but seems necessary based on the `node-vite` binary implementation\nawait server.pluginContainer.buildStart({})\n\n// Load environment variables from `.env` files in the same way as Vite does.\n// Note that Sanity also provides environment variables through `process.env.*` for compat reasons,\n// and so we need to do the same here.\nconst env = loadEnv(server.config.mode, server.config.envDir, viteConfig.envPrefix ?? '')\nfor (const key in env) {\n process.env[key] ??= env[key]\n}\n\n// Now we're providing the glue that ensures node-specific loading and execution works.\nconst node = new ViteNodeServer(server)\n\n// Should make it easier to debug any crashes in the imported code…\ninstallSourcemapsSupport({\n getSourceMap: (source) => node.getSourceMap(source),\n})\n\nconst runner = new ViteNodeRunner({\n base: server.config.base,\n async fetchModule(id) {\n // Vite's SSR transform externalizes https:// imports, so Node's ESM loader\n // would reject them. We fetch the module over HTTP and run it through Vite's\n // SSR transform to rewrite ESM export/import syntax to the __vite_ssr_*\n // format that ViteNodeRunner expects.\n if (isHttpsUrl(id)) {\n const {code: rawCode} = await fetchHttpModule(id)\n const result = await server.ssrTransform(rawCode, null, id)\n return {code: result?.code || rawCode}\n }\n return node.fetchModule(id)\n },\n resolveId(id, importer) {\n // Prevent vite-node from trying to resolve HTTP URLs through Node's resolver\n if (isHttpsUrl(id)) return {id}\n // Resolve any import from an HTTP-fetched module against the remote origin\n // (e.g. esm.sh returns `export * from '/pkg@1.0/es2022/pkg.mjs'`)\n if (importer && isHttpsUrl(importer)) {\n return {id: new URL(id, importer).href}\n }\n return node.resolveId(id, importer)\n },\n root: server.config.root,\n})\n\n// Copied from `vite-node` - it appears that this applies the `define` config from\n// vite, but it also takes a surprisingly long time to execute. Not clear at this\n// point why this is, so we should investigate whether it's necessary or not.\nawait runner.executeId('/@vite/env')\n\nawait runner.executeId(workerScriptPath)\n"],"names":["isMainThread","createServer","loadEnv","mergeConfig","ViteNodeRunner","ViteNodeServer","installSourcemapsSupport","getCliConfig","subdebug","getStudioEnvironmentVariables","setupBrowserStubs","isRecord","isNotFoundError","Error","rootPath","process","env","STUDIO_WORKER_STUDIO_ROOT_PATH","debug","workerScriptPath","STUDIO_WORKER_TASK_FILE","studioEnvVars","cliConfig","err","console","warn","httpModuleCache","Map","fetchHttpModule","url","cached","get","code","response","fetch","signal","AbortSignal","timeout","ok","status","statusText","text","set","isHttpsUrl","id","startsWith","defaultViteConfig","build","target","configFile","define","Object","fromEntries","entries","map","key","value","JSON","stringify","envPrefix","esbuild","jsx","logLevel","optimizeDeps","include","undefined","noDiscovery","root","server","hmr","watch","ssr","noExternal","viteConfig","vite","command","isSsrBuild","mode","pluginContainer","buildStart","config","envDir","node","getSourceMap","source","runner","base","fetchModule","rawCode","result","ssrTransform","resolveId","importer","URL","href","executeId"],"mappings":"AAAA,SAAQA,YAAY,QAAO,sBAAqB;AAEhD,SAAQC,YAAY,EAAqBC,OAAO,EAAEC,WAAW,QAAO,OAAM;AAC1E,SAAQC,cAAc,QAAO,mBAAkB;AAC/C,SAAQC,cAAc,QAAO,mBAAkB;AAC/C,SAAQC,wBAAwB,QAAO,uBAAsB;AAE7D,SAAQC,YAAY,QAAO,mCAAkC;AAE7D,SAAQC,QAAQ,QAAO,iBAAgB;AACvC,SAAQC,6BAA6B,QAAO,0DAAyD;AACrG,SAAQC,iBAAiB,QAAO,8CAA6C;AAC7E,SAAQC,QAAQ,QAAO,yBAAwB;AAC/C,SAAQC,eAAe,QAAO,8BAA6B;AAE3D,IAAIZ,cAAc;IAChB,MAAM,IAAIa,MAAM;AAClB;AAEA,MAAMC,WAAWC,QAAQC,GAAG,CAACC,8BAA8B;AAC3D,IAAI,CAACH,UAAU;IACb,MAAM,IAAID,MAAM;AAClB;AAEA,MAAMK,QAAQV,SAAS;AAEvB,MAAMW,mBAAmBJ,QAAQC,GAAG,CAACI,uBAAuB;AAC5D,IAAI,CAACD,kBAAkB;IACrB,MAAM,IAAIN,MAAM;AAClB;AAEA,MAAMH;AAEN,MAAMW,gBAAgB,MAAMZ,8BAA8BK;AAE1D,oFAAoF;AACpF,+DAA+D;AAC/D,IAAIQ;AACJ,IAAI;IACFA,YAAY,MAAMf,aAAaO;AACjC,EAAE,OAAOS,KAAK;IACZL,MAAM,iCAAiCK;IACvC,IAAI,CAACX,gBAAgBW,MAAM;QACzB,sCAAsC;QACtCC,QAAQC,IAAI,CAAC,qCAAqCF;IACpD;AACF;AAEA;;;;CAIC,GACD,MAAMG,kBAAkB,IAAIC;AAC5B,eAAeC,gBAAgBC,GAAW;IACxC,MAAMC,SAASJ,gBAAgBK,GAAG,CAACF;IACnC,IAAIC,QAAQ,OAAO;QAACE,MAAMF;IAAM;IAEhCZ,MAAM,4BAA4BW;IAClC,MAAMI,WAAW,MAAMC,MAAML,KAAK;QAACM,QAAQC,YAAYC,OAAO,CAAC;IAAO;IACtE,IAAI,CAACJ,SAASK,EAAE,EAAE;QAChB,MAAM,IAAIzB,MAAM,CAAC,4BAA4B,EAAEgB,IAAI,EAAE,EAAEI,SAASM,MAAM,CAAC,CAAC,EAAEN,SAASO,UAAU,EAAE;IACjG;IAEA,MAAMR,OAAO,MAAMC,SAASQ,IAAI;IAChCf,gBAAgBgB,GAAG,CAACb,KAAKG;IACzB,OAAO;QAACA;IAAI;AACd;AAEA,SAASW,WAAWC,EAAU;IAC5B,OAAOA,GAAGC,UAAU,CAAC;AACvB;AAEA,MAAMC,oBAAkC;IACtCC,OAAO;QAACC,QAAQ;IAAM;IACtBC,YAAY;IACZ,kEAAkE;IAClEC,QAAQC,OAAOC,WAAW,CACxBD,OAAOE,OAAO,CAAChC,eAAeiC,GAAG,CAAC,CAAC,CAACC,KAAKC,MAAM,GAAK;YAClD,CAAC,YAAY,EAAED,KAAK;YACpBE,KAAKC,SAAS,CAACF;SAChB;IAEHG,WAAWrC,aAAa,SAASA,YAAY,gBAAgB;IAC7DsC,SAAS;QACPC,KAAK;IACP;IACAC,UAAU;IACVC,cAAc;QACZC,SAASC;QACTC,aAAa;IACf;IACAC,MAAMrD;IACNsD,QAAQ;QACNC,KAAK;QACLC,OAAO;IACT;IACAC,KAAK;QACH;;;KAGC,GACDC,YAAY;IACd;AACF;AAEA,kEAAkE;AAClE,IAAIC,aAAa3B;AACjB,IAAI,OAAOxB,WAAWoD,SAAS,YAAY;IACzCD,aAAc,MAAMnD,UAAUoD,IAAI,CAACD,YAAY;QAC7CE,SAAS;QACTC,YAAY;QACZC,MAAM;IACR;AACF,OAAO,IAAIlE,SAASW,WAAWoD,OAAO;IACpCD,aAAatE,YAAYsE,YAAYnD,UAAUoD,IAAI;AACrD;AAEAxD,MAAM,wCAAwCuD;AAC9C,oFAAoF;AACpF,4FAA4F;AAC5F,MAAML,SAAS,MAAMnE,aAAawE;AAElC,oFAAoF;AACpF,MAAML,OAAOU,eAAe,CAACC,UAAU,CAAC,CAAC;AAEzC,6EAA6E;AAC7E,mGAAmG;AACnG,sCAAsC;AACtC,MAAM/D,MAAMd,QAAQkE,OAAOY,MAAM,CAACH,IAAI,EAAET,OAAOY,MAAM,CAACC,MAAM,EAAER,WAAWd,SAAS,IAAI;AACtF,IAAK,MAAMJ,OAAOvC,IAAK;IACrBD,QAAQC,GAAG,CAACuC,IAAI,KAAKvC,GAAG,CAACuC,IAAI;AAC/B;AAEA,uFAAuF;AACvF,MAAM2B,OAAO,IAAI7E,eAAe+D;AAEhC,mEAAmE;AACnE9D,yBAAyB;IACvB6E,cAAc,CAACC,SAAWF,KAAKC,YAAY,CAACC;AAC9C;AAEA,MAAMC,SAAS,IAAIjF,eAAe;IAChCkF,MAAMlB,OAAOY,MAAM,CAACM,IAAI;IACxB,MAAMC,aAAY3C,EAAE;QAClB,2EAA2E;QAC3E,6EAA6E;QAC7E,wEAAwE;QACxE,sCAAsC;QACtC,IAAID,WAAWC,KAAK;YAClB,MAAM,EAACZ,MAAMwD,OAAO,EAAC,GAAG,MAAM5D,gBAAgBgB;YAC9C,MAAM6C,SAAS,MAAMrB,OAAOsB,YAAY,CAACF,SAAS,MAAM5C;YACxD,OAAO;gBAACZ,MAAMyD,QAAQzD,QAAQwD;YAAO;QACvC;QACA,OAAON,KAAKK,WAAW,CAAC3C;IAC1B;IACA+C,WAAU/C,EAAE,EAAEgD,QAAQ;QACpB,6EAA6E;QAC7E,IAAIjD,WAAWC,KAAK,OAAO;YAACA;QAAE;QAC9B,2EAA2E;QAC3E,kEAAkE;QAClE,IAAIgD,YAAYjD,WAAWiD,WAAW;YACpC,OAAO;gBAAChD,IAAI,IAAIiD,IAAIjD,IAAIgD,UAAUE,IAAI;YAAA;QACxC;QACA,OAAOZ,KAAKS,SAAS,CAAC/C,IAAIgD;IAC5B;IACAzB,MAAMC,OAAOY,MAAM,CAACb,IAAI;AAC1B;AAEA,kFAAkF;AAClF,iFAAiF;AACjF,6EAA6E;AAC7E,MAAMkB,OAAOU,SAAS,CAAC;AAEvB,MAAMV,OAAOU,SAAS,CAAC5E"}
@@ -30,8 +30,19 @@ import { promisifyWorker } from '../../util/promisifyWorker.js';
30
30
  * @throws If the worker exits with a non-zero code
31
31
  * @internal
32
32
  */ export function studioWorkerTask(filePath, options) {
33
- const worker = createStudioWorker(filePath, options);
34
- return promisifyWorker(worker);
33
+ const normalizedFilePath = fileURLToPath(filePath);
34
+ if (!/\.worker\.(js|ts)$/.test(normalizedFilePath)) {
35
+ throw new Error('Studio worker tasks must include `.worker.(js|ts)` in path');
36
+ }
37
+ const { studioRootPath, ...workerOptions } = options;
38
+ return promisifyWorker(new URL('studioWorkerLoader.worker.js', import.meta.url), {
39
+ ...workerOptions,
40
+ env: {
41
+ ...isRecord(workerOptions.env) ? workerOptions.env : process.env,
42
+ STUDIO_WORKER_STUDIO_ROOT_PATH: studioRootPath,
43
+ STUDIO_WORKER_TASK_FILE: normalizedFilePath
44
+ }
45
+ });
35
46
  }
36
47
  /**
37
48
  * Creates a new worker for a studio worker task.
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/loaders/studio/studioWorkerTask.ts"],"sourcesContent":["import {fileURLToPath} from 'node:url'\nimport {Worker, type WorkerOptions} from 'node:worker_threads'\n\nimport {type RequireProps} from '../../types.js'\nimport {isRecord} from '../../util/isRecord.js'\nimport {promisifyWorker} from '../../util/promisifyWorker.js'\n\n/**\n * Options for the studio worker task\n *\n * @internal\n */\ninterface StudioWorkerTaskOptions extends RequireProps<WorkerOptions, 'name'> {\n studioRootPath: string\n}\n\n/**\n * Executes a worker file in a Sanity Studio browser context.\n *\n * This uses a combination of vite for \"bundling\" + jsdom for emulating a browser\n * environment under the hood, which means that the same thing that will work in vite\n * _should_ work in the worker - to a degree. If the user has defined any typescript\n * path aliases, these will have to be added as aliases to the vite config - the same\n * behavior as you would see with regular vite. Other things that are accounted for:\n *\n * - TypeScript support (+JSX, enums and other \"compilation needed\" features)\n * - CSS, font and other file imports will resolve to a file path\n * - CSS module imports will resolve to a javascript object of class names\n * - Environment variables are available both as `import.meta.env` and `process.env`,\n * and `.env` files are loaded in the same way that they would in a Sanity studio.\n * - Browser globals not available in a Node.js environment but _are_ provided by JSDOM\n * are defined directly to the Node environment as globals. While this polutes the\n * global namespace, it is done only in the worker thread.\n * - Certain browser globals that are _not_ available in JSDOM are also provided to the\n * global namespace - things like `requestIdleCallback`, `IntersectionObserver` etc.\n * These are provided with a minimal stub implementation to make them not crash.\n *\n * @param filePath - Path to the worker file (`.ts` works and is encouraged)\n * @param options - Options to pass to the worker\n * @returns A promise that resolves with the message from the worker\n * @throws If the file does not exist\n * @throws If the worker exits with a non-zero code\n * @internal\n */\nexport function studioWorkerTask<T = unknown>(\n filePath: URL,\n options: StudioWorkerTaskOptions,\n): Promise<T> {\n const worker = createStudioWorker(filePath, options)\n return promisifyWorker<T>(worker)\n}\n\n/**\n * Creates a new worker for a studio worker task.\n *\n * This uses a combination of vite for \"bundling\" + jsdom for emulating a browser\n * environment under the hood, which means that the same thing that will work in vite\n * _should_ work in the worker - to a degree. If the user has defined any typescript\n * path aliases, these will have to be added as aliases to the vite config - the same\n * behavior as you would see with regular vite. Other things that are accounted for:\n *\n * - TypeScript support (+JSX, enums and other \"compilation needed\" features)\n * - CSS, font and other file imports will resolve to a file path\n * - CSS module imports will resolve to a javascript object of class names\n * - Environment variables are available both as `import.meta.env` and `process.env`,\n * and `.env` files are loaded in the same way that they would in a Sanity studio.\n * - Browser globals not available in a Node.js environment but _are_ provided by JSDOM\n * are defined directly to the Node environment as globals. While this polutes the\n * global namespace, it is done only in the worker thread.\n * - Certain browser globals that are _not_ available in JSDOM are also provided to the\n * global namespace - things like `requestIdleCallback`, `IntersectionObserver` etc.\n * These are provided with a minimal stub implementation to make them not crash.\n *\n * @param filePath - Path to the worker file (`.ts` works and is encouraged)\n * @param options - Options to pass to the worker\n * @returns A promise that resolves with the message from the worker\n * @throws If the file does not exist\n * @throws If the worker exits with a non-zero code\n * @internal\n */\nexport function createStudioWorker(filePath: URL, options: StudioWorkerTaskOptions) {\n const normalizedFilePath = fileURLToPath(filePath)\n\n if (!/\\.worker\\.(js|ts)$/.test(normalizedFilePath)) {\n throw new Error('Studio worker tasks must include `.worker.(js|ts)` in path')\n }\n\n return new Worker(new URL('studioWorkerLoader.worker.js', import.meta.url), {\n ...options,\n env: {\n ...(isRecord(options.env) ? options.env : process.env),\n STUDIO_WORKER_STUDIO_ROOT_PATH: options.studioRootPath,\n STUDIO_WORKER_TASK_FILE: normalizedFilePath,\n },\n })\n}\n"],"names":["fileURLToPath","Worker","isRecord","promisifyWorker","studioWorkerTask","filePath","options","worker","createStudioWorker","normalizedFilePath","test","Error","URL","url","env","process","STUDIO_WORKER_STUDIO_ROOT_PATH","studioRootPath","STUDIO_WORKER_TASK_FILE"],"mappings":"AAAA,SAAQA,aAAa,QAAO,WAAU;AACtC,SAAQC,MAAM,QAA2B,sBAAqB;AAG9D,SAAQC,QAAQ,QAAO,yBAAwB;AAC/C,SAAQC,eAAe,QAAO,gCAA+B;AAW7D;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2BC,GACD,OAAO,SAASC,iBACdC,QAAa,EACbC,OAAgC;IAEhC,MAAMC,SAASC,mBAAmBH,UAAUC;IAC5C,OAAOH,gBAAmBI;AAC5B;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2BC,GACD,OAAO,SAASC,mBAAmBH,QAAa,EAAEC,OAAgC;IAChF,MAAMG,qBAAqBT,cAAcK;IAEzC,IAAI,CAAC,qBAAqBK,IAAI,CAACD,qBAAqB;QAClD,MAAM,IAAIE,MAAM;IAClB;IAEA,OAAO,IAAIV,OAAO,IAAIW,IAAI,gCAAgC,YAAYC,GAAG,GAAG;QAC1E,GAAGP,OAAO;QACVQ,KAAK;YACH,GAAIZ,SAASI,QAAQQ,GAAG,IAAIR,QAAQQ,GAAG,GAAGC,QAAQD,GAAG;YACrDE,gCAAgCV,QAAQW,cAAc;YACtDC,yBAAyBT;QAC3B;IACF;AACF"}
1
+ {"version":3,"sources":["../../../src/loaders/studio/studioWorkerTask.ts"],"sourcesContent":["import {fileURLToPath} from 'node:url'\nimport {Worker, type WorkerOptions} from 'node:worker_threads'\n\nimport {type RequireProps} from '../../types.js'\nimport {isRecord} from '../../util/isRecord.js'\nimport {promisifyWorker} from '../../util/promisifyWorker.js'\n\n/**\n * Options for the studio worker task\n *\n * @internal\n */\ninterface StudioWorkerTaskOptions extends RequireProps<WorkerOptions, 'name'> {\n studioRootPath: string\n}\n\n/**\n * Executes a worker file in a Sanity Studio browser context.\n *\n * This uses a combination of vite for \"bundling\" + jsdom for emulating a browser\n * environment under the hood, which means that the same thing that will work in vite\n * _should_ work in the worker - to a degree. If the user has defined any typescript\n * path aliases, these will have to be added as aliases to the vite config - the same\n * behavior as you would see with regular vite. Other things that are accounted for:\n *\n * - TypeScript support (+JSX, enums and other \"compilation needed\" features)\n * - CSS, font and other file imports will resolve to a file path\n * - CSS module imports will resolve to a javascript object of class names\n * - Environment variables are available both as `import.meta.env` and `process.env`,\n * and `.env` files are loaded in the same way that they would in a Sanity studio.\n * - Browser globals not available in a Node.js environment but _are_ provided by JSDOM\n * are defined directly to the Node environment as globals. While this polutes the\n * global namespace, it is done only in the worker thread.\n * - Certain browser globals that are _not_ available in JSDOM are also provided to the\n * global namespace - things like `requestIdleCallback`, `IntersectionObserver` etc.\n * These are provided with a minimal stub implementation to make them not crash.\n *\n * @param filePath - Path to the worker file (`.ts` works and is encouraged)\n * @param options - Options to pass to the worker\n * @returns A promise that resolves with the message from the worker\n * @throws If the file does not exist\n * @throws If the worker exits with a non-zero code\n * @internal\n */\nexport function studioWorkerTask<T = unknown>(\n filePath: URL,\n options: StudioWorkerTaskOptions,\n): Promise<T> {\n const normalizedFilePath = fileURLToPath(filePath)\n\n if (!/\\.worker\\.(js|ts)$/.test(normalizedFilePath)) {\n throw new Error('Studio worker tasks must include `.worker.(js|ts)` in path')\n }\n\n const {studioRootPath, ...workerOptions} = options\n return promisifyWorker<T>(new URL('studioWorkerLoader.worker.js', import.meta.url), {\n ...workerOptions,\n env: {\n ...(isRecord(workerOptions.env) ? workerOptions.env : process.env),\n STUDIO_WORKER_STUDIO_ROOT_PATH: studioRootPath,\n STUDIO_WORKER_TASK_FILE: normalizedFilePath,\n },\n })\n}\n\n/**\n * Creates a new worker for a studio worker task.\n *\n * This uses a combination of vite for \"bundling\" + jsdom for emulating a browser\n * environment under the hood, which means that the same thing that will work in vite\n * _should_ work in the worker - to a degree. If the user has defined any typescript\n * path aliases, these will have to be added as aliases to the vite config - the same\n * behavior as you would see with regular vite. Other things that are accounted for:\n *\n * - TypeScript support (+JSX, enums and other \"compilation needed\" features)\n * - CSS, font and other file imports will resolve to a file path\n * - CSS module imports will resolve to a javascript object of class names\n * - Environment variables are available both as `import.meta.env` and `process.env`,\n * and `.env` files are loaded in the same way that they would in a Sanity studio.\n * - Browser globals not available in a Node.js environment but _are_ provided by JSDOM\n * are defined directly to the Node environment as globals. While this polutes the\n * global namespace, it is done only in the worker thread.\n * - Certain browser globals that are _not_ available in JSDOM are also provided to the\n * global namespace - things like `requestIdleCallback`, `IntersectionObserver` etc.\n * These are provided with a minimal stub implementation to make them not crash.\n *\n * @param filePath - Path to the worker file (`.ts` works and is encouraged)\n * @param options - Options to pass to the worker\n * @returns A promise that resolves with the message from the worker\n * @throws If the file does not exist\n * @throws If the worker exits with a non-zero code\n * @internal\n */\nexport function createStudioWorker(filePath: URL, options: StudioWorkerTaskOptions) {\n const normalizedFilePath = fileURLToPath(filePath)\n\n if (!/\\.worker\\.(js|ts)$/.test(normalizedFilePath)) {\n throw new Error('Studio worker tasks must include `.worker.(js|ts)` in path')\n }\n\n return new Worker(new URL('studioWorkerLoader.worker.js', import.meta.url), {\n ...options,\n env: {\n ...(isRecord(options.env) ? options.env : process.env),\n STUDIO_WORKER_STUDIO_ROOT_PATH: options.studioRootPath,\n STUDIO_WORKER_TASK_FILE: normalizedFilePath,\n },\n })\n}\n"],"names":["fileURLToPath","Worker","isRecord","promisifyWorker","studioWorkerTask","filePath","options","normalizedFilePath","test","Error","studioRootPath","workerOptions","URL","url","env","process","STUDIO_WORKER_STUDIO_ROOT_PATH","STUDIO_WORKER_TASK_FILE","createStudioWorker"],"mappings":"AAAA,SAAQA,aAAa,QAAO,WAAU;AACtC,SAAQC,MAAM,QAA2B,sBAAqB;AAG9D,SAAQC,QAAQ,QAAO,yBAAwB;AAC/C,SAAQC,eAAe,QAAO,gCAA+B;AAW7D;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2BC,GACD,OAAO,SAASC,iBACdC,QAAa,EACbC,OAAgC;IAEhC,MAAMC,qBAAqBP,cAAcK;IAEzC,IAAI,CAAC,qBAAqBG,IAAI,CAACD,qBAAqB;QAClD,MAAM,IAAIE,MAAM;IAClB;IAEA,MAAM,EAACC,cAAc,EAAE,GAAGC,eAAc,GAAGL;IAC3C,OAAOH,gBAAmB,IAAIS,IAAI,gCAAgC,YAAYC,GAAG,GAAG;QAClF,GAAGF,aAAa;QAChBG,KAAK;YACH,GAAIZ,SAASS,cAAcG,GAAG,IAAIH,cAAcG,GAAG,GAAGC,QAAQD,GAAG;YACjEE,gCAAgCN;YAChCO,yBAAyBV;QAC3B;IACF;AACF;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2BC,GACD,OAAO,SAASW,mBAAmBb,QAAa,EAAEC,OAAgC;IAChF,MAAMC,qBAAqBP,cAAcK;IAEzC,IAAI,CAAC,qBAAqBG,IAAI,CAACD,qBAAqB;QAClD,MAAM,IAAIE,MAAM;IAClB;IAEA,OAAO,IAAIR,OAAO,IAAIW,IAAI,gCAAgC,YAAYC,GAAG,GAAG;QAC1E,GAAGP,OAAO;QACVQ,KAAK;YACH,GAAIZ,SAASI,QAAQQ,GAAG,IAAIR,QAAQQ,GAAG,GAAGC,QAAQD,GAAG;YACrDE,gCAAgCV,QAAQI,cAAc;YACtDO,yBAAyBV;QAC3B;IACF;AACF"}
@@ -1,5 +1,4 @@
1
1
  import { fileURLToPath, URL } from 'node:url';
2
- import { Worker } from 'node:worker_threads';
3
2
  import { getTsconfig } from 'get-tsconfig';
4
3
  import { isRecord } from '../../util/isRecord.js';
5
4
  import { promisifyWorker } from '../../util/promisifyWorker.js';
@@ -26,11 +25,10 @@ import { promisifyWorker } from '../../util/promisifyWorker.js';
26
25
  } : {},
27
26
  TSX_WORKER_TASK_SCRIPT: fileURLToPath(filePath)
28
27
  };
29
- const worker = new Worker(new URL('tsxWorkerLoader.worker.js', import.meta.url), {
28
+ return promisifyWorker(new URL('tsxWorkerLoader.worker.js', import.meta.url), {
30
29
  ...options,
31
30
  env
32
31
  });
33
- return promisifyWorker(worker);
34
32
  }
35
33
 
36
34
  //# sourceMappingURL=tsxWorkerTask.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/loaders/tsx/tsxWorkerTask.ts"],"sourcesContent":["import {fileURLToPath, URL} from 'node:url'\nimport {Worker, type WorkerOptions} from 'node:worker_threads'\n\nimport {getTsconfig} from 'get-tsconfig'\n\nimport {type RequireProps} from '../../types.js'\nimport {isRecord} from '../../util/isRecord.js'\nimport {promisifyWorker} from '../../util/promisifyWorker.js'\n\n/**\n * Options for the tsx worker task\n *\n * @internal\n */\ninterface TsxWorkerTaskOptions extends RequireProps<WorkerOptions, 'name'> {\n rootPath: string\n}\n\n/**\n * Executes a worker file with tsx registered. This means you can import other\n * typescript with fairly rich syntax, and still have that only apply to the worker\n * thread instead of the full parent process. The worker should emit a message when\n * complete using `parentPort`. Once it has received a single message will resolve the\n * returned promise with that message. If you are expecting multiple messages, you will\n * have to implement another method ;)\n *\n * @param filePath - Path to the worker file\n * @param options - Options to pass to the worker\n * @returns A promise that resolves with the message from the worker\n * @throws If the file does not exist\n * @throws If the worker exits with a non-zero code\n * @internal\n */\nexport function tsxWorkerTask<T = unknown>(\n filePath: URL,\n options: TsxWorkerTaskOptions,\n): Promise<T> {\n const tsconfig = getTsconfig(options.rootPath)\n\n const env = {\n ...(isRecord(options.env) ? options.env : process.env),\n ...(tsconfig?.path ? {TSX_TSCONFIG_PATH: tsconfig.path} : {}),\n TSX_WORKER_TASK_SCRIPT: fileURLToPath(filePath),\n }\n\n const worker = new Worker(new URL('tsxWorkerLoader.worker.js', import.meta.url), {\n ...options,\n env,\n })\n\n return promisifyWorker<T>(worker)\n}\n"],"names":["fileURLToPath","URL","Worker","getTsconfig","isRecord","promisifyWorker","tsxWorkerTask","filePath","options","tsconfig","rootPath","env","process","path","TSX_TSCONFIG_PATH","TSX_WORKER_TASK_SCRIPT","worker","url"],"mappings":"AAAA,SAAQA,aAAa,EAAEC,GAAG,QAAO,WAAU;AAC3C,SAAQC,MAAM,QAA2B,sBAAqB;AAE9D,SAAQC,WAAW,QAAO,eAAc;AAGxC,SAAQC,QAAQ,QAAO,yBAAwB;AAC/C,SAAQC,eAAe,QAAO,gCAA+B;AAW7D;;;;;;;;;;;;;;CAcC,GACD,OAAO,SAASC,cACdC,QAAa,EACbC,OAA6B;IAE7B,MAAMC,WAAWN,YAAYK,QAAQE,QAAQ;IAE7C,MAAMC,MAAM;QACV,GAAIP,SAASI,QAAQG,GAAG,IAAIH,QAAQG,GAAG,GAAGC,QAAQD,GAAG;QACrD,GAAIF,UAAUI,OAAO;YAACC,mBAAmBL,SAASI,IAAI;QAAA,IAAI,CAAC,CAAC;QAC5DE,wBAAwBf,cAAcO;IACxC;IAEA,MAAMS,SAAS,IAAId,OAAO,IAAID,IAAI,6BAA6B,YAAYgB,GAAG,GAAG;QAC/E,GAAGT,OAAO;QACVG;IACF;IAEA,OAAON,gBAAmBW;AAC5B"}
1
+ {"version":3,"sources":["../../../src/loaders/tsx/tsxWorkerTask.ts"],"sourcesContent":["import {fileURLToPath, URL} from 'node:url'\nimport {type WorkerOptions} from 'node:worker_threads'\n\nimport {getTsconfig} from 'get-tsconfig'\n\nimport {type RequireProps} from '../../types.js'\nimport {isRecord} from '../../util/isRecord.js'\nimport {promisifyWorker} from '../../util/promisifyWorker.js'\n\n/**\n * Options for the tsx worker task\n *\n * @internal\n */\ninterface TsxWorkerTaskOptions extends RequireProps<WorkerOptions, 'name'> {\n rootPath: string\n}\n\n/**\n * Executes a worker file with tsx registered. This means you can import other\n * typescript with fairly rich syntax, and still have that only apply to the worker\n * thread instead of the full parent process. The worker should emit a message when\n * complete using `parentPort`. Once it has received a single message will resolve the\n * returned promise with that message. If you are expecting multiple messages, you will\n * have to implement another method ;)\n *\n * @param filePath - Path to the worker file\n * @param options - Options to pass to the worker\n * @returns A promise that resolves with the message from the worker\n * @throws If the file does not exist\n * @throws If the worker exits with a non-zero code\n * @internal\n */\nexport function tsxWorkerTask<T = unknown>(\n filePath: URL,\n options: TsxWorkerTaskOptions,\n): Promise<T> {\n const tsconfig = getTsconfig(options.rootPath)\n\n const env = {\n ...(isRecord(options.env) ? options.env : process.env),\n ...(tsconfig?.path ? {TSX_TSCONFIG_PATH: tsconfig.path} : {}),\n TSX_WORKER_TASK_SCRIPT: fileURLToPath(filePath),\n }\n\n return promisifyWorker<T>(new URL('tsxWorkerLoader.worker.js', import.meta.url), {\n ...options,\n env,\n })\n}\n"],"names":["fileURLToPath","URL","getTsconfig","isRecord","promisifyWorker","tsxWorkerTask","filePath","options","tsconfig","rootPath","env","process","path","TSX_TSCONFIG_PATH","TSX_WORKER_TASK_SCRIPT","url"],"mappings":"AAAA,SAAQA,aAAa,EAAEC,GAAG,QAAO,WAAU;AAG3C,SAAQC,WAAW,QAAO,eAAc;AAGxC,SAAQC,QAAQ,QAAO,yBAAwB;AAC/C,SAAQC,eAAe,QAAO,gCAA+B;AAW7D;;;;;;;;;;;;;;CAcC,GACD,OAAO,SAASC,cACdC,QAAa,EACbC,OAA6B;IAE7B,MAAMC,WAAWN,YAAYK,QAAQE,QAAQ;IAE7C,MAAMC,MAAM;QACV,GAAIP,SAASI,QAAQG,GAAG,IAAIH,QAAQG,GAAG,GAAGC,QAAQD,GAAG;QACrD,GAAIF,UAAUI,OAAO;YAACC,mBAAmBL,SAASI,IAAI;QAAA,IAAI,CAAC,CAAC;QAC5DE,wBAAwBd,cAAcM;IACxC;IAEA,OAAOF,gBAAmB,IAAIH,IAAI,6BAA6B,YAAYc,GAAG,GAAG;QAC/E,GAAGR,OAAO;QACVG;IACF;AACF"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Error thrown when a prompt is attempted in a non-interactive environment
3
+ * (e.g., CI, non-TTY, piped stdin). Callers can catch this specific error
4
+ * to provide appropriate fallback behavior.
5
+ */ export class NonInteractiveError extends Error {
6
+ constructor(promptName){
7
+ super(`Cannot run "${promptName}" prompt in a non-interactive environment. ` + 'Provide the required value via flags or environment variables, or run in an interactive terminal.');
8
+ this.name = 'NonInteractiveError';
9
+ }
10
+ }
11
+
12
+ //# sourceMappingURL=NonInteractiveError.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/util/NonInteractiveError.ts"],"sourcesContent":["/**\n * Error thrown when a prompt is attempted in a non-interactive environment\n * (e.g., CI, non-TTY, piped stdin). Callers can catch this specific error\n * to provide appropriate fallback behavior.\n */\nexport class NonInteractiveError extends Error {\n constructor(promptName: string) {\n super(\n `Cannot run \"${promptName}\" prompt in a non-interactive environment. ` +\n 'Provide the required value via flags or environment variables, or run in an interactive terminal.',\n )\n this.name = 'NonInteractiveError'\n }\n}\n"],"names":["NonInteractiveError","Error","promptName","name"],"mappings":"AAAA;;;;CAIC,GACD,OAAO,MAAMA,4BAA4BC;IACvC,YAAYC,UAAkB,CAAE;QAC9B,KAAK,CACH,CAAC,YAAY,EAAEA,WAAW,2CAA2C,CAAC,GACpE;QAEJ,IAAI,CAACC,IAAI,GAAG;IACd;AACF"}
@@ -9,8 +9,9 @@ import { pathToFileURL } from 'node:url';
9
9
  // Absolute paths in windows are not valid URLs and are not supported by import().
10
10
  // We need to convert the path to a file URL.
11
11
  // See: https://github.com/nodejs/node/issues/31710
12
+ const url = /^file:\/\//.test(source) ? source : pathToFileURL(source).href;
12
13
  // eslint-disable-next-line no-restricted-syntax
13
- return import(/^file:\/\//.test(source) ? source : pathToFileURL(source).href);
14
+ return import(/* @vite-ignore */ url);
14
15
  }
15
16
 
16
17
  //# sourceMappingURL=doImport.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/util/doImport.ts"],"sourcesContent":["// Only file that should be using dynamic import\nimport {pathToFileURL} from 'node:url'\n\n/**\n * This function is a replacement for built in dynamic import\n * This handles the case for windows file paths especially for absolute paths.\n *\n * @param source - File path\n */\nexport function doImport(source: string) {\n // Absolute paths in windows are not valid URLs and are not supported by import().\n // We need to convert the path to a file URL.\n // See: https://github.com/nodejs/node/issues/31710\n // eslint-disable-next-line no-restricted-syntax\n return import(/^file:\\/\\//.test(source) ? source : pathToFileURL(source).href)\n}\n"],"names":["pathToFileURL","doImport","source","test","href"],"mappings":"AAAA,gDAAgD;AAChD,SAAQA,aAAa,QAAO,WAAU;AAEtC;;;;;CAKC,GACD,OAAO,SAASC,SAASC,MAAc;IACrC,kFAAkF;IAClF,6CAA6C;IAC7C,mDAAmD;IACnD,gDAAgD;IAChD,OAAO,MAAM,CAAC,aAAaC,IAAI,CAACD,UAAUA,SAASF,cAAcE,QAAQE,IAAI;AAC/E"}
1
+ {"version":3,"sources":["../../src/util/doImport.ts"],"sourcesContent":["// Only file that should be using dynamic import\nimport {pathToFileURL} from 'node:url'\n\n/**\n * This function is a replacement for built in dynamic import\n * This handles the case for windows file paths especially for absolute paths.\n *\n * @param source - File path\n */\nexport function doImport(source: string) {\n // Absolute paths in windows are not valid URLs and are not supported by import().\n // We need to convert the path to a file URL.\n // See: https://github.com/nodejs/node/issues/31710\n const url = /^file:\\/\\//.test(source) ? source : pathToFileURL(source).href\n // eslint-disable-next-line no-restricted-syntax\n return import(\n /* @vite-ignore */\n url\n )\n}\n"],"names":["pathToFileURL","doImport","source","url","test","href"],"mappings":"AAAA,gDAAgD;AAChD,SAAQA,aAAa,QAAO,WAAU;AAEtC;;;;;CAKC,GACD,OAAO,SAASC,SAASC,MAAc;IACrC,kFAAkF;IAClF,6CAA6C;IAC7C,mDAAmD;IACnD,MAAMC,MAAM,aAAaC,IAAI,CAACF,UAAUA,SAASF,cAAcE,QAAQG,IAAI;IAC3E,gDAAgD;IAChD,OAAO,MAAM,CACX,gBAAgB,GAChBF;AAEJ"}
@@ -1,5 +1,5 @@
1
1
  export function isInteractive() {
2
- return process.stdout.isTTY && process.env.TERM !== 'dumb' && !('CI' in process.env);
2
+ return Boolean(process.stdin.isTTY) && process.env.TERM !== 'dumb' && !('CI' in process.env);
3
3
  }
4
4
 
5
5
  //# sourceMappingURL=isInteractive.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/util/isInteractive.ts"],"sourcesContent":["export function isInteractive(): boolean {\n return process.stdout.isTTY && process.env.TERM !== 'dumb' && !('CI' in process.env)\n}\n"],"names":["isInteractive","process","stdout","isTTY","env","TERM"],"mappings":"AAAA,OAAO,SAASA;IACd,OAAOC,QAAQC,MAAM,CAACC,KAAK,IAAIF,QAAQG,GAAG,CAACC,IAAI,KAAK,UAAU,CAAE,CAAA,QAAQJ,QAAQG,GAAG,AAAD;AACpF"}
1
+ {"version":3,"sources":["../../src/util/isInteractive.ts"],"sourcesContent":["export function isInteractive(): boolean {\n return Boolean(process.stdin.isTTY) && process.env.TERM !== 'dumb' && !('CI' in process.env)\n}\n"],"names":["isInteractive","Boolean","process","stdin","isTTY","env","TERM"],"mappings":"AAAA,OAAO,SAASA;IACd,OAAOC,QAAQC,QAAQC,KAAK,CAACC,KAAK,KAAKF,QAAQG,GAAG,CAACC,IAAI,KAAK,UAAU,CAAE,CAAA,QAAQJ,QAAQG,GAAG,AAAD;AAC5F"}
@@ -1,16 +1,20 @@
1
+ import { Worker } from 'node:worker_threads';
1
2
  import { subdebug } from '../debug.js';
2
- const debug = subdebug('worker');
3
+ const debug = subdebug('promisifyWorker');
3
4
  /**
4
- * Wraps a Node.js Worker in a Promise that resolves with the first message
5
- * the worker sends, and rejects on error, message deserialization failure,
6
- * or non-zero exit code. The worker is terminated after a message or error
7
- * is received.
5
+ * Creates a Node.js Worker from the given file path and options, and wraps it
6
+ * in a Promise that resolves with the first message the worker sends, and
7
+ * rejects on error, message deserialization failure, or non-zero exit code.
8
+ * The worker is terminated after a message or error is received.
8
9
  *
9
- * @param worker - The Worker instance to promisify
10
+ * @param filePath - URL to the worker file
11
+ * @param options - Options to pass to the Worker constructor
10
12
  * @returns A promise that resolves with the first message from the worker
11
13
  * @throws If the worker emits an error, a message deserialization error, or exits with a non-zero code
12
14
  * @internal
13
- */ export function promisifyWorker(worker) {
15
+ */ export function promisifyWorker(filePath, options) {
16
+ const worker = new Worker(filePath, options);
17
+ const fileName = `[${filePath.pathname}]`;
14
18
  return new Promise((resolve, reject)=>{
15
19
  let settled = false;
16
20
  worker.addListener('error', function onWorkerError(err) {
@@ -25,22 +29,22 @@ const debug = subdebug('worker');
25
29
  // so there is nothing to terminate or remove listeners from.
26
30
  worker.addListener('exit', function onWorkerExit(code) {
27
31
  if (code > 0) {
28
- debug(`Worker exited with code ${code}`);
32
+ debug(`${fileName} exited with code ${code}`);
29
33
  reject(new Error(`Worker exited with code ${code}`));
30
34
  } else if (!settled) {
31
- debug('Worker exited with code 0 without sending a message');
35
+ debug(`${fileName} exited with code 0 without sending a message`);
32
36
  reject(new Error('Worker exited without sending a message'));
33
37
  }
34
38
  });
35
39
  worker.addListener('messageerror', function onWorkerMessageError(err) {
36
40
  settled = true;
37
- debug(`Worker message error: ${err.message}`, err);
41
+ debug(`${fileName} message error: ${err.message}`, err);
38
42
  reject(new Error(`Failed to deserialize worker message: ${err}`));
39
43
  cleanup();
40
44
  });
41
45
  worker.addListener('message', function onWorkerMessage(message) {
42
46
  settled = true;
43
- debug(`Worker message: ${message}`);
47
+ debug(`${fileName} message %o`, message);
44
48
  resolve(message);
45
49
  cleanup();
46
50
  });
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/util/promisifyWorker.ts"],"sourcesContent":["import {type Worker} from 'node:worker_threads'\n\nimport {subdebug} from '../debug.js'\n\nconst debug = subdebug('worker')\n\n/**\n * Wraps a Node.js Worker in a Promise that resolves with the first message\n * the worker sends, and rejects on error, message deserialization failure,\n * or non-zero exit code. The worker is terminated after a message or error\n * is received.\n *\n * @param worker - The Worker instance to promisify\n * @returns A promise that resolves with the first message from the worker\n * @throws If the worker emits an error, a message deserialization error, or exits with a non-zero code\n * @internal\n */\nexport function promisifyWorker<T = unknown>(worker: Worker): Promise<T> {\n return new Promise<T>((resolve, reject) => {\n let settled = false\n\n worker.addListener('error', function onWorkerError(err) {\n settled = true\n debug(`Worker error: ${err.message}`, err)\n reject(new Error(`Worker error: ${err.message}`, {cause: err}))\n cleanup()\n })\n // No cleanup() here — the worker is already dead after exiting,\n // so there is nothing to terminate or remove listeners from.\n worker.addListener('exit', function onWorkerExit(code) {\n if (code > 0) {\n debug(`Worker exited with code ${code}`)\n reject(new Error(`Worker exited with code ${code}`))\n } else if (!settled) {\n debug('Worker exited with code 0 without sending a message')\n reject(new Error('Worker exited without sending a message'))\n }\n })\n worker.addListener('messageerror', function onWorkerMessageError(err) {\n settled = true\n debug(`Worker message error: ${err.message}`, err)\n reject(new Error(`Failed to deserialize worker message: ${err}`))\n cleanup()\n })\n worker.addListener('message', function onWorkerMessage(message) {\n settled = true\n debug(`Worker message: ${message}`)\n resolve(message)\n cleanup()\n })\n\n function cleanup() {\n setImmediate(() => worker.terminate())\n worker.removeAllListeners()\n }\n })\n}\n"],"names":["subdebug","debug","promisifyWorker","worker","Promise","resolve","reject","settled","addListener","onWorkerError","err","message","Error","cause","cleanup","onWorkerExit","code","onWorkerMessageError","onWorkerMessage","setImmediate","terminate","removeAllListeners"],"mappings":"AAEA,SAAQA,QAAQ,QAAO,cAAa;AAEpC,MAAMC,QAAQD,SAAS;AAEvB;;;;;;;;;;CAUC,GACD,OAAO,SAASE,gBAA6BC,MAAc;IACzD,OAAO,IAAIC,QAAW,CAACC,SAASC;QAC9B,IAAIC,UAAU;QAEdJ,OAAOK,WAAW,CAAC,SAAS,SAASC,cAAcC,GAAG;YACpDH,UAAU;YACVN,MAAM,CAAC,cAAc,EAAES,IAAIC,OAAO,EAAE,EAAED;YACtCJ,OAAO,IAAIM,MAAM,CAAC,cAAc,EAAEF,IAAIC,OAAO,EAAE,EAAE;gBAACE,OAAOH;YAAG;YAC5DI;QACF;QACA,gEAAgE;QAChE,6DAA6D;QAC7DX,OAAOK,WAAW,CAAC,QAAQ,SAASO,aAAaC,IAAI;YACnD,IAAIA,OAAO,GAAG;gBACZf,MAAM,CAAC,wBAAwB,EAAEe,MAAM;gBACvCV,OAAO,IAAIM,MAAM,CAAC,wBAAwB,EAAEI,MAAM;YACpD,OAAO,IAAI,CAACT,SAAS;gBACnBN,MAAM;gBACNK,OAAO,IAAIM,MAAM;YACnB;QACF;QACAT,OAAOK,WAAW,CAAC,gBAAgB,SAASS,qBAAqBP,GAAG;YAClEH,UAAU;YACVN,MAAM,CAAC,sBAAsB,EAAES,IAAIC,OAAO,EAAE,EAAED;YAC9CJ,OAAO,IAAIM,MAAM,CAAC,sCAAsC,EAAEF,KAAK;YAC/DI;QACF;QACAX,OAAOK,WAAW,CAAC,WAAW,SAASU,gBAAgBP,OAAO;YAC5DJ,UAAU;YACVN,MAAM,CAAC,gBAAgB,EAAEU,SAAS;YAClCN,QAAQM;YACRG;QACF;QAEA,SAASA;YACPK,aAAa,IAAMhB,OAAOiB,SAAS;YACnCjB,OAAOkB,kBAAkB;QAC3B;IACF;AACF"}
1
+ {"version":3,"sources":["../../src/util/promisifyWorker.ts"],"sourcesContent":["import {Worker, type WorkerOptions} from 'node:worker_threads'\n\nimport {subdebug} from '../debug.js'\n\nconst debug = subdebug('promisifyWorker')\n\n/**\n * Creates a Node.js Worker from the given file path and options, and wraps it\n * in a Promise that resolves with the first message the worker sends, and\n * rejects on error, message deserialization failure, or non-zero exit code.\n * The worker is terminated after a message or error is received.\n *\n * @param filePath - URL to the worker file\n * @param options - Options to pass to the Worker constructor\n * @returns A promise that resolves with the first message from the worker\n * @throws If the worker emits an error, a message deserialization error, or exits with a non-zero code\n * @internal\n */\nexport function promisifyWorker<T = unknown>(filePath: URL, options?: WorkerOptions): Promise<T> {\n const worker = new Worker(filePath, options)\n\n const fileName = `[${filePath.pathname}]`\n\n return new Promise<T>((resolve, reject) => {\n let settled = false\n\n worker.addListener('error', function onWorkerError(err) {\n settled = true\n debug(`Worker error: ${err.message}`, err)\n reject(new Error(`Worker error: ${err.message}`, {cause: err}))\n cleanup()\n })\n // No cleanup() here — the worker is already dead after exiting,\n // so there is nothing to terminate or remove listeners from.\n worker.addListener('exit', function onWorkerExit(code) {\n if (code > 0) {\n debug(`${fileName} exited with code ${code}`)\n reject(new Error(`Worker exited with code ${code}`))\n } else if (!settled) {\n debug(`${fileName} exited with code 0 without sending a message`)\n reject(new Error('Worker exited without sending a message'))\n }\n })\n worker.addListener('messageerror', function onWorkerMessageError(err) {\n settled = true\n debug(`${fileName} message error: ${err.message}`, err)\n reject(new Error(`Failed to deserialize worker message: ${err}`))\n cleanup()\n })\n worker.addListener('message', function onWorkerMessage(message) {\n settled = true\n debug(`${fileName} message %o`, message)\n resolve(message)\n cleanup()\n })\n\n function cleanup() {\n setImmediate(() => worker.terminate())\n worker.removeAllListeners()\n }\n })\n}\n"],"names":["Worker","subdebug","debug","promisifyWorker","filePath","options","worker","fileName","pathname","Promise","resolve","reject","settled","addListener","onWorkerError","err","message","Error","cause","cleanup","onWorkerExit","code","onWorkerMessageError","onWorkerMessage","setImmediate","terminate","removeAllListeners"],"mappings":"AAAA,SAAQA,MAAM,QAA2B,sBAAqB;AAE9D,SAAQC,QAAQ,QAAO,cAAa;AAEpC,MAAMC,QAAQD,SAAS;AAEvB;;;;;;;;;;;CAWC,GACD,OAAO,SAASE,gBAA6BC,QAAa,EAAEC,OAAuB;IACjF,MAAMC,SAAS,IAAIN,OAAOI,UAAUC;IAEpC,MAAME,WAAW,CAAC,CAAC,EAAEH,SAASI,QAAQ,CAAC,CAAC,CAAC;IAEzC,OAAO,IAAIC,QAAW,CAACC,SAASC;QAC9B,IAAIC,UAAU;QAEdN,OAAOO,WAAW,CAAC,SAAS,SAASC,cAAcC,GAAG;YACpDH,UAAU;YACVV,MAAM,CAAC,cAAc,EAAEa,IAAIC,OAAO,EAAE,EAAED;YACtCJ,OAAO,IAAIM,MAAM,CAAC,cAAc,EAAEF,IAAIC,OAAO,EAAE,EAAE;gBAACE,OAAOH;YAAG;YAC5DI;QACF;QACA,gEAAgE;QAChE,6DAA6D;QAC7Db,OAAOO,WAAW,CAAC,QAAQ,SAASO,aAAaC,IAAI;YACnD,IAAIA,OAAO,GAAG;gBACZnB,MAAM,GAAGK,SAAS,kBAAkB,EAAEc,MAAM;gBAC5CV,OAAO,IAAIM,MAAM,CAAC,wBAAwB,EAAEI,MAAM;YACpD,OAAO,IAAI,CAACT,SAAS;gBACnBV,MAAM,GAAGK,SAAS,6CAA6C,CAAC;gBAChEI,OAAO,IAAIM,MAAM;YACnB;QACF;QACAX,OAAOO,WAAW,CAAC,gBAAgB,SAASS,qBAAqBP,GAAG;YAClEH,UAAU;YACVV,MAAM,GAAGK,SAAS,gBAAgB,EAAEQ,IAAIC,OAAO,EAAE,EAAED;YACnDJ,OAAO,IAAIM,MAAM,CAAC,sCAAsC,EAAEF,KAAK;YAC/DI;QACF;QACAb,OAAOO,WAAW,CAAC,WAAW,SAASU,gBAAgBP,OAAO;YAC5DJ,UAAU;YACVV,MAAM,GAAGK,SAAS,WAAW,CAAC,EAAES;YAChCN,QAAQM;YACRG;QACF;QAEA,SAASA;YACPK,aAAa,IAAMlB,OAAOmB,SAAS;YACnCnB,OAAOoB,kBAAkB;QAC3B;IACF;AACF"}
@@ -1,3 +1,51 @@
1
- export * from '@inquirer/prompts';
1
+ import * as inquirer from '@inquirer/prompts';
2
+ import { isInteractive } from '../util/isInteractive.js';
3
+ import { NonInteractiveError } from '../util/NonInteractiveError.js';
4
+ export { Separator } from '@inquirer/prompts';
5
+ function assertInteractive(promptName) {
6
+ if (!isInteractive()) {
7
+ throw new NonInteractiveError(promptName);
8
+ }
9
+ }
10
+ export const checkbox = (...args)=>{
11
+ assertInteractive('checkbox');
12
+ return inquirer.checkbox(...args);
13
+ };
14
+ export const confirm = (...args)=>{
15
+ assertInteractive('confirm');
16
+ return inquirer.confirm(...args);
17
+ };
18
+ export const editor = (...args)=>{
19
+ assertInteractive('editor');
20
+ return inquirer.editor(...args);
21
+ };
22
+ export const expand = (...args)=>{
23
+ assertInteractive('expand');
24
+ return inquirer.expand(...args);
25
+ };
26
+ export const input = (...args)=>{
27
+ assertInteractive('input');
28
+ return inquirer.input(...args);
29
+ };
30
+ export const number = (...args)=>{
31
+ assertInteractive('number');
32
+ return inquirer.number(...args);
33
+ };
34
+ export const password = (...args)=>{
35
+ assertInteractive('password');
36
+ return inquirer.password(...args);
37
+ };
38
+ export const rawlist = (...args)=>{
39
+ assertInteractive('rawlist');
40
+ return inquirer.rawlist(...args);
41
+ };
42
+ export const search = (...args)=>{
43
+ assertInteractive('search');
44
+ return inquirer.search(...args);
45
+ };
46
+ export const select = (...args)=>{
47
+ assertInteractive('select');
48
+ return inquirer.select(...args);
49
+ };
2
50
 
3
51
  //# sourceMappingURL=prompts.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/ux/prompts.ts"],"sourcesContent":["export * from '@inquirer/prompts'\n"],"names":[],"mappings":"AAAA,cAAc,oBAAmB"}
1
+ {"version":3,"sources":["../../src/ux/prompts.ts"],"sourcesContent":["import * as inquirer from '@inquirer/prompts'\n\nimport {isInteractive} from '../util/isInteractive.js'\nimport {NonInteractiveError} from '../util/NonInteractiveError.js'\n\nexport {Separator} from '@inquirer/prompts'\n\nfunction assertInteractive(promptName: string): void {\n if (!isInteractive()) {\n throw new NonInteractiveError(promptName)\n }\n}\n\nexport const checkbox: typeof inquirer.checkbox = (...args) => {\n assertInteractive('checkbox')\n return inquirer.checkbox(...args)\n}\n\nexport const confirm: typeof inquirer.confirm = (...args) => {\n assertInteractive('confirm')\n return inquirer.confirm(...args)\n}\n\nexport const editor: typeof inquirer.editor = (...args) => {\n assertInteractive('editor')\n return inquirer.editor(...args)\n}\n\nexport const expand: typeof inquirer.expand = (...args) => {\n assertInteractive('expand')\n return inquirer.expand(...args)\n}\n\nexport const input: typeof inquirer.input = (...args) => {\n assertInteractive('input')\n return inquirer.input(...args)\n}\n\nexport const number: typeof inquirer.number = (...args) => {\n assertInteractive('number')\n return inquirer.number(...args)\n}\n\nexport const password: typeof inquirer.password = (...args) => {\n assertInteractive('password')\n return inquirer.password(...args)\n}\n\nexport const rawlist: typeof inquirer.rawlist = (...args) => {\n assertInteractive('rawlist')\n return inquirer.rawlist(...args)\n}\n\nexport const search: typeof inquirer.search = (...args) => {\n assertInteractive('search')\n return inquirer.search(...args)\n}\n\nexport const select: typeof inquirer.select = (...args) => {\n assertInteractive('select')\n return inquirer.select(...args)\n}\n"],"names":["inquirer","isInteractive","NonInteractiveError","Separator","assertInteractive","promptName","checkbox","args","confirm","editor","expand","input","number","password","rawlist","search","select"],"mappings":"AAAA,YAAYA,cAAc,oBAAmB;AAE7C,SAAQC,aAAa,QAAO,2BAA0B;AACtD,SAAQC,mBAAmB,QAAO,iCAAgC;AAElE,SAAQC,SAAS,QAAO,oBAAmB;AAE3C,SAASC,kBAAkBC,UAAkB;IAC3C,IAAI,CAACJ,iBAAiB;QACpB,MAAM,IAAIC,oBAAoBG;IAChC;AACF;AAEA,OAAO,MAAMC,WAAqC,CAAC,GAAGC;IACpDH,kBAAkB;IAClB,OAAOJ,SAASM,QAAQ,IAAIC;AAC9B,EAAC;AAED,OAAO,MAAMC,UAAmC,CAAC,GAAGD;IAClDH,kBAAkB;IAClB,OAAOJ,SAASQ,OAAO,IAAID;AAC7B,EAAC;AAED,OAAO,MAAME,SAAiC,CAAC,GAAGF;IAChDH,kBAAkB;IAClB,OAAOJ,SAASS,MAAM,IAAIF;AAC5B,EAAC;AAED,OAAO,MAAMG,SAAiC,CAAC,GAAGH;IAChDH,kBAAkB;IAClB,OAAOJ,SAASU,MAAM,IAAIH;AAC5B,EAAC;AAED,OAAO,MAAMI,QAA+B,CAAC,GAAGJ;IAC9CH,kBAAkB;IAClB,OAAOJ,SAASW,KAAK,IAAIJ;AAC3B,EAAC;AAED,OAAO,MAAMK,SAAiC,CAAC,GAAGL;IAChDH,kBAAkB;IAClB,OAAOJ,SAASY,MAAM,IAAIL;AAC5B,EAAC;AAED,OAAO,MAAMM,WAAqC,CAAC,GAAGN;IACpDH,kBAAkB;IAClB,OAAOJ,SAASa,QAAQ,IAAIN;AAC9B,EAAC;AAED,OAAO,MAAMO,UAAmC,CAAC,GAAGP;IAClDH,kBAAkB;IAClB,OAAOJ,SAASc,OAAO,IAAIP;AAC7B,EAAC;AAED,OAAO,MAAMQ,SAAiC,CAAC,GAAGR;IAChDH,kBAAkB;IAClB,OAAOJ,SAASe,MAAM,IAAIR;AAC5B,EAAC;AAED,OAAO,MAAMS,SAAiC,CAAC,GAAGT;IAChDH,kBAAkB;IAClB,OAAOJ,SAASgB,MAAM,IAAIT;AAC5B,EAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sanity/cli-core",
3
- "version": "0.1.0-alpha.15",
3
+ "version": "0.1.0-alpha.17",
4
4
  "description": "Sanity CLI core package",
5
5
  "keywords": [
6
6
  "sanity",
@@ -48,46 +48,47 @@
48
48
  ],
49
49
  "dependencies": {
50
50
  "@inquirer/prompts": "^8.2.0",
51
- "@oclif/core": "^4.8.0",
51
+ "@oclif/core": "^4.8.1",
52
52
  "@rexxars/jiti": "^2.6.2",
53
- "@sanity/client": "^7.15.0",
54
- "@sanity/types": "^5.11.0",
53
+ "@sanity/client": "^7.16.0",
54
+ "@sanity/types": "^5.12.0",
55
55
  "babel-plugin-react-compiler": "^1.0.0",
56
56
  "boxen": "^8.0.1",
57
57
  "configstore": "^7.0.0",
58
58
  "debug": "^4.4.3",
59
59
  "get-it": "^8.7.0",
60
- "read-package-up": "^12.0.0",
61
60
  "get-tsconfig": "^4.13.6",
62
61
  "import-meta-resolve": "^4.2.0",
63
- "jsdom": "^27.4.0",
62
+ "jsdom": "^28.1.0",
64
63
  "json-lexer": "^1.2.0",
65
64
  "log-symbols": "^7.0.1",
66
65
  "ora": "^9.0.0",
66
+ "read-package-up": "^12.0.0",
67
67
  "rxjs": "^7.8.2",
68
68
  "tinyglobby": "^0.2.15",
69
69
  "tsx": "^4.21.0",
70
70
  "typeid-js": "^1.2.0",
71
71
  "vite": "^7.3.1",
72
+ "vite-node": "^5.3.0",
72
73
  "zod": "^4.3.6"
73
74
  },
74
75
  "devDependencies": {
75
76
  "@eslint/compat": "^2.0.2",
76
- "@sanity/codegen": "^5.9.4",
77
+ "@sanity/codegen": "^5.10.1",
77
78
  "@sanity/pkg-utils": "^10.4.4",
78
79
  "@sanity/telemetry": "^0.8.1",
79
80
  "@swc/cli": "^0.8.0",
80
- "@swc/core": "^1.15.11",
81
+ "@swc/core": "^1.15.13",
81
82
  "@types/debug": "^4.1.12",
82
- "@types/jsdom": "^27.0.0",
83
- "@types/node": "^20.19.33",
84
- "eslint": "^9.39.2",
83
+ "@types/jsdom": "^28.0.0",
84
+ "@types/node": "^20.19.35",
85
+ "eslint": "^9.39.3",
85
86
  "publint": "^0.3.17",
86
- "sanity": "^5.11.0",
87
+ "sanity": "^5.12.0",
87
88
  "typescript": "^5.9.3",
88
89
  "vitest": "^4.0.18",
89
90
  "@repo/tsconfig": "3.70.0",
90
- "@sanity/eslint-config-cli": "0.0.0-alpha.2",
91
+ "@sanity/eslint-config-cli": "0.0.0-alpha.3",
91
92
  "@repo/package.config": "0.0.1"
92
93
  },
93
94
  "peerDependencies": {