@sveltejs/kit 1.0.0-next.45 → 1.0.0-next.452

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 (108) hide show
  1. package/README.md +12 -9
  2. package/package.json +92 -63
  3. package/src/cli.js +112 -0
  4. package/src/constants.js +7 -0
  5. package/src/core/adapt/builder.js +223 -0
  6. package/src/core/adapt/index.js +19 -0
  7. package/src/core/config/index.js +86 -0
  8. package/src/core/config/options.js +488 -0
  9. package/src/core/config/types.d.ts +1 -0
  10. package/src/core/env.js +112 -0
  11. package/src/core/generate_manifest/index.js +78 -0
  12. package/src/core/prerender/crawl.js +194 -0
  13. package/src/core/prerender/prerender.js +380 -0
  14. package/src/core/prerender/queue.js +80 -0
  15. package/src/core/sync/create_manifest_data/index.js +452 -0
  16. package/src/core/sync/create_manifest_data/types.d.ts +37 -0
  17. package/src/core/sync/sync.js +59 -0
  18. package/src/core/sync/utils.js +33 -0
  19. package/src/core/sync/write_ambient.js +53 -0
  20. package/src/core/sync/write_client_manifest.js +94 -0
  21. package/src/core/sync/write_matchers.js +25 -0
  22. package/src/core/sync/write_root.js +91 -0
  23. package/src/core/sync/write_tsconfig.js +195 -0
  24. package/src/core/sync/write_types/index.js +596 -0
  25. package/src/core/utils.js +70 -0
  26. package/src/exports/hooks/index.js +1 -0
  27. package/src/exports/hooks/sequence.js +26 -0
  28. package/src/exports/index.js +45 -0
  29. package/src/exports/node/index.js +145 -0
  30. package/src/exports/node/polyfills.js +40 -0
  31. package/src/exports/vite/build/build_server.js +348 -0
  32. package/src/exports/vite/build/build_service_worker.js +90 -0
  33. package/src/exports/vite/build/utils.js +160 -0
  34. package/src/exports/vite/dev/index.js +543 -0
  35. package/src/exports/vite/index.js +588 -0
  36. package/src/exports/vite/preview/index.js +186 -0
  37. package/src/exports/vite/types.d.ts +3 -0
  38. package/src/exports/vite/utils.js +345 -0
  39. package/src/runtime/app/env.js +1 -0
  40. package/src/runtime/app/environment.js +11 -0
  41. package/src/runtime/app/navigation.js +22 -0
  42. package/src/runtime/app/paths.js +1 -0
  43. package/src/runtime/app/stores.js +102 -0
  44. package/src/runtime/client/ambient.d.ts +24 -0
  45. package/src/runtime/client/client.js +1394 -0
  46. package/src/runtime/client/fetcher.js +60 -0
  47. package/src/runtime/client/parse.js +60 -0
  48. package/src/runtime/client/singletons.js +21 -0
  49. package/src/runtime/client/start.js +48 -0
  50. package/src/runtime/client/types.d.ts +88 -0
  51. package/src/runtime/client/utils.js +113 -0
  52. package/src/runtime/components/error.svelte +16 -0
  53. package/{assets → src/runtime}/components/layout.svelte +0 -0
  54. package/src/runtime/control.js +33 -0
  55. package/src/runtime/env/dynamic/private.js +1 -0
  56. package/src/runtime/env/dynamic/public.js +1 -0
  57. package/src/runtime/env-private.js +6 -0
  58. package/src/runtime/env-public.js +6 -0
  59. package/src/runtime/env.js +6 -0
  60. package/src/runtime/hash.js +16 -0
  61. package/src/runtime/paths.js +11 -0
  62. package/src/runtime/server/data/index.js +146 -0
  63. package/src/runtime/server/endpoint.js +50 -0
  64. package/src/runtime/server/index.js +369 -0
  65. package/src/runtime/server/page/cookie.js +25 -0
  66. package/src/runtime/server/page/crypto.js +239 -0
  67. package/src/runtime/server/page/csp.js +249 -0
  68. package/src/runtime/server/page/fetch.js +266 -0
  69. package/src/runtime/server/page/index.js +413 -0
  70. package/src/runtime/server/page/load_data.js +124 -0
  71. package/src/runtime/server/page/render.js +379 -0
  72. package/src/runtime/server/page/respond_with_error.js +94 -0
  73. package/src/runtime/server/page/types.d.ts +44 -0
  74. package/src/runtime/server/utils.js +137 -0
  75. package/src/utils/array.js +9 -0
  76. package/src/utils/error.js +22 -0
  77. package/src/utils/escape.js +104 -0
  78. package/src/utils/filesystem.js +108 -0
  79. package/src/utils/functions.js +16 -0
  80. package/src/utils/http.js +55 -0
  81. package/src/utils/misc.js +1 -0
  82. package/src/utils/routing.js +146 -0
  83. package/src/utils/url.js +142 -0
  84. package/svelte-kit.js +1 -1
  85. package/types/ambient.d.ts +319 -0
  86. package/types/index.d.ts +345 -0
  87. package/types/internal.d.ts +379 -0
  88. package/types/private.d.ts +209 -0
  89. package/CHANGELOG.md +0 -450
  90. package/assets/components/error.svelte +0 -13
  91. package/assets/runtime/app/env.js +0 -5
  92. package/assets/runtime/app/navigation.js +0 -41
  93. package/assets/runtime/app/paths.js +0 -1
  94. package/assets/runtime/app/stores.js +0 -93
  95. package/assets/runtime/chunks/utils.js +0 -19
  96. package/assets/runtime/internal/singletons.js +0 -23
  97. package/assets/runtime/internal/start.js +0 -770
  98. package/assets/runtime/paths.js +0 -12
  99. package/dist/chunks/index.js +0 -3521
  100. package/dist/chunks/index2.js +0 -587
  101. package/dist/chunks/index3.js +0 -246
  102. package/dist/chunks/index4.js +0 -536
  103. package/dist/chunks/index5.js +0 -761
  104. package/dist/chunks/index6.js +0 -322
  105. package/dist/chunks/standard.js +0 -99
  106. package/dist/chunks/utils.js +0 -83
  107. package/dist/cli.js +0 -546
  108. package/dist/ssr.js +0 -2580
