@sanity/cli-core 0.0.2-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +3 -0
- package/dist/SanityCommand.d.ts +56 -0
- package/dist/SanityCommand.js +72 -0
- package/dist/SanityCommand.js.map +1 -0
- package/dist/config/__tests__/cliToken.test.js +74 -0
- package/dist/config/__tests__/cliToken.test.js.map +1 -0
- package/dist/config/__tests__/cliUserConfig.test.js +131 -0
- package/dist/config/__tests__/cliUserConfig.test.js.map +1 -0
- package/dist/config/__tests__/findProjectRoot.test.js +159 -0
- package/dist/config/__tests__/findProjectRoot.test.js.map +1 -0
- package/dist/config/cli/getCliConfig.d.ts +16 -0
- package/dist/config/cli/getCliConfig.js +67 -0
- package/dist/config/cli/getCliConfig.js.map +1 -0
- package/dist/config/cli/getCliConfig.worker.d.ts +1 -0
- package/dist/config/cli/getCliConfig.worker.js +14 -0
- package/dist/config/cli/getCliConfig.worker.js.map +1 -0
- package/dist/config/cli/schemas.d.ts +204 -0
- package/dist/config/cli/schemas.js +77 -0
- package/dist/config/cli/schemas.js.map +1 -0
- package/dist/config/cli/types.d.ts +13 -0
- package/dist/config/cli/types.js +3 -0
- package/dist/config/cli/types.js.map +1 -0
- package/dist/config/findProjectRoot.d.ts +14 -0
- package/dist/config/findProjectRoot.js +56 -0
- package/dist/config/findProjectRoot.js.map +1 -0
- package/dist/config/studio/getStudioConfig.d.ts +14 -0
- package/dist/config/studio/getStudioConfig.js +16 -0
- package/dist/config/studio/getStudioConfig.js.map +1 -0
- package/dist/config/studio/readStudioConfig.d.ts +190 -0
- package/dist/config/studio/readStudioConfig.js +45 -0
- package/dist/config/studio/readStudioConfig.js.map +1 -0
- package/dist/config/studio/readStudioConfig.worker.d.ts +1 -0
- package/dist/config/studio/readStudioConfig.worker.js +64 -0
- package/dist/config/studio/readStudioConfig.worker.js.map +1 -0
- package/dist/config/util/findAppConfigPath.d.ts +8 -0
- package/dist/config/util/findAppConfigPath.js +22 -0
- package/dist/config/util/findAppConfigPath.js.map +1 -0
- package/dist/config/util/findConfigsPaths.d.ts +16 -0
- package/dist/config/util/findConfigsPaths.js +21 -0
- package/dist/config/util/findConfigsPaths.js.map +1 -0
- package/dist/config/util/findStudioConfigPath.d.ts +9 -0
- package/dist/config/util/findStudioConfigPath.js +31 -0
- package/dist/config/util/findStudioConfigPath.js.map +1 -0
- package/dist/config/util/isSanityV2StudioRoot.d.ts +8 -0
- package/dist/config/util/isSanityV2StudioRoot.js +19 -0
- package/dist/config/util/isSanityV2StudioRoot.js.map +1 -0
- package/dist/config/util/recursivelyResolveProjectRoot.d.ts +27 -0
- package/dist/config/util/recursivelyResolveProjectRoot.js +28 -0
- package/dist/config/util/recursivelyResolveProjectRoot.js.map +1 -0
- package/dist/debug.d.ts +15 -0
- package/dist/debug.js +15 -0
- package/dist/debug.js.map +1 -0
- package/dist/index.d.ts +28 -0
- package/dist/index.js +27 -0
- package/dist/index.js.map +1 -0
- package/dist/loaders/studio/stubs.d.ts +254 -0
- package/dist/loaders/studio/stubs.js +257 -0
- package/dist/loaders/studio/stubs.js.map +1 -0
- package/dist/loaders/studio/studioWorkerLoader.worker.d.ts +1 -0
- package/dist/loaders/studio/studioWorkerLoader.worker.js +117 -0
- package/dist/loaders/studio/studioWorkerLoader.worker.js.map +1 -0
- package/dist/loaders/studio/studioWorkerTask.d.ts +40 -0
- package/dist/loaders/studio/studioWorkerTask.js +69 -0
- package/dist/loaders/studio/studioWorkerTask.js.map +1 -0
- package/dist/loaders/tsx/tsxWorkerLoader.worker.d.ts +1 -0
- package/dist/loaders/tsx/tsxWorkerLoader.worker.js +12 -0
- package/dist/loaders/tsx/tsxWorkerLoader.worker.js.map +1 -0
- package/dist/loaders/tsx/tsxWorkerTask.d.ts +28 -0
- package/dist/loaders/tsx/tsxWorkerTask.js +61 -0
- package/dist/loaders/tsx/tsxWorkerTask.js.map +1 -0
- package/dist/services/apiClient.d.ts +39 -0
- package/dist/services/apiClient.js +88 -0
- package/dist/services/apiClient.js.map +1 -0
- package/dist/services/cliUserConfig.d.ts +57 -0
- package/dist/services/cliUserConfig.js +103 -0
- package/dist/services/cliUserConfig.js.map +1 -0
- package/dist/services/getCliToken.d.ts +7 -0
- package/dist/services/getCliToken.js +21 -0
- package/dist/services/getCliToken.js.map +1 -0
- package/dist/types.d.ts +7 -0
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -0
- package/dist/util/NotFoundError.d.ts +20 -0
- package/dist/util/NotFoundError.js +27 -0
- package/dist/util/NotFoundError.js.map +1 -0
- package/dist/util/__tests__/createExpiringConfig.test.js +309 -0
- package/dist/util/__tests__/createExpiringConfig.test.js.map +1 -0
- package/dist/util/createExpiringConfig.d.ts +32 -0
- package/dist/util/createExpiringConfig.js +35 -0
- package/dist/util/createExpiringConfig.js.map +1 -0
- package/dist/util/fileExists.d.ts +9 -0
- package/dist/util/fileExists.js +13 -0
- package/dist/util/fileExists.js.map +1 -0
- package/dist/util/generateHelpUrl.d.ts +8 -0
- package/dist/util/generateHelpUrl.js +11 -0
- package/dist/util/generateHelpUrl.js.map +1 -0
- package/dist/util/getSanityEnvVar.d.ts +19 -0
- package/dist/util/getSanityEnvVar.js +24 -0
- package/dist/util/getSanityEnvVar.js.map +1 -0
- package/dist/util/getSanityUrl.d.ts +5 -0
- package/dist/util/getSanityUrl.js +8 -0
- package/dist/util/getSanityUrl.js.map +1 -0
- package/dist/util/getUserConfig.d.ts +2 -0
- package/dist/util/getUserConfig.js +15 -0
- package/dist/util/getUserConfig.js.map +1 -0
- package/dist/util/isCi.d.ts +1 -0
- package/dist/util/isCi.js +7 -0
- package/dist/util/isCi.js.map +1 -0
- package/dist/util/isHttpError.d.ts +29 -0
- package/dist/util/isHttpError.js +18 -0
- package/dist/util/isHttpError.js.map +1 -0
- package/dist/util/isInteractive.d.ts +1 -0
- package/dist/util/isInteractive.js +5 -0
- package/dist/util/isInteractive.js.map +1 -0
- package/dist/util/isRecord.d.ts +8 -0
- package/dist/util/isRecord.js +11 -0
- package/dist/util/isRecord.js.map +1 -0
- package/dist/util/isTrueish.d.ts +1 -0
- package/dist/util/isTrueish.js +10 -0
- package/dist/util/isTrueish.js.map +1 -0
- package/dist/util/readJsonFile.d.ts +8 -0
- package/dist/util/readJsonFile.js +26 -0
- package/dist/util/readJsonFile.js.map +1 -0
- package/dist/util/safeStructuredClone.d.ts +8 -0
- package/dist/util/safeStructuredClone.js +40 -0
- package/dist/util/safeStructuredClone.js.map +1 -0
- package/dist/util/writeJsonFile.d.ts +9 -0
- package/dist/util/writeJsonFile.js +19 -0
- package/dist/util/writeJsonFile.js.map +1 -0
- package/dist/ux/colorizeJson.d.ts +1 -0
- package/dist/ux/colorizeJson.js +32 -0
- package/dist/ux/colorizeJson.js.map +1 -0
- package/dist/ux/formatObject.d.ts +1 -0
- package/dist/ux/formatObject.js +9 -0
- package/dist/ux/formatObject.js.map +1 -0
- package/dist/ux/logSymbols.d.ts +1 -0
- package/dist/ux/logSymbols.js +3 -0
- package/dist/ux/logSymbols.js.map +1 -0
- package/dist/ux/printKeyValue.d.ts +1 -0
- package/dist/ux/printKeyValue.js +16 -0
- package/dist/ux/printKeyValue.js.map +1 -0
- package/dist/ux/spinner.d.ts +1 -0
- package/dist/ux/spinner.js +3 -0
- package/dist/ux/spinner.js.map +1 -0
- package/dist/ux/timer.d.ts +12 -0
- package/dist/ux/timer.js +29 -0
- package/dist/ux/timer.js.map +1 -0
- package/package.json +81 -0
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { resolve } from 'node:path';
|
|
2
|
+
import { pathToFileURL } from 'node:url';
|
|
3
|
+
import { isMainThread } from 'node:worker_threads';
|
|
4
|
+
import { moduleResolve } from 'import-meta-resolve';
|
|
5
|
+
import { createServer, loadEnv, mergeConfig } from 'vite';
|
|
6
|
+
import { ViteNodeRunner } from 'vite-node/client';
|
|
7
|
+
import { ViteNodeServer } from 'vite-node/server';
|
|
8
|
+
import { installSourcemapsSupport } from 'vite-node/source-map';
|
|
9
|
+
import { getCliConfig } from '../../config/cli/getCliConfig.js';
|
|
10
|
+
import { isRecord } from '../../util/isRecord.js';
|
|
11
|
+
import { isNotFoundError } from '../../util/NotFoundError.js';
|
|
12
|
+
import * as stubs from './stubs.js';
|
|
13
|
+
if (isMainThread) {
|
|
14
|
+
throw new Error('Should be child of thread, not the main thread');
|
|
15
|
+
}
|
|
16
|
+
const rootPath = process.env.STUDIO_WORKER_STUDIO_ROOT_PATH;
|
|
17
|
+
if (!rootPath) {
|
|
18
|
+
throw new Error('Missing `STUDIO_WORKER_STUDIO_ROOT_PATH` environment variable');
|
|
19
|
+
}
|
|
20
|
+
const workerScriptPath = process.env.STUDIO_WORKER_TASK_FILE;
|
|
21
|
+
if (!workerScriptPath) {
|
|
22
|
+
throw new Error('Missing `STUDIO_WORKER_TASK_FILE` environment variable');
|
|
23
|
+
}
|
|
24
|
+
const mockStubs = stubs;
|
|
25
|
+
const mockedGlobalThis = globalThis;
|
|
26
|
+
for(const key in stubs){
|
|
27
|
+
if (!(key in mockedGlobalThis)) {
|
|
28
|
+
mockedGlobalThis[key] = mockStubs[key];
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
// Doesn't have to be correct, just need the root path to be
|
|
32
|
+
const fakeConfigUrl = pathToFileURL(resolve(rootPath, 'sanity.config.mjs'));
|
|
33
|
+
// We'll load `getStudioEnvironmentVariables` from the `sanity/cli` module installed
|
|
34
|
+
// relative to where the studio is located, instead of resolving from where this CLI is
|
|
35
|
+
// running in, in order to ensure we're using the same version as the studio would.
|
|
36
|
+
const sanityCliUrl = await moduleResolve('sanity/cli', fakeConfigUrl);
|
|
37
|
+
const { getStudioEnvironmentVariables } = await import(sanityCliUrl.href);
|
|
38
|
+
if (typeof getStudioEnvironmentVariables !== 'function') {
|
|
39
|
+
throw new TypeError('Expected `getStudioEnvironmentVariables` from `sanity/cli` to be a function');
|
|
40
|
+
}
|
|
41
|
+
const defaultViteConfig = {
|
|
42
|
+
build: {
|
|
43
|
+
target: 'node'
|
|
44
|
+
},
|
|
45
|
+
configFile: false,
|
|
46
|
+
define: {
|
|
47
|
+
...getStudioEnvironmentVariables({
|
|
48
|
+
jsonEncode: true,
|
|
49
|
+
prefix: 'process.env.'
|
|
50
|
+
})
|
|
51
|
+
},
|
|
52
|
+
logLevel: 'error',
|
|
53
|
+
optimizeDeps: {
|
|
54
|
+
disabled: true
|
|
55
|
+
},
|
|
56
|
+
root: rootPath,
|
|
57
|
+
server: {
|
|
58
|
+
hmr: false,
|
|
59
|
+
watch: null
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
// Allow the CLI config (`sanity.cli.(js|ts)`) to define a `vite` property which can
|
|
63
|
+
// extend/modify the default vite configuration for the studio.
|
|
64
|
+
let cliConfig;
|
|
65
|
+
try {
|
|
66
|
+
cliConfig = await getCliConfig(rootPath);
|
|
67
|
+
} catch (err) {
|
|
68
|
+
if (!isNotFoundError(err)) {
|
|
69
|
+
console.warn('[warn] Failed to load CLI config:', err);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
let viteConfig = defaultViteConfig;
|
|
73
|
+
if (typeof cliConfig?.vite === 'function') {
|
|
74
|
+
viteConfig = await cliConfig.vite(viteConfig, {
|
|
75
|
+
command: 'build',
|
|
76
|
+
isSsrBuild: true,
|
|
77
|
+
mode: 'production'
|
|
78
|
+
});
|
|
79
|
+
} else if (isRecord(cliConfig?.vite)) {
|
|
80
|
+
viteConfig = mergeConfig(viteConfig, cliConfig.vite);
|
|
81
|
+
}
|
|
82
|
+
// Vite will build the files we give it - targetting Node.js instead of the browser.
|
|
83
|
+
// We include the inject plugin in order to provide the stubs for the undefined global APIs.
|
|
84
|
+
const server = await createServer(viteConfig);
|
|
85
|
+
// Bit of a hack, but seems necessary based on the `node-vite` binary implementation
|
|
86
|
+
await server.pluginContainer.buildStart({});
|
|
87
|
+
// Load environment variables from `.env` files in the same way as Vite does.
|
|
88
|
+
// Note that Sanity also provides environment variables through `process.env.*` for compat reasons,
|
|
89
|
+
// and so we need to do the same here.
|
|
90
|
+
// @todo is this in line with sanity?
|
|
91
|
+
const env = loadEnv(server.config.mode, server.config.envDir, '');
|
|
92
|
+
for(const key in env){
|
|
93
|
+
process.env[key] ??= env[key];
|
|
94
|
+
}
|
|
95
|
+
// Now we're providing the glue that ensures node-specific loading and execution works.
|
|
96
|
+
const node = new ViteNodeServer(server);
|
|
97
|
+
// Should make it easier to debug any crashes in the imported code…
|
|
98
|
+
installSourcemapsSupport({
|
|
99
|
+
getSourceMap: (source)=>node.getSourceMap(source)
|
|
100
|
+
});
|
|
101
|
+
const runner = new ViteNodeRunner({
|
|
102
|
+
base: server.config.base,
|
|
103
|
+
async fetchModule (id) {
|
|
104
|
+
return node.fetchModule(id);
|
|
105
|
+
},
|
|
106
|
+
resolveId (id, importer) {
|
|
107
|
+
return node.resolveId(id, importer);
|
|
108
|
+
},
|
|
109
|
+
root: server.config.root
|
|
110
|
+
});
|
|
111
|
+
// Copied from `vite-node` - it appears that this applies the `define` config from
|
|
112
|
+
// vite, but it also takes a surprisingly long time to execute. Not clear at this
|
|
113
|
+
// point why this is, so we should investigate whether it's necessary or not.
|
|
114
|
+
await runner.executeId('/@vite/env');
|
|
115
|
+
await runner.executeId(workerScriptPath);
|
|
116
|
+
|
|
117
|
+
//# sourceMappingURL=studioWorkerLoader.worker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/loaders/studio/studioWorkerLoader.worker.ts"],"sourcesContent":["import {resolve} from 'node:path'\nimport {pathToFileURL} from 'node:url'\nimport {isMainThread} from 'node:worker_threads'\n\nimport {moduleResolve} from 'import-meta-resolve'\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.js'\nimport {isRecord} from '../../util/isRecord.js'\nimport {isNotFoundError} from '../../util/NotFoundError.js'\nimport * as stubs from './stubs.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\nconst mockStubs = stubs as Record<string, unknown>\nconst mockedGlobalThis: Record<string, unknown> = globalThis\nfor (const key in stubs) {\n if (!(key in mockedGlobalThis)) {\n mockedGlobalThis[key] = mockStubs[key]\n }\n}\n\n// Doesn't have to be correct, just need the root path to be\nconst fakeConfigUrl = pathToFileURL(resolve(rootPath, 'sanity.config.mjs'))\n\n// We'll load `getStudioEnvironmentVariables` from the `sanity/cli` module installed\n// relative to where the studio is located, instead of resolving from where this CLI is\n// running in, in order to ensure we're using the same version as the studio would.\nconst sanityCliUrl = await moduleResolve('sanity/cli', fakeConfigUrl)\nconst {getStudioEnvironmentVariables} = await import(sanityCliUrl.href)\nif (typeof getStudioEnvironmentVariables !== 'function') {\n throw new TypeError('Expected `getStudioEnvironmentVariables` from `sanity/cli` to be a function')\n}\n\nconst defaultViteConfig: InlineConfig = {\n build: {target: 'node'},\n configFile: false, // @todo Should use `vite` prop from `sanity.cli.ts` (if any)\n define: {\n ...getStudioEnvironmentVariables({jsonEncode: true, prefix: 'process.env.'}),\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 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 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 return node.fetchModule(id)\n },\n resolveId(id, importer) {\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":["resolve","pathToFileURL","isMainThread","moduleResolve","createServer","loadEnv","mergeConfig","ViteNodeRunner","ViteNodeServer","installSourcemapsSupport","getCliConfig","isRecord","isNotFoundError","stubs","Error","rootPath","process","env","STUDIO_WORKER_STUDIO_ROOT_PATH","workerScriptPath","STUDIO_WORKER_TASK_FILE","mockStubs","mockedGlobalThis","globalThis","key","fakeConfigUrl","sanityCliUrl","getStudioEnvironmentVariables","href","TypeError","defaultViteConfig","build","target","configFile","define","jsonEncode","prefix","logLevel","optimizeDeps","disabled","root","server","hmr","watch","cliConfig","err","console","warn","viteConfig","vite","command","isSsrBuild","mode","pluginContainer","buildStart","config","envDir","node","getSourceMap","source","runner","base","fetchModule","id","resolveId","importer","executeId"],"mappings":"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"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { type WorkerOptions } from 'node:worker_threads';
|
|
2
|
+
import { type RequireProps } from '../../types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Options for the studio worker task
|
|
5
|
+
*
|
|
6
|
+
* @internal
|
|
7
|
+
*/
|
|
8
|
+
interface StudioWorkerTaskOptions extends RequireProps<WorkerOptions, 'name'> {
|
|
9
|
+
studioRootPath: string;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Executes a worker file in a Sanity Studio browser context.
|
|
13
|
+
*
|
|
14
|
+
* This uses a combination of vite for "bundling" + jsdom for emulating a browser
|
|
15
|
+
* environment under the hood, which means that the same thing that will work in vite
|
|
16
|
+
* _should_ work in the worker - to a degree. If the user has defined any typescript
|
|
17
|
+
* path aliases, these will have to be added as aliases to the vite config - the same
|
|
18
|
+
* behavior as you would see with regular vite. Other things that are accounted for:
|
|
19
|
+
*
|
|
20
|
+
* - TypeScript support (+JSX, enums and other "compilation needed" features)
|
|
21
|
+
* - CSS, font and other file imports will resolve to a file path
|
|
22
|
+
* - CSS module imports will resolve to a javascript object of class names
|
|
23
|
+
* - Environment variables are available both as `import.meta.env` and `process.env`,
|
|
24
|
+
* and `.env` files are loaded in the same way that they would in a Sanity studio.
|
|
25
|
+
* - Browser globals not available in a Node.js environment but _are_ provided by JSDOM
|
|
26
|
+
* are defined directly to the Node environment as globals. While this polutes the
|
|
27
|
+
* global namespace, it is done only in the worker thread.
|
|
28
|
+
* - Certain browser globals that are _not_ available in JSDOM are also provided to the
|
|
29
|
+
* global namespace - things like `requestIdleCallback`, `IntersectionObserver` etc.
|
|
30
|
+
* These are provided with a minimal stub implementation to make them not crash.
|
|
31
|
+
*
|
|
32
|
+
* @param filePath - Path to the worker file (`.ts` works and is encouraged)
|
|
33
|
+
* @param options - Options to pass to the worker
|
|
34
|
+
* @returns A promise that resolves with the message from the worker
|
|
35
|
+
* @throws If the file does not exist
|
|
36
|
+
* @throws If the worker exits with a non-zero code
|
|
37
|
+
* @internal
|
|
38
|
+
*/
|
|
39
|
+
export declare function studioWorkerTask(filePath: URL, options: StudioWorkerTaskOptions): Promise<unknown>;
|
|
40
|
+
export {};
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { Worker } from 'node:worker_threads';
|
|
2
|
+
import { isRecord } from '../../util/isRecord.js';
|
|
3
|
+
/**
|
|
4
|
+
* Executes a worker file in a Sanity Studio browser context.
|
|
5
|
+
*
|
|
6
|
+
* This uses a combination of vite for "bundling" + jsdom for emulating a browser
|
|
7
|
+
* environment under the hood, which means that the same thing that will work in vite
|
|
8
|
+
* _should_ work in the worker - to a degree. If the user has defined any typescript
|
|
9
|
+
* path aliases, these will have to be added as aliases to the vite config - the same
|
|
10
|
+
* behavior as you would see with regular vite. Other things that are accounted for:
|
|
11
|
+
*
|
|
12
|
+
* - TypeScript support (+JSX, enums and other "compilation needed" features)
|
|
13
|
+
* - CSS, font and other file imports will resolve to a file path
|
|
14
|
+
* - CSS module imports will resolve to a javascript object of class names
|
|
15
|
+
* - Environment variables are available both as `import.meta.env` and `process.env`,
|
|
16
|
+
* and `.env` files are loaded in the same way that they would in a Sanity studio.
|
|
17
|
+
* - Browser globals not available in a Node.js environment but _are_ provided by JSDOM
|
|
18
|
+
* are defined directly to the Node environment as globals. While this polutes the
|
|
19
|
+
* global namespace, it is done only in the worker thread.
|
|
20
|
+
* - Certain browser globals that are _not_ available in JSDOM are also provided to the
|
|
21
|
+
* global namespace - things like `requestIdleCallback`, `IntersectionObserver` etc.
|
|
22
|
+
* These are provided with a minimal stub implementation to make them not crash.
|
|
23
|
+
*
|
|
24
|
+
* @param filePath - Path to the worker file (`.ts` works and is encouraged)
|
|
25
|
+
* @param options - Options to pass to the worker
|
|
26
|
+
* @returns A promise that resolves with the message from the worker
|
|
27
|
+
* @throws If the file does not exist
|
|
28
|
+
* @throws If the worker exits with a non-zero code
|
|
29
|
+
* @internal
|
|
30
|
+
*/ export function studioWorkerTask(filePath, options) {
|
|
31
|
+
return new Promise((resolve, reject)=>{
|
|
32
|
+
if (!/\.worker\.(js|ts)$/.test(filePath.pathname)) {
|
|
33
|
+
throw new Error('Studio worker tasks must include `.worker.(js|ts)` in path');
|
|
34
|
+
}
|
|
35
|
+
const worker = new Worker(new URL('studioWorkerLoader.worker.js', import.meta.url), {
|
|
36
|
+
...options,
|
|
37
|
+
env: {
|
|
38
|
+
...isRecord(options.env) ? options.env : process.env,
|
|
39
|
+
STUDIO_WORKER_STUDIO_ROOT_PATH: options.studioRootPath,
|
|
40
|
+
STUDIO_WORKER_TASK_FILE: filePath.pathname
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
worker.addListener('error', function onWorkerError(err) {
|
|
44
|
+
reject(new Error(`Fail to load file through worker: ${err.message}`));
|
|
45
|
+
cleanup();
|
|
46
|
+
});
|
|
47
|
+
worker.addListener('exit', function onWorkerExit(code) {
|
|
48
|
+
if (code > 0) {
|
|
49
|
+
reject(new Error(`Worker exited with code ${code}`));
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
worker.addListener('messageerror', function onWorkerMessageError(err) {
|
|
53
|
+
reject(new Error(`Fail to parse message from worker: ${err}`));
|
|
54
|
+
cleanup();
|
|
55
|
+
});
|
|
56
|
+
worker.addListener('message', function onWorkerMessage(message) {
|
|
57
|
+
resolve(message);
|
|
58
|
+
cleanup();
|
|
59
|
+
});
|
|
60
|
+
function cleanup() {
|
|
61
|
+
// Allow the worker a _bit_ of time to clean up, but ensure that we don't have
|
|
62
|
+
// lingering processes hanging around forever if the worker doesn't exit on its
|
|
63
|
+
// own.
|
|
64
|
+
setImmediate(()=>worker.terminate());
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
//# sourceMappingURL=studioWorkerTask.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/loaders/studio/studioWorkerTask.ts"],"sourcesContent":["import {Worker, type WorkerOptions} from 'node:worker_threads'\n\nimport {type RequireProps} from '../../types.js'\nimport {isRecord} from '../../util/isRecord.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(\n filePath: URL,\n options: StudioWorkerTaskOptions,\n): Promise<unknown> {\n return new Promise((resolve, reject) => {\n if (!/\\.worker\\.(js|ts)$/.test(filePath.pathname)) {\n throw new Error('Studio worker tasks must include `.worker.(js|ts)` in path')\n }\n\n const worker = 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: filePath.pathname,\n },\n })\n\n worker.addListener('error', function onWorkerError(err) {\n reject(new Error(`Fail to load file through worker: ${err.message}`))\n cleanup()\n })\n worker.addListener('exit', function onWorkerExit(code) {\n if (code > 0) {\n reject(new Error(`Worker exited with code ${code}`))\n }\n })\n worker.addListener('messageerror', function onWorkerMessageError(err) {\n reject(new Error(`Fail to parse message from worker: ${err}`))\n cleanup()\n })\n worker.addListener('message', function onWorkerMessage(message) {\n resolve(message)\n cleanup()\n })\n\n function cleanup() {\n // Allow the worker a _bit_ of time to clean up, but ensure that we don't have\n // lingering processes hanging around forever if the worker doesn't exit on its\n // own.\n setImmediate(() => worker.terminate())\n }\n })\n}\n"],"names":["Worker","isRecord","studioWorkerTask","filePath","options","Promise","resolve","reject","test","pathname","Error","worker","URL","url","env","process","STUDIO_WORKER_STUDIO_ROOT_PATH","studioRootPath","STUDIO_WORKER_TASK_FILE","addListener","onWorkerError","err","message","cleanup","onWorkerExit","code","onWorkerMessageError","onWorkerMessage","setImmediate","terminate"],"mappings":"AAAA,SAAQA,MAAM,QAA2B,sBAAqB;AAG9D,SAAQC,QAAQ,QAAO,yBAAwB;AAW/C;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2BC,GACD,OAAO,SAASC,iBACdC,QAAa,EACbC,OAAgC;IAEhC,OAAO,IAAIC,QAAQ,CAACC,SAASC;QAC3B,IAAI,CAAC,qBAAqBC,IAAI,CAACL,SAASM,QAAQ,GAAG;YACjD,MAAM,IAAIC,MAAM;QAClB;QAEA,MAAMC,SAAS,IAAIX,OAAO,IAAIY,IAAI,gCAAgC,YAAYC,GAAG,GAAG;YAClF,GAAGT,OAAO;YACVU,KAAK;gBACH,GAAIb,SAASG,QAAQU,GAAG,IAAIV,QAAQU,GAAG,GAAGC,QAAQD,GAAG;gBACrDE,gCAAgCZ,QAAQa,cAAc;gBACtDC,yBAAyBf,SAASM,QAAQ;YAC5C;QACF;QAEAE,OAAOQ,WAAW,CAAC,SAAS,SAASC,cAAcC,GAAG;YACpDd,OAAO,IAAIG,MAAM,CAAC,kCAAkC,EAAEW,IAAIC,OAAO,EAAE;YACnEC;QACF;QACAZ,OAAOQ,WAAW,CAAC,QAAQ,SAASK,aAAaC,IAAI;YACnD,IAAIA,OAAO,GAAG;gBACZlB,OAAO,IAAIG,MAAM,CAAC,wBAAwB,EAAEe,MAAM;YACpD;QACF;QACAd,OAAOQ,WAAW,CAAC,gBAAgB,SAASO,qBAAqBL,GAAG;YAClEd,OAAO,IAAIG,MAAM,CAAC,mCAAmC,EAAEW,KAAK;YAC5DE;QACF;QACAZ,OAAOQ,WAAW,CAAC,WAAW,SAASQ,gBAAgBL,OAAO;YAC5DhB,QAAQgB;YACRC;QACF;QAEA,SAASA;YACP,8EAA8E;YAC9E,+EAA+E;YAC/E,OAAO;YACPK,aAAa,IAAMjB,OAAOkB,SAAS;QACrC;IACF;AACF"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { tsImport } from 'tsx/esm/api';
|
|
2
|
+
const workerScript = process.env.TSX_WORKER_TASK_SCRIPT;
|
|
3
|
+
if (workerScript) {
|
|
4
|
+
await tsImport(workerScript, {
|
|
5
|
+
parentURL: import.meta.url,
|
|
6
|
+
tsconfig: process.env.TSX_TSCONFIG_PATH
|
|
7
|
+
});
|
|
8
|
+
} else {
|
|
9
|
+
throw new Error('`TX_WORKER_TASK_SCRIPT` not defined');
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
//# sourceMappingURL=tsxWorkerLoader.worker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/loaders/tsx/tsxWorkerLoader.worker.ts"],"sourcesContent":["import {tsImport} from 'tsx/esm/api'\n\nconst workerScript = process.env.TSX_WORKER_TASK_SCRIPT\n\nif (workerScript) {\n await tsImport(workerScript, {\n parentURL: import.meta.url,\n tsconfig: process.env.TSX_TSCONFIG_PATH,\n })\n} else {\n throw new Error('`TX_WORKER_TASK_SCRIPT` not defined')\n}\n"],"names":["tsImport","workerScript","process","env","TSX_WORKER_TASK_SCRIPT","parentURL","url","tsconfig","TSX_TSCONFIG_PATH","Error"],"mappings":"AAAA,SAAQA,QAAQ,QAAO,cAAa;AAEpC,MAAMC,eAAeC,QAAQC,GAAG,CAACC,sBAAsB;AAEvD,IAAIH,cAAc;IAChB,MAAMD,SAASC,cAAc;QAC3BI,WAAW,YAAYC,GAAG;QAC1BC,UAAUL,QAAQC,GAAG,CAACK,iBAAiB;IACzC;AACF,OAAO;IACL,MAAM,IAAIC,MAAM;AAClB"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { URL } from 'node:url';
|
|
2
|
+
import { type WorkerOptions } from 'node:worker_threads';
|
|
3
|
+
import { type RequireProps } from '../../types.js';
|
|
4
|
+
/**
|
|
5
|
+
* Options for the tsx worker task
|
|
6
|
+
*
|
|
7
|
+
* @internal
|
|
8
|
+
*/
|
|
9
|
+
interface TsxWorkerTaskOptions extends RequireProps<WorkerOptions, 'name'> {
|
|
10
|
+
rootPath: string;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Executes a worker file with tsx registered. This means you can import other
|
|
14
|
+
* typescript with fairly rich syntax, and still have that only apply to the worker
|
|
15
|
+
* thread instead of the full parent process. The worker should emit a message when
|
|
16
|
+
* complete using `parentPort`. Once it has received a single message will resolve the
|
|
17
|
+
* returned promise with that message. If you are expecting multiple messages, you will
|
|
18
|
+
* have to implement another method ;)
|
|
19
|
+
*
|
|
20
|
+
* @param filePath - Path to the worker file
|
|
21
|
+
* @param options - Options to pass to the worker
|
|
22
|
+
* @returns A promise that resolves with the message from the worker
|
|
23
|
+
* @throws If the file does not exist
|
|
24
|
+
* @throws If the worker exits with a non-zero code
|
|
25
|
+
* @internal
|
|
26
|
+
*/
|
|
27
|
+
export declare function tsxWorkerTask<T = unknown>(filePath: URL, options: TsxWorkerTaskOptions): Promise<T>;
|
|
28
|
+
export {};
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { URL } from 'node:url';
|
|
2
|
+
import { Worker } from 'node:worker_threads';
|
|
3
|
+
import { getTsconfig } from 'get-tsconfig';
|
|
4
|
+
import { isRecord } from '../../util/isRecord.js';
|
|
5
|
+
/**
|
|
6
|
+
* Executes a worker file with tsx registered. This means you can import other
|
|
7
|
+
* typescript with fairly rich syntax, and still have that only apply to the worker
|
|
8
|
+
* thread instead of the full parent process. The worker should emit a message when
|
|
9
|
+
* complete using `parentPort`. Once it has received a single message will resolve the
|
|
10
|
+
* returned promise with that message. If you are expecting multiple messages, you will
|
|
11
|
+
* have to implement another method ;)
|
|
12
|
+
*
|
|
13
|
+
* @param filePath - Path to the worker file
|
|
14
|
+
* @param options - Options to pass to the worker
|
|
15
|
+
* @returns A promise that resolves with the message from the worker
|
|
16
|
+
* @throws If the file does not exist
|
|
17
|
+
* @throws If the worker exits with a non-zero code
|
|
18
|
+
* @internal
|
|
19
|
+
*/ export function tsxWorkerTask(filePath, options) {
|
|
20
|
+
const tsconfig = getTsconfig(options.rootPath);
|
|
21
|
+
const env = {
|
|
22
|
+
...isRecord(options.env) ? options.env : process.env,
|
|
23
|
+
...tsconfig?.path ? {
|
|
24
|
+
TSX_TSCONFIG_PATH: tsconfig.path
|
|
25
|
+
} : {},
|
|
26
|
+
TSX_WORKER_TASK_SCRIPT: filePath.pathname
|
|
27
|
+
};
|
|
28
|
+
const worker = new Worker(new URL('tsxWorkerLoader.worker.js', import.meta.url), {
|
|
29
|
+
...options,
|
|
30
|
+
env
|
|
31
|
+
});
|
|
32
|
+
return new Promise((resolve, reject)=>{
|
|
33
|
+
worker.addListener('error', function onWorkerError(err) {
|
|
34
|
+
reject(new Error(`Failed to load file through worker: ${err.message}`, {
|
|
35
|
+
cause: err
|
|
36
|
+
}));
|
|
37
|
+
cleanup();
|
|
38
|
+
});
|
|
39
|
+
worker.addListener('exit', function onWorkerExit(code) {
|
|
40
|
+
if (code > 0) {
|
|
41
|
+
reject(new Error(`Worker exited with code ${code}`));
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
worker.addListener('messageerror', function onWorkerMessageError(err) {
|
|
45
|
+
reject(new Error(`Fail to parse message from worker: ${err}`));
|
|
46
|
+
cleanup();
|
|
47
|
+
});
|
|
48
|
+
worker.addListener('message', function onWorkerMessage(message) {
|
|
49
|
+
resolve(message);
|
|
50
|
+
cleanup();
|
|
51
|
+
});
|
|
52
|
+
function cleanup() {
|
|
53
|
+
// Allow the worker a _bit_ of time to clean up, but ensure that we don't have
|
|
54
|
+
// lingering processes hanging around forever if the worker doesn't exit on its
|
|
55
|
+
// own.
|
|
56
|
+
setImmediate(()=>worker.terminate());
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
//# sourceMappingURL=tsxWorkerTask.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/loaders/tsx/tsxWorkerTask.ts"],"sourcesContent":["import {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'\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: filePath.pathname,\n }\n\n const worker = new Worker(new URL('tsxWorkerLoader.worker.js', import.meta.url), {\n ...options,\n env,\n })\n\n return new Promise((resolve, reject) => {\n worker.addListener('error', function onWorkerError(err) {\n reject(new Error(`Failed to load file through worker: ${err.message}`, {cause: err}))\n cleanup()\n })\n worker.addListener('exit', function onWorkerExit(code) {\n if (code > 0) {\n reject(new Error(`Worker exited with code ${code}`))\n }\n })\n worker.addListener('messageerror', function onWorkerMessageError(err) {\n reject(new Error(`Fail to parse message from worker: ${err}`))\n cleanup()\n })\n worker.addListener('message', function onWorkerMessage(message) {\n resolve(message)\n cleanup()\n })\n\n function cleanup() {\n // Allow the worker a _bit_ of time to clean up, but ensure that we don't have\n // lingering processes hanging around forever if the worker doesn't exit on its\n // own.\n setImmediate(() => worker.terminate())\n }\n })\n}\n"],"names":["URL","Worker","getTsconfig","isRecord","tsxWorkerTask","filePath","options","tsconfig","rootPath","env","process","path","TSX_TSCONFIG_PATH","TSX_WORKER_TASK_SCRIPT","pathname","worker","url","Promise","resolve","reject","addListener","onWorkerError","err","Error","message","cause","cleanup","onWorkerExit","code","onWorkerMessageError","onWorkerMessage","setImmediate","terminate"],"mappings":"AAAA,SAAQA,GAAG,QAAO,WAAU;AAC5B,SAAQC,MAAM,QAA2B,sBAAqB;AAE9D,SAAQC,WAAW,QAAO,eAAc;AAGxC,SAAQC,QAAQ,QAAO,yBAAwB;AAW/C;;;;;;;;;;;;;;CAcC,GACD,OAAO,SAASC,cACdC,QAAa,EACbC,OAA6B;IAE7B,MAAMC,WAAWL,YAAYI,QAAQE,QAAQ;IAE7C,MAAMC,MAAM;QACV,GAAIN,SAASG,QAAQG,GAAG,IAAIH,QAAQG,GAAG,GAAGC,QAAQD,GAAG;QACrD,GAAIF,UAAUI,OAAO;YAACC,mBAAmBL,SAASI,IAAI;QAAA,IAAI,CAAC,CAAC;QAC5DE,wBAAwBR,SAASS,QAAQ;IAC3C;IAEA,MAAMC,SAAS,IAAId,OAAO,IAAID,IAAI,6BAA6B,YAAYgB,GAAG,GAAG;QAC/E,GAAGV,OAAO;QACVG;IACF;IAEA,OAAO,IAAIQ,QAAQ,CAACC,SAASC;QAC3BJ,OAAOK,WAAW,CAAC,SAAS,SAASC,cAAcC,GAAG;YACpDH,OAAO,IAAII,MAAM,CAAC,oCAAoC,EAAED,IAAIE,OAAO,EAAE,EAAE;gBAACC,OAAOH;YAAG;YAClFI;QACF;QACAX,OAAOK,WAAW,CAAC,QAAQ,SAASO,aAAaC,IAAI;YACnD,IAAIA,OAAO,GAAG;gBACZT,OAAO,IAAII,MAAM,CAAC,wBAAwB,EAAEK,MAAM;YACpD;QACF;QACAb,OAAOK,WAAW,CAAC,gBAAgB,SAASS,qBAAqBP,GAAG;YAClEH,OAAO,IAAII,MAAM,CAAC,mCAAmC,EAAED,KAAK;YAC5DI;QACF;QACAX,OAAOK,WAAW,CAAC,WAAW,SAASU,gBAAgBN,OAAO;YAC5DN,QAAQM;YACRE;QACF;QAEA,SAASA;YACP,8EAA8E;YAC9E,+EAA+E;YAC/E,OAAO;YACPK,aAAa,IAAMhB,OAAOiB,SAAS;QACrC;IACF;AACF"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { type SanityClient } from '@sanity/client';
|
|
2
|
+
/**
|
|
3
|
+
* @internal
|
|
4
|
+
*/
|
|
5
|
+
export interface GlobalCliClientOptions {
|
|
6
|
+
/**
|
|
7
|
+
* The API version to use for this client.
|
|
8
|
+
*/
|
|
9
|
+
apiVersion: string;
|
|
10
|
+
/**
|
|
11
|
+
* Whether to require a user to be authenticated to use this client.
|
|
12
|
+
* Default: `false`.
|
|
13
|
+
* Throws an error if `true` and user is not authenticated.
|
|
14
|
+
*/
|
|
15
|
+
requireUser?: boolean;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Create a "global" (unscoped) Sanity API client.
|
|
19
|
+
*
|
|
20
|
+
* @param options - The options to use for the client.
|
|
21
|
+
* @returns Promise that resolves to a configured Sanity API client.
|
|
22
|
+
*/
|
|
23
|
+
export declare function getGlobalCliClient({ apiVersion, requireUser, }: GlobalCliClientOptions): Promise<SanityClient>;
|
|
24
|
+
/**
|
|
25
|
+
* @internal
|
|
26
|
+
*/
|
|
27
|
+
export interface ProjectCliClientOptions {
|
|
28
|
+
apiVersion: string;
|
|
29
|
+
projectId: string;
|
|
30
|
+
dataset?: string;
|
|
31
|
+
requireUser?: boolean;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Create a "global" (unscoped) Sanity API client.
|
|
35
|
+
*
|
|
36
|
+
* @param options - The options to use for the client.
|
|
37
|
+
* @returns Promise that resolves to a configured Sanity API client.
|
|
38
|
+
*/
|
|
39
|
+
export declare function getProjectCliClient({ apiVersion, dataset, projectId, requireUser, }: ProjectCliClientOptions): Promise<SanityClient>;
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { ux } from '@oclif/core';
|
|
2
|
+
import { createClient, requester as defaultRequester } from '@sanity/client';
|
|
3
|
+
import { generateHelpUrl } from '../util/generateHelpUrl.js';
|
|
4
|
+
import { isHttpError } from '../util/isHttpError.js';
|
|
5
|
+
import { getCliToken } from './getCliToken.js';
|
|
6
|
+
const apiHosts = {
|
|
7
|
+
staging: 'https://api.sanity.work'
|
|
8
|
+
};
|
|
9
|
+
const CLI_REQUEST_TAG_PREFIX = 'sanity.cli';
|
|
10
|
+
/**
|
|
11
|
+
* Create a "global" (unscoped) Sanity API client.
|
|
12
|
+
*
|
|
13
|
+
* @param options - The options to use for the client.
|
|
14
|
+
* @returns Promise that resolves to a configured Sanity API client.
|
|
15
|
+
*/ export async function getGlobalCliClient({ apiVersion, requireUser }) {
|
|
16
|
+
const requester = defaultRequester.clone();
|
|
17
|
+
requester.use(authErrors());
|
|
18
|
+
const sanityEnv = process.env.SANITY_INTERNAL_ENV || 'production';
|
|
19
|
+
const token = await getCliToken();
|
|
20
|
+
const apiHost = apiHosts[sanityEnv];
|
|
21
|
+
if (requireUser && !token) {
|
|
22
|
+
throw new Error('You must login first - run "sanity login"');
|
|
23
|
+
}
|
|
24
|
+
return createClient({
|
|
25
|
+
...apiHost ? {
|
|
26
|
+
apiHost
|
|
27
|
+
} : {},
|
|
28
|
+
apiVersion,
|
|
29
|
+
requester,
|
|
30
|
+
requestTagPrefix: CLI_REQUEST_TAG_PREFIX,
|
|
31
|
+
token,
|
|
32
|
+
useCdn: false,
|
|
33
|
+
useProjectHostname: false
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Create a "global" (unscoped) Sanity API client.
|
|
38
|
+
*
|
|
39
|
+
* @param options - The options to use for the client.
|
|
40
|
+
* @returns Promise that resolves to a configured Sanity API client.
|
|
41
|
+
*/ export async function getProjectCliClient({ apiVersion, dataset, projectId, requireUser }) {
|
|
42
|
+
const requester = defaultRequester.clone();
|
|
43
|
+
requester.use(authErrors());
|
|
44
|
+
const sanityEnv = process.env.SANITY_INTERNAL_ENV || 'production';
|
|
45
|
+
const token = await getCliToken();
|
|
46
|
+
const apiHost = apiHosts[sanityEnv];
|
|
47
|
+
if (requireUser && !token) {
|
|
48
|
+
throw new Error('You must login first - run "sanity login"');
|
|
49
|
+
}
|
|
50
|
+
return createClient({
|
|
51
|
+
...apiHost ? {
|
|
52
|
+
apiHost
|
|
53
|
+
} : {},
|
|
54
|
+
apiVersion,
|
|
55
|
+
dataset,
|
|
56
|
+
projectId,
|
|
57
|
+
requester,
|
|
58
|
+
requestTagPrefix: CLI_REQUEST_TAG_PREFIX,
|
|
59
|
+
token,
|
|
60
|
+
useCdn: false,
|
|
61
|
+
useProjectHostname: true
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* `get-it` middleware that checks for 401 authentication errors and extends the error with more
|
|
66
|
+
* helpful guidance on what to do next.
|
|
67
|
+
*
|
|
68
|
+
* @returns get-it middleware with `onError` handler
|
|
69
|
+
* @internal
|
|
70
|
+
*/ function authErrors() {
|
|
71
|
+
return {
|
|
72
|
+
onError: (err)=>{
|
|
73
|
+
if (!err || !isReqResError(err)) {
|
|
74
|
+
return err;
|
|
75
|
+
}
|
|
76
|
+
const statusCode = isHttpError(err) && err.response.body.statusCode;
|
|
77
|
+
if (statusCode === 401) {
|
|
78
|
+
err.message = `${err.message}. You may need to login again with ${ux.colorize('cyan', 'sanity login')}.\nFor more information, see ${generateHelpUrl('cli-errors')}.`;
|
|
79
|
+
}
|
|
80
|
+
return err;
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
function isReqResError(err) {
|
|
85
|
+
return Object.prototype.hasOwnProperty.call(err, 'response');
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
//# sourceMappingURL=apiClient.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/services/apiClient.ts"],"sourcesContent":["import {ux} from '@oclif/core'\nimport {\n type ClientError,\n createClient,\n requester as defaultRequester,\n type SanityClient,\n type ServerError,\n} from '@sanity/client'\n\nimport {generateHelpUrl} from '../util/generateHelpUrl.js'\nimport {isHttpError} from '../util/isHttpError.js'\nimport {getCliToken} from './getCliToken.js'\n\nconst apiHosts: Record<string, string | undefined> = {\n staging: 'https://api.sanity.work',\n}\n\nconst CLI_REQUEST_TAG_PREFIX = 'sanity.cli'\n\n/**\n * @internal\n */\nexport interface GlobalCliClientOptions {\n /**\n * The API version to use for this client.\n */\n apiVersion: string\n\n /**\n * Whether to require a user to be authenticated to use this client.\n * Default: `false`.\n * Throws an error if `true` and user is not authenticated.\n */\n requireUser?: boolean\n}\n\n/**\n * Create a \"global\" (unscoped) Sanity API client.\n *\n * @param options - The options to use for the client.\n * @returns Promise that resolves to a configured Sanity API client.\n */\nexport async function getGlobalCliClient({\n apiVersion,\n requireUser,\n}: GlobalCliClientOptions): Promise<SanityClient> {\n const requester = defaultRequester.clone()\n requester.use(authErrors())\n\n const sanityEnv = process.env.SANITY_INTERNAL_ENV || 'production'\n\n const token = await getCliToken()\n const apiHost = apiHosts[sanityEnv]\n\n if (requireUser && !token) {\n throw new Error('You must login first - run \"sanity login\"')\n }\n\n return createClient({\n ...(apiHost ? {apiHost} : {}),\n apiVersion,\n requester,\n requestTagPrefix: CLI_REQUEST_TAG_PREFIX,\n token,\n useCdn: false,\n useProjectHostname: false,\n })\n}\n\n/**\n * @internal\n */\nexport interface ProjectCliClientOptions {\n apiVersion: string\n projectId: string\n\n dataset?: string\n\n requireUser?: boolean\n}\n\n/**\n * Create a \"global\" (unscoped) Sanity API client.\n *\n * @param options - The options to use for the client.\n * @returns Promise that resolves to a configured Sanity API client.\n */\nexport async function getProjectCliClient({\n apiVersion,\n dataset,\n projectId,\n requireUser,\n}: ProjectCliClientOptions): Promise<SanityClient> {\n const requester = defaultRequester.clone()\n requester.use(authErrors())\n\n const sanityEnv = process.env.SANITY_INTERNAL_ENV || 'production'\n\n const token = await getCliToken()\n const apiHost = apiHosts[sanityEnv]\n\n if (requireUser && !token) {\n throw new Error('You must login first - run \"sanity login\"')\n }\n\n return createClient({\n ...(apiHost ? {apiHost} : {}),\n apiVersion,\n dataset,\n projectId,\n requester,\n requestTagPrefix: CLI_REQUEST_TAG_PREFIX,\n token,\n useCdn: false,\n useProjectHostname: true,\n })\n}\n\n/**\n * `get-it` middleware that checks for 401 authentication errors and extends the error with more\n * helpful guidance on what to do next.\n *\n * @returns get-it middleware with `onError` handler\n * @internal\n */\nfunction authErrors() {\n return {\n onError: (err: Error | null) => {\n if (!err || !isReqResError(err)) {\n return err\n }\n\n const statusCode = isHttpError(err) && err.response.body.statusCode\n if (statusCode === 401) {\n err.message = `${err.message}. You may need to login again with ${ux.colorize('cyan', 'sanity login')}.\\nFor more information, see ${generateHelpUrl('cli-errors')}.`\n }\n\n return err\n },\n }\n}\n\nfunction isReqResError(err: Error): err is ClientError | ServerError {\n return Object.prototype.hasOwnProperty.call(err, 'response')\n}\n"],"names":["ux","createClient","requester","defaultRequester","generateHelpUrl","isHttpError","getCliToken","apiHosts","staging","CLI_REQUEST_TAG_PREFIX","getGlobalCliClient","apiVersion","requireUser","clone","use","authErrors","sanityEnv","process","env","SANITY_INTERNAL_ENV","token","apiHost","Error","requestTagPrefix","useCdn","useProjectHostname","getProjectCliClient","dataset","projectId","onError","err","isReqResError","statusCode","response","body","message","colorize","Object","prototype","hasOwnProperty","call"],"mappings":"AAAA,SAAQA,EAAE,QAAO,cAAa;AAC9B,SAEEC,YAAY,EACZC,aAAaC,gBAAgB,QAGxB,iBAAgB;AAEvB,SAAQC,eAAe,QAAO,6BAA4B;AAC1D,SAAQC,WAAW,QAAO,yBAAwB;AAClD,SAAQC,WAAW,QAAO,mBAAkB;AAE5C,MAAMC,WAA+C;IACnDC,SAAS;AACX;AAEA,MAAMC,yBAAyB;AAmB/B;;;;;CAKC,GACD,OAAO,eAAeC,mBAAmB,EACvCC,UAAU,EACVC,WAAW,EACY;IACvB,MAAMV,YAAYC,iBAAiBU,KAAK;IACxCX,UAAUY,GAAG,CAACC;IAEd,MAAMC,YAAYC,QAAQC,GAAG,CAACC,mBAAmB,IAAI;IAErD,MAAMC,QAAQ,MAAMd;IACpB,MAAMe,UAAUd,QAAQ,CAACS,UAAU;IAEnC,IAAIJ,eAAe,CAACQ,OAAO;QACzB,MAAM,IAAIE,MAAM;IAClB;IAEA,OAAOrB,aAAa;QAClB,GAAIoB,UAAU;YAACA;QAAO,IAAI,CAAC,CAAC;QAC5BV;QACAT;QACAqB,kBAAkBd;QAClBW;QACAI,QAAQ;QACRC,oBAAoB;IACtB;AACF;AAcA;;;;;CAKC,GACD,OAAO,eAAeC,oBAAoB,EACxCf,UAAU,EACVgB,OAAO,EACPC,SAAS,EACThB,WAAW,EACa;IACxB,MAAMV,YAAYC,iBAAiBU,KAAK;IACxCX,UAAUY,GAAG,CAACC;IAEd,MAAMC,YAAYC,QAAQC,GAAG,CAACC,mBAAmB,IAAI;IAErD,MAAMC,QAAQ,MAAMd;IACpB,MAAMe,UAAUd,QAAQ,CAACS,UAAU;IAEnC,IAAIJ,eAAe,CAACQ,OAAO;QACzB,MAAM,IAAIE,MAAM;IAClB;IAEA,OAAOrB,aAAa;QAClB,GAAIoB,UAAU;YAACA;QAAO,IAAI,CAAC,CAAC;QAC5BV;QACAgB;QACAC;QACA1B;QACAqB,kBAAkBd;QAClBW;QACAI,QAAQ;QACRC,oBAAoB;IACtB;AACF;AAEA;;;;;;CAMC,GACD,SAASV;IACP,OAAO;QACLc,SAAS,CAACC;YACR,IAAI,CAACA,OAAO,CAACC,cAAcD,MAAM;gBAC/B,OAAOA;YACT;YAEA,MAAME,aAAa3B,YAAYyB,QAAQA,IAAIG,QAAQ,CAACC,IAAI,CAACF,UAAU;YACnE,IAAIA,eAAe,KAAK;gBACtBF,IAAIK,OAAO,GAAG,GAAGL,IAAIK,OAAO,CAAC,mCAAmC,EAAEnC,GAAGoC,QAAQ,CAAC,QAAQ,gBAAgB,6BAA6B,EAAEhC,gBAAgB,cAAc,CAAC,CAAC;YACvK;YAEA,OAAO0B;QACT;IACF;AACF;AAEA,SAASC,cAAcD,GAAU;IAC/B,OAAOO,OAAOC,SAAS,CAACC,cAAc,CAACC,IAAI,CAACV,KAAK;AACnD"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
declare const cliUserConfigSchema: {
|
|
3
|
+
authToken: z.ZodOptional<z.ZodString>;
|
|
4
|
+
telemetryConsent: z.ZodOptional<z.ZodObject<{
|
|
5
|
+
updatedAt: z.ZodOptional<z.ZodNumber>;
|
|
6
|
+
value: z.ZodObject<{
|
|
7
|
+
status: z.ZodEnum<["undetermined", "unset", "granted", "denied"]>;
|
|
8
|
+
type: z.ZodString;
|
|
9
|
+
}, "passthrough", z.ZodTypeAny, z.objectOutputType<{
|
|
10
|
+
status: z.ZodEnum<["undetermined", "unset", "granted", "denied"]>;
|
|
11
|
+
type: z.ZodString;
|
|
12
|
+
}, z.ZodTypeAny, "passthrough">, z.objectInputType<{
|
|
13
|
+
status: z.ZodEnum<["undetermined", "unset", "granted", "denied"]>;
|
|
14
|
+
type: z.ZodString;
|
|
15
|
+
}, z.ZodTypeAny, "passthrough">>;
|
|
16
|
+
}, "strip", z.ZodTypeAny, {
|
|
17
|
+
value: {
|
|
18
|
+
type: string;
|
|
19
|
+
status: "undetermined" | "unset" | "granted" | "denied";
|
|
20
|
+
} & {
|
|
21
|
+
[k: string]: unknown;
|
|
22
|
+
};
|
|
23
|
+
updatedAt?: number | undefined;
|
|
24
|
+
}, {
|
|
25
|
+
value: {
|
|
26
|
+
type: string;
|
|
27
|
+
status: "undetermined" | "unset" | "granted" | "denied";
|
|
28
|
+
} & {
|
|
29
|
+
[k: string]: unknown;
|
|
30
|
+
};
|
|
31
|
+
updatedAt?: number | undefined;
|
|
32
|
+
}>>;
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* The CLI user configuration schema.
|
|
36
|
+
*
|
|
37
|
+
* @internal
|
|
38
|
+
*/
|
|
39
|
+
type CliUserConfig = z.infer<z.ZodObject<typeof cliUserConfigSchema>>;
|
|
40
|
+
/**
|
|
41
|
+
* Set the config value for the given property.
|
|
42
|
+
* Validates that the passed value adheres to the defined CLI config schema.
|
|
43
|
+
*
|
|
44
|
+
* @param prop - The property to set the value for
|
|
45
|
+
* @param value - The value to set
|
|
46
|
+
* @internal
|
|
47
|
+
*/
|
|
48
|
+
export declare function setConfig<P extends keyof CliUserConfig>(prop: P, value: CliUserConfig[P]): Promise<void>;
|
|
49
|
+
/**
|
|
50
|
+
* Get the config value for the given property
|
|
51
|
+
*
|
|
52
|
+
* @param prop - The property to get the value for
|
|
53
|
+
* @returns The value of the given property
|
|
54
|
+
* @internal
|
|
55
|
+
*/
|
|
56
|
+
export declare function getConfig<P extends keyof CliUserConfig>(prop: P): Promise<CliUserConfig[P]>;
|
|
57
|
+
export {};
|