@sveltejs/kit 1.0.0-next.24 → 1.0.0-next.243

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.
Files changed (84) hide show
  1. package/README.md +12 -9
  2. package/assets/app/env.js +20 -0
  3. package/assets/app/navigation.js +79 -0
  4. package/assets/app/paths.js +1 -0
  5. package/assets/{runtime/app → app}/stores.js +19 -15
  6. package/assets/chunks/utils.js +13 -0
  7. package/assets/client/singletons.js +21 -0
  8. package/assets/client/start.js +1382 -0
  9. package/assets/components/error.svelte +19 -3
  10. package/assets/env.js +8 -0
  11. package/assets/paths.js +13 -0
  12. package/assets/server/index.js +1842 -0
  13. package/dist/chunks/build.js +658 -0
  14. package/dist/chunks/cert.js +28154 -0
  15. package/dist/chunks/index.js +2202 -0
  16. package/dist/chunks/index2.js +807 -0
  17. package/dist/chunks/index3.js +643 -0
  18. package/dist/chunks/index4.js +109 -0
  19. package/dist/chunks/index5.js +752 -0
  20. package/dist/chunks/index6.js +170 -0
  21. package/dist/chunks/index7.js +15578 -0
  22. package/dist/chunks/index8.js +4207 -0
  23. package/dist/chunks/misc.js +3 -0
  24. package/dist/chunks/multipart-parser.js +449 -0
  25. package/dist/chunks/url.js +119 -0
  26. package/dist/cli.js +1060 -84
  27. package/dist/hooks.js +28 -0
  28. package/dist/install-fetch.js +6518 -0
  29. package/dist/node.js +85 -0
  30. package/package.json +95 -54
  31. package/svelte-kit.js +2 -0
  32. package/types/ambient-modules.d.ts +201 -0
  33. package/types/app.d.ts +31 -0
  34. package/types/config.d.ts +164 -0
  35. package/types/endpoint.d.ts +20 -0
  36. package/types/helper.d.ts +32 -0
  37. package/types/hooks.d.ts +42 -0
  38. package/types/index.d.ts +10 -0
  39. package/types/internal.d.ts +234 -0
  40. package/types/page.d.ts +85 -0
  41. package/CHANGELOG.md +0 -300
  42. package/assets/runtime/app/navigation.js +0 -23
  43. package/assets/runtime/app/navigation.js.map +0 -1
  44. package/assets/runtime/app/paths.js +0 -2
  45. package/assets/runtime/app/paths.js.map +0 -1
  46. package/assets/runtime/app/stores.js.map +0 -1
  47. package/assets/runtime/internal/singletons.js +0 -15
  48. package/assets/runtime/internal/singletons.js.map +0 -1
  49. package/assets/runtime/internal/start.js +0 -591
  50. package/assets/runtime/internal/start.js.map +0 -1
  51. package/assets/runtime/utils-85ebcc60.js +0 -18
  52. package/assets/runtime/utils-85ebcc60.js.map +0 -1
  53. package/dist/api.js +0 -44
  54. package/dist/api.js.map +0 -1
  55. package/dist/build.js +0 -246
  56. package/dist/build.js.map +0 -1
  57. package/dist/cli.js.map +0 -1
  58. package/dist/colors.js +0 -37
  59. package/dist/colors.js.map +0 -1
  60. package/dist/create_app.js +0 -578
  61. package/dist/create_app.js.map +0 -1
  62. package/dist/index.js +0 -367
  63. package/dist/index.js.map +0 -1
  64. package/dist/index2.js +0 -12044
  65. package/dist/index2.js.map +0 -1
  66. package/dist/index3.js +0 -547
  67. package/dist/index3.js.map +0 -1
  68. package/dist/index4.js +0 -73
  69. package/dist/index4.js.map +0 -1
  70. package/dist/index5.js +0 -464
  71. package/dist/index5.js.map +0 -1
  72. package/dist/index6.js +0 -727
  73. package/dist/index6.js.map +0 -1
  74. package/dist/logging.js +0 -43
  75. package/dist/logging.js.map +0 -1
  76. package/dist/package.js +0 -432
  77. package/dist/package.js.map +0 -1
  78. package/dist/renderer.js +0 -2391
  79. package/dist/renderer.js.map +0 -1
  80. package/dist/standard.js +0 -101
  81. package/dist/standard.js.map +0 -1
  82. package/dist/utils.js +0 -54
  83. package/dist/utils.js.map +0 -1
  84. package/svelte-kit +0 -3
