@sveltejs/kit 3.0.0-next.10 → 3.0.0-next.11
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/package.json +1 -1
- package/src/constants.js +2 -0
- package/src/core/adapt/builder.js +3 -6
- package/src/core/config/index.js +6 -1
- package/src/core/config/options.js +11 -69
- package/src/core/postbuild/fallback.js +2 -1
- package/src/core/postbuild/prerender.js +75 -28
- package/src/core/postbuild/queue.js +2 -1
- package/src/core/sync/write_server.js +2 -2
- package/src/core/utils.js +28 -3
- package/src/exports/env/index.js +68 -3
- package/src/exports/internal/env.js +6 -3
- package/src/exports/params.js +9 -4
- package/src/exports/public.d.ts +41 -20
- package/src/exports/vite/dev/index.js +50 -6
- package/src/exports/vite/index.js +130 -125
- package/src/exports/vite/module_ids.js +0 -2
- package/src/exports/vite/preview/index.js +3 -2
- package/src/exports/vite/utils.js +20 -0
- package/src/runtime/app/paths/server.js +1 -1
- package/src/runtime/app/server/index.js +1 -1
- package/src/runtime/app/server/remote/query.js +1 -1
- package/src/runtime/client/ndjson.js +1 -1
- package/src/runtime/client/stream.js +3 -2
- package/src/runtime/server/data/index.js +1 -1
- package/src/runtime/server/errors.js +135 -0
- package/src/runtime/server/fetch.js +1 -1
- package/src/runtime/server/index.js +20 -10
- package/src/runtime/server/internal.js +25 -0
- package/src/runtime/server/page/actions.js +2 -1
- package/src/runtime/server/page/data_serializer.js +10 -10
- package/src/runtime/server/page/index.js +3 -2
- package/src/runtime/server/page/load_data.js +1 -1
- package/src/runtime/server/page/render.js +3 -7
- package/src/runtime/server/page/respond_with_error.js +6 -5
- package/src/runtime/server/{remote.js → remote-functions.js} +1 -1
- package/src/runtime/server/respond.js +3 -7
- package/src/runtime/server/sourcemaps.js +183 -0
- package/src/runtime/server/utils.js +2 -157
- package/src/types/ambient-private.d.ts +2 -0
- package/src/types/global-private.d.ts +0 -5
- package/src/types/internal.d.ts +6 -6
- package/src/types/private.d.ts +8 -0
- package/src/utils/escape.js +9 -25
- package/src/utils/features.js +1 -1
- package/src/utils/fork.js +7 -2
- package/src/utils/page_nodes.js +3 -5
- package/src/version.js +1 -1
- package/types/index.d.ts +72 -22
- package/types/index.d.ts.map +3 -1
- package/src/runtime/shared-server.js +0 -7
package/package.json
CHANGED
package/src/constants.js
CHANGED
|
@@ -8,7 +8,7 @@ import * as devalue from 'devalue';
|
|
|
8
8
|
import { createReadStream, createWriteStream, existsSync, statSync } from 'node:fs';
|
|
9
9
|
import { extname, resolve, join, dirname, relative } from 'node:path';
|
|
10
10
|
import { pipeline } from 'node:stream';
|
|
11
|
-
import { promisify
|
|
11
|
+
import { promisify } from 'node:util';
|
|
12
12
|
import zlib from 'node:zlib';
|
|
13
13
|
import { copy, rimraf, mkdirp } from '../../utils/filesystem.js';
|
|
14
14
|
import { posixify } from '../../utils/os.js';
|
|
@@ -142,11 +142,8 @@ export function create_builder({
|
|
|
142
142
|
});
|
|
143
143
|
|
|
144
144
|
if (existsSync(dest)) {
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
['bold', 'yellow'],
|
|
148
|
-
`Overwriting ${dest} with fallback page. Consider using a different name for the fallback.`
|
|
149
|
-
)
|
|
145
|
+
log.warn(
|
|
146
|
+
`\nOverwriting ${dest} with fallback page. Consider using a different name for the fallback.\n`
|
|
150
147
|
);
|
|
151
148
|
}
|
|
152
149
|
|
package/src/core/config/index.js
CHANGED
|
@@ -6,6 +6,7 @@ import fs from 'node:fs';
|
|
|
6
6
|
import path from 'node:path';
|
|
7
7
|
import process from 'node:process';
|
|
8
8
|
import * as url from 'node:url';
|
|
9
|
+
import { styleText } from 'node:util';
|
|
9
10
|
import {
|
|
10
11
|
validate_kit_options,
|
|
11
12
|
kit_options,
|
|
@@ -223,6 +224,10 @@ export function validate_config(config) {
|
|
|
223
224
|
return validated;
|
|
224
225
|
} catch (e) {
|
|
225
226
|
const error = /** @type {Error} */ (e);
|
|
226
|
-
|
|
227
|
+
|
|
228
|
+
// Print a nicer version of the error to the console
|
|
229
|
+
console.log(styleText(['bold', 'red'], `\n${error.message}\n`));
|
|
230
|
+
|
|
231
|
+
throw stackless('Failed to load SvelteKit options from Vite config');
|
|
227
232
|
}
|
|
228
233
|
}
|
|
@@ -60,6 +60,12 @@ export const validate_svelte_options = object(
|
|
|
60
60
|
true
|
|
61
61
|
);
|
|
62
62
|
|
|
63
|
+
const prerender_handler = validate(undefined, (input, keypath) => {
|
|
64
|
+
if (typeof input === 'function') return input;
|
|
65
|
+
if (['fail', 'warn', 'ignore'].includes(input)) return input;
|
|
66
|
+
throw new Error(`${keypath} should be "fail", "warn", "ignore" or a custom function`);
|
|
67
|
+
});
|
|
68
|
+
|
|
63
69
|
/** @type {Validator<ValidatedKitConfig>} */
|
|
64
70
|
export const validate_kit_options = object({
|
|
65
71
|
adapter: validate(undefined, (input, keypath) => {
|
|
@@ -247,75 +253,11 @@ export const validate_kit_options = object({
|
|
|
247
253
|
return input;
|
|
248
254
|
}),
|
|
249
255
|
|
|
250
|
-
handleHttpError:
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
);
|
|
256
|
-
},
|
|
257
|
-
(input, keypath) => {
|
|
258
|
-
if (typeof input === 'function') return input;
|
|
259
|
-
if (['fail', 'warn', 'ignore'].includes(input)) return input;
|
|
260
|
-
throw new Error(`${keypath} should be "fail", "warn", "ignore" or a custom function`);
|
|
261
|
-
}
|
|
262
|
-
),
|
|
263
|
-
|
|
264
|
-
handleMissingId: validate(
|
|
265
|
-
(/** @type {any} */ { message }) => {
|
|
266
|
-
throw new Error(
|
|
267
|
-
message +
|
|
268
|
-
'\nTo suppress or handle this error, implement `handleMissingId` in https://svelte.dev/docs/kit/configuration#prerender'
|
|
269
|
-
);
|
|
270
|
-
},
|
|
271
|
-
(input, keypath) => {
|
|
272
|
-
if (typeof input === 'function') return input;
|
|
273
|
-
if (['fail', 'warn', 'ignore'].includes(input)) return input;
|
|
274
|
-
throw new Error(`${keypath} should be "fail", "warn", "ignore" or a custom function`);
|
|
275
|
-
}
|
|
276
|
-
),
|
|
277
|
-
|
|
278
|
-
handleEntryGeneratorMismatch: validate(
|
|
279
|
-
(/** @type {any} */ { message }) => {
|
|
280
|
-
throw new Error(
|
|
281
|
-
message +
|
|
282
|
-
'\nTo suppress or handle this error, implement `handleEntryGeneratorMismatch` in https://svelte.dev/docs/kit/configuration#prerender'
|
|
283
|
-
);
|
|
284
|
-
},
|
|
285
|
-
(input, keypath) => {
|
|
286
|
-
if (typeof input === 'function') return input;
|
|
287
|
-
if (['fail', 'warn', 'ignore'].includes(input)) return input;
|
|
288
|
-
throw new Error(`${keypath} should be "fail", "warn", "ignore" or a custom function`);
|
|
289
|
-
}
|
|
290
|
-
),
|
|
291
|
-
|
|
292
|
-
handleUnseenRoutes: validate(
|
|
293
|
-
(/** @type {any} */ { message }) => {
|
|
294
|
-
throw new Error(
|
|
295
|
-
message +
|
|
296
|
-
'\nTo suppress or handle this error, implement `handleUnseenRoutes` in https://svelte.dev/docs/kit/configuration#prerender'
|
|
297
|
-
);
|
|
298
|
-
},
|
|
299
|
-
(input, keypath) => {
|
|
300
|
-
if (typeof input === 'function') return input;
|
|
301
|
-
if (['fail', 'warn', 'ignore'].includes(input)) return input;
|
|
302
|
-
throw new Error(`${keypath} should be "fail", "warn", "ignore" or a custom function`);
|
|
303
|
-
}
|
|
304
|
-
),
|
|
305
|
-
|
|
306
|
-
handleInvalidUrl: validate(
|
|
307
|
-
(/** @type {any} */ { message }) => {
|
|
308
|
-
throw new Error(
|
|
309
|
-
message +
|
|
310
|
-
'\nTo suppress or handle this error, implement `handleInvalidUrl` in https://svelte.dev/docs/kit/configuration#prerender'
|
|
311
|
-
);
|
|
312
|
-
},
|
|
313
|
-
(input, keypath) => {
|
|
314
|
-
if (typeof input === 'function') return input;
|
|
315
|
-
if (['fail', 'warn', 'ignore'].includes(input)) return input;
|
|
316
|
-
throw new Error(`${keypath} should be "fail", "warn", "ignore" or a custom function`);
|
|
317
|
-
}
|
|
318
|
-
),
|
|
256
|
+
handleHttpError: prerender_handler,
|
|
257
|
+
handleMissingId: prerender_handler,
|
|
258
|
+
handleEntryGeneratorMismatch: prerender_handler,
|
|
259
|
+
handleUnseenRoutes: prerender_handler,
|
|
260
|
+
handleInvalidUrl: prerender_handler,
|
|
319
261
|
|
|
320
262
|
origin: removed(
|
|
321
263
|
(keypath) => `\`${keypath}\` has been removed in favour of \`config.paths.origin\``
|
|
@@ -2,6 +2,7 @@ import { readFileSync } from 'node:fs';
|
|
|
2
2
|
import { join } from 'node:path';
|
|
3
3
|
import { pathToFileURL } from 'node:url';
|
|
4
4
|
import { forked } from '../../utils/fork.js';
|
|
5
|
+
import { stackless } from '../../utils/error.js';
|
|
5
6
|
|
|
6
7
|
export default forked(import.meta.url, generate_fallback);
|
|
7
8
|
|
|
@@ -47,5 +48,5 @@ async function generate_fallback({ manifest_path, env, out_dir, origin, assets }
|
|
|
47
48
|
return await response.text();
|
|
48
49
|
}
|
|
49
50
|
|
|
50
|
-
throw
|
|
51
|
+
throw stackless('Could not create a fallback page');
|
|
51
52
|
}
|
|
@@ -16,6 +16,7 @@ import * as devalue from 'devalue';
|
|
|
16
16
|
import { createReadableStream } from '@sveltejs/kit/node';
|
|
17
17
|
import generate_fallback from './fallback.js';
|
|
18
18
|
import { stringify_remote_arg } from '../../runtime/shared.js';
|
|
19
|
+
import { log_response } from '../../exports/vite/utils.js';
|
|
19
20
|
|
|
20
21
|
export default forked(import.meta.url, prerender);
|
|
21
22
|
|
|
@@ -57,29 +58,60 @@ async function prerender({ hash, out, manifest_path, metadata, verbose, env, vit
|
|
|
57
58
|
/** @type {import('types').ServerModule} */
|
|
58
59
|
const { Server } = await import(pathToFileURL(`${out}/server/index.js`).href);
|
|
59
60
|
|
|
61
|
+
const throw_handled = () => {
|
|
62
|
+
throw new Error('__handled__');
|
|
63
|
+
};
|
|
64
|
+
|
|
60
65
|
/**
|
|
61
66
|
* @template {{message: string}} T
|
|
62
67
|
* @template {Omit<T, 'message'>} K
|
|
63
|
-
* @param {
|
|
64
|
-
* @param {'fail' | 'warn' | 'ignore' | ((details: T) => void)} input
|
|
68
|
+
* @param {string} name
|
|
69
|
+
* @param {'fail' | 'warn' | 'ignore' | undefined | ((details: T) => void)} input
|
|
65
70
|
* @param {(details: K) => string} format
|
|
66
|
-
* @returns {(details: K) => void}
|
|
71
|
+
* @returns {(details: K & { error?: unknown }) => void}
|
|
67
72
|
*/
|
|
68
|
-
function normalise_error_handler(
|
|
73
|
+
function normalise_error_handler(name, input, format) {
|
|
74
|
+
/**
|
|
75
|
+
* @param {any} details
|
|
76
|
+
*/
|
|
77
|
+
function log_failure(details) {
|
|
78
|
+
const message = format(details);
|
|
79
|
+
log.error(`\n${message}\n`);
|
|
80
|
+
}
|
|
81
|
+
|
|
69
82
|
switch (input) {
|
|
70
83
|
case 'fail':
|
|
71
84
|
return (details) => {
|
|
72
|
-
|
|
85
|
+
log_failure(details);
|
|
86
|
+
throw_handled();
|
|
73
87
|
};
|
|
74
88
|
case 'warn':
|
|
75
|
-
return
|
|
76
|
-
log.error(format(details));
|
|
77
|
-
};
|
|
89
|
+
return log_failure;
|
|
78
90
|
case 'ignore':
|
|
79
91
|
return noop;
|
|
92
|
+
case undefined: {
|
|
93
|
+
return (details) => {
|
|
94
|
+
log_failure(details);
|
|
95
|
+
|
|
96
|
+
log.err(
|
|
97
|
+
`To suppress or handle this error, implement \`${name}\` in https://svelte.dev/docs/kit/configuration#prerender\n`
|
|
98
|
+
);
|
|
99
|
+
|
|
100
|
+
throw_handled();
|
|
101
|
+
};
|
|
102
|
+
}
|
|
80
103
|
default:
|
|
81
|
-
|
|
82
|
-
|
|
104
|
+
return (details) => {
|
|
105
|
+
const message = format(details);
|
|
106
|
+
|
|
107
|
+
try {
|
|
108
|
+
// @ts-expect-error TS thinks T might be of a different kind, but it's not
|
|
109
|
+
input({ ...details, message });
|
|
110
|
+
} catch (error) {
|
|
111
|
+
log.prettyError(error, import.meta.dirname);
|
|
112
|
+
throw_handled();
|
|
113
|
+
}
|
|
114
|
+
};
|
|
83
115
|
}
|
|
84
116
|
}
|
|
85
117
|
|
|
@@ -141,48 +173,55 @@ async function prerender({ hash, out, manifest_path, metadata, verbose, env, vit
|
|
|
141
173
|
const saved = new Map();
|
|
142
174
|
|
|
143
175
|
const handle_http_error = normalise_error_handler(
|
|
144
|
-
|
|
176
|
+
'handleHttpError',
|
|
145
177
|
config.prerender.handleHttpError,
|
|
146
178
|
({ status, path, referrer, referenceType }) => {
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
179
|
+
let message = `Failed to prerender ${path}`;
|
|
180
|
+
|
|
181
|
+
if (status === 404) {
|
|
182
|
+
if (!path.startsWith(config.paths.base)) {
|
|
183
|
+
message = referrer ? `${path} (${referenceType} from ${referrer})` : path;
|
|
184
|
+
|
|
185
|
+
message += ` does not begin with \`base\`. You can fix this by using \`resolve('${path}')\` from \`$app/paths\`. The base path is configurable from \`paths.base\``;
|
|
186
|
+
} else if (referrer) {
|
|
187
|
+
message = `${path} was ${referenceType} from ${referrer}`;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
151
190
|
|
|
152
|
-
return
|
|
191
|
+
return message;
|
|
153
192
|
}
|
|
154
193
|
);
|
|
155
194
|
|
|
156
195
|
const handle_missing_id = normalise_error_handler(
|
|
157
|
-
|
|
196
|
+
'handleMissingId',
|
|
158
197
|
config.prerender.handleMissingId,
|
|
159
198
|
({ path, id, referrers }) => {
|
|
160
199
|
return (
|
|
161
|
-
`The following pages contain links to ${path}#${id}, but no element with id="${id}" exists on ${path}
|
|
200
|
+
`The following pages contain links to ${path}#${id}, but no element with id="${id}" exists on ${path}:` +
|
|
162
201
|
referrers.map((l) => `\n - ${l}`).join('')
|
|
163
202
|
);
|
|
164
203
|
}
|
|
165
204
|
);
|
|
166
205
|
|
|
167
206
|
const handle_entry_generator_mismatch = normalise_error_handler(
|
|
168
|
-
|
|
207
|
+
'handleEntryGeneratorMismatch',
|
|
169
208
|
config.prerender.handleEntryGeneratorMismatch,
|
|
170
209
|
({ generatedFromId, entry, matchedId }) => {
|
|
171
|
-
return `The entries export from ${generatedFromId} generated entry ${entry}, which was matched by ${matchedId
|
|
210
|
+
return `The entries export from ${generatedFromId} generated entry ${entry}, which was matched by ${matchedId === entry ? 'a static route' : matchedId}`;
|
|
172
211
|
}
|
|
173
212
|
);
|
|
174
213
|
|
|
175
214
|
const handle_not_prerendered_route = normalise_error_handler(
|
|
176
|
-
|
|
215
|
+
'handleUnseenRoutes',
|
|
177
216
|
config.prerender.handleUnseenRoutes,
|
|
178
217
|
({ routes }) => {
|
|
179
218
|
const list = routes.map((id) => ` - ${id}`).join('\n');
|
|
180
|
-
return `The following routes were marked as prerenderable, but were not prerendered because they were not found while crawling your app:\n${list}
|
|
219
|
+
return `The following routes were marked as prerenderable, but were not prerendered because they were not found while crawling your app:\n${list}`;
|
|
181
220
|
}
|
|
182
221
|
);
|
|
183
222
|
|
|
184
223
|
const handle_invalid_url = normalise_error_handler(
|
|
185
|
-
|
|
224
|
+
'handleInvalidUrl',
|
|
186
225
|
config.prerender.handleInvalidUrl,
|
|
187
226
|
({ href, referrer }) => {
|
|
188
227
|
return `Invalid URL ${href}${referrer ? ` (linked from ${referrer})` : ''}`;
|
|
@@ -260,7 +299,9 @@ async function prerender({ hash, out, manifest_path, metadata, verbose, env, vit
|
|
|
260
299
|
/** @type {Map<string, import('types').PrerenderDependency>} */
|
|
261
300
|
const dependencies = new Map();
|
|
262
301
|
|
|
263
|
-
const
|
|
302
|
+
const request = new Request(prerender_origin + encoded);
|
|
303
|
+
|
|
304
|
+
const response = await server.respond(request, {
|
|
264
305
|
getClientAddress() {
|
|
265
306
|
throw new Error('Cannot read clientAddress during prerendering');
|
|
266
307
|
},
|
|
@@ -298,6 +339,10 @@ async function prerender({ hash, out, manifest_path, metadata, verbose, env, vit
|
|
|
298
339
|
});
|
|
299
340
|
}
|
|
300
341
|
|
|
342
|
+
if (response.status !== 204) {
|
|
343
|
+
log_response(response.status, request);
|
|
344
|
+
}
|
|
345
|
+
|
|
301
346
|
const body = Buffer.from(await response.arrayBuffer());
|
|
302
347
|
|
|
303
348
|
const category = decoded.startsWith(remote_prefix) ? 'data' : 'pages';
|
|
@@ -428,8 +473,6 @@ async function prerender({ hash, out, manifest_path, metadata, verbose, env, vit
|
|
|
428
473
|
if (!headers['x-sveltekit-normalize']) {
|
|
429
474
|
mkdirp(dirname(dest));
|
|
430
475
|
|
|
431
|
-
log.warn(`${response.status} ${decoded} -> ${location}`);
|
|
432
|
-
|
|
433
476
|
writeFileSync(
|
|
434
477
|
dest,
|
|
435
478
|
`<script>location.href=${devalue.uneval(
|
|
@@ -476,7 +519,6 @@ async function prerender({ hash, out, manifest_path, metadata, verbose, env, vit
|
|
|
476
519
|
|
|
477
520
|
mkdirp(dir);
|
|
478
521
|
|
|
479
|
-
log.info(`${response.status} ${decoded}`);
|
|
480
522
|
writeFileSync(dest, body);
|
|
481
523
|
written.add(file);
|
|
482
524
|
|
|
@@ -492,7 +534,12 @@ async function prerender({ hash, out, manifest_path, metadata, verbose, env, vit
|
|
|
492
534
|
|
|
493
535
|
prerendered.paths.push(decoded);
|
|
494
536
|
} else if (response_type !== OK) {
|
|
495
|
-
handle_http_error({
|
|
537
|
+
handle_http_error({
|
|
538
|
+
status: response.status,
|
|
539
|
+
path: decoded,
|
|
540
|
+
referrer,
|
|
541
|
+
referenceType
|
|
542
|
+
});
|
|
496
543
|
}
|
|
497
544
|
|
|
498
545
|
manifest.assets.add(file);
|
|
@@ -28,7 +28,7 @@ export function queue(concurrency) {
|
|
|
28
28
|
|
|
29
29
|
if (task) {
|
|
30
30
|
current += 1;
|
|
31
|
-
const promise =
|
|
31
|
+
const promise = (async () => task.fn())(); // could throw synchronously
|
|
32
32
|
|
|
33
33
|
void promise
|
|
34
34
|
.then(task.fulfil, (err) => {
|
|
@@ -54,6 +54,7 @@ export function queue(concurrency) {
|
|
|
54
54
|
const promise = new Promise((fulfil, reject) => {
|
|
55
55
|
tasks.push({ fn, fulfil, reject });
|
|
56
56
|
});
|
|
57
|
+
promise.catch(() => {});
|
|
57
58
|
|
|
58
59
|
dequeue();
|
|
59
60
|
return promise;
|
|
@@ -26,7 +26,7 @@ const server_template = ({
|
|
|
26
26
|
}) => `
|
|
27
27
|
import { set_building, set_prerendering } from '$app/env/internal';
|
|
28
28
|
import { set_assets } from '$app/paths/internal/server';
|
|
29
|
-
import { set_manifest, set_read_implementation } from '__sveltekit/server';
|
|
29
|
+
import { set_fix_stack_trace, set_manifest, set_read_implementation } from '__sveltekit/server';
|
|
30
30
|
import error from '../shared/error-template.js';
|
|
31
31
|
|
|
32
32
|
export const options = {
|
|
@@ -80,7 +80,7 @@ export async function get_hooks() {
|
|
|
80
80
|
};
|
|
81
81
|
}
|
|
82
82
|
|
|
83
|
-
export { set_assets, set_building, set_manifest, set_prerendering, set_read_implementation };
|
|
83
|
+
export { set_assets, set_building, set_fix_stack_trace, set_manifest, set_prerendering, set_read_implementation };
|
|
84
84
|
`;
|
|
85
85
|
|
|
86
86
|
// TODO need to re-run this whenever src/app.html or src/error.html are
|
package/src/core/utils.js
CHANGED
|
@@ -30,18 +30,43 @@ export function get_runtime_base(root) {
|
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
/** @param {{ verbose: boolean }} opts */
|
|
33
|
-
export function logger({ verbose }) {
|
|
33
|
+
export function logger({ verbose } = { verbose: true }) {
|
|
34
34
|
/** @type {import('types').Logger} */
|
|
35
|
-
const log = (msg) => console.log(msg
|
|
35
|
+
const log = (msg) => console.log(msg);
|
|
36
36
|
|
|
37
37
|
/** @param {string} msg */
|
|
38
|
-
const err = (msg) => console.error(msg
|
|
38
|
+
const err = (msg) => console.error(msg);
|
|
39
39
|
|
|
40
40
|
log.success = (msg) => log(styleText('green', `✔ ${msg}`));
|
|
41
41
|
log.error = (msg) => err(styleText(['bold', 'red'], msg));
|
|
42
42
|
log.warn = (msg) => log(styleText(['bold', 'yellow'], msg));
|
|
43
43
|
log.minor = verbose ? (msg) => log(styleText('grey', msg)) : noop;
|
|
44
44
|
log.info = verbose ? log : noop;
|
|
45
|
+
log.err = err;
|
|
46
|
+
|
|
47
|
+
log.prettyError = (error, caller) => {
|
|
48
|
+
/** @type {unknown} */
|
|
49
|
+
let e = error;
|
|
50
|
+
|
|
51
|
+
while (e instanceof Error) {
|
|
52
|
+
let stack = e.stack;
|
|
53
|
+
if (stack) {
|
|
54
|
+
if (caller) {
|
|
55
|
+
const i = stack.indexOf(caller);
|
|
56
|
+
// Cut the stack trace off at the point when our internal one starts
|
|
57
|
+
stack = stack.slice(0, stack.lastIndexOf('\n', i));
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
err(stack);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
e = e.cause;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (e) {
|
|
67
|
+
err(String(e));
|
|
68
|
+
}
|
|
69
|
+
};
|
|
45
70
|
|
|
46
71
|
return log;
|
|
47
72
|
}
|
package/src/exports/env/index.js
CHANGED
|
@@ -1,12 +1,77 @@
|
|
|
1
|
-
/** @import {
|
|
1
|
+
/** @import { StandardSchemaV1 } from '@standard-schema/spec' */
|
|
2
|
+
/** @import { DefinedEnvVars, EnvVarConfig } from '@sveltejs/kit' */
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* Utility for defining [environment variables](https://svelte.dev/docs/kit/environment-variables),
|
|
5
6
|
* which are made available via `$app/env/public` and `$app/env/private`.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```js
|
|
10
|
+
* import { defineEnvVars } from '@sveltejs/kit/env';
|
|
11
|
+
* import * as v from 'valibot';
|
|
12
|
+
*
|
|
13
|
+
* export const variables = defineEnvVars({
|
|
14
|
+
* API_URL: {
|
|
15
|
+
* schema: v.pipe(v.string(), v.url())
|
|
16
|
+
* },
|
|
17
|
+
* PORT: {
|
|
18
|
+
* schema: (value) => {
|
|
19
|
+
* if (value === undefined) return 3000;
|
|
20
|
+
* const port = Number(value);
|
|
21
|
+
* if (!Number.isInteger(port)) throw new Error('PORT must be an integer');
|
|
22
|
+
* return port;
|
|
23
|
+
* }
|
|
24
|
+
* }
|
|
25
|
+
* });
|
|
26
|
+
* ```
|
|
27
|
+
*
|
|
6
28
|
* @template {Record<string, EnvVarConfig<any>>} T
|
|
7
29
|
* @param {T} variables
|
|
8
|
-
* @returns {T}
|
|
30
|
+
* @returns {DefinedEnvVars<T>}
|
|
9
31
|
*/
|
|
10
32
|
export function defineEnvVars(variables) {
|
|
11
|
-
|
|
33
|
+
/** @type {Record<string, EnvVarConfig<any>>} */
|
|
34
|
+
const normalized = {};
|
|
35
|
+
|
|
36
|
+
for (const [name, config] of Object.entries(variables)) {
|
|
37
|
+
// standard schemas can be callable (e.g. ArkType), so a function is only a validator if it isn't one
|
|
38
|
+
normalized[name] =
|
|
39
|
+
typeof config.schema === 'function' && !('~standard' in config.schema)
|
|
40
|
+
? { ...config, schema: normalize_env_schema(config.schema) }
|
|
41
|
+
: config;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return /** @type {DefinedEnvVars<T>} */ (normalized);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* @param {(value: string | undefined) => any} fn
|
|
49
|
+
* @returns {StandardSchemaV1<string | undefined, any>}
|
|
50
|
+
*/
|
|
51
|
+
function normalize_env_schema(fn) {
|
|
52
|
+
return /** @type {StandardSchemaV1<string | undefined, any>} */ (
|
|
53
|
+
/** @type {unknown} */ ({
|
|
54
|
+
'~standard': {
|
|
55
|
+
validate(/** @type {unknown} */ value) {
|
|
56
|
+
let result;
|
|
57
|
+
|
|
58
|
+
try {
|
|
59
|
+
result = fn(/** @type {string | undefined} */ (value));
|
|
60
|
+
} catch (error) {
|
|
61
|
+
return {
|
|
62
|
+
issues: [
|
|
63
|
+
{
|
|
64
|
+
message: error instanceof Error ? error.message || 'Invalid value' : String(error)
|
|
65
|
+
}
|
|
66
|
+
]
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if (result instanceof Promise) return result; // will be rejected upstream
|
|
71
|
+
|
|
72
|
+
return { value: result };
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
})
|
|
76
|
+
);
|
|
12
77
|
}
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
import { stackless } from '../../utils/error.js';
|
|
5
5
|
|
|
6
6
|
const MISSING = {
|
|
7
|
-
message: `Value is missing. If it is optional, add a
|
|
7
|
+
message: `Value is missing. If it is optional, add a validator declaring it as such.`
|
|
8
8
|
};
|
|
9
9
|
|
|
10
10
|
const BAD_VALIDATOR = {
|
|
@@ -24,10 +24,13 @@ const ASYNC_VALIDATOR = {
|
|
|
24
24
|
*/
|
|
25
25
|
export function validate(variables, value, name, issues) {
|
|
26
26
|
const config = variables[name] ?? {};
|
|
27
|
-
|
|
27
|
+
// `defineEnvVars` normalizes function validators to standard schemas
|
|
28
|
+
const validator = /** @type {StandardSchemaV1<string | undefined, any> | undefined} */ (
|
|
29
|
+
config.schema
|
|
30
|
+
);
|
|
28
31
|
|
|
29
32
|
if (!validator) {
|
|
30
|
-
if (
|
|
33
|
+
if (value === undefined) issues[name] = [MISSING];
|
|
31
34
|
return value;
|
|
32
35
|
}
|
|
33
36
|
|
package/src/exports/params.js
CHANGED
|
@@ -35,6 +35,15 @@ export function defineParams(definitions) {
|
|
|
35
35
|
* @returns {import('@sveltejs/kit').ParamMatcher}
|
|
36
36
|
*/
|
|
37
37
|
export function normalize_param_definition(definition) {
|
|
38
|
+
// standard schemas can be callable (e.g. ArkType), so this must be checked before the function case
|
|
39
|
+
if (
|
|
40
|
+
definition &&
|
|
41
|
+
(typeof definition === 'object' || typeof definition === 'function') &&
|
|
42
|
+
'~standard' in definition
|
|
43
|
+
) {
|
|
44
|
+
return definition;
|
|
45
|
+
}
|
|
46
|
+
|
|
38
47
|
if (typeof definition === 'function') {
|
|
39
48
|
return /** @type {import('@sveltejs/kit').ParamMatcher} */ (
|
|
40
49
|
/** @type {unknown} */ ({
|
|
@@ -55,9 +64,5 @@ export function normalize_param_definition(definition) {
|
|
|
55
64
|
);
|
|
56
65
|
}
|
|
57
66
|
|
|
58
|
-
if (definition && typeof definition === 'object' && '~standard' in definition) {
|
|
59
|
-
return definition;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
67
|
throw new Error('Invalid param definition');
|
|
63
68
|
}
|