@@ -0,0 +1,413 @@
1
+ import { devalue } from 'devalue';
2
+ import { negotiate } from '../../../utils/http.js';
3
+ import { render_response } from './render.js';
4
+ import { respond_with_error } from './respond_with_error.js';
5
+ import { method_not_allowed, error_to_pojo, allowed_methods } from '../utils.js';
6
+ import { create_fetch } from './fetch.js';
7
+ import { HttpError, Redirect } from '../../control.js';
8
+ import { error, json } from '../../../exports/index.js';
9
+ import { compact } from '../../../utils/array.js';
10
+ import { normalize_error } from '../../../utils/error.js';
11
+ import { load_data, load_server_data } from './load_data.js';
12
+ import { DATA_SUFFIX } from '../../../constants.js';
13
+
14
+ /**
15
+ * @typedef {import('./types.js').Loaded} Loaded
16
+ * @typedef {import('types').SSRNode} SSRNode
17
+ * @typedef {import('types').SSROptions} SSROptions
18
+ * @typedef {import('types').SSRState} SSRState
19
+ */
20
+
21
+ /**
22
+ * @param {import('types').RequestEvent} event
23
+ * @param {import('types').SSRRoute} route
24
+ * @param {import('types').PageNodeIndexes} page
25
+ * @param {import('types').SSROptions} options
26
+ * @param {import('types').SSRState} state
27
+ * @param {import('types').RequiredResolveOptions} resolve_opts
28
+ * @returns {Promise<Response>}
29
+ */
30
+ export async function render_page(event, route, page, options, state, resolve_opts) {
31
+ if (state.initiator === route) {
32
+ // infinite request cycle detected
33
+ return new Response(`Not found: ${event.url.pathname}`, {
34
+ status: 404
35
+ });
36
+ }
37
+
38
+ const accept = negotiate(event.request.headers.get('accept') || 'text/html', [
39
+ 'text/html',
40
+ 'application/json'
41
+ ]);
42
+
43
+ if (
44
+ accept === 'application/json' &&
45
+ event.request.method !== 'GET' &&
46
+ event.request.method !== 'HEAD'
47
+ ) {
48
+ const node = await options.manifest._.nodes[page.leaf]();
49
+ if (node.server) {
50
+ return handle_json_request(event, options, node.server);
51
+ }
52
+ }
53
+
54
+ const { fetcher, fetched, cookies } = create_fetch({ event, options, state, route });
55
+
56
+ try {
57
+ const nodes = await Promise.all([
58
+ // we use == here rather than === because [undefined] serializes as "[null]"
59
+ ...page.layouts.map((n) => (n == undefined ? n : options.manifest._.nodes[n]())),
60
+ options.manifest._.nodes[page.leaf]()
61
+ ]);
62
+
63
+ const leaf_node = /** @type {import('types').SSRNode} */ (nodes.at(-1));
64
+
65
+ let status = 200;
66
+
67
+ /** @type {HttpError | Error} */
68
+ let mutation_error;
69
+
70
+ /** @type {Record<string, string> | undefined} */
71
+ let validation_errors;
72
+
73
+ if (leaf_node.server && event.request.method !== 'GET' && event.request.method !== 'HEAD') {
74
+ // for non-GET requests, first call handler in +page.server.js
75
+ // (this also determines status code)
76
+ try {
77
+ const method = /** @type {'POST' | 'PATCH' | 'PUT' | 'DELETE'} */ (event.request.method);
78
+ const handler = leaf_node.server[method];
79
+ if (handler) {
80
+ const result = await handler.call(null, event);
81
+
82
+ if (result?.errors) {
83
+ validation_errors = result.errors;
84
+ status = result.status ?? 400;
85
+ }
86
+
87
+ if (event.request.method === 'POST' && result?.location) {
88
+ return redirect_response(303, result.location);
89
+ }
90
+ } else {
91
+ event.setHeaders({
92
+ allow: allowed_methods(leaf_node.server).join(', ')
93
+ });
94
+
95
+ mutation_error = error(405, 'Method not allowed');
96
+ }
97
+ } catch (e) {
98
+ if (e instanceof Redirect) {
99
+ return redirect_response(e.status, e.location);
100
+ }
101
+
102
+ mutation_error = /** @type {HttpError | Error} */ (e);
103
+ }
104
+ }
105
+
106
+ const should_prerender_data = nodes.some((node) => node?.server);
107
+ const data_pathname = event.url.pathname.replace(/\/$/, '') + DATA_SUFFIX;
108
+
109
+ // it's crucial that we do this before returning the non-SSR response, otherwise
110
+ // SvelteKit will erroneously believe that the path has been prerendered,
111
+ // causing functions to be omitted from the manifesst generated later
112
+ const should_prerender =
113
+ leaf_node.shared?.prerender ?? leaf_node.server?.prerender ?? options.prerender.default;
114
+ if (should_prerender) {
115
+ const mod = leaf_node.server;
116
+ if (mod && (mod.POST || mod.PUT || mod.DELETE || mod.PATCH)) {
117
+ throw new Error('Cannot prerender pages that have endpoints with mutative methods');
118
+ }
119
+ } else if (state.prerendering) {
120
+ // if the page isn't marked as prerenderable (or is explicitly
121
+ // marked NOT prerenderable, if `prerender.default` is `true`),
122
+ // then bail out at this point
123
+ if (!should_prerender) {
124
+ return new Response(undefined, {
125
+ status: 204
126
+ });
127
+ }
128
+ }
129
+
130
+ if (!resolve_opts.ssr) {
131
+ return await render_response({
132
+ branch: [],
133
+ validation_errors: undefined,
134
+ fetched,
135
+ cookies,
136
+ page_config: {
137
+ hydrate: true,
138
+ router: true
139
+ },
140
+ status,
141
+ error: null,
142
+ event,
143
+ options,
144
+ state,
145
+ resolve_opts
146
+ });
147
+ }
148
+
149
+ /** @type {Array<Loaded | null>} */
150
+ let branch = [];
151
+
152
+ /** @type {Error | null} */
153
+ let load_error = null;
154
+
155
+ /** @type {Array<Promise<import('types').ServerDataNode | null>>} */
156
+ const server_promises = nodes.map((node, i) => {
157
+ if (load_error) {
158
+ // if an error happens immediately, don't bother with the rest of the nodes
159
+ throw load_error;
160
+ }
161
+
162
+ return Promise.resolve().then(async () => {
163
+ try {
164
+ if (node === leaf_node && mutation_error) {
165
+ // we wait until here to throw the error so that we can use
166
+ // any nested +error.svelte components that were defined
167
+ throw mutation_error;
168
+ }
169
+
170
+ return await load_server_data({
171
+ event,
172
+ state,
173
+ node,
174
+ parent: async () => {
175
+ /** @type {Record<string, any>} */
176
+ const data = {};
177
+ for (let j = 0; j < i; j += 1) {
178
+ const parent = await server_promises[j];
179
+ if (parent) Object.assign(data, await parent.data);
180
+ }
181
+ return data;
182
+ }
183
+ });
184
+ } catch (e) {
185
+ load_error = /** @type {Error} */ (e);
186
+ throw load_error;
187
+ }
188
+ });
189
+ });
190
+
191
+ /** @type {Array<Promise<Record<string, any> | null>>} */
192
+ const load_promises = nodes.map((node, i) => {
193
+ if (load_error) throw load_error;
194
+ return Promise.resolve().then(async () => {
195
+ try {
196
+ return await load_data({
197
+ event,
198
+ fetcher,
199
+ node,
200
+ parent: async () => {
201
+ const data = {};
202
+ for (let j = 0; j < i; j += 1) {
203
+ Object.assign(data, await load_promises[j]);
204
+ }
205
+ return data;
206
+ },
207
+ server_data_promise: server_promises[i],
208
+ state
209
+ });
210
+ } catch (e) {
211
+ load_error = /** @type {Error} */ (e);
212
+ throw load_error;
213
+ }
214
+ });
215
+ });
216
+
217
+ // if we don't do this, rejections will be unhandled
218
+ for (const p of server_promises) p.catch(() => {});
219
+ for (const p of load_promises) p.catch(() => {});
220
+
221
+ for (let i = 0; i < nodes.length; i += 1) {
222
+ const node = nodes[i];
223
+
224
+ if (node) {
225
+ try {
226
+ const server_data = await server_promises[i];
227
+ const data = await load_promises[i];
228
+
229
+ branch.push({ node, server_data, data });
230
+ } catch (e) {
231
+ const error = normalize_error(e);
232
+
233
+ if (error instanceof Redirect) {
234
+ if (state.prerendering && should_prerender_data) {
235
+ const body = `window.__sveltekit_data = ${JSON.stringify({
236
+ type: 'redirect',
237
+ location: error.location
238
+ })}`;
239
+
240
+ state.prerendering.dependencies.set(data_pathname, {
241
+ response: new Response(body),
242
+ body
243
+ });
244
+ }
245
+
246
+ return redirect_response(error.status, error.location);
247
+ }
248
+
249
+ if (!(error instanceof HttpError)) {
250
+ options.handle_error(/** @type {Error} */ (error), event);
251
+ }
252
+
253
+ const status = error instanceof HttpError ? error.status : 500;
254
+
255
+ while (i--) {
256
+ if (page.errors[i]) {
257
+ const index = /** @type {number} */ (page.errors[i]);
258
+ const node = await options.manifest._.nodes[index]();
259
+
260
+ let j = i;
261
+ while (!branch[j]) j -= 1;
262
+
263
+ return await render_response({
264
+ event,
265
+ options,
266
+ state,
267
+ resolve_opts,
268
+ page_config: { router: true, hydrate: true },
269
+ status,
270
+ error,
271
+ branch: compact(branch.slice(0, j + 1)).concat({
272
+ node,
273
+ data: null,
274
+ server_data: null
275
+ }),
276
+ fetched,
277
+ cookies,
278
+ validation_errors: undefined
279
+ });
280
+ }
281
+ }
282
+
283
+ // if we're still here, it means the error happened in the root layout,
284
+ // which means we have to fall back to a plain text response
285
+ // TODO since the requester is expecting HTML, maybe it makes sense to
286
+ // doll this up a bit
287
+ return new Response(
288
+ error instanceof HttpError ? error.message : options.get_stack(error),
289
+ { status }
290
+ );
291
+ }
292
+ } else {
293
+ // push an empty slot so we can rewind past gaps to the
294
+ // layout that corresponds with an +error.svelte page
295
+ branch.push(null);
296
+ }
297
+ }
298
+
299
+ if (state.prerendering && should_prerender_data) {
300
+ const body = `window.__sveltekit_data = ${devalue({
301
+ type: 'data',
302
+ nodes: branch.map((branch_node) => branch_node?.server_data)
303
+ })}`;
304
+
305
+ state.prerendering.dependencies.set(data_pathname, {
306
+ response: new Response(body),
307
+ body
308
+ });
309
+ }
310
+
311
+ // TODO use validation_errors
312
+
313
+ return await render_response({
314
+ event,
315
+ options,
316
+ state,
317
+ resolve_opts,
318
+ page_config: get_page_config(leaf_node, options),
319
+ status,
320
+ error: null,
321
+ branch: compact(branch),
322
+ validation_errors,
323
+ fetched,
324
+ cookies
325
+ });
326
+ } catch (error) {
327
+ // if we end up here, it means the data loaded successfull
328
+ // but the page failed to render
329
+ options.handle_error(/** @type {Error} */ (error), event);
330
+
331
+ return await respond_with_error({
332
+ event,
333
+ options,
334
+ state,
335
+ status: 500,
336
+ error: /** @type {Error} */ (error),
337
+ resolve_opts
338
+ });
339
+ }
340
+ }
341
+
342
+ /**
343
+ * @param {import('types').SSRNode} leaf
344
+ * @param {SSROptions} options
345
+ */
346
+ function get_page_config(leaf, options) {
347
+ // TODO we can reinstate this now that it's in the module
348
+ if (leaf.shared && 'ssr' in leaf.shared) {
349
+ throw new Error(
350
+ '`export const ssr` has been removed — use the handle hook instead: https://kit.svelte.dev/docs/hooks#handle'
351
+ );
352
+ }
353
+
354
+ return {
355
+ router: leaf.shared?.router ?? options.router,
356
+ hydrate: leaf.shared?.hydrate ?? options.hydrate
357
+ };
358
+ }
359
+
360
+ /**
361
+ * @param {import('types').RequestEvent} event
362
+ * @param {import('types').SSROptions} options
363
+ * @param {import('types').SSRNode['server']} mod
364
+ */
365
+ export async function handle_json_request(event, options, mod) {
366
+ const method = /** @type {'POST' | 'PUT' | 'PATCH' | 'DELETE'} */ (event.request.method);
367
+ const handler = mod[method];
368
+
369
+ if (!handler) {
370
+ return method_not_allowed(mod, method);
371
+ }
372
+
373
+ try {
374
+ // @ts-ignore
375
+ const result = await handler.call(null, event);
376
+
377
+ if (result?.errors) {
378
+ // @ts-ignore
379
+ return json({ errors: result.errors }, { status: result.status || 400 });
380
+ }
381
+
382
+ return new Response(undefined, {
383
+ status: 204,
384
+ // @ts-ignore
385
+ headers: result?.location ? { location: result.location } : undefined
386
+ });
387
+ } catch (e) {
388
+ const error = normalize_error(e);
389
+
390
+ if (error instanceof Redirect) {
391
+ return redirect_response(error.status, error.location);
392
+ }
393
+
394
+ if (!(error instanceof HttpError)) {
395
+ options.handle_error(error, event);
396
+ }
397
+
398
+ return json(error_to_pojo(error, options.get_stack), {
399
+ status: error instanceof HttpError ? error.status : 500
400
+ });
401
+ }
402
+ }
403
+
404
+ /**
405
+ * @param {number} status
406
+ * @param {string} location
407
+ */
408
+ function redirect_response(status, location) {
409
+ return new Response(undefined, {
410
+ status,
411
+ headers: { location }
412
+ });
413
+ }
@@ -0,0 +1,124 @@
1
+ import { disable_search, make_trackable } from '../../../utils/url.js';
2
+
3
+ /**
4
+ * Calls the user's `load` function.
5
+ * @param {{
6
+ * event: import('types').RequestEvent;
7
+ * state: import('types').SSRState;
8
+ * node: import('types').SSRNode | undefined;
9
+ * parent: () => Promise<Record<string, any>>;
10
+ * }} opts
11
+ * @returns {Promise<import('types').ServerDataNode | null>}
12
+ */
13
+ export async function load_server_data({ event, state, node, parent }) {
14
+ if (!node?.server) return null;
15
+
16
+ const uses = {
17
+ dependencies: new Set(),
18
+ params: new Set(),
19
+ parent: false,
20
+ url: false
21
+ };
22
+
23
+ const url = make_trackable(event.url, () => {
24
+ uses.url = true;
25
+ });
26
+
27
+ if (state.prerendering) {
28
+ disable_search(url);
29
+ }
30
+
31
+ const result = await node.server.load?.call(null, {
32
+ ...event,
33
+ /** @param {string[]} deps */
34
+ depends: (...deps) => {
35
+ for (const dep of deps) {
36
+ const { href } = new URL(dep, event.url);
37
+ uses.dependencies.add(href);
38
+ }
39
+ },
40
+ params: new Proxy(event.params, {
41
+ get: (target, key) => {
42
+ uses.params.add(key);
43
+ return target[/** @type {string} */ (key)];
44
+ }
45
+ }),
46
+ parent: async () => {
47
+ uses.parent = true;
48
+ return parent();
49
+ },
50
+ url
51
+ });
52
+
53
+ const data = result ? await unwrap_promises(result) : null;
54
+
55
+ return {
56
+ type: 'data',
57
+ data,
58
+ uses: {
59
+ dependencies: uses.dependencies.size > 0 ? Array.from(uses.dependencies) : undefined,
60
+ params: uses.params.size > 0 ? Array.from(uses.params) : undefined,
61
+ parent: uses.parent ? 1 : undefined,
62
+ url: uses.url ? 1 : undefined
63
+ }
64
+ };
65
+ }
66
+
67
+ /**
68
+ * Calls the user's `load` function.
69
+ * @param {{
70
+ * event: import('types').RequestEvent;
71
+ * fetcher: typeof fetch;
72
+ * node: import('types').SSRNode | undefined;
73
+ * parent: () => Promise<Record<string, any>>;
74
+ * server_data_promise: Promise<import('types').ServerDataNode | null>;
75
+ * state: import('types').SSRState;
76
+ * }} opts
77
+ * @returns {Promise<Record<string, any> | null>}
78
+ */
79
+ export async function load_data({ event, fetcher, node, parent, server_data_promise }) {
80
+ const server_data_node = await server_data_promise;
81
+
82
+ if (!node?.shared?.load) {
83
+ return server_data_node?.data ?? null;
84
+ }
85
+
86
+ const load_event = {
87
+ url: event.url,
88
+ params: event.params,
89
+ data: server_data_node?.data ?? null,
90
+ routeId: event.routeId,
91
+ fetch: fetcher,
92
+ setHeaders: event.setHeaders,
93
+ depends: () => {},
94
+ parent
95
+ };
96
+
97
+ // TODO remove this for 1.0
98
+ Object.defineProperties(load_event, {
99
+ session: {
100
+ get() {
101
+ throw new Error(
102
+ 'session is no longer available. See https://github.com/sveltejs/kit/discussions/5883'
103
+ );
104
+ },
105
+ enumerable: false
106
+ }
107
+ });
108
+
109
+ const data = await node.shared.load.call(null, load_event);
110
+
111
+ return data ? unwrap_promises(data) : null;
112
+ }
113
+
114
+ /** @param {Record<string, any>} object */
115
+ async function unwrap_promises(object) {
116
+ /** @type {Record<string, any>} */
117
+ const unwrapped = {};
118
+
119
+ for (const key in object) {
120
+ unwrapped[key] = await object[key];
121
+ }
122
+
123
+ return unwrapped;
124
+ }