@sveltejs/kit 1.0.0-next.43 → 1.0.0-next.430

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