@noverax/courier-build 0.0.0-stage → 0.5.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 +295 -2
- package/lib/config/index.d.ts +811 -0
- package/lib/config/index.js +75 -0
- package/lib/config-file-of-Clf_dWUQ.js +28 -0
- package/lib/config-in-page-message-DLd3f0Jd.js +20 -0
- package/lib/courier-routes-options-BYF7Sfdf.d.cts +13 -0
- package/lib/courier-routes-options-BYF7Sfdf.d.ts +13 -0
- package/lib/engine/worker.d.ts +1 -0
- package/lib/engine/worker.js +548 -0
- package/lib/errno-code-CNx_E80R.js +32 -0
- package/lib/esbuild/index.d.ts +58 -0
- package/lib/esbuild/index.js +191 -0
- package/lib/index-_VUU5N5v.d.ts +134 -0
- package/lib/index.d.ts +101 -0
- package/lib/index.js +4 -0
- package/lib/jest/routes-thread.d.ts +1 -0
- package/lib/jest/routes-thread.js +46 -0
- package/lib/jest/transformer.cjs +121 -0
- package/lib/jest/transformer.d.cts +39 -0
- package/lib/load-config-barNPfXN.js +2834 -0
- package/lib/metro/index.cjs +25 -0
- package/lib/metro/index.d.cts +55 -0
- package/lib/metro/index.d.ts +67 -0
- package/lib/metro/index.js +105 -0
- package/lib/package-file-CVAKY_Nu.js +39 -0
- package/lib/read-limits-DUuUaEQM.js +41 -0
- package/lib/rollup/index.d.ts +51 -0
- package/lib/rollup/index.js +95 -0
- package/lib/routes-engine-BfwrCuNL.d.ts +117 -0
- package/lib/routes-file-DRoqUZ0S.js +206 -0
- package/lib/routes-loader-context-40OKDrQp.d.ts +26 -0
- package/lib/routes-module-code-DYtP7uj1.js +405 -0
- package/lib/routes-module-id-CnUjQjYF.js +12 -0
- package/lib/routes-read-error-DQhKIE2F.js +30 -0
- package/lib/routes-rule-Pu1Tz8Xm.js +108 -0
- package/lib/rsbuild/index.d.ts +41 -0
- package/lib/rsbuild/index.js +37 -0
- package/lib/rspack/index.d.ts +3 -0
- package/lib/rspack/index.js +1 -0
- package/lib/shared-engine-D0j7uXg8.js +28 -0
- package/lib/vite/index.d.ts +33 -0
- package/lib/vite/index.js +357 -0
- package/lib/webpack/index.d.ts +4 -0
- package/lib/webpack/index.js +3 -0
- package/lib/webpack/loader.cjs +31 -0
- package/lib/webpack/loader.d.cts +40 -0
- package/lib/webpack/run-routes-loader.d.ts +22 -0
- package/lib/webpack/run-routes-loader.js +103 -0
- package/lib/webpack-BPxhBYGV.js +42 -0
- package/lib/worker-messages-BT2vvNQJ.js +35 -0
- package/package.json +209 -4
|
@@ -0,0 +1,811 @@
|
|
|
1
|
+
import { CourierError } from "@noverax/courier";
|
|
2
|
+
import { Jiti, ModuleCache, TransformOptions, TransformResult } from "jiti";
|
|
3
|
+
import { CourierConfig } from "@noverax/courier/config";
|
|
4
|
+
/** The file names a Courier config may have, in the order they are looked for */
|
|
5
|
+
export declare const CONFIG_BASENAMES: ReadonlyArray<string>;
|
|
6
|
+
/**
|
|
7
|
+
* Every path a config is looked for at from a folder, in the order it is
|
|
8
|
+
* looked for: each of {@link CONFIG_BASENAMES} in the folder, then in each
|
|
9
|
+
* folder above it, up to the top of the project — the first folder that
|
|
10
|
+
* holds its repository (`.git`, `.hg`, `.jj`) or is the root of its
|
|
11
|
+
* workspace (`pnpm-workspace.yaml`, or a `package.json` that declares
|
|
12
|
+
* `workspaces`) — or, with no such folder, the root of the file system.
|
|
13
|
+
*
|
|
14
|
+
* @param startDir - The folder to look in first
|
|
15
|
+
* @returns The paths, absolute, whether there or not
|
|
16
|
+
* @example
|
|
17
|
+
* ```ts
|
|
18
|
+
* configCandidates("/repo/apps/web"); // → ["/repo/apps/web/courier.config.ts", …, "/repo/courier.config.cjs"]
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
21
|
+
export declare function configCandidates(startDir: string): string[];
|
|
22
|
+
/** The frameworks Courier tells apart. */
|
|
23
|
+
type FrameworkId = "next" | "nuxt" | "sveltekit" | "astro" | "react-router" | "remix" | "solid-start" | "expo" | "nestjs" | "fastify" | "hono" | "express" | "koa" | "hapi" | "elysia" | "h3" | "nitro" | "react" | "vue";
|
|
24
|
+
/** A framework, and the packages a project that uses it lists. */
|
|
25
|
+
interface FrameworkMarker {
|
|
26
|
+
readonly id: FrameworkId;
|
|
27
|
+
/** The framework as its users name it. */
|
|
28
|
+
readonly label: string;
|
|
29
|
+
/** The package whose presence tells the framework, and whose version is the framework's. */
|
|
30
|
+
readonly marker: string;
|
|
31
|
+
/** Another package the project must list too. */
|
|
32
|
+
readonly also?: string;
|
|
33
|
+
/**
|
|
34
|
+
* Whether the marker tells the framework first as a dependency the app
|
|
35
|
+
* runs with: Courier's setup installs Hono for Studio's mock as a dev
|
|
36
|
+
* dependency, in an app built with another framework. Listed only among
|
|
37
|
+
* the dev dependencies, it still tells the framework where no other is
|
|
38
|
+
* listed, as for a worker a bundler builds.
|
|
39
|
+
*/
|
|
40
|
+
readonly runsWith?: boolean;
|
|
41
|
+
/**
|
|
42
|
+
* Whether it runs a server alone, which a package may list beside the
|
|
43
|
+
* framework its page is built with: such a package is told by its
|
|
44
|
+
* server, which comes before the page's in the list, and is not a
|
|
45
|
+
* page's alone. The same servers as the upgrade's, in create-courier.
|
|
46
|
+
*/
|
|
47
|
+
readonly server?: boolean;
|
|
48
|
+
}
|
|
49
|
+
/** The frameworks, the ones built on others first: a Next.js app lists React too; a server before a page Vite builds. */
|
|
50
|
+
export declare const FRAMEWORK_MARKERS: readonly FrameworkMarker[];
|
|
51
|
+
/** The packages a package.json lists, by the field it lists them in. */
|
|
52
|
+
interface ListedPackages {
|
|
53
|
+
readonly dependencies: Readonly<Record<string, unknown>>;
|
|
54
|
+
readonly devDependencies: Readonly<Record<string, unknown>>;
|
|
55
|
+
readonly peerDependencies: Readonly<Record<string, unknown>>;
|
|
56
|
+
readonly optionalDependencies: Readonly<Record<string, unknown>>;
|
|
57
|
+
}
|
|
58
|
+
/** The framework a project is built with, and the package.json that says so. */
|
|
59
|
+
interface ProjectFramework {
|
|
60
|
+
/** The framework, or `undefined` when the package.json lists none Courier tells. */
|
|
61
|
+
readonly framework: FrameworkMarker | undefined;
|
|
62
|
+
/** The package.json read, absolute; `undefined` when there is none up to the root of the disk. */
|
|
63
|
+
readonly manifest: string | undefined;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* The framework a project is built with, told by the packages it lists: a
|
|
67
|
+
* framework told first by what the app runs with counts among the dev
|
|
68
|
+
* dependencies only where no other framework is listed.
|
|
69
|
+
*
|
|
70
|
+
* @param listed - The packages the project's package.json lists
|
|
71
|
+
* @returns The framework, or `undefined` when it lists none Courier tells
|
|
72
|
+
* @example
|
|
73
|
+
* ```ts
|
|
74
|
+
* detectFramework({ dependencies: { next: "^16.0.0", react: "^19.0.0" }, … })?.label; // "Next.js"
|
|
75
|
+
* ```
|
|
76
|
+
*/
|
|
77
|
+
export declare function detectFramework(listed: ListedPackages): FrameworkMarker | undefined;
|
|
78
|
+
/**
|
|
79
|
+
* The framework of the project a folder belongs to, told by the nearest
|
|
80
|
+
* package.json at or above it. A package.json that does not parse lists
|
|
81
|
+
* nothing: the project is then read as plain Node, as it would be with none.
|
|
82
|
+
*
|
|
83
|
+
* @param folder - A folder of the project, absolute: the config's own
|
|
84
|
+
* @returns The framework, and the package.json that told it
|
|
85
|
+
* @example
|
|
86
|
+
* ```ts
|
|
87
|
+
* projectFramework("/app").framework?.id; // "sveltekit", where /app/package.json lists @sveltejs/kit
|
|
88
|
+
* ```
|
|
89
|
+
*/
|
|
90
|
+
export declare function projectFramework(folder: string): ProjectFramework;
|
|
91
|
+
/** What a module of the project gets for an import its framework's server answers itself. */
|
|
92
|
+
type ModuleRule = {
|
|
93
|
+
readonly kind: "empty";
|
|
94
|
+
} | {
|
|
95
|
+
readonly kind: "provided";
|
|
96
|
+
readonly exports: () => object;
|
|
97
|
+
} | {
|
|
98
|
+
readonly kind: "refused";
|
|
99
|
+
readonly reason: string;
|
|
100
|
+
readonly remedy: string;
|
|
101
|
+
};
|
|
102
|
+
/** What a framework says of an import or a name of its own that the load could not find. */
|
|
103
|
+
interface Diagnosis {
|
|
104
|
+
/** What the import or the name is, worded to follow it: `is a module of SvelteKit's runtime, …`. */
|
|
105
|
+
readonly reason: string;
|
|
106
|
+
/** What to do about it, worded as an instruction. */
|
|
107
|
+
readonly remedy: string;
|
|
108
|
+
}
|
|
109
|
+
/** What a framework's server answers outside its build, and what it says of what it does not. */
|
|
110
|
+
interface FrameworkRules {
|
|
111
|
+
/** The imports the framework's server answers itself, by specifier. */
|
|
112
|
+
readonly modules: ReadonlyMap<string, ModuleRule>;
|
|
113
|
+
/** What the framework says of an import of its own that does not resolve outside its build. */
|
|
114
|
+
readonly unresolved?: ((specifier: string) => Diagnosis | undefined) | undefined;
|
|
115
|
+
/** What the framework says of a name its build provides where the code imports nothing. */
|
|
116
|
+
readonly undefinedName?: ((name: string) => Diagnosis | undefined) | undefined;
|
|
117
|
+
}
|
|
118
|
+
/** How a framework's server answers imports outside its build. */
|
|
119
|
+
interface ResolutionProfile extends FrameworkRules {
|
|
120
|
+
/** The framework; `undefined` for a project read as plain Node. */
|
|
121
|
+
readonly framework: FrameworkMarker | undefined;
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* A store of jiti transforms: TypeScript and ESM sources compiled to the
|
|
125
|
+
* CommonJS jiti evaluates, reused while the bytes and options that produced
|
|
126
|
+
* them are unchanged.
|
|
127
|
+
*/
|
|
128
|
+
interface TransformCache {
|
|
129
|
+
/**
|
|
130
|
+
* What jiti's transform yields for `options`: the kept code when the store
|
|
131
|
+
* holds a successful transform of the same file from the same bytes and
|
|
132
|
+
* options, and otherwise whatever `compute` returns.
|
|
133
|
+
*
|
|
134
|
+
* @param options - What jiti hands its transform
|
|
135
|
+
* @param compute - jiti's own transform, run on a miss
|
|
136
|
+
* @returns The result of `compute`, or its kept code, byte for byte
|
|
137
|
+
*/
|
|
138
|
+
transform(options: TransformOptions, compute: (options: TransformOptions) => TransformResult): TransformResult;
|
|
139
|
+
}
|
|
140
|
+
/** Where a {@link TransformCache} keeps transforms, and how much in memory. */
|
|
141
|
+
interface TransformCacheOptions {
|
|
142
|
+
/**
|
|
143
|
+
* A directory to keep transforms in across processes, as
|
|
144
|
+
* `findTransformCacheDirectory` finds it. Without one, or with `null`,
|
|
145
|
+
* transforms are kept in memory only.
|
|
146
|
+
*/
|
|
147
|
+
directory?: string | null | undefined;
|
|
148
|
+
/**
|
|
149
|
+
* Characters of transformed code kept in memory across all files; the file
|
|
150
|
+
* used least recently is dropped first once they are exceeded. `0` keeps
|
|
151
|
+
* none, for a process that loads each module once. Defaults to 128 Mi
|
|
152
|
+
* characters.
|
|
153
|
+
*/
|
|
154
|
+
maxMemoryChars?: number | undefined;
|
|
155
|
+
/**
|
|
156
|
+
* Whether the `directory` is only read: nothing in it is created, written,
|
|
157
|
+
* pruned or marked as used, so a transform computed on a miss stays in
|
|
158
|
+
* this process. For a process that loads, once, what another process has
|
|
159
|
+
* just kept there, as a mock worker loads the modules Studio loaded: its
|
|
160
|
+
* own entries would only duplicate that process's. Defaults to `false`.
|
|
161
|
+
*/
|
|
162
|
+
readOnly?: boolean | undefined;
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Create a {@link TransformCache} that keeps transforms in memory for the
|
|
166
|
+
* life of the process and, given a `directory`, on disk for the next one.
|
|
167
|
+
*
|
|
168
|
+
* Each file holds one entry per module system — required and imported are
|
|
169
|
+
* transformed differently, and a module reached both ways keeps both. An
|
|
170
|
+
* entry is reused only when the digest of jiti's version, the options and
|
|
171
|
+
* the source matches, so an edited file is transformed again the first time
|
|
172
|
+
* it is loaded.
|
|
173
|
+
*
|
|
174
|
+
* A transform is looked for in memory, then in the directory, where a hit
|
|
175
|
+
* is also kept in memory; only when both miss is it computed, and a success
|
|
176
|
+
* is then kept in both. The directory is shared with every process that
|
|
177
|
+
* names it, and a directory that cannot be read or written only costs
|
|
178
|
+
* transforms; see `createTransformCacheDisk` for what an entry must be to be
|
|
179
|
+
* used. A mock worker, which loads once the modules Studio has just loaded,
|
|
180
|
+
* opens Studio's directory `readOnly` with `maxMemoryChars: 0`: it reads
|
|
181
|
+
* what Studio kept, adds nothing to the directory, and holds nothing in
|
|
182
|
+
* memory past its one load.
|
|
183
|
+
*
|
|
184
|
+
* A failed transform, one whose result carries an `error`, is never kept:
|
|
185
|
+
* babel can fail on bytes it transforms without complaint a moment later,
|
|
186
|
+
* such as a deeply nested module that overflows the stack while babel is
|
|
187
|
+
* still cold. Such a file is transformed again on every load, and every
|
|
188
|
+
* failure reaches jiti with its error, as it does without a cache. A file
|
|
189
|
+
* named by a relative path, or not named, is transformed every time.
|
|
190
|
+
*
|
|
191
|
+
* @param options - The directory (default: none, memory only), the memory
|
|
192
|
+
* bound (default: 128 Mi characters), and whether the directory is only
|
|
193
|
+
* read (default: no)
|
|
194
|
+
* @returns A cache to pass to `createConfigJiti` or `loadCourierConfig`
|
|
195
|
+
* @example
|
|
196
|
+
* ```ts
|
|
197
|
+
* const transformCache = createTransformCache({
|
|
198
|
+
* directory: findTransformCacheDirectory(projectRoot),
|
|
199
|
+
* });
|
|
200
|
+
* const first = await loadCourierConfig({ cwd: projectRoot, transformCache });
|
|
201
|
+
* // Unchanged modules are not transformed again, here or in the next process:
|
|
202
|
+
* const second = await loadCourierConfig({ cwd: projectRoot, transformCache });
|
|
203
|
+
*
|
|
204
|
+
* // A process that loads once what another has just kept:
|
|
205
|
+
* const reader = createTransformCache({ directory, readOnly: true, maxMemoryChars: 0 });
|
|
206
|
+
* ```
|
|
207
|
+
*/
|
|
208
|
+
export declare function createTransformCache({ directory, maxMemoryChars, readOnly }?: TransformCacheOptions): TransformCache;
|
|
209
|
+
/** How a project-file loader resolves imports and transforms modules. */
|
|
210
|
+
interface ConfigJitiOptions {
|
|
211
|
+
/**
|
|
212
|
+
* Whether imports resolve through the project's tsconfig path aliases, as
|
|
213
|
+
* the project's own files expect. Off to load an installed package as it is:
|
|
214
|
+
* an alias of its scope would send its imports to project sources.
|
|
215
|
+
*/
|
|
216
|
+
aliases?: boolean | undefined;
|
|
217
|
+
/**
|
|
218
|
+
* Where to reuse each module's transform while its bytes are unchanged.
|
|
219
|
+
* Without one, every module is transformed on every load. Aliases take no
|
|
220
|
+
* part in it: they change where an import resolves, never the code a
|
|
221
|
+
* module's own bytes transform to.
|
|
222
|
+
*/
|
|
223
|
+
transformCache?: TransformCache | undefined;
|
|
224
|
+
/**
|
|
225
|
+
* Told the file of each module the load transforms — the config and every
|
|
226
|
+
* TypeScript or ES module of the project it reaches — so whoever follows
|
|
227
|
+
* the project knows which files its config depends on.
|
|
228
|
+
*/
|
|
229
|
+
onModule?: ((filename: string) => void) | undefined;
|
|
230
|
+
/**
|
|
231
|
+
* Runs each transform the load makes, the first of which loads the
|
|
232
|
+
* transformer itself. A caller noting what the config's code reads runs it
|
|
233
|
+
* unnoted: what the transformer reads is its own, not the config's.
|
|
234
|
+
*/
|
|
235
|
+
runTransform?: (<TResult>(transform: () => TResult) => TResult) | undefined;
|
|
236
|
+
/**
|
|
237
|
+
* How the project's framework answers the imports its server answers
|
|
238
|
+
* itself — Next's `server-only`, SvelteKit's `$env/static/private`; see
|
|
239
|
+
* `ResolutionProfile`. Left out, the framework the nearest package.json to
|
|
240
|
+
* the file lists.
|
|
241
|
+
*/
|
|
242
|
+
profile?: ResolutionProfile | undefined;
|
|
243
|
+
/**
|
|
244
|
+
* Told of each module whose transform failed — its syntax — with what the
|
|
245
|
+
* transformer said, so whoever reports the load's failure can say which
|
|
246
|
+
* module would not compile.
|
|
247
|
+
*/
|
|
248
|
+
onTransformError?: ((filename: string, error: unknown) => void) | undefined;
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* The module loader for Courier's project files — `courier.config.*` and
|
|
252
|
+
* `courier.mocks.*` — with the options both need: the project's tsconfig path
|
|
253
|
+
* aliases, the imports its framework's server answers itself, default-export
|
|
254
|
+
* interop, no module cache, and no native import tried before the loader's
|
|
255
|
+
* own.
|
|
256
|
+
*
|
|
257
|
+
* A framework resolves some imports where it builds the server, never
|
|
258
|
+
* through Node: Next makes `server-only` an empty module on its server
|
|
259
|
+
* layers, SvelteKit and Astro write their env modules from the environment.
|
|
260
|
+
* The loader answers them as that server does, by the framework the
|
|
261
|
+
* project's package.json lists (see `profileOf`), in every module it
|
|
262
|
+
* transforms; one the project's own path aliases name is theirs. A package
|
|
263
|
+
* the loader hands to Node — an installed library — resolves its own imports
|
|
264
|
+
* as Node does while that works; where it fails — a library that imports
|
|
265
|
+
* `server-only` itself — the loader runs the package itself, and answers
|
|
266
|
+
* them there too. A package Node loads without a failure keeps Node's
|
|
267
|
+
* answers: one that imports an installed `client-only` is not refused.
|
|
268
|
+
*
|
|
269
|
+
* The module cache is off because this is also the reload path: the dev
|
|
270
|
+
* server loads the files again on every edit, and a cached module would hand
|
|
271
|
+
* back the file as it was before the user changed it. Every load therefore
|
|
272
|
+
* reads and evaluates every file again; a `transformCache` only spares the
|
|
273
|
+
* transform of a file whose bytes are unchanged.
|
|
274
|
+
*
|
|
275
|
+
* jiti's native attempt, which imports every module natively before falling
|
|
276
|
+
* back to its own loader, stays off too, whatever `JITI_TRY_NATIVE` says and
|
|
277
|
+
* under Bun, where it defaults to on: a module imported natively is the
|
|
278
|
+
* runtime's first evaluation of it for the life of the process, so an edit to
|
|
279
|
+
* it would never be seen, and the attempt comes before the module cache
|
|
280
|
+
* `evalModule` is handed, so two files evaluated over one cache would each
|
|
281
|
+
* evaluate a module they both import.
|
|
282
|
+
*
|
|
283
|
+
* jiti's own file cache stays off, with or without a `transformCache`:
|
|
284
|
+
* - it writes each entry in place, so concurrent writers can leave an entry
|
|
285
|
+
* torn between two transforms that its check still accepts;
|
|
286
|
+
* - an entry it cannot write makes the whole load throw `EACCES`;
|
|
287
|
+
* - unless the file's own directory has a `node_modules`, it falls back to
|
|
288
|
+
* `os.tmpdir()/jiti`, where another user of the machine can place an entry
|
|
289
|
+
* that is then run;
|
|
290
|
+
* - its key ignores `interopDefault` and the babel options, so a transform
|
|
291
|
+
* made under other options can be handed back;
|
|
292
|
+
* - nothing ever prunes it.
|
|
293
|
+
*
|
|
294
|
+
* jiti is loaded here rather than at the top of a module so a bundler that
|
|
295
|
+
* merely reaches this code does not pull a TypeScript transpiler into its
|
|
296
|
+
* graph; only a process that actually reads such a file pays for it.
|
|
297
|
+
*
|
|
298
|
+
* @param file - Absolute, symlink-resolved path of the file to load; modules
|
|
299
|
+
* and aliases resolve from its directory
|
|
300
|
+
* @param options - Whether to resolve through the project's path aliases
|
|
301
|
+
* (default: yes), where to reuse transforms (default: nowhere), and how the
|
|
302
|
+
* framework answers its own imports (default: as package.json tells it)
|
|
303
|
+
* @returns A jiti instance for that file
|
|
304
|
+
* @example
|
|
305
|
+
* ```ts
|
|
306
|
+
* const transformCache = createTransformCache();
|
|
307
|
+
* const jiti = await createConfigJiti(configFile, { transformCache });
|
|
308
|
+
* const config = await jiti.import(configFile, { default: true });
|
|
309
|
+
* ```
|
|
310
|
+
*/
|
|
311
|
+
export declare function createConfigJiti(file: string, { aliases, transformCache, onModule, runTransform, profile, onTransformError }?: ConfigJitiOptions): Promise<Jiti>;
|
|
312
|
+
/**
|
|
313
|
+
* The signal a project's code reads to tell that Courier is reading its
|
|
314
|
+
* definitions rather than serving requests: `COURIER_PHASE` holds
|
|
315
|
+
* `definitions` in every process Courier starts to read them — the
|
|
316
|
+
* `courier-cli routes` command, `courier-mcp --list`, Studio, the process a
|
|
317
|
+
* bundler plugin reads the routes in — after the fashion of `NEXT_PHASE`.
|
|
318
|
+
* Code that checks the environment as it is imported can skip the check
|
|
319
|
+
* then, as `@t3-oss/env-core` does with `skipValidation`; Courier guesses
|
|
320
|
+
* nothing for it. Where the application runs — `courier-server`,
|
|
321
|
+
* `courier-mcp` serving an agent, `attachRuntime()`, the app itself — the
|
|
322
|
+
* variable is not set.
|
|
323
|
+
*/
|
|
324
|
+
/** The variable a project's code reads the phase from. */
|
|
325
|
+
export declare const COURIER_PHASE = "COURIER_PHASE";
|
|
326
|
+
/** Its value while Courier reads the project's definitions. */
|
|
327
|
+
export declare const DEFINITIONS_PHASE = "definitions";
|
|
328
|
+
/**
|
|
329
|
+
* Mark the process as one that reads the project's definitions, before the
|
|
330
|
+
* project's code runs in it.
|
|
331
|
+
*
|
|
332
|
+
* @param env - The environment to mark (default: the process's)
|
|
333
|
+
* @example
|
|
334
|
+
* ```ts
|
|
335
|
+
* enterDefinitionsPhase();
|
|
336
|
+
* process.env.COURIER_PHASE; // "definitions"
|
|
337
|
+
* ```
|
|
338
|
+
*/
|
|
339
|
+
export declare function enterDefinitionsPhase(env?: NodeJS.ProcessEnv): void;
|
|
340
|
+
/** Why a project's config — or its mocks file — did not load. */
|
|
341
|
+
type ConfigLoadErrorCode = "MODULE_NOT_FOUND" | "MODULE_REFUSED" | "TRANSFORM_FAILED" | "EVALUATION_FAILED" | "LOAD_TIMED_OUT";
|
|
342
|
+
/** Where a load failed. */
|
|
343
|
+
interface ConfigLoadErrorContext extends Record<string, unknown> {
|
|
344
|
+
/** The file loaded, absolute: `courier.config.*` or `courier.mocks.*`. */
|
|
345
|
+
readonly entry: string;
|
|
346
|
+
/** The import that did not resolve or was refused, as written. */
|
|
347
|
+
readonly specifier: string | undefined;
|
|
348
|
+
/**
|
|
349
|
+
* The modules from the entry to the one that failed, the entry first: each
|
|
350
|
+
* of the project's by its absolute path, as the system names it — with `\`
|
|
351
|
+
* on Windows — and an installed package by its name.
|
|
352
|
+
*/
|
|
353
|
+
readonly importChain: readonly string[];
|
|
354
|
+
}
|
|
355
|
+
/**
|
|
356
|
+
* A project's config, or its mocks file, did not load. The message says
|
|
357
|
+
* what failed and in which module, with the chain of imports that led there
|
|
358
|
+
* from the entry — `src/api.ts imports "server-only", which does not resolve
|
|
359
|
+
* (courier.config.ts → src/api.ts).` — in one line; `hint` says what to do,
|
|
360
|
+
* in another. Neither holds a secret: the project's own message is quoted
|
|
361
|
+
* with the environment's values masked and every credential `redact()`
|
|
362
|
+
* finds cut, each as `[redacted]`. What the project threw is the `cause`,
|
|
363
|
+
* for a log at debug level, cut the same way in its message and its stack.
|
|
364
|
+
*
|
|
365
|
+
* @example
|
|
366
|
+
* ```ts
|
|
367
|
+
* if (error instanceof ConfigLoadError) log.error(`${error.message}\n${error.hint}`);
|
|
368
|
+
* ```
|
|
369
|
+
*/
|
|
370
|
+
export declare class ConfigLoadError extends CourierError<ConfigLoadErrorCode> {
|
|
371
|
+
readonly context: ConfigLoadErrorContext;
|
|
372
|
+
/** What to do about it, in a sentence or two. */
|
|
373
|
+
readonly hint: string;
|
|
374
|
+
/**
|
|
375
|
+
* @param code - Why the load failed
|
|
376
|
+
* @param message - What failed and where, in one line
|
|
377
|
+
* @param details - Where it failed, what to do, and what the project threw
|
|
378
|
+
*/
|
|
379
|
+
constructor(code: ConfigLoadErrorCode, message: string, details: {
|
|
380
|
+
context: ConfigLoadErrorContext;
|
|
381
|
+
hint: string;
|
|
382
|
+
cause?: unknown;
|
|
383
|
+
});
|
|
384
|
+
}
|
|
385
|
+
/** What a loader knows of a load that failed. */
|
|
386
|
+
interface FailedLoad {
|
|
387
|
+
/** The file loaded, absolute: `courier.config.*` or `courier.mocks.*`. */
|
|
388
|
+
readonly entry: string;
|
|
389
|
+
/** The load's module cache, which tells the chain of imports; none, and the chain is the entry. */
|
|
390
|
+
readonly cache?: ModuleCache | undefined;
|
|
391
|
+
/** The entry's key in the cache, when the loader registered it under another than its path. */
|
|
392
|
+
readonly entryKey?: string | undefined;
|
|
393
|
+
/** The framework Courier read the project as; left out, the one the entry's package.json lists. */
|
|
394
|
+
readonly profile?: ResolutionProfile | undefined;
|
|
395
|
+
/** The package.json that told the framework, absolute. */
|
|
396
|
+
readonly manifest?: string | undefined;
|
|
397
|
+
/** Each module whose transform failed in the load, by file, with what the transformer said. */
|
|
398
|
+
readonly transformFailures?: ReadonlyMap<string, unknown> | undefined;
|
|
399
|
+
}
|
|
400
|
+
/**
|
|
401
|
+
* The load error that says why a load failed, what to do, and where — the
|
|
402
|
+
* chain of imports from the entry to the module that failed.
|
|
403
|
+
*
|
|
404
|
+
* @param error - What the load threw
|
|
405
|
+
* @param load - What the loader knows of the load
|
|
406
|
+
* @returns The error, typed: an error that already is one is handed back
|
|
407
|
+
* @example
|
|
408
|
+
* ```ts
|
|
409
|
+
* try { await jiti.evalModule(source, { filename: file, cache }); }
|
|
410
|
+
* catch (error) { throw configLoadError(error, { entry: file, cache }); }
|
|
411
|
+
* ```
|
|
412
|
+
*/
|
|
413
|
+
export declare function configLoadError(error: unknown, load: FailedLoad): ConfigLoadError;
|
|
414
|
+
/**
|
|
415
|
+
* The load error for a load given up after its time: the evaluation goes on
|
|
416
|
+
* — nothing stops a module's top-level code — and the process that gave up
|
|
417
|
+
* on it ends rather than wait.
|
|
418
|
+
*
|
|
419
|
+
* @param load - What the loader knows of the load
|
|
420
|
+
* @param limitMs - How long it was given
|
|
421
|
+
* @returns The error
|
|
422
|
+
* @example
|
|
423
|
+
* ```ts
|
|
424
|
+
* reject(loadTimedOut({ entry: configFile }, 60_000));
|
|
425
|
+
* ```
|
|
426
|
+
*/
|
|
427
|
+
export declare function loadTimedOut(load: FailedLoad, limitMs: number): ConfigLoadError;
|
|
428
|
+
/** How one of the project's files is run, what runs just before its code does, and how long it may take. */
|
|
429
|
+
interface ImportProjectFileOptions extends ConfigJitiOptions {
|
|
430
|
+
/**
|
|
431
|
+
* Called once the loader is made, just before the file's code runs. A
|
|
432
|
+
* caller noting what that code reads starts here, so the loader's own
|
|
433
|
+
* start-up is not taken for the file's.
|
|
434
|
+
*/
|
|
435
|
+
beforeRun?: (() => void) | undefined;
|
|
436
|
+
/**
|
|
437
|
+
* How long the file may take to run before it is given up with
|
|
438
|
+
* `ConfigLoadError` `LOAD_TIMED_OUT`, in milliseconds. Its code runs on —
|
|
439
|
+
* nothing stops a module's top-level code — so a process that gives up
|
|
440
|
+
* should end. Left out, it is waited for however long it takes.
|
|
441
|
+
*/
|
|
442
|
+
timeoutMs?: number | undefined;
|
|
443
|
+
/**
|
|
444
|
+
* Hand back the file's default export rather than its namespace, as the
|
|
445
|
+
* runtime's loader does for `import(file, { default: true })`: see
|
|
446
|
+
* {@link settledDefault}. A promise it exports is waited for within the
|
|
447
|
+
* load's time.
|
|
448
|
+
*/
|
|
449
|
+
default?: boolean | undefined;
|
|
450
|
+
}
|
|
451
|
+
/**
|
|
452
|
+
* Run one of the project's files — `courier.config.*`, `courier.mocks.*` —
|
|
453
|
+
* with the project's loader, and hand back its module namespace. The
|
|
454
|
+
* modules it runs go into a cache of this load's own, so a failure names the
|
|
455
|
+
* chain of imports that led to it: the file runs as the loader's `import`
|
|
456
|
+
* runs it, the loader choosing by its format whether to transform it or hand
|
|
457
|
+
* it to Node.
|
|
458
|
+
*
|
|
459
|
+
* @param file - The file, absolute and symlink-resolved
|
|
460
|
+
* @param options - How the loader resolves and transforms, what runs before the file, how long it may take, and whether its default is wanted
|
|
461
|
+
* @returns The file's module namespace, or its default export, settled
|
|
462
|
+
* @throws ConfigLoadError saying why the file did not load, where, and what to do
|
|
463
|
+
* @example
|
|
464
|
+
* ```ts
|
|
465
|
+
* const namespace = await importProjectFile("/app/courier.mocks.ts");
|
|
466
|
+
* ```
|
|
467
|
+
*/
|
|
468
|
+
export declare function importProjectFile(file: string, { beforeRun, timeoutMs, default: wantsDefault, ...options }?: ImportProjectFileOptions): Promise<unknown>;
|
|
469
|
+
/**
|
|
470
|
+
* A project file's default export, as the runtime's loader hands it back
|
|
471
|
+
* for `import(file, { default: true })`: the namespace's default, or the
|
|
472
|
+
* namespace itself where that is nullish — a promise among them settled.
|
|
473
|
+
* A promise that rejects fails the load as the file's code throwing does,
|
|
474
|
+
* with `ConfigLoadError`, whose text and cause hold no value of the
|
|
475
|
+
* environment. Every loader of a project's file settles its default here.
|
|
476
|
+
*
|
|
477
|
+
* @param namespace - The file's module namespace, as its loader evaluated it
|
|
478
|
+
* @param load - What the loader knows of the load
|
|
479
|
+
* @returns The default export, settled
|
|
480
|
+
* @throws ConfigLoadError when the promise rejects
|
|
481
|
+
* @example
|
|
482
|
+
* ```ts
|
|
483
|
+
* const config = await settledDefault(await loadCourierEntry(file, cache, transformCache), { entry: file });
|
|
484
|
+
* ```
|
|
485
|
+
*/
|
|
486
|
+
export declare function settledDefault(namespace: unknown, load: FailedLoad): Promise<unknown>;
|
|
487
|
+
/**
|
|
488
|
+
* Result of a successful `loadCourierConfig` call.
|
|
489
|
+
*
|
|
490
|
+
* `configFile` is the absolute, symlink-resolved path of the file that
|
|
491
|
+
* was loaded — the dev-server side uses it for the `fs.watch` dep tracker;
|
|
492
|
+
* the runtime side uses it only for log/debug output.
|
|
493
|
+
*/
|
|
494
|
+
interface LoadedCourierConfig {
|
|
495
|
+
config: CourierConfig;
|
|
496
|
+
configFile: string;
|
|
497
|
+
}
|
|
498
|
+
/**
|
|
499
|
+
* Options for `loadCourierConfig`.
|
|
500
|
+
*/
|
|
501
|
+
interface LoadCourierConfigOptions {
|
|
502
|
+
/**
|
|
503
|
+
* Starting directory for the config search. Defaults to `process.cwd()`.
|
|
504
|
+
* The dev-server passes the explicit project root; the runtime path
|
|
505
|
+
* passes `process.cwd()` so the walk-up finds configs located at the
|
|
506
|
+
* workspace root from a nested package cwd (common in monorepos).
|
|
507
|
+
*/
|
|
508
|
+
cwd?: string | undefined;
|
|
509
|
+
/**
|
|
510
|
+
* When true, skip the walk-up and require the config file to exist at
|
|
511
|
+
* exactly `cwd`. The dev-server uses this because it was told the
|
|
512
|
+
* project root explicitly and wants to distinguish "no config in root"
|
|
513
|
+
* from "config found higher up" (which would usually mean the user
|
|
514
|
+
* pointed at the wrong directory). The runtime path leaves this false
|
|
515
|
+
* so a nested `cwd` still discovers a root-level config.
|
|
516
|
+
*
|
|
517
|
+
* Defaults to false (walk up).
|
|
518
|
+
*/
|
|
519
|
+
requireAtCwd?: boolean | undefined;
|
|
520
|
+
/**
|
|
521
|
+
* Where to reuse each module's transform while its bytes are unchanged. A
|
|
522
|
+
* caller that keeps one across loads transforms only the modules whose
|
|
523
|
+
* bytes changed; without one, every module is transformed on every load.
|
|
524
|
+
*/
|
|
525
|
+
transformCache?: TransformCache | undefined;
|
|
526
|
+
/** Told the file of each module the load transforms; see `createConfigJiti`. */
|
|
527
|
+
onModule?: ((filename: string) => void) | undefined;
|
|
528
|
+
/**
|
|
529
|
+
* Reuse the transforms kept in the project's `node_modules/.cache`, the
|
|
530
|
+
* ones Studio keeps, and keep there the ones this load makes: a process
|
|
531
|
+
* that loads the config beside Studio — an app that attaches, the MCP
|
|
532
|
+
* server, `courier-server` — transforms only the modules no process has
|
|
533
|
+
* transformed yet. On a project of a thousand endpoints that is hundreds
|
|
534
|
+
* of modules, most of a second. Passed over when `transformCache` is given.
|
|
535
|
+
*/
|
|
536
|
+
projectTransforms?: boolean | undefined;
|
|
537
|
+
/**
|
|
538
|
+
* How long the load may take before it is given up with `ConfigLoadError`
|
|
539
|
+
* `LOAD_TIMED_OUT`, in milliseconds. The config's code runs on — nothing
|
|
540
|
+
* stops a module's top-level code — so a process that gives up should
|
|
541
|
+
* end. Left out, the load is waited for however long it takes.
|
|
542
|
+
*/
|
|
543
|
+
timeoutMs?: number | undefined;
|
|
544
|
+
}
|
|
545
|
+
/**
|
|
546
|
+
* Walk up from `startDir` looking for a `courier.config.*` file, up to the
|
|
547
|
+
* top of the project: the folder that holds its repository or is the root
|
|
548
|
+
* of its workspace (see {@link configCandidates}). A config found in a folder
|
|
549
|
+
* above `startDir` is taken only when it belongs to this user or to the
|
|
550
|
+
* owner of `startDir`, and no user outside its group may write it: a folder
|
|
551
|
+
* many users share, such as `/tmp`, would otherwise run anyone's config.
|
|
552
|
+
*
|
|
553
|
+
* @param startDir - The directory to look in first
|
|
554
|
+
* @returns The absolute path of the first match, or `null` when no directory
|
|
555
|
+
* up to the top of the project holds one
|
|
556
|
+
* @throws UntrustedConfigError when the nearest config lies above `startDir`
|
|
557
|
+
* and someone else could have put it there
|
|
558
|
+
* @example
|
|
559
|
+
* ```ts
|
|
560
|
+
* findConfigFile("/app/src"); // → "/app/courier.config.ts", or null
|
|
561
|
+
* ```
|
|
562
|
+
*/
|
|
563
|
+
export declare function findConfigFile(startDir: string): string | null;
|
|
564
|
+
/**
|
|
565
|
+
* Find a config file in `cwd` itself, without walking up.
|
|
566
|
+
*
|
|
567
|
+
* @param cwd - The directory to look in
|
|
568
|
+
* @returns The first of {@link CONFIG_BASENAMES} present there, or `null`
|
|
569
|
+
* @example
|
|
570
|
+
* ```ts
|
|
571
|
+
* findConfigFileAt(process.cwd()); // → "/app/courier.config.ts", or null
|
|
572
|
+
* ```
|
|
573
|
+
*/
|
|
574
|
+
export declare function findConfigFileAt(cwd: string): string | null;
|
|
575
|
+
/**
|
|
576
|
+
* Find and load a `courier.config.*` file.
|
|
577
|
+
*
|
|
578
|
+
* Returns `null` when no config file exists, so a caller can fall back.
|
|
579
|
+
* Throws `ConfigLoadError` when a file was found and loading it failed,
|
|
580
|
+
* saying why, where — the chain of imports — and what to do.
|
|
581
|
+
*
|
|
582
|
+
* @param options - Where to look, where to reuse transforms, and how long to wait
|
|
583
|
+
* @returns The config and its canonical path, or `null` when there is no config
|
|
584
|
+
* @example
|
|
585
|
+
* ```ts
|
|
586
|
+
* const loaded = await loadCourierConfig({ cwd: projectRoot, requireAtCwd: true });
|
|
587
|
+
* ```
|
|
588
|
+
*/
|
|
589
|
+
export declare function loadCourierConfig(options?: LoadCourierConfigOptions): Promise<LoadedCourierConfig | null>;
|
|
590
|
+
/**
|
|
591
|
+
* The transforms kept in a project's `node_modules/.cache` — the ones Studio
|
|
592
|
+
* keeps — for a process that loads the project's modules once: it reuses
|
|
593
|
+
* them, keeps there the ones it makes, and holds none in memory.
|
|
594
|
+
*
|
|
595
|
+
* @param projectRoot - The project's root
|
|
596
|
+
* @returns The cache, or `undefined` when the project has no directory to keep them in
|
|
597
|
+
* @example
|
|
598
|
+
* ```ts
|
|
599
|
+
* await loadCourierConfigFile(file, { transformCache: projectTransformCache(dirname(file)) });
|
|
600
|
+
* ```
|
|
601
|
+
*/
|
|
602
|
+
export declare function projectTransformCache(projectRoot: string): TransformCache | undefined;
|
|
603
|
+
/**
|
|
604
|
+
* How one config file is loaded: the loader's options, what runs just before
|
|
605
|
+
* the config's code does, and how long it may take; see `importProjectFile`.
|
|
606
|
+
*/
|
|
607
|
+
interface LoadConfigFileOptions extends Omit<ImportProjectFileOptions, "default"> {}
|
|
608
|
+
/**
|
|
609
|
+
* Load one config file, found by whatever means the caller chose — the
|
|
610
|
+
* standalone server takes it from `--config`.
|
|
611
|
+
*
|
|
612
|
+
* @param file - Absolute path of an existing config file
|
|
613
|
+
* @param options - How the loader resolves imports and where it reuses
|
|
614
|
+
* transforms, see {@link ConfigJitiOptions}, what runs before the config,
|
|
615
|
+
* and how long it may take
|
|
616
|
+
* @returns The config and the canonical path it was loaded from
|
|
617
|
+
* @throws ConfigLoadError when the file will not load: an import that does
|
|
618
|
+
* not resolve or that the framework refuses, a module that does not
|
|
619
|
+
* compile, or code that throws
|
|
620
|
+
* @example
|
|
621
|
+
* ```ts
|
|
622
|
+
* const { config } = await loadCourierConfigFile("/app/courier.config.ts", {
|
|
623
|
+
* transformCache: createTransformCache(),
|
|
624
|
+
* });
|
|
625
|
+
* ```
|
|
626
|
+
*/
|
|
627
|
+
export declare function loadCourierConfigFile(file: string, options?: LoadConfigFileOptions): Promise<LoadedCourierConfig>;
|
|
628
|
+
/** An environment, as a process holds it. */
|
|
629
|
+
type Environment = Readonly<Record<string, string | undefined>>;
|
|
630
|
+
/**
|
|
631
|
+
* The text with no secret left to quote, by the rules above.
|
|
632
|
+
*
|
|
633
|
+
* @param text - The message, as the project's code wrote it
|
|
634
|
+
* @param env - The environment whose values are masked
|
|
635
|
+
* @returns The message, with the one sign in place of each secret
|
|
636
|
+
* @example
|
|
637
|
+
* ```ts
|
|
638
|
+
* withoutSecrets("cannot reach postgres://app:pw@db/shop", { PGUSER: "postgres" });
|
|
639
|
+
* // → "cannot reach [redacted]://db/shop"
|
|
640
|
+
* ```
|
|
641
|
+
*/
|
|
642
|
+
export declare function withoutSecrets(text: string, env?: Environment): string;
|
|
643
|
+
/**
|
|
644
|
+
* What the project's code threw, as an error whose message and stack hold
|
|
645
|
+
* no secret, by the rules above: the error a load error carries as its
|
|
646
|
+
* `cause`, so no log that prints it — at debug level, by a bundler — holds
|
|
647
|
+
* one either. It keeps the thrown error's name and `code`; a value thrown
|
|
648
|
+
* that is no error becomes one, its text cut the same way.
|
|
649
|
+
*
|
|
650
|
+
* @param thrown - What the code threw
|
|
651
|
+
* @param env - The environment whose values are masked
|
|
652
|
+
* @returns The error, masked
|
|
653
|
+
* @example
|
|
654
|
+
* ```ts
|
|
655
|
+
* maskedError(new TypeError(`bad ${process.env.API_KEY}`)).message; // "bad [redacted]"
|
|
656
|
+
* ```
|
|
657
|
+
*/
|
|
658
|
+
export declare function maskedError(thrown: unknown, env?: Environment): Error;
|
|
659
|
+
/** Path aliases a project declares, ready for both consumers. */
|
|
660
|
+
interface PathAliases {
|
|
661
|
+
/**
|
|
662
|
+
* Prefix → absolute target, in the shape jiti's `alias` option takes.
|
|
663
|
+
* Only the first target of a mapping appears: jiti resolves one path per
|
|
664
|
+
* alias, while `candidatesFor` offers every declared target.
|
|
665
|
+
*/
|
|
666
|
+
readonly loader: Readonly<Record<string, string>>;
|
|
667
|
+
/** Absolute paths `specifier` may denote, in declaration order. */
|
|
668
|
+
candidatesFor(specifier: string): string[];
|
|
669
|
+
}
|
|
670
|
+
/**
|
|
671
|
+
* Read the path aliases that apply to `projectRoot`.
|
|
672
|
+
*
|
|
673
|
+
* @param projectRoot - Directory holding the project's `tsconfig.json`
|
|
674
|
+
* @returns The aliases, empty when the project declares none
|
|
675
|
+
*
|
|
676
|
+
* @example
|
|
677
|
+
* ```ts
|
|
678
|
+
* const aliases = readPathAliases("/app");
|
|
679
|
+
* aliases.candidatesFor("@/lib/sources"); // → ["/app/src/lib/sources"]
|
|
680
|
+
* ```
|
|
681
|
+
*/
|
|
682
|
+
export declare function readPathAliases(projectRoot: string): PathAliases;
|
|
683
|
+
/**
|
|
684
|
+
* How a framework's server answers the imports it answers itself. A
|
|
685
|
+
* framework that answers none, and a project that lists no framework, are
|
|
686
|
+
* read as plain Node.
|
|
687
|
+
*
|
|
688
|
+
* @param framework - The project's framework, as its package.json tells it
|
|
689
|
+
* @returns The profile every loader of the project's files applies
|
|
690
|
+
* @example
|
|
691
|
+
* ```ts
|
|
692
|
+
* profileOf(projectFramework(projectRoot).framework).modules.has("server-only"); // true for Next.js
|
|
693
|
+
* ```
|
|
694
|
+
*/
|
|
695
|
+
export declare function profileOf(framework: FrameworkMarker | undefined): ResolutionProfile;
|
|
696
|
+
/** The import a profile refused, and the framework whose rule refused it. */
|
|
697
|
+
interface RefusedModuleContext extends Record<string, unknown> {
|
|
698
|
+
readonly specifier: string;
|
|
699
|
+
/** The framework, as its users name it. */
|
|
700
|
+
readonly framework: string | undefined;
|
|
701
|
+
}
|
|
702
|
+
/**
|
|
703
|
+
* A module of the project imported one its framework refuses where
|
|
704
|
+
* definitions run — Next's `client-only` — so the config did not load.
|
|
705
|
+
*
|
|
706
|
+
* @example
|
|
707
|
+
* ```ts
|
|
708
|
+
* throw new RefusedModuleError("client-only", rule, nextMarker);
|
|
709
|
+
* ```
|
|
710
|
+
*/
|
|
711
|
+
export declare class RefusedModuleError extends CourierError<"MODULE_REFUSED"> {
|
|
712
|
+
readonly context: RefusedModuleContext;
|
|
713
|
+
/** Why the framework refuses it, worded to follow the import: `is the marker of …`. */
|
|
714
|
+
readonly reason: string;
|
|
715
|
+
/** What to do about it, worded as an instruction. */
|
|
716
|
+
readonly remedy: string;
|
|
717
|
+
/**
|
|
718
|
+
* @param specifier - The import, as written
|
|
719
|
+
* @param rule - Why the framework refuses it, and what to do
|
|
720
|
+
* @param framework - The framework whose rule it is
|
|
721
|
+
*/
|
|
722
|
+
constructor(specifier: string, rule: {
|
|
723
|
+
readonly reason: string;
|
|
724
|
+
readonly remedy: string;
|
|
725
|
+
}, framework: FrameworkMarker | undefined);
|
|
726
|
+
}
|
|
727
|
+
/**
|
|
728
|
+
* How long one reading of a project's config may take before it is given
|
|
729
|
+
* up, in milliseconds: a config that waits on the network, or on a timer,
|
|
730
|
+
* never ends. The routes plugin's process and `courier-cli routes` hold to
|
|
731
|
+
* it; Studio, which keeps running what it loaded last, has its own,
|
|
732
|
+
* `COURIER_CONFIG_LOAD_TIMEOUT_MS`.
|
|
733
|
+
*/
|
|
734
|
+
export declare const CONFIG_READ_LIMIT_MS = 6e4;
|
|
735
|
+
/**
|
|
736
|
+
* Where a project's transforms are kept across processes:
|
|
737
|
+
* `.cache/courier/transform` in the nearest `node_modules` directory at or
|
|
738
|
+
* above the project root.
|
|
739
|
+
*
|
|
740
|
+
* The nearest one is taken, not the one module resolution would reach: under
|
|
741
|
+
* pnpm that lies inside `.pnpm`, and what keeps the directory safe is the
|
|
742
|
+
* rule below, not where it is. Every file in it holds code that Studio, mock
|
|
743
|
+
* workers and build plugins run, so on POSIX the directory is refused when
|
|
744
|
+
* `node_modules`, `.cache`, `courier` or `transform` — those that exist — is
|
|
745
|
+
* a symbolic link or belongs to another user, and when `courier` or
|
|
746
|
+
* `transform`, which only Studio creates, is writable by its group or
|
|
747
|
+
* others; any of these lets someone else replace or remove entries, or put
|
|
748
|
+
* the directory somewhere they control. `node_modules` and `.cache` may be
|
|
749
|
+
* group-writable, as package managers leave them under a umask of 002:
|
|
750
|
+
* whoever can write `node_modules` can replace any package in it already. On
|
|
751
|
+
* Windows only links and other kinds of file are refused.
|
|
752
|
+
*
|
|
753
|
+
* There is none when no `node_modules` exists, as with Yarn Plug'n'Play, or
|
|
754
|
+
* when `COURIER_TRANSFORM_CACHE` is `0`, `false` or `off` in any case. The
|
|
755
|
+
* system temporary directory, which every user of the machine may write, is
|
|
756
|
+
* never used instead. Why there is none is logged at debug level, once for
|
|
757
|
+
* each root until the reason changes, however often the root is looked up.
|
|
758
|
+
*
|
|
759
|
+
* @param projectRoot - The directory holding `courier.config.*`
|
|
760
|
+
* @param env - The environment to read `COURIER_TRANSFORM_CACHE` from
|
|
761
|
+
* (default: `process.env`)
|
|
762
|
+
* @returns The directory, which may not exist yet, or `null` for none
|
|
763
|
+
* @example
|
|
764
|
+
* ```ts
|
|
765
|
+
* const transformCache = createTransformCache({
|
|
766
|
+
* directory: findTransformCacheDirectory(projectRoot),
|
|
767
|
+
* });
|
|
768
|
+
* ```
|
|
769
|
+
*/
|
|
770
|
+
export declare function findTransformCacheDirectory(projectRoot: string, env?: Readonly<Record<string, string | undefined>>): string | null;
|
|
771
|
+
/**
|
|
772
|
+
* The keys of a courier.config that Courier does not read, at the top and
|
|
773
|
+
* in its `studio`, `server`, `runtime` and `agents` blocks — a misspelt `studo:` say
|
|
774
|
+
* — so a load can name them rather than ignore them in silence.
|
|
775
|
+
*
|
|
776
|
+
* @param config - The config, as its module exported it
|
|
777
|
+
* @returns Each such key, dotted under its block
|
|
778
|
+
* @example
|
|
779
|
+
* ```ts
|
|
780
|
+
* unknownConfigKeys({ sources: {}, studo: {}, server: { prot: 3001 } }); // → ["studo", "server.prot"]
|
|
781
|
+
* ```
|
|
782
|
+
*/
|
|
783
|
+
export declare function unknownConfigKeys(config: unknown): string[];
|
|
784
|
+
/** Where a config that was not run lies, and the folder it was looked for from. */
|
|
785
|
+
interface UntrustedConfigContext extends Record<string, unknown> {
|
|
786
|
+
/** The config, absolute. */
|
|
787
|
+
configFile: string;
|
|
788
|
+
/** The folder the config was looked for from, below it. */
|
|
789
|
+
folder: string;
|
|
790
|
+
}
|
|
791
|
+
/**
|
|
792
|
+
* The config nearest a folder lies in a folder above it, and someone else
|
|
793
|
+
* could have put it there: it belongs to another user, or any user may
|
|
794
|
+
* write it. It was not run, as it would run with the rights of whoever
|
|
795
|
+
* builds or serves the project.
|
|
796
|
+
*
|
|
797
|
+
* @example
|
|
798
|
+
* ```ts
|
|
799
|
+
* throw new UntrustedConfigError("/tmp/courier.config.ts", "/tmp/app", "it belongs to uid 1001");
|
|
800
|
+
* ```
|
|
801
|
+
*/
|
|
802
|
+
export declare class UntrustedConfigError extends CourierError<"CONFIG_NOT_TRUSTED"> {
|
|
803
|
+
readonly context: UntrustedConfigContext;
|
|
804
|
+
/**
|
|
805
|
+
* @param configFile - The config that was not run, absolute
|
|
806
|
+
* @param folder - The folder it was looked for from
|
|
807
|
+
* @param reason - Why it is not trusted, worded to follow "and"
|
|
808
|
+
*/
|
|
809
|
+
constructor(configFile: string, folder: string, reason: string);
|
|
810
|
+
}
|
|
811
|
+
export type { ConfigJitiOptions, ConfigLoadErrorCode, ConfigLoadErrorContext, FailedLoad, FrameworkId, FrameworkMarker, ImportProjectFileOptions, ListedPackages, LoadConfigFileOptions, LoadCourierConfigOptions, LoadedCourierConfig, ModuleRule, PathAliases, ProjectFramework, RefusedModuleContext, ResolutionProfile, TransformCache, TransformCacheOptions, UntrustedConfigContext };
|