@@ -0,0 +1,2202 @@
1
+ import path__default from 'path';
2
+ import { svelte } from '@sveltejs/vite-plugin-svelte';
3
+ import vite from 'vite';
4
+ import { c as create_manifest_data, a as create_app, d as deep_merge } from './index2.js';
5
+ import { c as coalesce_to_error, S as SVELTE_KIT_ASSETS, r as resolve_entry, $, a as SVELTE_KIT, b as runtime, l as load_template, g as get_mime_lookup, d as copy_assets, e as get_aliases, p as print_config_conflicts } from '../cli.js';
6
+ import fs__default from 'fs';
7
+ import { URL as URL$1 } from 'url';
8
+ import { s as sirv } from './build.js';
9
+ import { e as escape_html_attr, r as resolve, i as is_root_relative, a as escape_json_string_in_html } from './url.js';
10
+ import { s } from './misc.js';
11
+ import { __fetch_polyfill } from '../install-fetch.js';
12
+ import { getRequest, setResponse } from '../node.js';
13
+ import 'sade';
14
+ import 'child_process';
15
+ import 'net';
16
+ import 'os';
17
+ import 'querystring';
18
+ import 'node:http';
19
+ import 'node:https';
20
+ import 'node:zlib';
21
+ import 'node:stream';
22
+ import 'node:util';
23
+ import 'node:url';
24
+ import 'stream';
25
+
26
+ /** @param {Partial<import('types/helper').ResponseHeaders> | undefined} object */
27
+ function to_headers(object) {
28
+ const headers = new Headers();
29
+
30
+ if (object) {
31
+ for (const key in object) {
32
+ const value = object[key];
33
+ if (!value) continue;
34
+
35
+ if (typeof value === 'string') {
36
+ headers.set(key, value);
37
+ } else {
38
+ value.forEach((value) => {
39
+ headers.append(key, value);
40
+ });
41
+ }
42
+ }
43
+ }
44
+
45
+ return headers;
46
+ }
47
+
48
+ /**
49
+ * Hash using djb2
50
+ * @param {import('types/hooks').StrictBody} value
51
+ */
52
+ function hash(value) {
53
+ let hash = 5381;
54
+ let i = value.length;
55
+
56
+ if (typeof value === 'string') {
57
+ while (i) hash = (hash * 33) ^ value.charCodeAt(--i);
58
+ } else {
59
+ while (i) hash = (hash * 33) ^ value[--i];
60
+ }
61
+
62
+ return (hash >>> 0).toString(36);
63
+ }
64
+
65
+ /** @param {Record<string, any>} obj */
66
+
67
+ /** @param {Record<string, string>} params */
68
+ function decode_params(params) {
69
+ for (const key in params) {
70
+ // input has already been decoded by decodeURI
71
+ // now handle the rest that decodeURIComponent would do
72
+ params[key] = params[key]
73
+ .replace(/%23/g, '#')
74
+ .replace(/%3[Bb]/g, ';')
75
+ .replace(/%2[Cc]/g, ',')
76
+ .replace(/%2[Ff]/g, '/')
77
+ .replace(/%3[Ff]/g, '?')
78
+ .replace(/%3[Aa]/g, ':')
79
+ .replace(/%40/g, '@')
80
+ .replace(/%26/g, '&')
81
+ .replace(/%3[Dd]/g, '=')
82
+ .replace(/%2[Bb]/g, '+')
83
+ .replace(/%24/g, '$');
84
+ }
85
+
86
+ return params;
87
+ }
88
+
89
+ /** @param {string} body */
90
+ function error(body) {
91
+ return new Response(body, {
92
+ status: 500
93
+ });
94
+ }
95
+
96
+ /** @param {unknown} s */
97
+ function is_string(s) {
98
+ return typeof s === 'string' || s instanceof String;
99
+ }
100
+
101
+ const text_types = new Set([
102
+ 'application/xml',
103
+ 'application/json',
104
+ 'application/x-www-form-urlencoded',
105
+ 'multipart/form-data'
106
+ ]);
107
+
108
+ /**
109
+ * Decides how the body should be parsed based on its mime type. Should match what's in parse_body
110
+ *
111
+ * @param {string | undefined | null} content_type The `content-type` header of a request/response.
112
+ * @returns {boolean}
113
+ */
114
+ function is_text(content_type) {
115
+ if (!content_type) return true; // defaults to json
116
+ const type = content_type.split(';')[0].toLowerCase(); // get the mime type
117
+
118
+ return type.startsWith('text/') || type.endsWith('+xml') || text_types.has(type);
119
+ }
120
+
121
+ /**
122
+ * @param {import('types/hooks').RequestEvent} event
123
+ * @param {import('types/internal').SSREndpoint} route
124
+ * @param {RegExpExecArray} match
125
+ * @returns {Promise<Response | undefined>}
126
+ */
127
+ async function render_endpoint(event, route, match) {
128
+ const mod = await route.load();
129
+
130
+ /** @type {import('types/endpoint').RequestHandler} */
131
+ const handler = mod[event.request.method.toLowerCase().replace('delete', 'del')]; // 'delete' is a reserved word
132
+
133
+ if (!handler) {
134
+ return;
135
+ }
136
+
137
+ // we're mutating `request` so that we don't have to do { ...request, params }
138
+ // on the next line, since that breaks the getters that replace path, query and
139
+ // origin. We could revert that once we remove the getters
140
+ event.params = route.params ? decode_params(route.params(match)) : {};
141
+
142
+ const response = await handler(event);
143
+ const preface = `Invalid response from route ${event.url.pathname}`;
144
+
145
+ if (typeof response !== 'object') {
146
+ return error(`${preface}: expected an object, got ${typeof response}`);
147
+ }
148
+
149
+ if (response.fallthrough) {
150
+ return;
151
+ }
152
+
153
+ const { status = 200, body = {} } = response;
154
+ const headers =
155
+ response.headers instanceof Headers ? response.headers : to_headers(response.headers);
156
+
157
+ const type = headers.get('content-type');
158
+
159
+ if (!is_text(type) && !(body instanceof Uint8Array || is_string(body))) {
160
+ return error(
161
+ `${preface}: body must be an instance of string or Uint8Array if content-type is not a supported textual content-type`
162
+ );
163
+ }
164
+
165
+ /** @type {import('types/hooks').StrictBody} */
166
+ let normalized_body;
167
+
168
+ if (is_pojo(body) && (!type || type.startsWith('application/json'))) {
169
+ headers.set('content-type', 'application/json; charset=utf-8');
170
+ normalized_body = JSON.stringify(body);
171
+ } else {
172
+ normalized_body = /** @type {import('types/hooks').StrictBody} */ (body);
173
+ }
174
+
175
+ if (
176
+ (typeof normalized_body === 'string' || normalized_body instanceof Uint8Array) &&
177
+ !headers.has('etag')
178
+ ) {
179
+ const cache_control = headers.get('cache-control');
180
+ if (!cache_control || !/(no-store|immutable)/.test(cache_control)) {
181
+ headers.set('etag', `"${hash(normalized_body)}"`);
182
+ }
183
+ }
184
+
185
+ return new Response(normalized_body, {
186
+ status,
187
+ headers
188
+ });
189
+ }
190
+
191
+ /** @param {any} body */
192
+ function is_pojo(body) {
193
+ if (typeof body !== 'object') return false;
194
+
195
+ if (body) {
196
+ if (body instanceof Uint8Array) return false;
197
+
198
+ // body could be a node Readable, but we don't want to import
199
+ // node built-ins, so we use duck typing
200
+ if (body._readableState && body._writableState && body._events) return false;
201
+
202
+ // similarly, it could be a web ReadableStream
203
+ if (body[Symbol.toStringTag] === 'ReadableStream') return false;
204
+ }
205
+
206
+ return true;
207
+ }
208
+
209
+ var chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_$';
210
+ var unsafeChars = /[<>\b\f\n\r\t\0\u2028\u2029]/g;
211
+ var reserved = /^(?:do|if|in|for|int|let|new|try|var|byte|case|char|else|enum|goto|long|this|void|with|await|break|catch|class|const|final|float|short|super|throw|while|yield|delete|double|export|import|native|return|switch|throws|typeof|boolean|default|extends|finally|package|private|abstract|continue|debugger|function|volatile|interface|protected|transient|implements|instanceof|synchronized)$/;
212
+ var escaped = {
213
+ '<': '\\u003C',
214
+ '>': '\\u003E',
215
+ '/': '\\u002F',
216
+ '\\': '\\\\',
217
+ '\b': '\\b',
218
+ '\f': '\\f',
219
+ '\n': '\\n',
220
+ '\r': '\\r',
221
+ '\t': '\\t',
222
+ '\0': '\\0',
223
+ '\u2028': '\\u2028',
224
+ '\u2029': '\\u2029'
225
+ };
226
+ var objectProtoOwnPropertyNames = Object.getOwnPropertyNames(Object.prototype).sort().join('\0');
227
+ function devalue(value) {
228
+ var counts = new Map();
229
+ function walk(thing) {
230
+ if (typeof thing === 'function') {
231
+ throw new Error("Cannot stringify a function");
232
+ }
233
+ if (counts.has(thing)) {
234
+ counts.set(thing, counts.get(thing) + 1);
235
+ return;
236
+ }
237
+ counts.set(thing, 1);
238
+ if (!isPrimitive(thing)) {
239
+ var type = getType(thing);
240
+ switch (type) {
241
+ case 'Number':
242
+ case 'String':
243
+ case 'Boolean':
244
+ case 'Date':
245
+ case 'RegExp':
246
+ return;
247
+ case 'Array':
248
+ thing.forEach(walk);
249
+ break;
250
+ case 'Set':
251
+ case 'Map':
252
+ Array.from(thing).forEach(walk);
253
+ break;
254
+ default:
255
+ var proto = Object.getPrototypeOf(thing);
256
+ if (proto !== Object.prototype &&
257
+ proto !== null &&
258
+ Object.getOwnPropertyNames(proto).sort().join('\0') !== objectProtoOwnPropertyNames) {
259
+ throw new Error("Cannot stringify arbitrary non-POJOs");
260
+ }
261
+ if (Object.getOwnPropertySymbols(thing).length > 0) {
262
+ throw new Error("Cannot stringify POJOs with symbolic keys");
263
+ }
264
+ Object.keys(thing).forEach(function (key) { return walk(thing[key]); });
265
+ }
266
+ }
267
+ }
268
+ walk(value);
269
+ var names = new Map();
270
+ Array.from(counts)
271
+ .filter(function (entry) { return entry[1] > 1; })
272
+ .sort(function (a, b) { return b[1] - a[1]; })
273
+ .forEach(function (entry, i) {
274
+ names.set(entry[0], getName(i));
275
+ });
276
+ function stringify(thing) {
277
+ if (names.has(thing)) {
278
+ return names.get(thing);
279
+ }
280
+ if (isPrimitive(thing)) {
281
+ return stringifyPrimitive(thing);
282
+ }
283
+ var type = getType(thing);
284
+ switch (type) {
285
+ case 'Number':
286
+ case 'String':
287
+ case 'Boolean':
288
+ return "Object(" + stringify(thing.valueOf()) + ")";
289
+ case 'RegExp':
290
+ return "new RegExp(" + stringifyString(thing.source) + ", \"" + thing.flags + "\")";
291
+ case 'Date':
292
+ return "new Date(" + thing.getTime() + ")";
293
+ case 'Array':
294
+ var members = thing.map(function (v, i) { return i in thing ? stringify(v) : ''; });
295
+ var tail = thing.length === 0 || (thing.length - 1 in thing) ? '' : ',';
296
+ return "[" + members.join(',') + tail + "]";
297
+ case 'Set':
298
+ case 'Map':
299
+ return "new " + type + "([" + Array.from(thing).map(stringify).join(',') + "])";
300
+ default:
301
+ var obj = "{" + Object.keys(thing).map(function (key) { return safeKey(key) + ":" + stringify(thing[key]); }).join(',') + "}";
302
+ var proto = Object.getPrototypeOf(thing);
303
+ if (proto === null) {
304
+ return Object.keys(thing).length > 0
305
+ ? "Object.assign(Object.create(null)," + obj + ")"
306
+ : "Object.create(null)";
307
+ }
308
+ return obj;
309
+ }
310
+ }
311
+ var str = stringify(value);
312
+ if (names.size) {
313
+ var params_1 = [];
314
+ var statements_1 = [];
315
+ var values_1 = [];
316
+ names.forEach(function (name, thing) {
317
+ params_1.push(name);
318
+ if (isPrimitive(thing)) {
319
+ values_1.push(stringifyPrimitive(thing));
320
+ return;
321
+ }
322
+ var type = getType(thing);
323
+ switch (type) {
324
+ case 'Number':
325
+ case 'String':
326
+ case 'Boolean':
327
+ values_1.push("Object(" + stringify(thing.valueOf()) + ")");
328
+ break;
329
+ case 'RegExp':
330
+ values_1.push(thing.toString());
331
+ break;
332
+ case 'Date':
333
+ values_1.push("new Date(" + thing.getTime() + ")");
334
+ break;
335
+ case 'Array':
336
+ values_1.push("Array(" + thing.length + ")");
337
+ thing.forEach(function (v, i) {
338
+ statements_1.push(name + "[" + i + "]=" + stringify(v));
339
+ });
340
+ break;
341
+ case 'Set':
342
+ values_1.push("new Set");
343
+ statements_1.push(name + "." + Array.from(thing).map(function (v) { return "add(" + stringify(v) + ")"; }).join('.'));
344
+ break;
345
+ case 'Map':
346
+ values_1.push("new Map");
347
+ statements_1.push(name + "." + Array.from(thing).map(function (_a) {
348
+ var k = _a[0], v = _a[1];
349
+ return "set(" + stringify(k) + ", " + stringify(v) + ")";
350
+ }).join('.'));
351
+ break;
352
+ default:
353
+ values_1.push(Object.getPrototypeOf(thing) === null ? 'Object.create(null)' : '{}');
354
+ Object.keys(thing).forEach(function (key) {
355
+ statements_1.push("" + name + safeProp(key) + "=" + stringify(thing[key]));
356
+ });
357
+ }
358
+ });
359
+ statements_1.push("return " + str);
360
+ return "(function(" + params_1.join(',') + "){" + statements_1.join(';') + "}(" + values_1.join(',') + "))";
361
+ }
362
+ else {
363
+ return str;
364
+ }
365
+ }
366
+ function getName(num) {
367
+ var name = '';
368
+ do {
369
+ name = chars[num % chars.length] + name;
370
+ num = ~~(num / chars.length) - 1;
371
+ } while (num >= 0);
372
+ return reserved.test(name) ? name + "_" : name;
373
+ }
374
+ function isPrimitive(thing) {
375
+ return Object(thing) !== thing;
376
+ }
377
+ function stringifyPrimitive(thing) {
378
+ if (typeof thing === 'string')
379
+ return stringifyString(thing);
380
+ if (thing === void 0)
381
+ return 'void 0';
382
+ if (thing === 0 && 1 / thing < 0)
383
+ return '-0';
384
+ var str = String(thing);
385
+ if (typeof thing === 'number')
386
+ return str.replace(/^(-)?0\./, '$1.');
387
+ return str;
388
+ }
389
+ function getType(thing) {
390
+ return Object.prototype.toString.call(thing).slice(8, -1);
391
+ }
392
+ function escapeUnsafeChar(c) {
393
+ return escaped[c] || c;
394
+ }
395
+ function escapeUnsafeChars(str) {
396
+ return str.replace(unsafeChars, escapeUnsafeChar);
397
+ }
398
+ function safeKey(key) {
399
+ return /^[_$a-zA-Z][_$a-zA-Z0-9]*$/.test(key) ? key : escapeUnsafeChars(JSON.stringify(key));
400
+ }
401
+ function safeProp(key) {
402
+ return /^[_$a-zA-Z][_$a-zA-Z0-9]*$/.test(key) ? "." + key : "[" + escapeUnsafeChars(JSON.stringify(key)) + "]";
403
+ }
404
+ function stringifyString(str) {
405
+ var result = '"';
406
+ for (var i = 0; i < str.length; i += 1) {
407
+ var char = str.charAt(i);
408
+ var code = char.charCodeAt(0);
409
+ if (char === '"') {
410
+ result += '\\"';
411
+ }
412
+ else if (char in escaped) {
413
+ result += escaped[char];
414
+ }
415
+ else if (code >= 0xd800 && code <= 0xdfff) {
416
+ var next = str.charCodeAt(i + 1);
417
+ // If this is the beginning of a [high, low] surrogate pair,
418
+ // add the next two characters, otherwise escape
419
+ if (code <= 0xdbff && (next >= 0xdc00 && next <= 0xdfff)) {
420
+ result += char + str[++i];
421
+ }
422
+ else {
423
+ result += "\\u" + code.toString(16).toUpperCase();
424
+ }
425
+ }
426
+ else {
427
+ result += char;
428
+ }
429
+ }
430
+ result += '"';
431
+ return result;
432
+ }
433
+
434
+ function noop() { }
435
+ function safe_not_equal(a, b) {
436
+ return a != a ? b == b : a !== b || ((a && typeof a === 'object') || typeof a === 'function');
437
+ }
438
+ Promise.resolve();
439
+
440
+ const subscriber_queue = [];
441
+ /**
442
+ * Create a `Writable` store that allows both updating and reading by subscription.
443
+ * @param {*=}value initial value
444
+ * @param {StartStopNotifier=}start start and stop notifications for subscriptions
445
+ */
446
+ function writable(value, start = noop) {
447
+ let stop;
448
+ const subscribers = new Set();
449
+ function set(new_value) {
450
+ if (safe_not_equal(value, new_value)) {
451
+ value = new_value;
452
+ if (stop) { // store is ready
453
+ const run_queue = !subscriber_queue.length;
454
+ for (const subscriber of subscribers) {
455
+ subscriber[1]();
456
+ subscriber_queue.push(subscriber, value);
457
+ }
458
+ if (run_queue) {
459
+ for (let i = 0; i < subscriber_queue.length; i += 2) {
460
+ subscriber_queue[i][0](subscriber_queue[i + 1]);
461
+ }
462
+ subscriber_queue.length = 0;
463
+ }
464
+ }
465
+ }
466
+ }
467
+ function update(fn) {
468
+ set(fn(value));
469
+ }
470
+ function subscribe(run, invalidate = noop) {
471
+ const subscriber = [run, invalidate];
472
+ subscribers.add(subscriber);
473
+ if (subscribers.size === 1) {
474
+ stop = start(set) || noop;
475
+ }
476
+ run(value);
477
+ return () => {
478
+ subscribers.delete(subscriber);
479
+ if (subscribers.size === 0) {
480
+ stop();
481
+ stop = null;
482
+ }
483
+ };
484
+ }
485
+ return { set, update, subscribe };
486
+ }
487
+
488
+ /** @param {URL} url */
489
+ function create_prerendering_url_proxy(url) {
490
+ return new Proxy(url, {
491
+ get: (target, prop, receiver) => {
492
+ if (prop === 'search' || prop === 'searchParams') {
493
+ throw new Error(`Cannot access url.${prop} on a page with prerendering enabled`);
494
+ }
495
+ return Reflect.get(target, prop, receiver);
496
+ }
497
+ });
498
+ }
499
+
500
+ // TODO rename this function/module
501
+
502
+ /**
503
+ * @param {{
504
+ * branch: Array<import('./types').Loaded>;
505
+ * options: import('types/internal').SSRRenderOptions;
506
+ * state: import('types/internal').SSRRenderState;
507
+ * $session: any;
508
+ * page_config: { hydrate: boolean, router: boolean };
509
+ * status: number;
510
+ * error?: Error;
511
+ * url: URL;
512
+ * params: Record<string, string>;
513
+ * ssr: boolean;
514
+ * stuff: Record<string, any>;
515
+ * }} opts
516
+ */
517
+ async function render_response({
518
+ branch,
519
+ options,
520
+ state,
521
+ $session,
522
+ page_config,
523
+ status,
524
+ error,
525
+ url,
526
+ params,
527
+ ssr,
528
+ stuff
529
+ }) {
530
+ const css = new Set(options.manifest._.entry.css);
531
+ const js = new Set(options.manifest._.entry.js);
532
+ /** @type {Map<string, string>} */
533
+ const styles = new Map();
534
+
535
+ /** @type {Array<{ url: string, body: string, json: string }>} */
536
+ const serialized_data = [];
537
+
538
+ let rendered;
539
+
540
+ let is_private = false;
541
+ let maxage;
542
+
543
+ if (error) {
544
+ error.stack = options.get_stack(error);
545
+ }
546
+
547
+ if (ssr) {
548
+ branch.forEach(({ node, loaded, fetched, uses_credentials }) => {
549
+ if (node.css) node.css.forEach((url) => css.add(url));
550
+ if (node.js) node.js.forEach((url) => js.add(url));
551
+ if (node.styles) Object.entries(node.styles).forEach(([k, v]) => styles.set(k, v));
552
+
553
+ // TODO probably better if `fetched` wasn't populated unless `hydrate`
554
+ if (fetched && page_config.hydrate) serialized_data.push(...fetched);
555
+
556
+ if (uses_credentials) is_private = true;
557
+
558
+ maxage = loaded.maxage;
559
+ });
560
+
561
+ const session = writable($session);
562
+
563
+ /** @type {Record<string, any>} */
564
+ const props = {
565
+ stores: {
566
+ page: writable(null),
567
+ navigating: writable(null),
568
+ session
569
+ },
570
+ page: {
571
+ url: state.prerender ? create_prerendering_url_proxy(url) : url,
572
+ params,
573
+ status,
574
+ error,
575
+ stuff
576
+ },
577
+ components: branch.map(({ node }) => node.module.default)
578
+ };
579
+
580
+ // TODO remove this for 1.0
581
+ /**
582
+ * @param {string} property
583
+ * @param {string} replacement
584
+ */
585
+ const print_error = (property, replacement) => {
586
+ Object.defineProperty(props.page, property, {
587
+ get: () => {
588
+ throw new Error(`$page.${property} has been replaced by $page.url.${replacement}`);
589
+ }
590
+ });
591
+ };
592
+
593
+ print_error('origin', 'origin');
594
+ print_error('path', 'pathname');
595
+ print_error('query', 'searchParams');
596
+
597
+ // props_n (instead of props[n]) makes it easy to avoid
598
+ // unnecessary updates for layout components
599
+ for (let i = 0; i < branch.length; i += 1) {
600
+ props[`props_${i}`] = await branch[i].loaded.props;
601
+ }
602
+
603
+ let session_tracking_active = false;
604
+ const unsubscribe = session.subscribe(() => {
605
+ if (session_tracking_active) is_private = true;
606
+ });
607
+ session_tracking_active = true;
608
+
609
+ try {
610
+ rendered = options.root.render(props);
611
+ } finally {
612
+ unsubscribe();
613
+ }
614
+ } else {
615
+ rendered = { head: '', html: '', css: { code: '', map: null } };
616
+ }
617
+
618
+ let { head, html: body } = rendered;
619
+
620
+ const inlined_style = Array.from(styles.values()).join('\n');
621
+
622
+ if (state.prerender) {
623
+ if (maxage) {
624
+ head += `<meta http-equiv="cache-control" content="max-age=${maxage}">`;
625
+ }
626
+ }
627
+
628
+ if (options.amp) {
629
+ head += `
630
+ <style amp-boilerplate>body{-webkit-animation:-amp-start 8s steps(1,end) 0s 1 normal both;-moz-animation:-amp-start 8s steps(1,end) 0s 1 normal both;-ms-animation:-amp-start 8s steps(1,end) 0s 1 normal both;animation:-amp-start 8s steps(1,end) 0s 1 normal both}@-webkit-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-moz-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-ms-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-o-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}</style>
631
+ <noscript><style amp-boilerplate>body{-webkit-animation:none;-moz-animation:none;-ms-animation:none;animation:none}</style></noscript>
632
+ <script async src="https://cdn.ampproject.org/v0.js"></script>
633
+
634
+ <style amp-custom>${inlined_style}\n${rendered.css.code}</style>`;
635
+
636
+ if (options.service_worker) {
637
+ head +=
638
+ '<script async custom-element="amp-install-serviceworker" src="https://cdn.ampproject.org/v0/amp-install-serviceworker-0.1.js"></script>';
639
+
640
+ body += `<amp-install-serviceworker src="${options.service_worker}" layout="nodisplay"></amp-install-serviceworker>`;
641
+ }
642
+ } else {
643
+ if (inlined_style) {
644
+ head += `\n\t<style${options.dev ? ' data-svelte' : ''}>${inlined_style}</style>`;
645
+ }
646
+ // prettier-ignore
647
+ head += Array.from(css)
648
+ .map((dep) => `\n\t<link${styles.has(dep) ? ' disabled media="(max-width: 0)"' : ''} rel="stylesheet" href="${options.prefix + dep}">`)
649
+ .join('');
650
+
651
+ if (page_config.router || page_config.hydrate) {
652
+ head += Array.from(js)
653
+ .map((dep) => `\n\t<link rel="modulepreload" href="${options.prefix + dep}">`)
654
+ .join('');
655
+ // prettier-ignore
656
+ head += `
657
+ <script type="module">
658
+ import { start } from ${s(options.prefix + options.manifest._.entry.file)};
659
+ start({
660
+ target: ${options.target ? `document.querySelector(${s(options.target)})` : 'document.body'},
661
+ paths: ${s(options.paths)},
662
+ session: ${try_serialize($session, (error) => {
663
+ throw new Error(`Failed to serialize session data: ${error.message}`);
664
+ })},
665
+ route: ${!!page_config.router},
666
+ spa: ${!ssr},
667
+ trailing_slash: ${s(options.trailing_slash)},
668
+ hydrate: ${ssr && page_config.hydrate ? `{
669
+ status: ${status},
670
+ error: ${serialize_error(error)},
671
+ nodes: [
672
+ ${(branch || [])
673
+ .map(({ node }) => `import(${s(options.prefix + node.entry)})`)
674
+ .join(',\n\t\t\t\t\t\t')}
675
+ ],
676
+ url: new URL(${s(url.href)}),
677
+ params: ${devalue(params)}
678
+ }` : 'null'}
679
+ });
680
+ </script>`;
681
+
682
+ body += serialized_data
683
+ .map(({ url, body, json }) => {
684
+ let attributes = `type="application/json" data-type="svelte-data" data-url=${escape_html_attr(
685
+ url
686
+ )}`;
687
+ if (body) attributes += ` data-body="${hash(body)}"`;
688
+
689
+ return `<script ${attributes}>${json}</script>`;
690
+ })
691
+ .join('\n\n\t');
692
+ }
693
+
694
+ if (options.service_worker) {
695
+ // always include service worker unless it's turned off explicitly
696
+ head += `
697
+ <script>
698
+ if ('serviceWorker' in navigator) {
699
+ navigator.serviceWorker.register('${options.service_worker}');
700
+ }
701
+ </script>`;
702
+ }
703
+ }
704
+
705
+ const segments = url.pathname.slice(options.paths.base.length).split('/').slice(2);
706
+ const assets =
707
+ options.paths.assets || (segments.length > 0 ? segments.map(() => '..').join('/') : '.');
708
+
709
+ const html = options.template({ head, body, assets });
710
+
711
+ const headers = new Headers({
712
+ 'content-type': 'text/html',
713
+ etag: `"${hash(html)}"`
714
+ });
715
+
716
+ if (maxage) {
717
+ headers.set('cache-control', `${is_private ? 'private' : 'public'}, max-age=${maxage}`);
718
+ }
719
+
720
+ if (!options.floc) {
721
+ headers.set('permissions-policy', 'interest-cohort=()');
722
+ }
723
+
724
+ return new Response(html, {
725
+ status,
726
+ headers
727
+ });
728
+ }
729
+
730
+ /**
731
+ * @param {any} data
732
+ * @param {(error: Error) => void} [fail]
733
+ */
734
+ function try_serialize(data, fail) {
735
+ try {
736
+ return devalue(data);
737
+ } catch (err) {
738
+ if (fail) fail(coalesce_to_error(err));
739
+ return null;
740
+ }
741
+ }
742
+
743
+ // Ensure we return something truthy so the client will not re-render the page over the error
744
+
745
+ /** @param {(Error & {frame?: string} & {loc?: object}) | undefined | null} error */
746
+ function serialize_error(error) {
747
+ if (!error) return null;
748
+ let serialized = try_serialize(error);
749
+ if (!serialized) {
750
+ const { name, message, stack } = error;
751
+ serialized = try_serialize({ ...error, name, message, stack });
752
+ }
753
+ if (!serialized) {
754
+ serialized = '{}';
755
+ }
756
+ return serialized;
757
+ }
758
+
759
+ /**
760
+ * @param {import('types/page').LoadOutput} loaded
761
+ * @returns {import('types/internal').NormalizedLoadOutput}
762
+ */
763
+ function normalize(loaded) {
764
+ const has_error_status =
765
+ loaded.status && loaded.status >= 400 && loaded.status <= 599 && !loaded.redirect;
766
+ if (loaded.error || has_error_status) {
767
+ const status = loaded.status;
768
+
769
+ if (!loaded.error && has_error_status) {
770
+ return {
771
+ status: status || 500,
772
+ error: new Error()
773
+ };
774
+ }
775
+
776
+ const error = typeof loaded.error === 'string' ? new Error(loaded.error) : loaded.error;
777
+
778
+ if (!(error instanceof Error)) {
779
+ return {
780
+ status: 500,
781
+ error: new Error(
782
+ `"error" property returned from load() must be a string or instance of Error, received type "${typeof error}"`
783
+ )
784
+ };
785
+ }
786
+
787
+ if (!status || status < 400 || status > 599) {
788
+ console.warn('"error" returned from load() without a valid status code — defaulting to 500');
789
+ return { status: 500, error };
790
+ }
791
+
792
+ return { status, error };
793
+ }
794
+
795
+ if (loaded.redirect) {
796
+ if (!loaded.status || Math.floor(loaded.status / 100) !== 3) {
797
+ return {
798
+ status: 500,
799
+ error: new Error(
800
+ '"redirect" property returned from load() must be accompanied by a 3xx status code'
801
+ )
802
+ };
803
+ }
804
+
805
+ if (typeof loaded.redirect !== 'string') {
806
+ return {
807
+ status: 500,
808
+ error: new Error('"redirect" property returned from load() must be a string')
809
+ };
810
+ }
811
+ }
812
+
813
+ // TODO remove before 1.0
814
+ if (/** @type {any} */ (loaded).context) {
815
+ throw new Error(
816
+ 'You are returning "context" from a load function. ' +
817
+ '"context" was renamed to "stuff", please adjust your code accordingly.'
818
+ );
819
+ }
820
+
821
+ return /** @type {import('types/internal').NormalizedLoadOutput} */ (loaded);
822
+ }
823
+
824
+ /**
825
+ * @param {{
826
+ * event: import('types/hooks').RequestEvent;
827
+ * options: import('types/internal').SSRRenderOptions;
828
+ * state: import('types/internal').SSRRenderState;
829
+ * route: import('types/internal').SSRPage | null;
830
+ * url: URL;
831
+ * params: Record<string, string>;
832
+ * node: import('types/internal').SSRNode;
833
+ * $session: any;
834
+ * stuff: Record<string, any>;
835
+ * is_error: boolean;
836
+ * status?: number;
837
+ * error?: Error;
838
+ * }} opts
839
+ * @returns {Promise<import('./types').Loaded | undefined>} undefined for fallthrough
840
+ */
841
+ async function load_node({
842
+ event,
843
+ options,
844
+ state,
845
+ route,
846
+ url,
847
+ params,
848
+ node,
849
+ $session,
850
+ stuff,
851
+ is_error,
852
+ status,
853
+ error
854
+ }) {
855
+ const { module } = node;
856
+
857
+ let uses_credentials = false;
858
+
859
+ /**
860
+ * @type {Array<{
861
+ * url: string;
862
+ * body: string;
863
+ * json: string;
864
+ * }>}
865
+ */
866
+ const fetched = [];
867
+
868
+ /**
869
+ * @type {string[]}
870
+ */
871
+ let set_cookie_headers = [];
872
+
873
+ let loaded;
874
+
875
+ if (module.load) {
876
+ /** @type {import('types/page').LoadInput | import('types/page').ErrorLoadInput} */
877
+ const load_input = {
878
+ url: state.prerender ? create_prerendering_url_proxy(url) : url,
879
+ params,
880
+ get session() {
881
+ uses_credentials = true;
882
+ return $session;
883
+ },
884
+ /**
885
+ * @param {RequestInfo} resource
886
+ * @param {RequestInit} opts
887
+ */
888
+ fetch: async (resource, opts = {}) => {
889
+ /** @type {string} */
890
+ let requested;
891
+
892
+ if (typeof resource === 'string') {
893
+ requested = resource;
894
+ } else {
895
+ requested = resource.url;
896
+
897
+ opts = {
898
+ method: resource.method,
899
+ headers: resource.headers,
900
+ body: resource.body,
901
+ mode: resource.mode,
902
+ credentials: resource.credentials,
903
+ cache: resource.cache,
904
+ redirect: resource.redirect,
905
+ referrer: resource.referrer,
906
+ integrity: resource.integrity,
907
+ ...opts
908
+ };
909
+ }
910
+
911
+ opts.headers = new Headers(opts.headers);
912
+
913
+ const resolved = resolve(event.url.pathname, requested.split('?')[0]);
914
+
915
+ /** @type {Response} */
916
+ let response;
917
+
918
+ // handle fetch requests for static assets. e.g. prebaked data, etc.
919
+ // we need to support everything the browser's fetch supports
920
+ const prefix = options.paths.assets || options.paths.base;
921
+ const filename = (
922
+ resolved.startsWith(prefix) ? resolved.slice(prefix.length) : resolved
923
+ ).slice(1);
924
+ const filename_html = `${filename}/index.html`; // path may also match path/index.html
925
+
926
+ const is_asset = options.manifest.assets.has(filename);
927
+ const is_asset_html = options.manifest.assets.has(filename_html);
928
+
929
+ if (is_asset || is_asset_html) {
930
+ const file = is_asset ? filename : filename_html;
931
+
932
+ if (options.read) {
933
+ const type = is_asset
934
+ ? options.manifest._.mime[filename.slice(filename.lastIndexOf('.'))]
935
+ : 'text/html';
936
+
937
+ response = new Response(options.read(file), {
938
+ headers: type ? { 'content-type': type } : {}
939
+ });
940
+ } else {
941
+ response = await fetch(`${url.origin}/${file}`, /** @type {RequestInit} */ (opts));
942
+ }
943
+ } else if (is_root_relative(resolved)) {
944
+ const relative = resolved;
945
+
946
+ if (opts.credentials !== 'omit') {
947
+ uses_credentials = true;
948
+
949
+ const cookie = event.request.headers.get('cookie');
950
+ const authorization = event.request.headers.get('authorization');
951
+
952
+ if (cookie) {
953
+ opts.headers.set('cookie', cookie);
954
+ }
955
+
956
+ if (authorization && !opts.headers.has('authorization')) {
957
+ opts.headers.set('authorization', authorization);
958
+ }
959
+ }
960
+
961
+ if (opts.body && typeof opts.body !== 'string') {
962
+ // per https://developer.mozilla.org/en-US/docs/Web/API/Request/Request, this can be a
963
+ // Blob, BufferSource, FormData, URLSearchParams, USVString, or ReadableStream object.
964
+ // non-string bodies are irksome to deal with, but luckily aren't particularly useful
965
+ // in this context anyway, so we take the easy route and ban them
966
+ throw new Error('Request body must be a string');
967
+ }
968
+
969
+ const rendered = await respond(
970
+ new Request(new URL(requested, event.url).href, opts),
971
+ options,
972
+ {
973
+ fetched: requested,
974
+ initiator: route
975
+ }
976
+ );
977
+
978
+ if (rendered) {
979
+ if (state.prerender) {
980
+ state.prerender.dependencies.set(relative, rendered);
981
+ }
982
+
983
+ response = rendered;
984
+ } else {
985
+ // we can't load the endpoint from our own manifest,
986
+ // so we need to make an actual HTTP request
987
+ response = await fetch(new URL(requested, event.url).href, {
988
+ method: opts.method || 'GET',
989
+ headers: opts.headers
990
+ });
991
+ }
992
+ } else {
993
+ // external
994
+ if (resolved.startsWith('//')) {
995
+ throw new Error(
996
+ `Cannot request protocol-relative URL (${requested}) in server-side fetch`
997
+ );
998
+ }
999
+
1000
+ // external fetch
1001
+ // allow cookie passthrough for "same-origin"
1002
+ // if SvelteKit is serving my.domain.com:
1003
+ // - domain.com WILL NOT receive cookies
1004
+ // - my.domain.com WILL receive cookies
1005
+ // - api.domain.dom WILL NOT receive cookies
1006
+ // - sub.my.domain.com WILL receive cookies
1007
+ // ports do not affect the resolution
1008
+ // leading dot prevents mydomain.com matching domain.com
1009
+ if (
1010
+ `.${new URL(requested).hostname}`.endsWith(`.${event.url.hostname}`) &&
1011
+ opts.credentials !== 'omit'
1012
+ ) {
1013
+ uses_credentials = true;
1014
+
1015
+ const cookie = event.request.headers.get('cookie');
1016
+ if (cookie) opts.headers.set('cookie', cookie);
1017
+ }
1018
+
1019
+ const external_request = new Request(requested, /** @type {RequestInit} */ (opts));
1020
+ response = await options.hooks.externalFetch.call(null, external_request);
1021
+ }
1022
+
1023
+ if (response) {
1024
+ const proxy = new Proxy(response, {
1025
+ get(response, key, _receiver) {
1026
+ async function text() {
1027
+ const body = await response.text();
1028
+
1029
+ /** @type {import('types/helper').ResponseHeaders} */
1030
+ const headers = {};
1031
+ for (const [key, value] of response.headers) {
1032
+ if (key === 'set-cookie') {
1033
+ set_cookie_headers = set_cookie_headers.concat(value);
1034
+ } else if (key !== 'etag') {
1035
+ headers[key] = value;
1036
+ }
1037
+ }
1038
+
1039
+ if (!opts.body || typeof opts.body === 'string') {
1040
+ // prettier-ignore
1041
+ fetched.push({
1042
+ url: requested,
1043
+ body: /** @type {string} */ (opts.body),
1044
+ json: `{"status":${response.status},"statusText":${s(response.statusText)},"headers":${s(headers)},"body":"${escape_json_string_in_html(body)}"}`
1045
+ });
1046
+ }
1047
+
1048
+ return body;
1049
+ }
1050
+
1051
+ if (key === 'text') {
1052
+ return text;
1053
+ }
1054
+
1055
+ if (key === 'json') {
1056
+ return async () => {
1057
+ return JSON.parse(await text());
1058
+ };
1059
+ }
1060
+
1061
+ // TODO arrayBuffer?
1062
+
1063
+ return Reflect.get(response, key, response);
1064
+ }
1065
+ });
1066
+
1067
+ return proxy;
1068
+ }
1069
+
1070
+ return (
1071
+ response ||
1072
+ new Response('Not found', {
1073
+ status: 404
1074
+ })
1075
+ );
1076
+ },
1077
+ stuff: { ...stuff }
1078
+ };
1079
+
1080
+ if (options.dev) {
1081
+ // TODO remove this for 1.0
1082
+ Object.defineProperty(load_input, 'page', {
1083
+ get: () => {
1084
+ throw new Error('`page` in `load` functions has been replaced by `url` and `params`');
1085
+ }
1086
+ });
1087
+ }
1088
+
1089
+ if (is_error) {
1090
+ /** @type {import('types/page').ErrorLoadInput} */ (load_input).status = status;
1091
+ /** @type {import('types/page').ErrorLoadInput} */ (load_input).error = error;
1092
+ }
1093
+
1094
+ loaded = await module.load.call(null, load_input);
1095
+
1096
+ if (!loaded) {
1097
+ throw new Error(`load function must return a value${options.dev ? ` (${node.entry})` : ''}`);
1098
+ }
1099
+ } else {
1100
+ loaded = {};
1101
+ }
1102
+
1103
+ if (loaded.fallthrough && !is_error) {
1104
+ return;
1105
+ }
1106
+
1107
+ return {
1108
+ node,
1109
+ loaded: normalize(loaded),
1110
+ stuff: loaded.stuff || stuff,
1111
+ fetched,
1112
+ set_cookie_headers,
1113
+ uses_credentials
1114
+ };
1115
+ }
1116
+
1117
+ /**
1118
+ * @typedef {import('./types.js').Loaded} Loaded
1119
+ * @typedef {import('types/internal').SSRRenderOptions} SSRRenderOptions
1120
+ * @typedef {import('types/internal').SSRRenderState} SSRRenderState
1121
+ */
1122
+
1123
+ /**
1124
+ * @param {{
1125
+ * event: import('types/hooks').RequestEvent;
1126
+ * options: SSRRenderOptions;
1127
+ * state: SSRRenderState;
1128
+ * $session: any;
1129
+ * status: number;
1130
+ * error: Error;
1131
+ * ssr: boolean;
1132
+ * }} opts
1133
+ */
1134
+ async function respond_with_error({ event, options, state, $session, status, error, ssr }) {
1135
+ try {
1136
+ const default_layout = await options.manifest._.nodes[0](); // 0 is always the root layout
1137
+ const default_error = await options.manifest._.nodes[1](); // 1 is always the root error
1138
+
1139
+ /** @type {Record<string, string>} */
1140
+ const params = {}; // error page has no params
1141
+
1142
+ const layout_loaded = /** @type {Loaded} */ (
1143
+ await load_node({
1144
+ event,
1145
+ options,
1146
+ state,
1147
+ route: null,
1148
+ url: event.url, // TODO this is redundant, no?
1149
+ params,
1150
+ node: default_layout,
1151
+ $session,
1152
+ stuff: {},
1153
+ is_error: false
1154
+ })
1155
+ );
1156
+
1157
+ const error_loaded = /** @type {Loaded} */ (
1158
+ await load_node({
1159
+ event,
1160
+ options,
1161
+ state,
1162
+ route: null,
1163
+ url: event.url,
1164
+ params,
1165
+ node: default_error,
1166
+ $session,
1167
+ stuff: layout_loaded ? layout_loaded.stuff : {},
1168
+ is_error: true,
1169
+ status,
1170
+ error
1171
+ })
1172
+ );
1173
+
1174
+ return await render_response({
1175
+ options,
1176
+ state,
1177
+ $session,
1178
+ page_config: {
1179
+ hydrate: options.hydrate,
1180
+ router: options.router
1181
+ },
1182
+ stuff: error_loaded.stuff,
1183
+ status,
1184
+ error,
1185
+ branch: [layout_loaded, error_loaded],
1186
+ url: event.url,
1187
+ params,
1188
+ ssr
1189
+ });
1190
+ } catch (err) {
1191
+ const error = coalesce_to_error(err);
1192
+
1193
+ options.handle_error(error, event);
1194
+
1195
+ return new Response(error.stack, {
1196
+ status: 500
1197
+ });
1198
+ }
1199
+ }
1200
+
1201
+ /**
1202
+ * @typedef {import('./types.js').Loaded} Loaded
1203
+ * @typedef {import('types/internal').SSRNode} SSRNode
1204
+ * @typedef {import('types/internal').SSRRenderOptions} SSRRenderOptions
1205
+ * @typedef {import('types/internal').SSRRenderState} SSRRenderState
1206
+ */
1207
+
1208
+ /**
1209
+ * @param {{
1210
+ * event: import('types/hooks').RequestEvent;
1211
+ * options: SSRRenderOptions;
1212
+ * state: SSRRenderState;
1213
+ * $session: any;
1214
+ * route: import('types/internal').SSRPage;
1215
+ * params: Record<string, string>;
1216
+ * ssr: boolean;
1217
+ * }} opts
1218
+ * @returns {Promise<Response | undefined>}
1219
+ */
1220
+ async function respond$1(opts) {
1221
+ const { event, options, state, $session, route, ssr } = opts;
1222
+
1223
+ /** @type {Array<SSRNode | undefined>} */
1224
+ let nodes;
1225
+
1226
+ if (!ssr) {
1227
+ return await render_response({
1228
+ ...opts,
1229
+ branch: [],
1230
+ page_config: {
1231
+ hydrate: true,
1232
+ router: true
1233
+ },
1234
+ status: 200,
1235
+ url: event.url,
1236
+ stuff: {}
1237
+ });
1238
+ }
1239
+
1240
+ try {
1241
+ nodes = await Promise.all(
1242
+ route.a.map((n) => options.manifest._.nodes[n] && options.manifest._.nodes[n]())
1243
+ );
1244
+ } catch (err) {
1245
+ const error = coalesce_to_error(err);
1246
+
1247
+ options.handle_error(error, event);
1248
+
1249
+ return await respond_with_error({
1250
+ event,
1251
+ options,
1252
+ state,
1253
+ $session,
1254
+ status: 500,
1255
+ error,
1256
+ ssr
1257
+ });
1258
+ }
1259
+
1260
+ // the leaf node will be present. only layouts may be undefined
1261
+ const leaf = /** @type {SSRNode} */ (nodes[nodes.length - 1]).module;
1262
+
1263
+ let page_config = get_page_config(leaf, options);
1264
+
1265
+ if (!leaf.prerender && state.prerender && !state.prerender.all) {
1266
+ // if the page has `export const prerender = true`, continue,
1267
+ // otherwise bail out at this point
1268
+ return new Response(undefined, {
1269
+ status: 204
1270
+ });
1271
+ }
1272
+
1273
+ /** @type {Array<Loaded>} */
1274
+ let branch = [];
1275
+
1276
+ /** @type {number} */
1277
+ let status = 200;
1278
+
1279
+ /** @type {Error|undefined} */
1280
+ let error;
1281
+
1282
+ /** @type {string[]} */
1283
+ let set_cookie_headers = [];
1284
+
1285
+ let stuff = {};
1286
+
1287
+ ssr: if (ssr) {
1288
+ for (let i = 0; i < nodes.length; i += 1) {
1289
+ const node = nodes[i];
1290
+
1291
+ /** @type {Loaded | undefined} */
1292
+ let loaded;
1293
+
1294
+ if (node) {
1295
+ try {
1296
+ loaded = await load_node({
1297
+ ...opts,
1298
+ url: event.url,
1299
+ node,
1300
+ stuff,
1301
+ is_error: false
1302
+ });
1303
+
1304
+ if (!loaded) return;
1305
+
1306
+ set_cookie_headers = set_cookie_headers.concat(loaded.set_cookie_headers);
1307
+
1308
+ if (loaded.loaded.redirect) {
1309
+ return with_cookies(
1310
+ new Response(undefined, {
1311
+ status: loaded.loaded.status,
1312
+ headers: {
1313
+ location: loaded.loaded.redirect
1314
+ }
1315
+ }),
1316
+ set_cookie_headers
1317
+ );
1318
+ }
1319
+
1320
+ if (loaded.loaded.error) {
1321
+ ({ status, error } = loaded.loaded);
1322
+ }
1323
+ } catch (err) {
1324
+ const e = coalesce_to_error(err);
1325
+
1326
+ options.handle_error(e, event);
1327
+
1328
+ status = 500;
1329
+ error = e;
1330
+ }
1331
+
1332
+ if (loaded && !error) {
1333
+ branch.push(loaded);
1334
+ }
1335
+
1336
+ if (error) {
1337
+ while (i--) {
1338
+ if (route.b[i]) {
1339
+ const error_node = await options.manifest._.nodes[route.b[i]]();
1340
+
1341
+ /** @type {Loaded} */
1342
+ let node_loaded;
1343
+ let j = i;
1344
+ while (!(node_loaded = branch[j])) {
1345
+ j -= 1;
1346
+ }
1347
+
1348
+ try {
1349
+ const error_loaded = /** @type {import('./types').Loaded} */ (
1350
+ await load_node({
1351
+ ...opts,
1352
+ url: event.url,
1353
+ node: error_node,
1354
+ stuff: node_loaded.stuff,
1355
+ is_error: true,
1356
+ status,
1357
+ error
1358
+ })
1359
+ );
1360
+
1361
+ if (error_loaded.loaded.error) {
1362
+ continue;
1363
+ }
1364
+
1365
+ page_config = get_page_config(error_node.module, options);
1366
+ branch = branch.slice(0, j + 1).concat(error_loaded);
1367
+ stuff = { ...node_loaded.stuff, ...error_loaded.stuff };
1368
+ break ssr;
1369
+ } catch (err) {
1370
+ const e = coalesce_to_error(err);
1371
+
1372
+ options.handle_error(e, event);
1373
+
1374
+ continue;
1375
+ }
1376
+ }
1377
+ }
1378
+
1379
+ // TODO backtrack until we find an __error.svelte component
1380
+ // that we can use as the leaf node
1381
+ // for now just return regular error page
1382
+ return with_cookies(
1383
+ await respond_with_error({
1384
+ event,
1385
+ options,
1386
+ state,
1387
+ $session,
1388
+ status,
1389
+ error,
1390
+ ssr
1391
+ }),
1392
+ set_cookie_headers
1393
+ );
1394
+ }
1395
+ }
1396
+
1397
+ if (loaded && loaded.loaded.stuff) {
1398
+ stuff = {
1399
+ ...stuff,
1400
+ ...loaded.loaded.stuff
1401
+ };
1402
+ }
1403
+ }
1404
+ }
1405
+
1406
+ try {
1407
+ return with_cookies(
1408
+ await render_response({
1409
+ ...opts,
1410
+ stuff,
1411
+ url: event.url,
1412
+ page_config,
1413
+ status,
1414
+ error,
1415
+ branch: branch.filter(Boolean)
1416
+ }),
1417
+ set_cookie_headers
1418
+ );
1419
+ } catch (err) {
1420
+ const error = coalesce_to_error(err);
1421
+
1422
+ options.handle_error(error, event);
1423
+
1424
+ return with_cookies(
1425
+ await respond_with_error({
1426
+ ...opts,
1427
+ status: 500,
1428
+ error
1429
+ }),
1430
+ set_cookie_headers
1431
+ );
1432
+ }
1433
+ }
1434
+
1435
+ /**
1436
+ * @param {import('types/internal').SSRComponent} leaf
1437
+ * @param {SSRRenderOptions} options
1438
+ */
1439
+ function get_page_config(leaf, options) {
1440
+ // TODO remove for 1.0
1441
+ if ('ssr' in leaf) {
1442
+ throw new Error(
1443
+ '`export const ssr` has been removed — use the handle hook instead: https://kit.svelte.dev/docs#hooks-handle'
1444
+ );
1445
+ }
1446
+
1447
+ return {
1448
+ router: 'router' in leaf ? !!leaf.router : options.router,
1449
+ hydrate: 'hydrate' in leaf ? !!leaf.hydrate : options.hydrate
1450
+ };
1451
+ }
1452
+
1453
+ /**
1454
+ * @param {Response} response
1455
+ * @param {string[]} set_cookie_headers
1456
+ */
1457
+ function with_cookies(response, set_cookie_headers) {
1458
+ if (set_cookie_headers.length) {
1459
+ set_cookie_headers.forEach((value) => {
1460
+ response.headers.append('set-cookie', value);
1461
+ });
1462
+ }
1463
+ return response;
1464
+ }
1465
+
1466
+ /**
1467
+ * @param {import('types/hooks').RequestEvent} event
1468
+ * @param {import('types/internal').SSRPage} route
1469
+ * @param {RegExpExecArray} match
1470
+ * @param {import('types/internal').SSRRenderOptions} options
1471
+ * @param {import('types/internal').SSRRenderState} state
1472
+ * @param {boolean} ssr
1473
+ * @returns {Promise<Response | undefined>}
1474
+ */
1475
+ async function render_page(event, route, match, options, state, ssr) {
1476
+ if (state.initiator === route) {
1477
+ // infinite request cycle detected
1478
+ return new Response(`Not found: ${event.url.pathname}`, {
1479
+ status: 404
1480
+ });
1481
+ }
1482
+
1483
+ const params = route.params ? decode_params(route.params(match)) : {};
1484
+
1485
+ const $session = await options.hooks.getSession(event);
1486
+
1487
+ const response = await respond$1({
1488
+ event,
1489
+ options,
1490
+ state,
1491
+ $session,
1492
+ route,
1493
+ params,
1494
+ ssr
1495
+ });
1496
+
1497
+ if (response) {
1498
+ return response;
1499
+ }
1500
+
1501
+ if (state.fetched) {
1502
+ // we came here because of a bad request in a `load` function.
1503
+ // rather than render the error page — which could lead to an
1504
+ // infinite loop, if the `load` belonged to the root layout,
1505
+ // we respond with a bare-bones 500
1506
+ return new Response(`Bad request in load function: failed to fetch ${state.fetched}`, {
1507
+ status: 500
1508
+ });
1509
+ }
1510
+ }
1511
+
1512
+ /** @type {import('types/internal').Respond} */
1513
+ async function respond(request, options, state = {}) {
1514
+ const url = new URL(request.url);
1515
+
1516
+ if (url.pathname !== '/' && options.trailing_slash !== 'ignore') {
1517
+ const has_trailing_slash = url.pathname.endsWith('/');
1518
+
1519
+ if (
1520
+ (has_trailing_slash && options.trailing_slash === 'never') ||
1521
+ (!has_trailing_slash &&
1522
+ options.trailing_slash === 'always' &&
1523
+ !(url.pathname.split('/').pop() || '').includes('.'))
1524
+ ) {
1525
+ url.pathname = has_trailing_slash ? url.pathname.slice(0, -1) : url.pathname + '/';
1526
+
1527
+ if (url.search === '?') url.search = '';
1528
+
1529
+ return new Response(undefined, {
1530
+ status: 301,
1531
+ headers: {
1532
+ location: url.pathname + url.search
1533
+ }
1534
+ });
1535
+ }
1536
+ }
1537
+
1538
+ const { parameter, allowed } = options.method_override;
1539
+ const method_override = url.searchParams.get(parameter)?.toUpperCase();
1540
+
1541
+ if (method_override) {
1542
+ if (request.method === 'POST') {
1543
+ if (allowed.includes(method_override)) {
1544
+ request = new Proxy(request, {
1545
+ get: (target, property, _receiver) => {
1546
+ if (property === 'method') return method_override;
1547
+ return Reflect.get(target, property, target);
1548
+ }
1549
+ });
1550
+ } else {
1551
+ const verb = allowed.length === 0 ? 'enabled' : 'allowed';
1552
+ const body = `${parameter}=${method_override} is not ${verb}. See https://kit.svelte.dev/docs#configuration-methodoverride`;
1553
+
1554
+ return new Response(body, {
1555
+ status: 400
1556
+ });
1557
+ }
1558
+ } else {
1559
+ throw new Error(`${parameter}=${method_override} is only allowed with POST requests`);
1560
+ }
1561
+ }
1562
+
1563
+ /** @type {import('types/hooks').RequestEvent} */
1564
+ const event = {
1565
+ request,
1566
+ url,
1567
+ params: {},
1568
+ locals: {}
1569
+ };
1570
+
1571
+ // TODO remove this for 1.0
1572
+ /**
1573
+ * @param {string} property
1574
+ * @param {string} replacement
1575
+ * @param {string} suffix
1576
+ */
1577
+ const removed = (property, replacement, suffix = '') => ({
1578
+ get: () => {
1579
+ throw new Error(`event.${property} has been replaced by event.${replacement}` + suffix);
1580
+ }
1581
+ });
1582
+
1583
+ const details = '. See https://github.com/sveltejs/kit/pull/3384 for details';
1584
+
1585
+ const body_getter = {
1586
+ get: () => {
1587
+ throw new Error(
1588
+ 'To access the request body use the text/json/arrayBuffer/formData methods, e.g. `body = await request.json()`' +
1589
+ details
1590
+ );
1591
+ }
1592
+ };
1593
+
1594
+ Object.defineProperties(event, {
1595
+ method: removed('method', 'request.method', details),
1596
+ headers: removed('headers', 'request.headers', details),
1597
+ origin: removed('origin', 'url.origin'),
1598
+ path: removed('path', 'url.pathname'),
1599
+ query: removed('query', 'url.searchParams'),
1600
+ body: body_getter,
1601
+ rawBody: body_getter
1602
+ });
1603
+
1604
+ let ssr = true;
1605
+
1606
+ try {
1607
+ const response = await options.hooks.handle({
1608
+ event,
1609
+ resolve: async (event, opts) => {
1610
+ if (opts && 'ssr' in opts) ssr = /** @type {boolean} */ (opts.ssr);
1611
+
1612
+ if (state.prerender && state.prerender.fallback) {
1613
+ return await render_response({
1614
+ url: event.url,
1615
+ params: event.params,
1616
+ options,
1617
+ state,
1618
+ $session: await options.hooks.getSession(event),
1619
+ page_config: { router: true, hydrate: true },
1620
+ stuff: {},
1621
+ status: 200,
1622
+ branch: [],
1623
+ ssr: false
1624
+ });
1625
+ }
1626
+
1627
+ let decoded = decodeURI(event.url.pathname);
1628
+
1629
+ if (options.paths.base) {
1630
+ if (!decoded.startsWith(options.paths.base)) return;
1631
+ decoded = decoded.slice(options.paths.base.length) || '/';
1632
+ }
1633
+
1634
+ for (const route of options.manifest._.routes) {
1635
+ const match = route.pattern.exec(decoded);
1636
+ if (!match) continue;
1637
+
1638
+ const response =
1639
+ route.type === 'endpoint'
1640
+ ? await render_endpoint(event, route, match)
1641
+ : await render_page(event, route, match, options, state, ssr);
1642
+
1643
+ if (response) {
1644
+ // respond with 304 if etag matches
1645
+ if (response.status === 200 && response.headers.has('etag')) {
1646
+ let if_none_match_value = request.headers.get('if-none-match');
1647
+
1648
+ // ignore W/ prefix https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/If-None-Match#directives
1649
+ if (if_none_match_value?.startsWith('W/"')) {
1650
+ if_none_match_value = if_none_match_value.substring(2);
1651
+ }
1652
+
1653
+ const etag = /** @type {string} */ (response.headers.get('etag'));
1654
+
1655
+ if (if_none_match_value === etag) {
1656
+ const headers = new Headers({ etag });
1657
+
1658
+ // https://datatracker.ietf.org/doc/html/rfc7232#section-4.1
1659
+ for (const key of [
1660
+ 'cache-control',
1661
+ 'content-location',
1662
+ 'date',
1663
+ 'expires',
1664
+ 'vary'
1665
+ ]) {
1666
+ const value = response.headers.get(key);
1667
+ if (value) headers.set(key, value);
1668
+ }
1669
+
1670
+ return new Response(undefined, {
1671
+ status: 304,
1672
+ headers
1673
+ });
1674
+ }
1675
+ }
1676
+
1677
+ return response;
1678
+ }
1679
+ }
1680
+
1681
+ // if this request came direct from the user, rather than
1682
+ // via a `fetch` in a `load`, render a 404 page
1683
+ if (!state.initiator) {
1684
+ const $session = await options.hooks.getSession(event);
1685
+ return await respond_with_error({
1686
+ event,
1687
+ options,
1688
+ state,
1689
+ $session,
1690
+ status: 404,
1691
+ error: new Error(`Not found: ${event.url.pathname}`),
1692
+ ssr
1693
+ });
1694
+ }
1695
+ },
1696
+
1697
+ // TODO remove for 1.0
1698
+ // @ts-expect-error
1699
+ get request() {
1700
+ throw new Error('request in handle has been replaced with event' + details);
1701
+ }
1702
+ });
1703
+
1704
+ // TODO for 1.0, change the error message to point to docs rather than PR
1705
+ if (response && !(response instanceof Response)) {
1706
+ throw new Error('handle must return a Response object' + details);
1707
+ }
1708
+
1709
+ return response;
1710
+ } catch (/** @type {unknown} */ e) {
1711
+ const error = coalesce_to_error(e);
1712
+
1713
+ options.handle_error(error, event);
1714
+
1715
+ try {
1716
+ const $session = await options.hooks.getSession(event);
1717
+ return await respond_with_error({
1718
+ event,
1719
+ options,
1720
+ state,
1721
+ $session,
1722
+ status: 500,
1723
+ error,
1724
+ ssr
1725
+ });
1726
+ } catch (/** @type {unknown} */ e) {
1727
+ const error = coalesce_to_error(e);
1728
+
1729
+ return new Response(options.dev ? error.stack : error.message, {
1730
+ status: 500
1731
+ });
1732
+ }
1733
+ }
1734
+ }
1735
+
1736
+ /**
1737
+ * @param {import('types/config').ValidatedConfig} config
1738
+ * @param {string} cwd
1739
+ * @returns {Promise<import('vite').Plugin>}
1740
+ */
1741
+ async function create_plugin(config, cwd) {
1742
+ /** @type {import('amphtml-validator').Validator} */
1743
+ let amp;
1744
+
1745
+ if (config.kit.amp) {
1746
+ process.env.VITE_SVELTEKIT_AMP = 'true';
1747
+ amp = await (await import('./index8.js').then(function (n) { return n.i; })).getInstance();
1748
+ }
1749
+
1750
+ return {
1751
+ name: 'vite-plugin-svelte-kit',
1752
+
1753
+ configureServer(vite) {
1754
+ __fetch_polyfill();
1755
+
1756
+ /** @type {import('types/app').SSRManifest} */
1757
+ let manifest;
1758
+
1759
+ function update_manifest() {
1760
+ const manifest_data = create_manifest_data({ config, cwd });
1761
+
1762
+ create_app({ manifest_data, output: `${SVELTE_KIT}/generated`, cwd });
1763
+
1764
+ manifest = {
1765
+ appDir: config.kit.appDir,
1766
+ assets: new Set(manifest_data.assets.map((asset) => asset.file)),
1767
+ _: {
1768
+ mime: get_mime_lookup(manifest_data),
1769
+ entry: {
1770
+ file: `/@fs${runtime}/client/start.js`,
1771
+ css: [],
1772
+ js: []
1773
+ },
1774
+ nodes: manifest_data.components.map((id) => {
1775
+ return async () => {
1776
+ const url = id.startsWith('..') ? `/@fs${path__default.posix.resolve(id)}` : `/${id}`;
1777
+
1778
+ const module = /** @type {import('types/internal').SSRComponent} */ (
1779
+ await vite.ssrLoadModule(url)
1780
+ );
1781
+ const node = await vite.moduleGraph.getModuleByUrl(url);
1782
+
1783
+ if (!node) throw new Error(`Could not find node for ${url}`);
1784
+
1785
+ const deps = new Set();
1786
+ find_deps(node, deps);
1787
+
1788
+ /** @type {Record<string, string>} */
1789
+ const styles = {};
1790
+
1791
+ for (const dep of deps) {
1792
+ const parsed = new URL$1(dep.url, 'http://localhost/');
1793
+ const query = parsed.searchParams;
1794
+
1795
+ // TODO what about .scss files, etc?
1796
+ if (
1797
+ dep.file.endsWith('.css') ||
1798
+ (query.has('svelte') && query.get('type') === 'style')
1799
+ ) {
1800
+ try {
1801
+ const mod = await vite.ssrLoadModule(dep.url);
1802
+ styles[dep.url] = mod.default;
1803
+ } catch {
1804
+ // this can happen with dynamically imported modules, I think
1805
+ // because the Vite module graph doesn't distinguish between
1806
+ // static and dynamic imports? TODO investigate, submit fix
1807
+ }
1808
+ }
1809
+ }
1810
+
1811
+ return {
1812
+ module,
1813
+ entry: url.endsWith('.svelte') ? url : url + '?import',
1814
+ css: [],
1815
+ js: [],
1816
+ styles
1817
+ };
1818
+ };
1819
+ }),
1820
+ routes: manifest_data.routes.map((route) => {
1821
+ if (route.type === 'page') {
1822
+ return {
1823
+ type: 'page',
1824
+ pattern: route.pattern,
1825
+ params: get_params(route.params),
1826
+ a: route.a.map((id) => manifest_data.components.indexOf(id)),
1827
+ b: route.b.map((id) => manifest_data.components.indexOf(id))
1828
+ };
1829
+ }
1830
+
1831
+ return {
1832
+ type: 'endpoint',
1833
+ pattern: route.pattern,
1834
+ params: get_params(route.params),
1835
+ load: async () => {
1836
+ const url = path__default.resolve(cwd, route.file);
1837
+ return await vite.ssrLoadModule(url);
1838
+ }
1839
+ };
1840
+ })
1841
+ }
1842
+ };
1843
+ }
1844
+
1845
+ update_manifest();
1846
+
1847
+ vite.watcher.on('add', update_manifest);
1848
+ vite.watcher.on('remove', update_manifest);
1849
+
1850
+ const assets = config.kit.paths.assets ? SVELTE_KIT_ASSETS : config.kit.paths.base;
1851
+ const asset_server = sirv(config.kit.files.assets, {
1852
+ dev: true,
1853
+ etag: true,
1854
+ maxAge: 0,
1855
+ extensions: []
1856
+ });
1857
+
1858
+ return () => {
1859
+ remove_html_middlewares(vite.middlewares);
1860
+
1861
+ vite.middlewares.use(async (req, res) => {
1862
+ try {
1863
+ if (!req.url || !req.method) throw new Error('Incomplete request');
1864
+ if (req.url === '/favicon.ico') return not_found(res);
1865
+
1866
+ const base = `${vite.config.server.https ? 'https' : 'http'}://${req.headers.host}`;
1867
+
1868
+ const decoded = decodeURI(new URL$1(base + req.url).pathname);
1869
+
1870
+ if (decoded.startsWith(assets)) {
1871
+ const pathname = decoded.slice(assets.length);
1872
+ const file = config.kit.files.assets + pathname;
1873
+
1874
+ if (fs__default.existsSync(file) && !fs__default.statSync(file).isDirectory()) {
1875
+ req.url = encodeURI(pathname); // don't need query/hash
1876
+ asset_server(req, res);
1877
+ return;
1878
+ }
1879
+ }
1880
+
1881
+ if (!decoded.startsWith(config.kit.paths.base)) return not_found(res);
1882
+
1883
+ /** @type {Partial<import('types/internal').Hooks>} */
1884
+ const user_hooks = resolve_entry(config.kit.files.hooks)
1885
+ ? await vite.ssrLoadModule(`/${config.kit.files.hooks}`)
1886
+ : {};
1887
+
1888
+ /** @type {import('types/internal').Hooks} */
1889
+ const hooks = {
1890
+ getSession: user_hooks.getSession || (() => ({})),
1891
+ handle: user_hooks.handle || (({ event, resolve }) => resolve(event)),
1892
+ handleError:
1893
+ user_hooks.handleError ||
1894
+ (({ /** @type {Error & { frame?: string }} */ error }) => {
1895
+ console.error($.bold().red(error.message));
1896
+ if (error.frame) {
1897
+ console.error($.gray(error.frame));
1898
+ }
1899
+ if (error.stack) {
1900
+ console.error($.gray(error.stack));
1901
+ }
1902
+ }),
1903
+ externalFetch: user_hooks.externalFetch || fetch
1904
+ };
1905
+
1906
+ if (/** @type {any} */ (hooks).getContext) {
1907
+ // TODO remove this for 1.0
1908
+ throw new Error(
1909
+ 'The getContext hook has been removed. See https://kit.svelte.dev/docs#hooks'
1910
+ );
1911
+ }
1912
+
1913
+ if (/** @type {any} */ (hooks).serverFetch) {
1914
+ // TODO remove this for 1.0
1915
+ throw new Error('The serverFetch hook has been renamed to externalFetch.');
1916
+ }
1917
+
1918
+ const root = (await vite.ssrLoadModule(`/${SVELTE_KIT}/generated/root.svelte`)).default;
1919
+ const paths = await vite.ssrLoadModule(
1920
+ true ? `/${SVELTE_KIT}/runtime/paths.js` : `/@fs${runtime}/paths.js`
1921
+ );
1922
+
1923
+ paths.set_paths({
1924
+ base: config.kit.paths.base,
1925
+ assets
1926
+ });
1927
+
1928
+ let request;
1929
+
1930
+ try {
1931
+ request = await getRequest(base, req);
1932
+ } catch (/** @type {any} */ err) {
1933
+ res.statusCode = err.status || 400;
1934
+ return res.end(err.reason || 'Invalid request body');
1935
+ }
1936
+
1937
+ const rendered = await respond(request, {
1938
+ amp: config.kit.amp,
1939
+ dev: true,
1940
+ floc: config.kit.floc,
1941
+ get_stack: (error) => {
1942
+ vite.ssrFixStacktrace(error);
1943
+ return error.stack;
1944
+ },
1945
+ handle_error: (error, event) => {
1946
+ vite.ssrFixStacktrace(error);
1947
+ hooks.handleError({
1948
+ error,
1949
+ event,
1950
+
1951
+ // TODO remove for 1.0
1952
+ // @ts-expect-error
1953
+ get request() {
1954
+ throw new Error(
1955
+ 'request in handleError has been replaced with event. See https://github.com/sveltejs/kit/pull/3384 for details'
1956
+ );
1957
+ }
1958
+ });
1959
+ },
1960
+ hooks,
1961
+ hydrate: config.kit.hydrate,
1962
+ manifest,
1963
+ method_override: config.kit.methodOverride,
1964
+ paths: {
1965
+ base: config.kit.paths.base,
1966
+ assets
1967
+ },
1968
+ prefix: '',
1969
+ prerender: config.kit.prerender.enabled,
1970
+ read: (file) => fs__default.readFileSync(path__default.join(config.kit.files.assets, file)),
1971
+ root,
1972
+ router: config.kit.router,
1973
+ target: config.kit.target,
1974
+ template: ({ head, body, assets }) => {
1975
+ let rendered = load_template(cwd, config)
1976
+ .replace(/%svelte\.assets%/g, assets)
1977
+ // head and body must be replaced last, in case someone tries to sneak in %svelte.assets% etc
1978
+ .replace('%svelte.head%', () => head)
1979
+ .replace('%svelte.body%', () => body);
1980
+
1981
+ if (amp) {
1982
+ const result = amp.validateString(rendered);
1983
+
1984
+ if (result.status !== 'PASS') {
1985
+ const lines = rendered.split('\n');
1986
+
1987
+ /** @param {string} str */
1988
+ const escape = (str) =>
1989
+ str.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
1990
+
1991
+ rendered = `<!doctype html>
1992
+ <head>
1993
+ <meta charset="utf-8" />
1994
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
1995
+ <style>
1996
+ body {
1997
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
1998
+ color: #333;
1999
+ }
2000
+
2001
+ pre {
2002
+ background: #f4f4f4;
2003
+ padding: 1em;
2004
+ overflow-x: auto;
2005
+ }
2006
+ </style>
2007
+ </head>
2008
+ <h1>AMP validation failed</h1>
2009
+
2010
+ ${result.errors
2011
+ .map(
2012
+ (error) => `
2013
+ <h2>${error.severity}</h2>
2014
+ <p>Line ${error.line}, column ${error.col}: ${error.message} (<a href="${error.specUrl}">${
2015
+ error.code
2016
+ }</a>)</p>
2017
+ <pre>${escape(lines[error.line - 1])}</pre>
2018
+ `
2019
+ )
2020
+ .join('\n\n')}
2021
+ `;
2022
+ }
2023
+ }
2024
+
2025
+ return rendered;
2026
+ },
2027
+ trailing_slash: config.kit.trailingSlash
2028
+ });
2029
+
2030
+ if (rendered) {
2031
+ setResponse(res, rendered);
2032
+ } else {
2033
+ not_found(res);
2034
+ }
2035
+ } catch (e) {
2036
+ const error = coalesce_to_error(e);
2037
+ vite.ssrFixStacktrace(error);
2038
+ res.statusCode = 500;
2039
+ res.end(error.stack);
2040
+ }
2041
+ });
2042
+ };
2043
+ }
2044
+ };
2045
+ }
2046
+
2047
+ /** @param {string[]} array */
2048
+ function get_params(array) {
2049
+ // given an array of params like `['x', 'y', 'z']` for
2050
+ // src/routes/[x]/[y]/[z]/svelte, create a function
2051
+ // that turns a RegExpExecArray into ({ x, y, z })
2052
+
2053
+ /** @param {RegExpExecArray} match */
2054
+ const fn = (match) => {
2055
+ /** @type {Record<string, string>} */
2056
+ const params = {};
2057
+ array.forEach((key, i) => {
2058
+ if (key.startsWith('...')) {
2059
+ params[key.slice(3)] = match[i + 1] || '';
2060
+ } else {
2061
+ params[key] = match[i + 1];
2062
+ }
2063
+ });
2064
+ return params;
2065
+ };
2066
+
2067
+ return fn;
2068
+ }
2069
+
2070
+ /** @param {import('http').ServerResponse} res */
2071
+ function not_found(res) {
2072
+ res.statusCode = 404;
2073
+ res.end('Not found');
2074
+ }
2075
+
2076
+ /**
2077
+ * @param {import('connect').Server} server
2078
+ */
2079
+ function remove_html_middlewares(server) {
2080
+ const html_middlewares = [
2081
+ 'viteIndexHtmlMiddleware',
2082
+ 'vite404Middleware',
2083
+ 'viteSpaFallbackMiddleware'
2084
+ ];
2085
+ for (let i = server.stack.length - 1; i > 0; i--) {
2086
+ // @ts-expect-error using internals until https://github.com/vitejs/vite/pull/4640 is merged
2087
+ if (html_middlewares.includes(server.stack[i].handle.name)) {
2088
+ server.stack.splice(i, 1);
2089
+ }
2090
+ }
2091
+ }
2092
+
2093
+ /**
2094
+ * @param {import('vite').ModuleNode} node
2095
+ * @param {Set<import('vite').ModuleNode>} deps
2096
+ */
2097
+ function find_deps(node, deps) {
2098
+ for (const dep of node.importedModules) {
2099
+ if (!deps.has(dep)) {
2100
+ deps.add(dep);
2101
+ find_deps(dep, deps);
2102
+ }
2103
+ }
2104
+ }
2105
+
2106
+ /**
2107
+ * @typedef {{
2108
+ * cwd: string,
2109
+ * port: number,
2110
+ * host?: string,
2111
+ * https: boolean,
2112
+ * config: import('types/config').ValidatedConfig
2113
+ * }} Options
2114
+ * @typedef {import('types/internal').SSRComponent} SSRComponent
2115
+ */
2116
+
2117
+ /** @param {Options} opts */
2118
+ async function dev({ cwd, port, host, https, config }) {
2119
+ copy_assets(`${SVELTE_KIT}/runtime`);
2120
+
2121
+ const [vite_config] = deep_merge(
2122
+ {
2123
+ server: {
2124
+ fs: {
2125
+ allow: [
2126
+ ...new Set([
2127
+ config.kit.files.assets,
2128
+ config.kit.files.lib,
2129
+ config.kit.files.routes,
2130
+ path__default.resolve(cwd, 'src'),
2131
+ path__default.resolve(cwd, SVELTE_KIT),
2132
+ path__default.resolve(cwd, 'node_modules'),
2133
+ path__default.resolve(vite.searchForWorkspaceRoot(cwd), 'node_modules')
2134
+ ])
2135
+ ]
2136
+ },
2137
+ strictPort: true
2138
+ }
2139
+ },
2140
+ config.kit.vite()
2141
+ );
2142
+
2143
+ /** @type {[any, string[]]} */
2144
+ const [merged_config, conflicts] = deep_merge(vite_config, {
2145
+ configFile: false,
2146
+ root: cwd,
2147
+ resolve: {
2148
+ alias: get_aliases(config)
2149
+ },
2150
+ build: {
2151
+ rollupOptions: {
2152
+ // Vite dependency crawler needs an explicit JS entry point
2153
+ // eventhough server otherwise works without it
2154
+ input: `${runtime}/client/start.js`
2155
+ }
2156
+ },
2157
+ plugins: [
2158
+ svelte({
2159
+ extensions: config.extensions,
2160
+ emitCss: !config.kit.amp,
2161
+ compilerOptions: {
2162
+ hydratable: !!config.kit.hydrate
2163
+ }
2164
+ }),
2165
+ await create_plugin(config, cwd)
2166
+ ],
2167
+ base: '/'
2168
+ });
2169
+
2170
+ print_config_conflicts(conflicts, 'kit.vite.');
2171
+
2172
+ // optional config from command-line flags
2173
+ // these should take precedence, but not print conflict warnings
2174
+ if (host) {
2175
+ merged_config.server.host = host;
2176
+ }
2177
+
2178
+ // if https is already enabled then do nothing. it could be an object and we
2179
+ // don't want to overwrite with a boolean
2180
+ if (https && !merged_config.server.https) {
2181
+ merged_config.server.https = https;
2182
+ }
2183
+
2184
+ if (port) {
2185
+ merged_config.server.port = port;
2186
+ }
2187
+
2188
+ const server = await vite.createServer(merged_config);
2189
+ await server.listen(port);
2190
+
2191
+ const address_info = /** @type {import('net').AddressInfo} */ (
2192
+ /** @type {import('http').Server} */ (server.httpServer).address()
2193
+ );
2194
+
2195
+ return {
2196
+ address_info,
2197
+ server_config: vite_config.server,
2198
+ close: () => server.close()
2199
+ };
2200
+ }
2201
+
2202
+ export { dev };