@craft-ts/deploy 0.7.0-beta.15
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 +41 -0
- package/package.json +42 -0
- package/src/index.d.ts +18 -0
- package/src/index.d.ts.map +1 -0
- package/src/index.js +10 -0
- package/src/index.js.map +1 -0
- package/src/lib/artifact.d.ts +18 -0
- package/src/lib/artifact.d.ts.map +1 -0
- package/src/lib/artifact.js +121 -0
- package/src/lib/artifact.js.map +1 -0
- package/src/lib/check.d.ts +31 -0
- package/src/lib/check.d.ts.map +1 -0
- package/src/lib/check.js +278 -0
- package/src/lib/check.js.map +1 -0
- package/src/lib/diagnostics.d.ts +38 -0
- package/src/lib/diagnostics.d.ts.map +1 -0
- package/src/lib/diagnostics.js +297 -0
- package/src/lib/diagnostics.js.map +1 -0
- package/src/lib/format.d.ts +17 -0
- package/src/lib/format.d.ts.map +1 -0
- package/src/lib/format.js +42 -0
- package/src/lib/format.js.map +1 -0
- package/src/lib/manifest.d.ts +236 -0
- package/src/lib/manifest.d.ts.map +1 -0
- package/src/lib/manifest.js +47 -0
- package/src/lib/manifest.js.map +1 -0
- package/src/lib/protocol.d.ts +22 -0
- package/src/lib/protocol.d.ts.map +1 -0
- package/src/lib/protocol.js +182 -0
- package/src/lib/protocol.js.map +1 -0
- package/src/lib/providers.d.ts +111 -0
- package/src/lib/providers.d.ts.map +1 -0
- package/src/lib/providers.js +156 -0
- package/src/lib/providers.js.map +1 -0
- package/src/lib/sources.d.ts +31 -0
- package/src/lib/sources.d.ts.map +1 -0
- package/src/lib/sources.js +155 -0
- package/src/lib/sources.js.map +1 -0
- package/src/lib/validate.d.ts +16 -0
- package/src/lib/validate.d.ts.map +1 -0
- package/src/lib/validate.js +361 -0
- package/src/lib/validate.js.map +1 -0
|
@@ -0,0 +1,361 @@
|
|
|
1
|
+
import { CRAFT_DEPLOYMENT_PLATFORMS, CRAFT_DEPLOYMENT_RUNTIMES, CRAFT_SOURCE_MAP_POLICIES, CRAFT_STATIC_MODES, } from './manifest.js';
|
|
2
|
+
import { isRuntimeSupportedByPlatform } from './providers.js';
|
|
3
|
+
const ENV_NAME = /^[A-Z][A-Z0-9_]*$/;
|
|
4
|
+
/** A route is pre-renderable only when it maps to exactly one document. */
|
|
5
|
+
const STATIC_ROUTE = /^\/[^\s:*?#]*$/;
|
|
6
|
+
const SECTION_BY_RUNTIME = Object.freeze({
|
|
7
|
+
static: ['static', 'client'],
|
|
8
|
+
node: ['server'],
|
|
9
|
+
worker: ['worker'],
|
|
10
|
+
lambda: ['lambda'],
|
|
11
|
+
});
|
|
12
|
+
const RUNTIME_SECTIONS = ['static', 'server', 'worker', 'lambda'];
|
|
13
|
+
const isRecord = (value) => typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
14
|
+
const isNonEmptyString = (value) => typeof value === 'string' && value.trim().length > 0;
|
|
15
|
+
/**
|
|
16
|
+
* Validates the structure and the pure semantics of a deployment manifest.
|
|
17
|
+
*
|
|
18
|
+
* Everything checked here is decidable without touching the filesystem, so the
|
|
19
|
+
* same function guards a hand-written `craft.deploy.ts`, a manifest parsed
|
|
20
|
+
* from JSON and a manifest received by a provider.
|
|
21
|
+
*/
|
|
22
|
+
export function validateCraftDeploymentDefinition(value) {
|
|
23
|
+
const diagnostics = [];
|
|
24
|
+
const report = (diagnostic) => {
|
|
25
|
+
diagnostics.push({ severity: 'error', ...diagnostic });
|
|
26
|
+
};
|
|
27
|
+
if (!isRecord(value)) {
|
|
28
|
+
report({
|
|
29
|
+
code: 'CRAFT_DEPLOY_MANIFEST_NOT_AN_OBJECT',
|
|
30
|
+
message: `The manifest is a ${describe(value)} instead of an object.`,
|
|
31
|
+
fix: 'Export the object returned by `defineCraftDeployment`.',
|
|
32
|
+
});
|
|
33
|
+
return { definition: null, diagnostics };
|
|
34
|
+
}
|
|
35
|
+
let structural = true;
|
|
36
|
+
const missing = (path, expected) => {
|
|
37
|
+
structural = false;
|
|
38
|
+
report({
|
|
39
|
+
code: 'CRAFT_DEPLOY_MANIFEST_MISSING_FIELD',
|
|
40
|
+
path,
|
|
41
|
+
message: `\`${path}\` is missing.`,
|
|
42
|
+
fix: expected,
|
|
43
|
+
});
|
|
44
|
+
};
|
|
45
|
+
const invalid = (path, expected, severity = 'error') => {
|
|
46
|
+
if (severity === 'error')
|
|
47
|
+
structural = false;
|
|
48
|
+
report({
|
|
49
|
+
code: 'CRAFT_DEPLOY_MANIFEST_INVALID_FIELD',
|
|
50
|
+
path,
|
|
51
|
+
severity,
|
|
52
|
+
message: `\`${path}\` is invalid.`,
|
|
53
|
+
fix: expected,
|
|
54
|
+
});
|
|
55
|
+
};
|
|
56
|
+
if (!isNonEmptyString(value['name'])) {
|
|
57
|
+
missing('name', 'Give the deployment a non-empty name.');
|
|
58
|
+
}
|
|
59
|
+
if (value['environment'] !== undefined &&
|
|
60
|
+
!isNonEmptyString(value['environment'])) {
|
|
61
|
+
invalid('environment', 'Use a non-empty string such as `production`.');
|
|
62
|
+
}
|
|
63
|
+
const runtime = value['runtime'];
|
|
64
|
+
const knownRuntime = CRAFT_DEPLOYMENT_RUNTIMES.includes(runtime);
|
|
65
|
+
if (!knownRuntime) {
|
|
66
|
+
structural = false;
|
|
67
|
+
report({
|
|
68
|
+
code: 'CRAFT_DEPLOY_MANIFEST_UNKNOWN_RUNTIME',
|
|
69
|
+
path: 'runtime',
|
|
70
|
+
message: `\`runtime\` is ${describe(runtime)}.`,
|
|
71
|
+
fix: `Use one of ${CRAFT_DEPLOYMENT_RUNTIMES.join(', ')}.`,
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
const platform = value['platform'];
|
|
75
|
+
const knownPlatform = CRAFT_DEPLOYMENT_PLATFORMS.includes(platform);
|
|
76
|
+
if (!knownPlatform) {
|
|
77
|
+
structural = false;
|
|
78
|
+
report({
|
|
79
|
+
code: 'CRAFT_DEPLOY_MANIFEST_UNKNOWN_PLATFORM',
|
|
80
|
+
path: 'platform',
|
|
81
|
+
message: `\`platform\` is ${describe(platform)}.`,
|
|
82
|
+
fix: `Use one of ${CRAFT_DEPLOYMENT_PLATFORMS.join(', ')}.`,
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
if (knownRuntime) {
|
|
86
|
+
const typedRuntime = runtime;
|
|
87
|
+
for (const section of SECTION_BY_RUNTIME[typedRuntime]) {
|
|
88
|
+
if (!isRecord(value[section])) {
|
|
89
|
+
structural = false;
|
|
90
|
+
report({
|
|
91
|
+
code: 'CRAFT_DEPLOY_MANIFEST_SECTION_MISSING',
|
|
92
|
+
path: section,
|
|
93
|
+
runtime: typedRuntime,
|
|
94
|
+
message: `The \`${typedRuntime}\` runtime requires a \`${section}\` section.`,
|
|
95
|
+
fix: `Add \`${section}\` to the manifest.`,
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
for (const section of RUNTIME_SECTIONS) {
|
|
100
|
+
if (value[section] !== undefined &&
|
|
101
|
+
!SECTION_BY_RUNTIME[typedRuntime].includes(section)) {
|
|
102
|
+
report({
|
|
103
|
+
code: 'CRAFT_DEPLOY_MANIFEST_SECTION_UNEXPECTED',
|
|
104
|
+
path: section,
|
|
105
|
+
runtime: typedRuntime,
|
|
106
|
+
message: `\`${section}\` does not belong to the \`${typedRuntime}\` runtime.`,
|
|
107
|
+
fix: `Remove \`${section}\`, or switch the runtime to the one that uses it.`,
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
const client = value['client'];
|
|
113
|
+
if (client !== undefined) {
|
|
114
|
+
if (!isRecord(client)) {
|
|
115
|
+
invalid('client', 'Use an object with `build` and `outDir`.');
|
|
116
|
+
}
|
|
117
|
+
else {
|
|
118
|
+
if (!isNonEmptyString(client['build'])) {
|
|
119
|
+
missing('client.build', 'Declare the command building the client.');
|
|
120
|
+
}
|
|
121
|
+
if (!isNonEmptyString(client['outDir'])) {
|
|
122
|
+
missing('client.outDir', 'Declare the directory that command writes to.');
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
const staticSection = value['static'];
|
|
127
|
+
if (isRecord(staticSection)) {
|
|
128
|
+
const mode = staticSection['mode'];
|
|
129
|
+
if (!CRAFT_STATIC_MODES.includes(mode)) {
|
|
130
|
+
structural = false;
|
|
131
|
+
invalid('static.mode', `Use one of ${CRAFT_STATIC_MODES.join(', ')}.`);
|
|
132
|
+
}
|
|
133
|
+
if (staticSection['fallback'] !== undefined &&
|
|
134
|
+
!isNonEmptyString(staticSection['fallback'])) {
|
|
135
|
+
invalid('static.fallback', 'Use a document name such as `index.html`.');
|
|
136
|
+
}
|
|
137
|
+
const routes = staticSection['routes'];
|
|
138
|
+
if (routes !== undefined && !isStringArray(routes)) {
|
|
139
|
+
invalid('static.routes', 'Use an array of absolute route paths.');
|
|
140
|
+
}
|
|
141
|
+
else if (mode === 'ssg') {
|
|
142
|
+
const list = (routes ?? []);
|
|
143
|
+
if (list.length === 0) {
|
|
144
|
+
report({
|
|
145
|
+
code: 'CRAFT_DEPLOY_SSG_ROUTES_MISSING',
|
|
146
|
+
path: 'static.routes',
|
|
147
|
+
runtime: 'static',
|
|
148
|
+
message: 'The `ssg` mode declares no route to pre-render.',
|
|
149
|
+
fix: 'List the routes in `static.routes`, or switch the mode to `spa`.',
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
for (const [index, route] of list.entries()) {
|
|
153
|
+
if (!STATIC_ROUTE.test(route)) {
|
|
154
|
+
report({
|
|
155
|
+
code: 'CRAFT_DEPLOY_SSG_ROUTE_NOT_STATIC',
|
|
156
|
+
path: `static.routes[${index}]`,
|
|
157
|
+
runtime: 'static',
|
|
158
|
+
message: `\`${route}\` does not designate a single document.`,
|
|
159
|
+
fix: 'Expand the route into literal paths, or move it to `static.serverRoutes`.',
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
if (staticSection['serverRoutes'] !== undefined &&
|
|
165
|
+
!isStringArray(staticSection['serverRoutes'])) {
|
|
166
|
+
invalid('static.serverRoutes', 'Use an array of route paths that need a server runtime.');
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
const server = value['server'];
|
|
170
|
+
if (isRecord(server)) {
|
|
171
|
+
if (!isNonEmptyString(server['entry'])) {
|
|
172
|
+
missing('server.entry', 'Declare the SSR entry produced by the build.');
|
|
173
|
+
}
|
|
174
|
+
for (const key of ['healthPath', 'readyPath']) {
|
|
175
|
+
const path = server[key];
|
|
176
|
+
if (!isNonEmptyString(path)) {
|
|
177
|
+
missing(`server.${key}`, 'Declare an absolute HTTP path.');
|
|
178
|
+
}
|
|
179
|
+
else if (!path.startsWith('/')) {
|
|
180
|
+
invalid(`server.${key}`, 'Start the path with `/`.');
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
for (const key of ['build', 'start']) {
|
|
184
|
+
if (server[key] !== undefined && !isNonEmptyString(server[key])) {
|
|
185
|
+
invalid(`server.${key}`, 'Use a non-empty command.');
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
if (server['source'] !== undefined && !isNonEmptyString(server['source'])) {
|
|
189
|
+
invalid('server.source', 'Use the path of the module producing `entry`.');
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
const worker = value['worker'];
|
|
193
|
+
if (isRecord(worker)) {
|
|
194
|
+
if (!isNonEmptyString(worker['entry'])) {
|
|
195
|
+
missing('worker.entry', 'Declare the module exporting `fetch(request, env, ctx)`.');
|
|
196
|
+
}
|
|
197
|
+
if (worker['source'] !== undefined && !isNonEmptyString(worker['source'])) {
|
|
198
|
+
invalid('worker.source', 'Use the path of the module producing `entry`.');
|
|
199
|
+
}
|
|
200
|
+
const bindings = worker['bindings'];
|
|
201
|
+
if (bindings !== undefined) {
|
|
202
|
+
if (!Array.isArray(bindings)) {
|
|
203
|
+
invalid('worker.bindings', 'Use an array of `{ name, type }`.');
|
|
204
|
+
}
|
|
205
|
+
else {
|
|
206
|
+
for (const [index, binding] of bindings.entries()) {
|
|
207
|
+
if (!isRecord(binding) ||
|
|
208
|
+
!isNonEmptyString(binding['name']) ||
|
|
209
|
+
!isNonEmptyString(binding['type'])) {
|
|
210
|
+
invalid(`worker.bindings[${index}]`, 'Use `{ name, type }` with non-empty strings.');
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
const lambda = value['lambda'];
|
|
217
|
+
if (isRecord(lambda)) {
|
|
218
|
+
if (!isNonEmptyString(lambda['entry'])) {
|
|
219
|
+
missing('lambda.entry', 'Declare the Function URL handler module.');
|
|
220
|
+
}
|
|
221
|
+
if (lambda['source'] !== undefined && !isNonEmptyString(lambda['source'])) {
|
|
222
|
+
invalid('lambda.source', 'Use the path of the module producing `entry`.');
|
|
223
|
+
}
|
|
224
|
+
if (lambda['permissions'] !== undefined &&
|
|
225
|
+
!isStringArray(lambda['permissions'])) {
|
|
226
|
+
invalid('lambda.permissions', 'Use an array of permission identifiers.');
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
const functions = value['functions'];
|
|
230
|
+
if (functions !== undefined) {
|
|
231
|
+
if (!isRecord(functions)) {
|
|
232
|
+
invalid('functions', 'Use an object with an `entry`.');
|
|
233
|
+
}
|
|
234
|
+
else {
|
|
235
|
+
if (!isNonEmptyString(functions['entry'])) {
|
|
236
|
+
missing('functions.entry', 'Declare the module building the server-function registry.');
|
|
237
|
+
}
|
|
238
|
+
const basePath = functions['basePath'];
|
|
239
|
+
if (basePath !== undefined) {
|
|
240
|
+
if (!isNonEmptyString(basePath)) {
|
|
241
|
+
invalid('functions.basePath', 'Use an absolute HTTP path.');
|
|
242
|
+
}
|
|
243
|
+
else if (!basePath.startsWith('/')) {
|
|
244
|
+
invalid('functions.basePath', 'Start the path with `/`.');
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
const ids = functions['ids'];
|
|
248
|
+
if (ids !== undefined && !isStringArray(ids)) {
|
|
249
|
+
invalid('functions.ids', 'Use an array of identifiers.');
|
|
250
|
+
}
|
|
251
|
+
else {
|
|
252
|
+
const seen = new Set();
|
|
253
|
+
for (const [index, id] of (ids ?? []).entries()) {
|
|
254
|
+
if (seen.has(id)) {
|
|
255
|
+
report({
|
|
256
|
+
code: 'CRAFT_DEPLOY_FUNCTION_ID_DUPLICATE',
|
|
257
|
+
path: `functions.ids[${index}]`,
|
|
258
|
+
message: `The server-function identifier \`${id}\` is declared twice.`,
|
|
259
|
+
fix: 'Keep one declaration per identifier.',
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
seen.add(id);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
const env = value['env'];
|
|
268
|
+
if (env !== undefined) {
|
|
269
|
+
if (!Array.isArray(env)) {
|
|
270
|
+
invalid('env', 'Use an array of `{ name, required }`.');
|
|
271
|
+
}
|
|
272
|
+
else {
|
|
273
|
+
for (const [index, variable] of env.entries()) {
|
|
274
|
+
const path = `env[${index}]`;
|
|
275
|
+
if (!isRecord(variable)) {
|
|
276
|
+
invalid(path, 'Use `{ name, required }`.');
|
|
277
|
+
continue;
|
|
278
|
+
}
|
|
279
|
+
const name = variable['name'];
|
|
280
|
+
if (!isNonEmptyString(name)) {
|
|
281
|
+
missing(`${path}.name`, 'Declare the variable name.');
|
|
282
|
+
}
|
|
283
|
+
else if (!ENV_NAME.test(name)) {
|
|
284
|
+
report({
|
|
285
|
+
code: 'CRAFT_DEPLOY_ENV_NAME_INVALID',
|
|
286
|
+
path: `${path}.name`,
|
|
287
|
+
message: `\`${name}\` is not an upper snake case identifier.`,
|
|
288
|
+
fix: 'Rename the variable to `UPPER_SNAKE_CASE`.',
|
|
289
|
+
});
|
|
290
|
+
}
|
|
291
|
+
if (typeof variable['required'] !== 'boolean') {
|
|
292
|
+
missing(`${path}.required`, 'State whether the deployment fails without it.');
|
|
293
|
+
}
|
|
294
|
+
for (const forbidden of ['value', 'default']) {
|
|
295
|
+
if (variable[forbidden] !== undefined) {
|
|
296
|
+
report({
|
|
297
|
+
code: 'CRAFT_DEPLOY_ENV_VALUE_FORBIDDEN',
|
|
298
|
+
path: `${path}.${forbidden}`,
|
|
299
|
+
message: `\`${path}\` carries a \`${forbidden}\`, and the manifest is committed.`,
|
|
300
|
+
fix: 'Remove it and provide the value through the CI or the provider secret store.',
|
|
301
|
+
});
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
const artifact = value['artifact'];
|
|
308
|
+
if (artifact !== undefined) {
|
|
309
|
+
if (!isRecord(artifact)) {
|
|
310
|
+
invalid('artifact', 'Use an object describing the produced artefact.');
|
|
311
|
+
}
|
|
312
|
+
else {
|
|
313
|
+
for (const key of ['publicDir', 'serverEntry', 'start']) {
|
|
314
|
+
if (artifact[key] !== undefined && !isNonEmptyString(artifact[key])) {
|
|
315
|
+
invalid(`artifact.${key}`, 'Use a non-empty string.');
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
if (artifact['configFiles'] !== undefined &&
|
|
319
|
+
!isStringArray(artifact['configFiles'])) {
|
|
320
|
+
invalid('artifact.configFiles', 'Use an array of file paths.');
|
|
321
|
+
}
|
|
322
|
+
if (artifact['sourceMaps'] !== undefined &&
|
|
323
|
+
!CRAFT_SOURCE_MAP_POLICIES.includes(artifact['sourceMaps'])) {
|
|
324
|
+
invalid('artifact.sourceMaps', `Use one of ${CRAFT_SOURCE_MAP_POLICIES.join(', ')}.`);
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
if (knownRuntime && knownPlatform) {
|
|
329
|
+
const typedRuntime = runtime;
|
|
330
|
+
const typedPlatform = platform;
|
|
331
|
+
if (!isRuntimeSupportedByPlatform(typedRuntime, typedPlatform)) {
|
|
332
|
+
report({
|
|
333
|
+
code: 'CRAFT_DEPLOY_RUNTIME_PLATFORM_INCOMPATIBLE',
|
|
334
|
+
path: 'platform',
|
|
335
|
+
runtime: typedRuntime,
|
|
336
|
+
platform: typedPlatform,
|
|
337
|
+
message: `\`${typedPlatform}\` cannot execute the \`${typedRuntime}\` runtime.`,
|
|
338
|
+
fix: 'Change the runtime or the platform; see the compatibility matrix.',
|
|
339
|
+
});
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
return {
|
|
343
|
+
definition: structural
|
|
344
|
+
? value
|
|
345
|
+
: null,
|
|
346
|
+
diagnostics,
|
|
347
|
+
};
|
|
348
|
+
}
|
|
349
|
+
function isStringArray(value) {
|
|
350
|
+
return Array.isArray(value) && value.every((item) => isNonEmptyString(item));
|
|
351
|
+
}
|
|
352
|
+
function describe(value) {
|
|
353
|
+
if (value === null)
|
|
354
|
+
return 'null';
|
|
355
|
+
if (Array.isArray(value))
|
|
356
|
+
return 'an array';
|
|
357
|
+
if (typeof value === 'string')
|
|
358
|
+
return `\`${value}\``;
|
|
359
|
+
return `a ${typeof value}`;
|
|
360
|
+
}
|
|
361
|
+
//# sourceMappingURL=validate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validate.js","sourceRoot":"","sources":["../../../../../libs/deploy/src/lib/validate.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n CraftDeploymentDiagnostic,\n CraftDeploymentSeverity,\n} from './diagnostics.js';\nimport {\n CRAFT_DEPLOYMENT_PLATFORMS,\n CRAFT_DEPLOYMENT_RUNTIMES,\n CRAFT_SOURCE_MAP_POLICIES,\n CRAFT_STATIC_MODES,\n type CraftDeploymentDefinition,\n type CraftDeploymentPlatform,\n type CraftDeploymentRuntime,\n} from './manifest.js';\nimport { isRuntimeSupportedByPlatform } from './providers.js';\n\nexport type CraftDeploymentValidation = Readonly<{\n /** `null` when a structural error makes the manifest unusable. */\n definition: CraftDeploymentDefinition | null;\n diagnostics: readonly CraftDeploymentDiagnostic[];\n}>;\n\nconst ENV_NAME = /^[A-Z][A-Z0-9_]*$/;\n/** A route is pre-renderable only when it maps to exactly one document. */\nconst STATIC_ROUTE = /^\\/[^\\s:*?#]*$/;\n\nconst SECTION_BY_RUNTIME: Readonly<\n Record<CraftDeploymentRuntime, readonly string[]>\n> = Object.freeze({\n static: ['static', 'client'],\n node: ['server'],\n worker: ['worker'],\n lambda: ['lambda'],\n});\n\nconst RUNTIME_SECTIONS = ['static', 'server', 'worker', 'lambda'] as const;\n\ntype Record_ = Record<string, unknown>;\n\nconst isRecord = (value: unknown): value is Record_ =>\n typeof value === 'object' && value !== null && !Array.isArray(value);\n\nconst isNonEmptyString = (value: unknown): value is string =>\n typeof value === 'string' && value.trim().length > 0;\n\n/**\n * Validates the structure and the pure semantics of a deployment manifest.\n *\n * Everything checked here is decidable without touching the filesystem, so the\n * same function guards a hand-written `craft.deploy.ts`, a manifest parsed\n * from JSON and a manifest received by a provider.\n */\nexport function validateCraftDeploymentDefinition(\n value: unknown,\n): CraftDeploymentValidation {\n const diagnostics: CraftDeploymentDiagnostic[] = [];\n const report = (\n diagnostic: Omit<CraftDeploymentDiagnostic, 'severity'> &\n Partial<Pick<CraftDeploymentDiagnostic, 'severity'>>,\n ) => {\n diagnostics.push({ severity: 'error', ...diagnostic });\n };\n\n if (!isRecord(value)) {\n report({\n code: 'CRAFT_DEPLOY_MANIFEST_NOT_AN_OBJECT',\n message: `The manifest is a ${describe(value)} instead of an object.`,\n fix: 'Export the object returned by `defineCraftDeployment`.',\n });\n return { definition: null, diagnostics };\n }\n\n let structural = true;\n const missing = (path: string, expected: string) => {\n structural = false;\n report({\n code: 'CRAFT_DEPLOY_MANIFEST_MISSING_FIELD',\n path,\n message: `\\`${path}\\` is missing.`,\n fix: expected,\n });\n };\n const invalid = (\n path: string,\n expected: string,\n severity: CraftDeploymentSeverity = 'error',\n ) => {\n if (severity === 'error') structural = false;\n report({\n code: 'CRAFT_DEPLOY_MANIFEST_INVALID_FIELD',\n path,\n severity,\n message: `\\`${path}\\` is invalid.`,\n fix: expected,\n });\n };\n\n if (!isNonEmptyString(value['name'])) {\n missing('name', 'Give the deployment a non-empty name.');\n }\n if (\n value['environment'] !== undefined &&\n !isNonEmptyString(value['environment'])\n ) {\n invalid('environment', 'Use a non-empty string such as `production`.');\n }\n\n const runtime = value['runtime'];\n const knownRuntime = CRAFT_DEPLOYMENT_RUNTIMES.includes(\n runtime as CraftDeploymentRuntime,\n );\n if (!knownRuntime) {\n structural = false;\n report({\n code: 'CRAFT_DEPLOY_MANIFEST_UNKNOWN_RUNTIME',\n path: 'runtime',\n message: `\\`runtime\\` is ${describe(runtime)}.`,\n fix: `Use one of ${CRAFT_DEPLOYMENT_RUNTIMES.join(', ')}.`,\n });\n }\n\n const platform = value['platform'];\n const knownPlatform = CRAFT_DEPLOYMENT_PLATFORMS.includes(\n platform as CraftDeploymentPlatform,\n );\n if (!knownPlatform) {\n structural = false;\n report({\n code: 'CRAFT_DEPLOY_MANIFEST_UNKNOWN_PLATFORM',\n path: 'platform',\n message: `\\`platform\\` is ${describe(platform)}.`,\n fix: `Use one of ${CRAFT_DEPLOYMENT_PLATFORMS.join(', ')}.`,\n });\n }\n\n if (knownRuntime) {\n const typedRuntime = runtime as CraftDeploymentRuntime;\n for (const section of SECTION_BY_RUNTIME[typedRuntime]) {\n if (!isRecord(value[section])) {\n structural = false;\n report({\n code: 'CRAFT_DEPLOY_MANIFEST_SECTION_MISSING',\n path: section,\n runtime: typedRuntime,\n message: `The \\`${typedRuntime}\\` runtime requires a \\`${section}\\` section.`,\n fix: `Add \\`${section}\\` to the manifest.`,\n });\n }\n }\n for (const section of RUNTIME_SECTIONS) {\n if (\n value[section] !== undefined &&\n !SECTION_BY_RUNTIME[typedRuntime].includes(section)\n ) {\n report({\n code: 'CRAFT_DEPLOY_MANIFEST_SECTION_UNEXPECTED',\n path: section,\n runtime: typedRuntime,\n message: `\\`${section}\\` does not belong to the \\`${typedRuntime}\\` runtime.`,\n fix: `Remove \\`${section}\\`, or switch the runtime to the one that uses it.`,\n });\n }\n }\n }\n\n const client = value['client'];\n if (client !== undefined) {\n if (!isRecord(client)) {\n invalid('client', 'Use an object with `build` and `outDir`.');\n } else {\n if (!isNonEmptyString(client['build'])) {\n missing('client.build', 'Declare the command building the client.');\n }\n if (!isNonEmptyString(client['outDir'])) {\n missing(\n 'client.outDir',\n 'Declare the directory that command writes to.',\n );\n }\n }\n }\n\n const staticSection = value['static'];\n if (isRecord(staticSection)) {\n const mode = staticSection['mode'];\n if (!CRAFT_STATIC_MODES.includes(mode as never)) {\n structural = false;\n invalid('static.mode', `Use one of ${CRAFT_STATIC_MODES.join(', ')}.`);\n }\n if (\n staticSection['fallback'] !== undefined &&\n !isNonEmptyString(staticSection['fallback'])\n ) {\n invalid('static.fallback', 'Use a document name such as `index.html`.');\n }\n const routes = staticSection['routes'];\n if (routes !== undefined && !isStringArray(routes)) {\n invalid('static.routes', 'Use an array of absolute route paths.');\n } else if (mode === 'ssg') {\n const list = (routes ?? []) as readonly string[];\n if (list.length === 0) {\n report({\n code: 'CRAFT_DEPLOY_SSG_ROUTES_MISSING',\n path: 'static.routes',\n runtime: 'static',\n message: 'The `ssg` mode declares no route to pre-render.',\n fix: 'List the routes in `static.routes`, or switch the mode to `spa`.',\n });\n }\n for (const [index, route] of list.entries()) {\n if (!STATIC_ROUTE.test(route)) {\n report({\n code: 'CRAFT_DEPLOY_SSG_ROUTE_NOT_STATIC',\n path: `static.routes[${index}]`,\n runtime: 'static',\n message: `\\`${route}\\` does not designate a single document.`,\n fix: 'Expand the route into literal paths, or move it to `static.serverRoutes`.',\n });\n }\n }\n }\n if (\n staticSection['serverRoutes'] !== undefined &&\n !isStringArray(staticSection['serverRoutes'])\n ) {\n invalid(\n 'static.serverRoutes',\n 'Use an array of route paths that need a server runtime.',\n );\n }\n }\n\n const server = value['server'];\n if (isRecord(server)) {\n if (!isNonEmptyString(server['entry'])) {\n missing('server.entry', 'Declare the SSR entry produced by the build.');\n }\n for (const key of ['healthPath', 'readyPath'] as const) {\n const path = server[key];\n if (!isNonEmptyString(path)) {\n missing(`server.${key}`, 'Declare an absolute HTTP path.');\n } else if (!path.startsWith('/')) {\n invalid(`server.${key}`, 'Start the path with `/`.');\n }\n }\n for (const key of ['build', 'start'] as const) {\n if (server[key] !== undefined && !isNonEmptyString(server[key])) {\n invalid(`server.${key}`, 'Use a non-empty command.');\n }\n }\n if (server['source'] !== undefined && !isNonEmptyString(server['source'])) {\n invalid('server.source', 'Use the path of the module producing `entry`.');\n }\n }\n\n const worker = value['worker'];\n if (isRecord(worker)) {\n if (!isNonEmptyString(worker['entry'])) {\n missing(\n 'worker.entry',\n 'Declare the module exporting `fetch(request, env, ctx)`.',\n );\n }\n if (worker['source'] !== undefined && !isNonEmptyString(worker['source'])) {\n invalid('worker.source', 'Use the path of the module producing `entry`.');\n }\n const bindings = worker['bindings'];\n if (bindings !== undefined) {\n if (!Array.isArray(bindings)) {\n invalid('worker.bindings', 'Use an array of `{ name, type }`.');\n } else {\n for (const [index, binding] of bindings.entries()) {\n if (\n !isRecord(binding) ||\n !isNonEmptyString(binding['name']) ||\n !isNonEmptyString(binding['type'])\n ) {\n invalid(\n `worker.bindings[${index}]`,\n 'Use `{ name, type }` with non-empty strings.',\n );\n }\n }\n }\n }\n }\n\n const lambda = value['lambda'];\n if (isRecord(lambda)) {\n if (!isNonEmptyString(lambda['entry'])) {\n missing('lambda.entry', 'Declare the Function URL handler module.');\n }\n if (lambda['source'] !== undefined && !isNonEmptyString(lambda['source'])) {\n invalid('lambda.source', 'Use the path of the module producing `entry`.');\n }\n if (\n lambda['permissions'] !== undefined &&\n !isStringArray(lambda['permissions'])\n ) {\n invalid('lambda.permissions', 'Use an array of permission identifiers.');\n }\n }\n\n const functions = value['functions'];\n if (functions !== undefined) {\n if (!isRecord(functions)) {\n invalid('functions', 'Use an object with an `entry`.');\n } else {\n if (!isNonEmptyString(functions['entry'])) {\n missing(\n 'functions.entry',\n 'Declare the module building the server-function registry.',\n );\n }\n const basePath = functions['basePath'];\n if (basePath !== undefined) {\n if (!isNonEmptyString(basePath)) {\n invalid('functions.basePath', 'Use an absolute HTTP path.');\n } else if (!basePath.startsWith('/')) {\n invalid('functions.basePath', 'Start the path with `/`.');\n }\n }\n const ids = functions['ids'];\n if (ids !== undefined && !isStringArray(ids)) {\n invalid('functions.ids', 'Use an array of identifiers.');\n } else {\n const seen = new Set<string>();\n for (const [index, id] of (\n (ids ?? []) as readonly string[]\n ).entries()) {\n if (seen.has(id)) {\n report({\n code: 'CRAFT_DEPLOY_FUNCTION_ID_DUPLICATE',\n path: `functions.ids[${index}]`,\n message: `The server-function identifier \\`${id}\\` is declared twice.`,\n fix: 'Keep one declaration per identifier.',\n });\n }\n seen.add(id);\n }\n }\n }\n }\n\n const env = value['env'];\n if (env !== undefined) {\n if (!Array.isArray(env)) {\n invalid('env', 'Use an array of `{ name, required }`.');\n } else {\n for (const [index, variable] of env.entries()) {\n const path = `env[${index}]`;\n if (!isRecord(variable)) {\n invalid(path, 'Use `{ name, required }`.');\n continue;\n }\n const name = variable['name'];\n if (!isNonEmptyString(name)) {\n missing(`${path}.name`, 'Declare the variable name.');\n } else if (!ENV_NAME.test(name)) {\n report({\n code: 'CRAFT_DEPLOY_ENV_NAME_INVALID',\n path: `${path}.name`,\n message: `\\`${name}\\` is not an upper snake case identifier.`,\n fix: 'Rename the variable to `UPPER_SNAKE_CASE`.',\n });\n }\n if (typeof variable['required'] !== 'boolean') {\n missing(\n `${path}.required`,\n 'State whether the deployment fails without it.',\n );\n }\n for (const forbidden of ['value', 'default'] as const) {\n if (variable[forbidden] !== undefined) {\n report({\n code: 'CRAFT_DEPLOY_ENV_VALUE_FORBIDDEN',\n path: `${path}.${forbidden}`,\n message: `\\`${path}\\` carries a \\`${forbidden}\\`, and the manifest is committed.`,\n fix: 'Remove it and provide the value through the CI or the provider secret store.',\n });\n }\n }\n }\n }\n }\n\n const artifact = value['artifact'];\n if (artifact !== undefined) {\n if (!isRecord(artifact)) {\n invalid('artifact', 'Use an object describing the produced artefact.');\n } else {\n for (const key of ['publicDir', 'serverEntry', 'start'] as const) {\n if (artifact[key] !== undefined && !isNonEmptyString(artifact[key])) {\n invalid(`artifact.${key}`, 'Use a non-empty string.');\n }\n }\n if (\n artifact['configFiles'] !== undefined &&\n !isStringArray(artifact['configFiles'])\n ) {\n invalid('artifact.configFiles', 'Use an array of file paths.');\n }\n if (\n artifact['sourceMaps'] !== undefined &&\n !CRAFT_SOURCE_MAP_POLICIES.includes(artifact['sourceMaps'] as never)\n ) {\n invalid(\n 'artifact.sourceMaps',\n `Use one of ${CRAFT_SOURCE_MAP_POLICIES.join(', ')}.`,\n );\n }\n }\n }\n\n if (knownRuntime && knownPlatform) {\n const typedRuntime = runtime as CraftDeploymentRuntime;\n const typedPlatform = platform as CraftDeploymentPlatform;\n if (!isRuntimeSupportedByPlatform(typedRuntime, typedPlatform)) {\n report({\n code: 'CRAFT_DEPLOY_RUNTIME_PLATFORM_INCOMPATIBLE',\n path: 'platform',\n runtime: typedRuntime,\n platform: typedPlatform,\n message: `\\`${typedPlatform}\\` cannot execute the \\`${typedRuntime}\\` runtime.`,\n fix: 'Change the runtime or the platform; see the compatibility matrix.',\n });\n }\n }\n\n return {\n definition: structural\n ? (value as unknown as CraftDeploymentDefinition)\n : null,\n diagnostics,\n };\n}\n\nfunction isStringArray(value: unknown): value is readonly string[] {\n return Array.isArray(value) && value.every((item) => isNonEmptyString(item));\n}\n\nfunction describe(value: unknown): string {\n if (value === null) return 'null';\n if (Array.isArray(value)) return 'an array';\n if (typeof value === 'string') return `\\`${value}\\``;\n return `a ${typeof value}`;\n}\n"]}
|