@sveltejs/kit 1.0.0-next.27 → 1.0.0-next.270

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 (86) 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/app/stores.js +97 -0
  6. package/assets/chunks/utils.js +13 -0
  7. package/assets/client/singletons.js +21 -0
  8. package/assets/client/start.js +1504 -0
  9. package/assets/components/error.svelte +18 -2
  10. package/assets/env.js +8 -0
  11. package/assets/paths.js +13 -0
  12. package/assets/server/index.js +2725 -0
  13. package/dist/chunks/amp_hook.js +56 -0
  14. package/dist/chunks/build.js +658 -0
  15. package/dist/chunks/cert.js +28154 -0
  16. package/dist/chunks/index.js +467 -0
  17. package/dist/chunks/index2.js +836 -0
  18. package/dist/chunks/index3.js +638 -0
  19. package/dist/chunks/index4.js +115 -0
  20. package/dist/chunks/index5.js +891 -0
  21. package/dist/chunks/index6.js +170 -0
  22. package/dist/chunks/index7.js +15584 -0
  23. package/dist/chunks/index8.js +4207 -0
  24. package/dist/chunks/misc.js +3 -0
  25. package/dist/chunks/multipart-parser.js +449 -0
  26. package/dist/cli.js +1132 -86
  27. package/dist/hooks.js +28 -0
  28. package/dist/install-fetch.js +6518 -0
  29. package/dist/node.js +95 -0
  30. package/package.json +96 -54
  31. package/svelte-kit.js +2 -0
  32. package/types/ambient-modules.d.ts +208 -0
  33. package/types/app.d.ts +35 -0
  34. package/types/config.d.ts +200 -0
  35. package/types/csp.d.ts +115 -0
  36. package/types/endpoint.d.ts +39 -0
  37. package/types/helper.d.ts +23 -0
  38. package/types/hooks.d.ts +34 -0
  39. package/types/index.d.ts +17 -0
  40. package/types/internal.d.ts +260 -0
  41. package/types/page.d.ts +33 -0
  42. package/CHANGELOG.md +0 -319
  43. package/assets/runtime/app/navigation.js +0 -23
  44. package/assets/runtime/app/navigation.js.map +0 -1
  45. package/assets/runtime/app/paths.js +0 -2
  46. package/assets/runtime/app/paths.js.map +0 -1
  47. package/assets/runtime/app/stores.js +0 -78
  48. package/assets/runtime/app/stores.js.map +0 -1
  49. package/assets/runtime/internal/singletons.js +0 -15
  50. package/assets/runtime/internal/singletons.js.map +0 -1
  51. package/assets/runtime/internal/start.js +0 -591
  52. package/assets/runtime/internal/start.js.map +0 -1
  53. package/assets/runtime/utils-85ebcc60.js +0 -18
  54. package/assets/runtime/utils-85ebcc60.js.map +0 -1
  55. package/dist/api.js +0 -44
  56. package/dist/api.js.map +0 -1
  57. package/dist/build.js +0 -246
  58. package/dist/build.js.map +0 -1
  59. package/dist/cli.js.map +0 -1
  60. package/dist/colors.js +0 -37
  61. package/dist/colors.js.map +0 -1
  62. package/dist/create_app.js +0 -580
  63. package/dist/create_app.js.map +0 -1
  64. package/dist/index.js +0 -368
  65. package/dist/index.js.map +0 -1
  66. package/dist/index2.js +0 -12035
  67. package/dist/index2.js.map +0 -1
  68. package/dist/index3.js +0 -547
  69. package/dist/index3.js.map +0 -1
  70. package/dist/index4.js +0 -74
  71. package/dist/index4.js.map +0 -1
  72. package/dist/index5.js +0 -464
  73. package/dist/index5.js.map +0 -1
  74. package/dist/index6.js +0 -734
  75. package/dist/index6.js.map +0 -1
  76. package/dist/logging.js +0 -43
  77. package/dist/logging.js.map +0 -1
  78. package/dist/package.js +0 -432
  79. package/dist/package.js.map +0 -1
  80. package/dist/renderer.js +0 -2403
  81. package/dist/renderer.js.map +0 -1
  82. package/dist/standard.js +0 -101
  83. package/dist/standard.js.map +0 -1
  84. package/dist/utils.js +0 -58
  85. package/dist/utils.js.map +0 -1
  86. package/svelte-kit +0 -3
@@ -0,0 +1,891 @@
1
+ import { b as SVELTE_KIT, m as mkdirp, h as rimraf, i as copy, $, j as logger } from '../cli.js';
2
+ import { readFileSync, writeFileSync } from 'fs';
3
+ import { resolve as resolve$1, join, dirname } from 'path';
4
+ import { pathToFileURL, URL } from 'url';
5
+ import { __fetch_polyfill } from '../install-fetch.js';
6
+ import { g as generate_manifest } from './index4.js';
7
+ import 'sade';
8
+ import 'child_process';
9
+ import 'net';
10
+ import 'os';
11
+ import 'node:http';
12
+ import 'node:https';
13
+ import 'node:zlib';
14
+ import 'node:stream';
15
+ import 'node:util';
16
+ import 'node:url';
17
+ import './misc.js';
18
+
19
+ const absolute = /^([a-z]+:)?\/?\//;
20
+ const scheme = /^[a-z]+:/;
21
+
22
+ /**
23
+ * @param {string} base
24
+ * @param {string} path
25
+ */
26
+ function resolve(base, path) {
27
+ if (scheme.test(path)) return path;
28
+
29
+ const base_match = absolute.exec(base);
30
+ const path_match = absolute.exec(path);
31
+
32
+ if (!base_match) {
33
+ throw new Error(`bad base path: "${base}"`);
34
+ }
35
+
36
+ const baseparts = path_match ? [] : base.slice(base_match[0].length).split('/');
37
+ const pathparts = path_match ? path.slice(path_match[0].length).split('/') : path.split('/');
38
+
39
+ baseparts.pop();
40
+
41
+ for (let i = 0; i < pathparts.length; i += 1) {
42
+ const part = pathparts[i];
43
+ if (part === '.') continue;
44
+ else if (part === '..') baseparts.pop();
45
+ else baseparts.push(part);
46
+ }
47
+
48
+ const prefix = (path_match && path_match[0]) || (base_match && base_match[0]) || '';
49
+
50
+ return `${prefix}${baseparts.join('/')}`;
51
+ }
52
+
53
+ /** @param {string} path */
54
+ function is_root_relative(path) {
55
+ return path[0] === '/' && path[1] !== '/';
56
+ }
57
+
58
+ /**
59
+ * @param {string} path
60
+ * @param {'always' | 'never' | 'ignore'} trailing_slash
61
+ */
62
+ function normalize_path(path, trailing_slash) {
63
+ if (path === '/' || trailing_slash === 'ignore') return path;
64
+
65
+ if (trailing_slash === 'never') {
66
+ return path.endsWith('/') ? path.slice(0, -1) : path;
67
+ } else if (trailing_slash === 'always' && /\/[^./]+$/.test(path)) {
68
+ return path + '/';
69
+ }
70
+
71
+ return path;
72
+ }
73
+
74
+ /** @typedef {{
75
+ * fn: () => Promise<any>,
76
+ * fulfil: (value: any) => void,
77
+ * reject: (error: Error) => void
78
+ * }} Task */
79
+
80
+ /** @param {number} concurrency */
81
+ function queue(concurrency) {
82
+ /** @type {Task[]} */
83
+ const tasks = [];
84
+
85
+ let current = 0;
86
+
87
+ /** @type {(value?: any) => void} */
88
+ let fulfil;
89
+
90
+ /** @type {(error: Error) => void} */
91
+ let reject;
92
+
93
+ let closed = false;
94
+
95
+ const done = new Promise((f, r) => {
96
+ fulfil = f;
97
+ reject = r;
98
+ });
99
+
100
+ done.catch(() => {
101
+ // this is necessary in case a catch handler is never added
102
+ // to the done promise by the user
103
+ });
104
+
105
+ function dequeue() {
106
+ if (current < concurrency) {
107
+ const task = tasks.shift();
108
+
109
+ if (task) {
110
+ current += 1;
111
+ const promise = Promise.resolve(task.fn());
112
+
113
+ promise
114
+ .then(task.fulfil, (err) => {
115
+ task.reject(err);
116
+ reject(err);
117
+ })
118
+ .then(() => {
119
+ current -= 1;
120
+ dequeue();
121
+ });
122
+ } else if (current === 0) {
123
+ closed = true;
124
+ fulfil();
125
+ }
126
+ }
127
+ }
128
+
129
+ return {
130
+ /** @param {() => any} fn */
131
+ add: (fn) => {
132
+ if (closed) throw new Error('Cannot add tasks to a queue that has ended');
133
+
134
+ const promise = new Promise((fulfil, reject) => {
135
+ tasks.push({ fn, fulfil, reject });
136
+ });
137
+
138
+ dequeue();
139
+ return promise;
140
+ },
141
+
142
+ done: () => {
143
+ if (current === 0) {
144
+ closed = true;
145
+ fulfil();
146
+ }
147
+
148
+ return done;
149
+ }
150
+ };
151
+ }
152
+
153
+ const DOCTYPE = 'DOCTYPE';
154
+ const CDATA_OPEN = '[CDATA[';
155
+ const CDATA_CLOSE = ']]>';
156
+ const COMMENT_OPEN = '--';
157
+ const COMMENT_CLOSE = '-->';
158
+
159
+ const TAG_OPEN = /[a-zA-Z]/;
160
+ const TAG_CHAR = /[a-zA-Z0-9]/;
161
+ const ATTRIBUTE_NAME = /[^\t\n\f />"'=]/;
162
+
163
+ const EXTERNAL = /\bexternal\b/;
164
+
165
+ const WHITESPACE = /[\s\n\r]/;
166
+
167
+ /** @param {string} html */
168
+ function crawl(html) {
169
+ /** @type {string[]} */
170
+ const hrefs = [];
171
+
172
+ let i = 0;
173
+ main: while (i < html.length) {
174
+ const char = html[i];
175
+
176
+ if (char === '<') {
177
+ if (html[i + 1] === '!') {
178
+ i += 2;
179
+
180
+ if (html.substr(i, DOCTYPE.length).toUpperCase() === DOCTYPE) {
181
+ i += DOCTYPE.length;
182
+ while (i < html.length) {
183
+ if (html[i++] === '>') {
184
+ continue main;
185
+ }
186
+ }
187
+ }
188
+
189
+ // skip cdata
190
+ if (html.substr(i, CDATA_OPEN.length) === CDATA_OPEN) {
191
+ i += CDATA_OPEN.length;
192
+ while (i < html.length) {
193
+ if (html.substr(i, CDATA_CLOSE.length) === CDATA_CLOSE) {
194
+ i += CDATA_CLOSE.length;
195
+ continue main;
196
+ }
197
+
198
+ i += 1;
199
+ }
200
+ }
201
+
202
+ // skip comments
203
+ if (html.substr(i, COMMENT_OPEN.length) === COMMENT_OPEN) {
204
+ i += COMMENT_OPEN.length;
205
+ while (i < html.length) {
206
+ if (html.substr(i, COMMENT_CLOSE.length) === COMMENT_CLOSE) {
207
+ i += COMMENT_CLOSE.length;
208
+ continue main;
209
+ }
210
+
211
+ i += 1;
212
+ }
213
+ }
214
+ }
215
+
216
+ // parse opening tags
217
+ const start = ++i;
218
+ if (TAG_OPEN.test(html[start])) {
219
+ while (i < html.length) {
220
+ if (!TAG_CHAR.test(html[i])) {
221
+ break;
222
+ }
223
+
224
+ i += 1;
225
+ }
226
+
227
+ const tag = html.slice(start, i).toUpperCase();
228
+
229
+ if (tag === 'SCRIPT' || tag === 'STYLE') {
230
+ while (i < html.length) {
231
+ if (
232
+ html[i] === '<' &&
233
+ html[i + 1] === '/' &&
234
+ html.substr(i + 2, tag.length).toUpperCase() === tag
235
+ ) {
236
+ continue main;
237
+ }
238
+
239
+ i += 1;
240
+ }
241
+ }
242
+
243
+ let rel = '';
244
+ let href = '';
245
+
246
+ while (i < html.length) {
247
+ const start = i;
248
+
249
+ const char = html[start];
250
+ if (char === '>') break;
251
+
252
+ if (ATTRIBUTE_NAME.test(char)) {
253
+ i += 1;
254
+
255
+ while (i < html.length) {
256
+ if (!ATTRIBUTE_NAME.test(html[i])) {
257
+ break;
258
+ }
259
+
260
+ i += 1;
261
+ }
262
+
263
+ const name = html.slice(start, i).toLowerCase();
264
+
265
+ while (WHITESPACE.test(html[i])) i += 1;
266
+
267
+ if (html[i] === '=') {
268
+ i += 1;
269
+ while (WHITESPACE.test(html[i])) i += 1;
270
+
271
+ let value;
272
+
273
+ if (html[i] === "'" || html[i] === '"') {
274
+ const quote = html[i++];
275
+
276
+ const start = i;
277
+ let escaped = false;
278
+
279
+ while (i < html.length) {
280
+ if (!escaped) {
281
+ const char = html[i];
282
+
283
+ if (html[i] === quote) {
284
+ break;
285
+ }
286
+
287
+ if (char === '\\') {
288
+ escaped = true;
289
+ }
290
+ }
291
+
292
+ i += 1;
293
+ }
294
+
295
+ value = html.slice(start, i);
296
+ } else {
297
+ const start = i;
298
+ while (html[i] !== '>' && !WHITESPACE.test(html[i])) i += 1;
299
+ value = html.slice(start, i);
300
+
301
+ i -= 1;
302
+ }
303
+
304
+ if (name === 'rel') {
305
+ rel = value;
306
+ } else if (name === 'href') {
307
+ href = value;
308
+ } else if (name === 'src') {
309
+ hrefs.push(value);
310
+ } else if (name === 'srcset') {
311
+ const candidates = [];
312
+ let insideURL = true;
313
+ value = value.trim();
314
+ for (let i = 0; i < value.length; i++) {
315
+ if (value[i] === ',' && (!insideURL || (insideURL && value[i + 1] === ' '))) {
316
+ candidates.push(value.slice(0, i));
317
+ value = value.substring(i + 1).trim();
318
+ i = 0;
319
+ insideURL = true;
320
+ } else if (value[i] === ' ') {
321
+ insideURL = false;
322
+ }
323
+ }
324
+ candidates.push(value);
325
+ for (const candidate of candidates) {
326
+ const src = candidate.split(WHITESPACE)[0];
327
+ hrefs.push(src);
328
+ }
329
+ }
330
+ } else {
331
+ i -= 1;
332
+ }
333
+ }
334
+
335
+ i += 1;
336
+ }
337
+
338
+ if (href && !EXTERNAL.test(rel)) {
339
+ hrefs.push(href);
340
+ }
341
+ }
342
+ }
343
+
344
+ i += 1;
345
+ }
346
+
347
+ return hrefs;
348
+ }
349
+
350
+ // dict from https://github.com/yahoo/serialize-javascript/blob/183c18a776e4635a379fdc620f81771f219832bb/index.js#L25
351
+ /** @type {Record<string, string>} */
352
+ const escape_json_in_html_dict = {
353
+ '<': '\\u003C',
354
+ '>': '\\u003E',
355
+ '/': '\\u002F',
356
+ '\u2028': '\\u2028',
357
+ '\u2029': '\\u2029'
358
+ };
359
+
360
+ new RegExp(
361
+ `[${Object.keys(escape_json_in_html_dict).join('')}]`,
362
+ 'g'
363
+ );
364
+
365
+ /**
366
+ * @param str {string} string to escape
367
+ * @param dict {Record<string, string>} dictionary of character replacements
368
+ * @param unicode_encoder {function(number): string} encoder to use for high unicode characters
369
+ * @returns {string}
370
+ */
371
+ function escape(str, dict, unicode_encoder) {
372
+ let result = '';
373
+
374
+ for (let i = 0; i < str.length; i += 1) {
375
+ const char = str.charAt(i);
376
+ const code = char.charCodeAt(0);
377
+
378
+ if (char in dict) {
379
+ result += dict[char];
380
+ } else if (code >= 0xd800 && code <= 0xdfff) {
381
+ const next = str.charCodeAt(i + 1);
382
+
383
+ // If this is the beginning of a [high, low] surrogate pair,
384
+ // add the next two characters, otherwise escape
385
+ if (code <= 0xdbff && next >= 0xdc00 && next <= 0xdfff) {
386
+ result += char + str[++i];
387
+ } else {
388
+ result += unicode_encoder(code);
389
+ }
390
+ } else {
391
+ result += char;
392
+ }
393
+ }
394
+
395
+ return result;
396
+ }
397
+
398
+ /** @type {Record<string, string>} */
399
+ const escape_html_attr_dict = {
400
+ '<': '&lt;',
401
+ '>': '&gt;',
402
+ '"': '&quot;'
403
+ };
404
+
405
+ /**
406
+ * use for escaping string values to be used html attributes on the page
407
+ * e.g.
408
+ * <script data-url="here">
409
+ *
410
+ * @param {string} str
411
+ * @returns string escaped string
412
+ */
413
+ function escape_html_attr(str) {
414
+ return '"' + escape(str, escape_html_attr_dict, (code) => `&#${code};`) + '"';
415
+ }
416
+
417
+ /**
418
+ * @typedef {import('types/config').PrerenderErrorHandler} PrerenderErrorHandler
419
+ * @typedef {import('types/config').PrerenderOnErrorValue} OnError
420
+ * @typedef {import('types/internal').Logger} Logger
421
+ */
422
+
423
+ /** @type {(details: Parameters<PrerenderErrorHandler>[0] ) => string} */
424
+ function format_error({ status, path, referrer, referenceType }) {
425
+ return `${status} ${path}${referrer ? ` (${referenceType} from ${referrer})` : ''}`;
426
+ }
427
+
428
+ /** @type {(log: Logger, onError: OnError) => PrerenderErrorHandler} */
429
+ function normalise_error_handler(log, onError) {
430
+ switch (onError) {
431
+ case 'continue':
432
+ return (details) => {
433
+ log.error(format_error(details));
434
+ };
435
+ case 'fail':
436
+ return (details) => {
437
+ throw new Error(format_error(details));
438
+ };
439
+ default:
440
+ return onError;
441
+ }
442
+ }
443
+
444
+ const OK = 2;
445
+ const REDIRECT = 3;
446
+
447
+ /**
448
+ * @param {{
449
+ * cwd: string;
450
+ * out: string;
451
+ * log: Logger;
452
+ * config: import('types/config').ValidatedConfig;
453
+ * build_data: import('types/internal').BuildData;
454
+ * fallback?: string;
455
+ * all: boolean; // disregard `export const prerender = true`
456
+ * }} opts
457
+ */
458
+ async function prerender({ cwd, out, log, config, build_data, fallback, all }) {
459
+ /** @type {import('types/config').Prerendered} */
460
+ const prerendered = {
461
+ pages: new Map(),
462
+ assets: new Map(),
463
+ redirects: new Map(),
464
+ paths: []
465
+ };
466
+
467
+ if (!config.kit.prerender.enabled && !fallback) {
468
+ return prerendered;
469
+ }
470
+
471
+ __fetch_polyfill();
472
+
473
+ const server_root = resolve$1(cwd, `${SVELTE_KIT}/output`);
474
+
475
+ /** @type {import('types/internal').AppModule} */
476
+ const { App, override } = await import(pathToFileURL(`${server_root}/server/app.js`).href);
477
+ const { manifest } = await import(pathToFileURL(`${server_root}/server/manifest.js`).href);
478
+
479
+ override({
480
+ paths: config.kit.paths,
481
+ prerendering: true,
482
+ read: (file) => readFileSync(join(config.kit.files.assets, file))
483
+ });
484
+
485
+ const app = new App(manifest);
486
+
487
+ const error = normalise_error_handler(log, config.kit.prerender.onError);
488
+
489
+ const files = new Set([
490
+ ...build_data.static,
491
+ ...build_data.client.chunks.map((chunk) => `${config.kit.appDir}/${chunk.fileName}`),
492
+ ...build_data.client.assets.map((chunk) => `${config.kit.appDir}/${chunk.fileName}`)
493
+ ]);
494
+
495
+ build_data.static.forEach((file) => {
496
+ if (file.endsWith('/index.html')) {
497
+ files.add(file.slice(0, -11));
498
+ }
499
+ });
500
+
501
+ const q = queue(config.kit.prerender.concurrency);
502
+
503
+ /**
504
+ * @param {string} path
505
+ * @param {boolean} is_html
506
+ */
507
+ function output_filename(path, is_html) {
508
+ const file = path.slice(config.kit.paths.base.length + 1);
509
+
510
+ if (file === '') {
511
+ return 'index.html';
512
+ }
513
+
514
+ if (is_html && !file.endsWith('.html')) {
515
+ return file + (config.kit.trailingSlash === 'always' ? 'index.html' : '.html');
516
+ }
517
+
518
+ return file;
519
+ }
520
+
521
+ const seen = new Set();
522
+ const written = new Set();
523
+
524
+ /**
525
+ * @param {string | null} referrer
526
+ * @param {string} decoded
527
+ * @param {string} [encoded]
528
+ */
529
+ function enqueue(referrer, decoded, encoded) {
530
+ if (seen.has(decoded)) return;
531
+ seen.add(decoded);
532
+
533
+ const file = decoded.slice(config.kit.paths.base.length + 1);
534
+ if (files.has(file)) return;
535
+
536
+ return q.add(() => visit(decoded, encoded || encodeURI(decoded), referrer));
537
+ }
538
+
539
+ /**
540
+ * @param {string} decoded
541
+ * @param {string} encoded
542
+ * @param {string?} referrer
543
+ */
544
+ async function visit(decoded, encoded, referrer) {
545
+ if (!decoded.startsWith(config.kit.paths.base)) {
546
+ error({ status: 404, path: decoded, referrer, referenceType: 'linked' });
547
+ return;
548
+ }
549
+
550
+ /** @type {Map<string, import('types/internal').PrerenderDependency>} */
551
+ const dependencies = new Map();
552
+
553
+ const response = await app.render(new Request(`http://sveltekit-prerender${encoded}`), {
554
+ prerender: {
555
+ all,
556
+ dependencies
557
+ }
558
+ });
559
+
560
+ const text = await response.text();
561
+
562
+ save(response, text, decoded, encoded, referrer, 'linked');
563
+
564
+ for (const [dependency_path, result] of dependencies) {
565
+ // this seems circuitous, but using new URL allows us to not care
566
+ // whether dependency_path is encoded or not
567
+ const encoded_dependency_path = new URL(dependency_path, 'http://localhost').pathname;
568
+ const decoded_dependency_path = decodeURI(encoded_dependency_path);
569
+
570
+ const body = result.body ?? new Uint8Array(await result.response.arrayBuffer());
571
+ save(
572
+ result.response,
573
+ body,
574
+ decoded_dependency_path,
575
+ encoded_dependency_path,
576
+ decoded,
577
+ 'fetched'
578
+ );
579
+ }
580
+
581
+ if (config.kit.prerender.crawl && response.headers.get('content-type') === 'text/html') {
582
+ for (const href of crawl(text)) {
583
+ if (href.startsWith('data:') || href.startsWith('#')) continue;
584
+
585
+ const resolved = resolve(encoded, href);
586
+ if (!is_root_relative(resolved)) continue;
587
+
588
+ const parsed = new URL(resolved, 'http://localhost');
589
+
590
+ if (parsed.search) ;
591
+
592
+ const pathname = normalize_path(parsed.pathname, config.kit.trailingSlash);
593
+ enqueue(decoded, decodeURI(pathname), pathname);
594
+ }
595
+ }
596
+ }
597
+
598
+ /**
599
+ * @param {Response} response
600
+ * @param {string | Uint8Array} body
601
+ * @param {string} decoded
602
+ * @param {string} encoded
603
+ * @param {string | null} referrer
604
+ * @param {'linked' | 'fetched'} referenceType
605
+ */
606
+ function save(response, body, decoded, encoded, referrer, referenceType) {
607
+ const response_type = Math.floor(response.status / 100);
608
+ const type = /** @type {string} */ (response.headers.get('content-type'));
609
+ const is_html = response_type === REDIRECT || type === 'text/html';
610
+
611
+ const file = output_filename(decoded, is_html);
612
+ const dest = `${out}/${file}`;
613
+
614
+ if (written.has(file)) return;
615
+ written.add(file);
616
+
617
+ if (response_type === REDIRECT) {
618
+ const location = response.headers.get('location');
619
+
620
+ if (location) {
621
+ mkdirp(dirname(dest));
622
+
623
+ log.warn(`${response.status} ${decoded} -> ${location}`);
624
+
625
+ writeFileSync(
626
+ dest,
627
+ `<meta http-equiv="refresh" content=${escape_html_attr(`0;url=${location}`)}>`
628
+ );
629
+
630
+ let resolved = resolve(encoded, location);
631
+ if (is_root_relative(resolved)) {
632
+ resolved = normalize_path(resolved, config.kit.trailingSlash);
633
+ enqueue(decoded, decodeURI(resolved), resolved);
634
+ }
635
+
636
+ if (!prerendered.redirects.has(decoded)) {
637
+ prerendered.redirects.set(decoded, {
638
+ status: response.status,
639
+ location: resolved
640
+ });
641
+
642
+ prerendered.paths.push(normalize_path(decoded, 'never'));
643
+ }
644
+ } else {
645
+ log.warn(`location header missing on redirect received from ${decoded}`);
646
+ }
647
+
648
+ return;
649
+ }
650
+
651
+ if (response.status === 200) {
652
+ mkdirp(dirname(dest));
653
+
654
+ log.info(`${response.status} ${decoded}`);
655
+ writeFileSync(dest, body);
656
+
657
+ if (is_html) {
658
+ prerendered.pages.set(decoded, {
659
+ file
660
+ });
661
+ } else {
662
+ prerendered.assets.set(decoded, {
663
+ type
664
+ });
665
+ }
666
+
667
+ prerendered.paths.push(normalize_path(decoded, 'never'));
668
+ } else if (response_type !== OK) {
669
+ error({ status: response.status, path: decoded, referrer, referenceType });
670
+ }
671
+ }
672
+
673
+ if (config.kit.prerender.enabled) {
674
+ for (const entry of config.kit.prerender.entries) {
675
+ if (entry === '*') {
676
+ for (const entry of build_data.entries) {
677
+ enqueue(null, normalize_path(config.kit.paths.base + entry, config.kit.trailingSlash)); // TODO can we pre-normalize these?
678
+ }
679
+ } else {
680
+ enqueue(null, normalize_path(config.kit.paths.base + entry, config.kit.trailingSlash));
681
+ }
682
+ }
683
+
684
+ await q.done();
685
+ }
686
+
687
+ if (fallback) {
688
+ const rendered = await app.render(new Request('http://sveltekit-prerender/[fallback]'), {
689
+ prerender: {
690
+ fallback,
691
+ all: false,
692
+ dependencies: new Map()
693
+ }
694
+ });
695
+
696
+ const file = join(out, fallback);
697
+ mkdirp(dirname(file));
698
+ writeFileSync(file, await rendered.text());
699
+ }
700
+
701
+ return prerendered;
702
+ }
703
+
704
+ /**
705
+ * @param {{
706
+ * cwd: string;
707
+ * config: import('types/config').ValidatedConfig;
708
+ * build_data: import('types/internal').BuildData;
709
+ * log: import('types/internal').Logger;
710
+ * }} opts
711
+ * @returns {import('types/config').Builder}
712
+ */
713
+ function create_builder({ cwd, config, build_data, log }) {
714
+ /** @type {Set<string>} */
715
+ let prerendered_paths;
716
+
717
+ let generated_manifest = false;
718
+
719
+ /** @param {import('types/internal').RouteData} route */
720
+ function not_prerendered(route) {
721
+ if (!prerendered_paths) return true;
722
+
723
+ if (route.type === 'page' && route.path) {
724
+ return !prerendered_paths.has(route.path);
725
+ }
726
+
727
+ return true;
728
+ }
729
+
730
+ return {
731
+ log,
732
+ rimraf,
733
+ mkdirp,
734
+ copy,
735
+
736
+ appDir: config.kit.appDir,
737
+ trailingSlash: config.kit.trailingSlash,
738
+
739
+ createEntries(fn) {
740
+ generated_manifest = true;
741
+
742
+ const { routes } = build_data.manifest_data;
743
+
744
+ /** @type {import('types/config').RouteDefinition[]} */
745
+ const facades = routes.map((route) => ({
746
+ type: route.type,
747
+ segments: route.segments,
748
+ pattern: route.pattern,
749
+ methods: route.type === 'page' ? ['get'] : build_data.server.methods[route.file]
750
+ }));
751
+
752
+ const seen = new Set();
753
+
754
+ for (let i = 0; i < routes.length; i += 1) {
755
+ const route = routes[i];
756
+ const { id, filter, complete } = fn(facades[i]);
757
+
758
+ if (seen.has(id)) continue;
759
+ seen.add(id);
760
+
761
+ const group = [route];
762
+
763
+ // figure out which lower priority routes should be considered fallbacks
764
+ for (let j = i + 1; j < routes.length; j += 1) {
765
+ if (filter(facades[j])) {
766
+ group.push(routes[j]);
767
+ }
768
+ }
769
+
770
+ const filtered = new Set(group.filter(not_prerendered));
771
+
772
+ // heuristic: if /foo/[bar] is included, /foo/[bar].json should
773
+ // also be included, since the page likely needs the endpoint
774
+ filtered.forEach((route) => {
775
+ if (route.type === 'page') {
776
+ const length = route.segments.length;
777
+
778
+ const endpoint = routes.find((candidate) => {
779
+ if (candidate.segments.length !== length) return false;
780
+
781
+ for (let i = 0; i < length; i += 1) {
782
+ const a = route.segments[i];
783
+ const b = candidate.segments[i];
784
+
785
+ if (i === length - 1) {
786
+ return b.content === `${a.content}.json`;
787
+ }
788
+
789
+ if (a.content !== b.content) return false;
790
+ }
791
+ });
792
+
793
+ if (endpoint) {
794
+ filtered.add(endpoint);
795
+ }
796
+ }
797
+ });
798
+
799
+ if (filtered.size > 0) {
800
+ complete({
801
+ generateManifest: ({ relativePath, format }) =>
802
+ generate_manifest(build_data, relativePath, Array.from(filtered), format)
803
+ });
804
+ }
805
+ }
806
+ },
807
+
808
+ generateManifest: ({ relativePath, format }) => {
809
+ generated_manifest = true;
810
+ return generate_manifest(
811
+ build_data,
812
+ relativePath,
813
+ build_data.manifest_data.routes.filter(not_prerendered),
814
+ format
815
+ );
816
+ },
817
+
818
+ getBuildDirectory(name) {
819
+ return `${cwd}/${SVELTE_KIT}/${name}`;
820
+ },
821
+
822
+ getClientDirectory() {
823
+ return `${cwd}/${SVELTE_KIT}/output/client`;
824
+ },
825
+
826
+ getServerDirectory() {
827
+ return `${cwd}/${SVELTE_KIT}/output/server`;
828
+ },
829
+
830
+ getStaticDirectory() {
831
+ return config.kit.files.assets;
832
+ },
833
+
834
+ writeClient(dest) {
835
+ return copy(`${cwd}/${SVELTE_KIT}/output/client`, dest, {
836
+ filter: (file) => file[0] !== '.'
837
+ });
838
+ },
839
+
840
+ writeServer(dest) {
841
+ return copy(`${cwd}/${SVELTE_KIT}/output/server`, dest, {
842
+ filter: (file) => file[0] !== '.'
843
+ });
844
+ },
845
+
846
+ writeStatic(dest) {
847
+ return copy(config.kit.files.assets, dest);
848
+ },
849
+
850
+ async prerender({ all = false, dest, fallback }) {
851
+ if (generated_manifest) {
852
+ throw new Error(
853
+ 'Adapters must call prerender(...) before createEntries(...) or generateManifest(...)'
854
+ );
855
+ }
856
+
857
+ const prerendered = await prerender({
858
+ out: dest,
859
+ all,
860
+ cwd,
861
+ config,
862
+ build_data,
863
+ fallback,
864
+ log
865
+ });
866
+
867
+ prerendered_paths = new Set(prerendered.paths);
868
+
869
+ return prerendered;
870
+ }
871
+ };
872
+ }
873
+
874
+ /**
875
+ * @param {import('types/config').ValidatedConfig} config
876
+ * @param {import('types/internal').BuildData} build_data
877
+ * @param {{ cwd?: string, verbose: boolean }} opts
878
+ */
879
+ async function adapt(config, build_data, { cwd = process.cwd(), verbose }) {
880
+ const { name, adapt } = config.kit.adapter;
881
+
882
+ console.log($.bold().cyan(`\n> Using ${name}`));
883
+
884
+ const log = logger({ verbose });
885
+ const builder = create_builder({ cwd, config, build_data, log });
886
+ await adapt(builder);
887
+
888
+ log.success('done');
889
+ }
890
+
891
+ export { adapt };