@sveltejs/kit 1.0.0-next.41 → 1.0.0-next.412

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 (129) hide show
  1. package/README.md +12 -9
  2. package/package.json +97 -63
  3. package/src/cli.js +119 -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 +3 -0
  10. package/src/core/generate_manifest/index.js +99 -0
  11. package/src/core/prerender/crawl.js +194 -0
  12. package/src/core/prerender/prerender.js +378 -0
  13. package/src/core/prerender/queue.js +80 -0
  14. package/src/core/sync/create_manifest_data/index.js +496 -0
  15. package/src/core/sync/create_manifest_data/types.d.ts +40 -0
  16. package/src/core/sync/sync.js +59 -0
  17. package/src/core/sync/utils.js +97 -0
  18. package/src/core/sync/write_ambient.js +87 -0
  19. package/src/core/sync/write_client_manifest.js +82 -0
  20. package/src/core/sync/write_matchers.js +25 -0
  21. package/src/core/sync/write_root.js +88 -0
  22. package/src/core/sync/write_tsconfig.js +189 -0
  23. package/src/core/sync/write_types.js +727 -0
  24. package/src/core/utils.js +58 -0
  25. package/src/hooks.js +26 -0
  26. package/src/index/index.js +45 -0
  27. package/src/index/private.js +33 -0
  28. package/src/node/index.js +145 -0
  29. package/src/node/polyfills.js +40 -0
  30. package/src/packaging/index.js +218 -0
  31. package/src/packaging/types.d.ts +8 -0
  32. package/src/packaging/typescript.js +150 -0
  33. package/src/packaging/utils.js +143 -0
  34. package/src/runtime/app/env.js +11 -0
  35. package/src/runtime/app/navigation.js +22 -0
  36. package/src/runtime/app/paths.js +1 -0
  37. package/src/runtime/app/stores.js +94 -0
  38. package/src/runtime/client/ambient.d.ts +17 -0
  39. package/src/runtime/client/client.js +1281 -0
  40. package/src/runtime/client/fetcher.js +60 -0
  41. package/src/runtime/client/parse.js +36 -0
  42. package/src/runtime/client/singletons.js +11 -0
  43. package/src/runtime/client/start.js +48 -0
  44. package/src/runtime/client/types.d.ts +106 -0
  45. package/src/runtime/client/utils.js +113 -0
  46. package/src/runtime/components/error.svelte +16 -0
  47. package/{assets → src/runtime}/components/layout.svelte +0 -0
  48. package/src/runtime/env/dynamic/private.js +1 -0
  49. package/src/runtime/env/dynamic/public.js +1 -0
  50. package/src/runtime/env-private.js +7 -0
  51. package/src/runtime/env-public.js +7 -0
  52. package/src/runtime/env.js +6 -0
  53. package/src/runtime/hash.js +16 -0
  54. package/src/runtime/paths.js +11 -0
  55. package/src/runtime/server/endpoint.js +42 -0
  56. package/src/runtime/server/index.js +434 -0
  57. package/src/runtime/server/page/cookie.js +25 -0
  58. package/src/runtime/server/page/crypto.js +239 -0
  59. package/src/runtime/server/page/csp.js +249 -0
  60. package/src/runtime/server/page/fetch.js +266 -0
  61. package/src/runtime/server/page/index.js +418 -0
  62. package/src/runtime/server/page/load_data.js +94 -0
  63. package/src/runtime/server/page/render.js +363 -0
  64. package/src/runtime/server/page/respond_with_error.js +105 -0
  65. package/src/runtime/server/page/types.d.ts +44 -0
  66. package/src/runtime/server/utils.js +116 -0
  67. package/src/utils/error.js +22 -0
  68. package/src/utils/escape.js +104 -0
  69. package/src/utils/filesystem.js +108 -0
  70. package/src/utils/http.js +55 -0
  71. package/src/utils/misc.js +1 -0
  72. package/src/utils/routing.js +107 -0
  73. package/src/utils/url.js +97 -0
  74. package/src/vite/build/build_server.js +339 -0
  75. package/src/vite/build/build_service_worker.js +90 -0
  76. package/src/vite/build/utils.js +153 -0
  77. package/src/vite/dev/index.js +569 -0
  78. package/src/vite/index.js +540 -0
  79. package/src/vite/preview/index.js +186 -0
  80. package/src/vite/types.d.ts +3 -0
  81. package/src/vite/utils.js +335 -0
  82. package/svelte-kit.js +1 -1
  83. package/types/ambient.d.ts +368 -0
  84. package/types/index.d.ts +345 -0
  85. package/types/internal.d.ts +309 -0
  86. package/types/private.d.ts +236 -0
  87. package/CHANGELOG.md +0 -419
  88. package/assets/components/error.svelte +0 -13
  89. package/assets/runtime/app/env.js +0 -5
  90. package/assets/runtime/app/navigation.js +0 -41
  91. package/assets/runtime/app/paths.js +0 -1
  92. package/assets/runtime/app/stores.js +0 -93
  93. package/assets/runtime/chunks/utils.js +0 -19
  94. package/assets/runtime/internal/singletons.js +0 -23
  95. package/assets/runtime/internal/start.js +0 -770
  96. package/assets/runtime/paths.js +0 -12
  97. package/dist/api.js +0 -28
  98. package/dist/api.js.map +0 -1
  99. package/dist/chunks/index.js +0 -3519
  100. package/dist/chunks/index2.js +0 -587
  101. package/dist/chunks/index3.js +0 -246
  102. package/dist/chunks/index4.js +0 -524
  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/cli.js.map +0 -1
  109. package/dist/create_app.js +0 -592
  110. package/dist/create_app.js.map +0 -1
  111. package/dist/index.js +0 -392
  112. package/dist/index.js.map +0 -1
  113. package/dist/index2.js +0 -3519
  114. package/dist/index2.js.map +0 -1
  115. package/dist/index3.js +0 -320
  116. package/dist/index3.js.map +0 -1
  117. package/dist/index4.js +0 -323
  118. package/dist/index4.js.map +0 -1
  119. package/dist/index5.js +0 -247
  120. package/dist/index5.js.map +0 -1
  121. package/dist/index6.js +0 -761
  122. package/dist/index6.js.map +0 -1
  123. package/dist/renderer.js +0 -2499
  124. package/dist/renderer.js.map +0 -1
  125. package/dist/ssr.js +0 -2581
  126. package/dist/standard.js +0 -100
  127. package/dist/standard.js.map +0 -1
  128. package/dist/utils.js +0 -84
  129. package/dist/utils.js.map +0 -1
@@ -0,0 +1,363 @@
1
+ import devalue from 'devalue';
2
+ import { readable, writable } from 'svelte/store';
3
+ import * as cookie from 'cookie';
4
+ import { coalesce_to_error } from '../../../utils/error.js';
5
+ import { hash } from '../../hash.js';
6
+ import { render_json_payload_script } from '../../../utils/escape.js';
7
+ import { s } from '../../../utils/misc.js';
8
+ import { Csp } from './csp.js';
9
+ import { PrerenderingURL } from '../../../utils/url.js';
10
+ import { serialize_error } from '../utils.js';
11
+ import { HttpError } from '../../../index/private.js';
12
+
13
+ // TODO rename this function/module
14
+
15
+ const updated = {
16
+ ...readable(false),
17
+ check: () => false
18
+ };
19
+
20
+ /**
21
+ * Creates the HTML response.
22
+ * @param {{
23
+ * branch: Array<import('./types').Loaded>;
24
+ * fetched: Array<import('./types').Fetched>;
25
+ * cookies: import('set-cookie-parser').Cookie[];
26
+ * options: import('types').SSROptions;
27
+ * state: import('types').SSRState;
28
+ * $session: any;
29
+ * page_config: { hydrate: boolean, router: boolean };
30
+ * status: number;
31
+ * error: HttpError | Error | null;
32
+ * event: import('types').RequestEvent;
33
+ * resolve_opts: import('types').RequiredResolveOptions;
34
+ * validation_errors: Record<string, string> | undefined;
35
+ * }} opts
36
+ */
37
+ export async function render_response({
38
+ branch,
39
+ fetched,
40
+ cookies,
41
+ options,
42
+ state,
43
+ $session,
44
+ page_config,
45
+ status,
46
+ error = null,
47
+ event,
48
+ resolve_opts,
49
+ validation_errors
50
+ }) {
51
+ if (state.prerendering) {
52
+ if (options.csp.mode === 'nonce') {
53
+ throw new Error('Cannot use prerendering if config.kit.csp.mode === "nonce"');
54
+ }
55
+
56
+ if (options.template_contains_nonce) {
57
+ throw new Error('Cannot use prerendering if page template contains %sveltekit.nonce%');
58
+ }
59
+ }
60
+
61
+ const { entry } = options.manifest._;
62
+
63
+ const stylesheets = new Set(entry.stylesheets);
64
+ const modulepreloads = new Set(entry.imports);
65
+
66
+ /** @type {Set<string>} */
67
+ const link_header_preloads = new Set();
68
+
69
+ /** @type {Map<string, string>} */
70
+ // TODO if we add a client entry point one day, we will need to include inline_styles with the entry, otherwise stylesheets will be linked even if they are below inlineStyleThreshold
71
+ const inline_styles = new Map();
72
+
73
+ let rendered;
74
+
75
+ const stack = error instanceof HttpError ? undefined : error?.stack;
76
+
77
+ if (error && options.dev && !(error instanceof HttpError)) {
78
+ error.stack = options.get_stack(error);
79
+ }
80
+
81
+ if (resolve_opts.ssr) {
82
+ const session = writable($session);
83
+
84
+ /** @type {Record<string, any>} */
85
+ const props = {
86
+ stores: {
87
+ page: writable(null),
88
+ navigating: writable(null),
89
+ session,
90
+ updated
91
+ },
92
+ /** @type {import('types').Page} */
93
+ page: {
94
+ error,
95
+ params: event.params,
96
+ routeId: event.routeId,
97
+ status,
98
+ url: state.prerendering ? new PrerenderingURL(event.url) : event.url,
99
+ data: branch.reduce((acc, { data }) => (Object.assign(acc, data), acc), {})
100
+ },
101
+ components: await Promise.all(branch.map(({ node }) => node.component()))
102
+ };
103
+
104
+ // TODO remove this for 1.0
105
+ /**
106
+ * @param {string} property
107
+ * @param {string} replacement
108
+ */
109
+ const print_error = (property, replacement) => {
110
+ Object.defineProperty(props.page, property, {
111
+ get: () => {
112
+ throw new Error(`$page.${property} has been replaced by $page.url.${replacement}`);
113
+ }
114
+ });
115
+ };
116
+
117
+ print_error('origin', 'origin');
118
+ print_error('path', 'pathname');
119
+ print_error('query', 'searchParams');
120
+
121
+ // props_n (instead of props[n]) makes it easy to avoid
122
+ // unnecessary updates for layout components
123
+ for (let i = 0; i < branch.length; i += 1) {
124
+ props[`data_${i}`] = branch[i].data;
125
+ }
126
+
127
+ if (validation_errors) {
128
+ props.errors = validation_errors;
129
+ }
130
+
131
+ rendered = options.root.render(props);
132
+
133
+ for (const { node } of branch) {
134
+ if (node.imports) {
135
+ node.imports.forEach((url) => modulepreloads.add(url));
136
+ }
137
+
138
+ if (node.stylesheets) {
139
+ node.stylesheets.forEach((url) => stylesheets.add(url));
140
+ }
141
+
142
+ if (node.inline_styles) {
143
+ Object.entries(await node.inline_styles()).forEach(([k, v]) => inline_styles.set(k, v));
144
+ }
145
+ }
146
+ } else {
147
+ rendered = { head: '', html: '', css: { code: '', map: null } };
148
+ }
149
+
150
+ let { head, html: body } = rendered;
151
+
152
+ const csp = new Csp(options.csp, {
153
+ dev: options.dev,
154
+ prerender: !!state.prerendering
155
+ });
156
+
157
+ const target = hash(body);
158
+
159
+ // prettier-ignore
160
+ const init_app = `
161
+ import { set_public_env, start } from ${s(options.prefix + entry.file)};
162
+
163
+ set_public_env(${s(options.public_env)});
164
+
165
+ start({
166
+ target: document.querySelector('[data-sveltekit-hydrate="${target}"]').parentNode,
167
+ paths: ${s(options.paths)},
168
+ session: ${try_serialize($session, (error) => {
169
+ throw new Error(`Failed to serialize session data: ${error.message}`);
170
+ })},
171
+ route: ${!!page_config.router},
172
+ spa: ${!resolve_opts.ssr},
173
+ trailing_slash: ${s(options.trailing_slash)},
174
+ hydrate: ${resolve_opts.ssr && page_config.hydrate ? `{
175
+ status: ${status},
176
+ error: ${error && serialize_error(error, e => e.stack)},
177
+ node_ids: [${branch.map(({ node }) => node.index).join(', ')}],
178
+ params: ${devalue(event.params)},
179
+ routeId: ${s(event.routeId)}
180
+ }` : 'null'}
181
+ });
182
+ `;
183
+
184
+ // we use an anonymous function instead of an arrow function to support
185
+ // older browsers (https://github.com/sveltejs/kit/pull/5417)
186
+ const init_service_worker = `
187
+ if ('serviceWorker' in navigator) {
188
+ addEventListener('load', function () {
189
+ navigator.serviceWorker.register('${options.service_worker}');
190
+ });
191
+ }
192
+ `;
193
+
194
+ if (inline_styles.size > 0) {
195
+ const content = Array.from(inline_styles.values()).join('\n');
196
+
197
+ const attributes = [];
198
+ if (options.dev) attributes.push(' data-sveltekit');
199
+ if (csp.style_needs_nonce) attributes.push(` nonce="${csp.nonce}"`);
200
+
201
+ csp.add_style(content);
202
+
203
+ head += `\n\t<style${attributes.join('')}>${content}</style>`;
204
+ }
205
+
206
+ for (const dep of stylesheets) {
207
+ const path = options.prefix + dep;
208
+ const attributes = [];
209
+
210
+ if (csp.style_needs_nonce) {
211
+ attributes.push(`nonce="${csp.nonce}"`);
212
+ }
213
+
214
+ if (inline_styles.has(dep)) {
215
+ // don't load stylesheets that are already inlined
216
+ // include them in disabled state so that Vite can detect them and doesn't try to add them
217
+ attributes.push('disabled', 'media="(max-width: 0)"');
218
+ } else {
219
+ const preload_atts = ['rel="preload"', 'as="style"'].concat(attributes);
220
+ link_header_preloads.add(`<${encodeURI(path)}>; ${preload_atts.join(';')}; nopush`);
221
+ }
222
+
223
+ attributes.unshift('rel="stylesheet"');
224
+ head += `\n\t<link href="${path}" ${attributes.join(' ')}>`;
225
+ }
226
+
227
+ if (page_config.router || page_config.hydrate) {
228
+ for (const dep of modulepreloads) {
229
+ const path = options.prefix + dep;
230
+ link_header_preloads.add(`<${encodeURI(path)}>; rel="modulepreload"; nopush`);
231
+ if (state.prerendering) {
232
+ head += `\n\t<link rel="modulepreload" href="${path}">`;
233
+ }
234
+ }
235
+
236
+ const attributes = ['type="module"', `data-sveltekit-hydrate="${target}"`];
237
+
238
+ csp.add_script(init_app);
239
+
240
+ if (csp.script_needs_nonce) {
241
+ attributes.push(`nonce="${csp.nonce}"`);
242
+ }
243
+
244
+ body += `\n\t\t<script ${attributes.join(' ')}>${init_app}</script>`;
245
+ }
246
+
247
+ if (resolve_opts.ssr && page_config.hydrate) {
248
+ /** @type {string[]} */
249
+ const serialized_data = [];
250
+
251
+ for (const { url, body, response } of fetched) {
252
+ serialized_data.push(
253
+ render_json_payload_script(
254
+ { type: 'data', url, body: typeof body === 'string' ? hash(body) : undefined },
255
+ response
256
+ )
257
+ );
258
+ }
259
+
260
+ if (branch.some((node) => node.server_data)) {
261
+ serialized_data.push(
262
+ render_json_payload_script(
263
+ { type: 'server_data' },
264
+ branch.map(({ server_data }) => server_data)
265
+ )
266
+ );
267
+ }
268
+
269
+ if (validation_errors) {
270
+ serialized_data.push(
271
+ render_json_payload_script({ type: 'validation_errors' }, validation_errors)
272
+ );
273
+ }
274
+
275
+ body += `\n\t${serialized_data.join('\n\t')}`;
276
+ }
277
+
278
+ if (options.service_worker) {
279
+ // always include service worker unless it's turned off explicitly
280
+ csp.add_script(init_service_worker);
281
+
282
+ head += `
283
+ <script${csp.script_needs_nonce ? ` nonce="${csp.nonce}"` : ''}>${init_service_worker}</script>`;
284
+ }
285
+
286
+ if (state.prerendering) {
287
+ // TODO read headers set with setHeaders and convert into http-equiv where possible
288
+ const http_equiv = [];
289
+
290
+ const csp_headers = csp.csp_provider.get_meta();
291
+ if (csp_headers) {
292
+ http_equiv.push(csp_headers);
293
+ }
294
+
295
+ if (state.prerendering.cache) {
296
+ http_equiv.push(`<meta http-equiv="cache-control" content="${state.prerendering.cache}">`);
297
+ }
298
+
299
+ if (http_equiv.length > 0) {
300
+ head = http_equiv.join('\n') + head;
301
+ }
302
+ }
303
+
304
+ const segments = event.url.pathname.slice(options.paths.base.length).split('/').slice(2);
305
+ const assets =
306
+ options.paths.assets || (segments.length > 0 ? segments.map(() => '..').join('/') : '.');
307
+
308
+ // TODO flush chunks as early as we can
309
+ const html =
310
+ (await resolve_opts.transformPageChunk({
311
+ html: options.template({ head, body, assets, nonce: /** @type {string} */ (csp.nonce) }),
312
+ done: true
313
+ })) || '';
314
+
315
+ const headers = new Headers({
316
+ 'content-type': 'text/html',
317
+ etag: `"${hash(html)}"`
318
+ });
319
+
320
+ if (!state.prerendering) {
321
+ const csp_header = csp.csp_provider.get_header();
322
+ if (csp_header) {
323
+ headers.set('content-security-policy', csp_header);
324
+ }
325
+ const report_only_header = csp.report_only_provider.get_header();
326
+ if (report_only_header) {
327
+ headers.set('content-security-policy-report-only', report_only_header);
328
+ }
329
+
330
+ for (const new_cookie of cookies) {
331
+ const { name, value, ...options } = new_cookie;
332
+ // @ts-expect-error
333
+ headers.append('set-cookie', cookie.serialize(name, value, options));
334
+ }
335
+
336
+ if (link_header_preloads.size) {
337
+ headers.set('link', Array.from(link_header_preloads).join(', '));
338
+ }
339
+ }
340
+
341
+ if (error && options.dev && !(error instanceof HttpError)) {
342
+ // reset stack, otherwise it may be 'fixed' a second time
343
+ error.stack = stack;
344
+ }
345
+
346
+ return new Response(html, {
347
+ status,
348
+ headers
349
+ });
350
+ }
351
+
352
+ /**
353
+ * @param {any} data
354
+ * @param {(error: Error) => void} [fail]
355
+ */
356
+ function try_serialize(data, fail) {
357
+ try {
358
+ return devalue(data);
359
+ } catch (err) {
360
+ if (fail) fail(coalesce_to_error(err));
361
+ return null;
362
+ }
363
+ }
@@ -0,0 +1,105 @@
1
+ import { render_response } from './render.js';
2
+ import { load_data, load_server_data } from './load_data.js';
3
+ import { coalesce_to_error } from '../../../utils/error.js';
4
+ import { GENERIC_ERROR } from '../utils.js';
5
+ import { create_fetch } from './fetch.js';
6
+
7
+ /**
8
+ * @typedef {import('./types.js').Loaded} Loaded
9
+ * @typedef {import('types').SSROptions} SSROptions
10
+ * @typedef {import('types').SSRState} SSRState
11
+ */
12
+
13
+ /**
14
+ * @param {{
15
+ * event: import('types').RequestEvent;
16
+ * options: SSROptions;
17
+ * state: SSRState;
18
+ * $session: any;
19
+ * status: number;
20
+ * error: Error;
21
+ * resolve_opts: import('types').RequiredResolveOptions;
22
+ * }} opts
23
+ */
24
+ export async function respond_with_error({
25
+ event,
26
+ options,
27
+ state,
28
+ $session,
29
+ status,
30
+ error,
31
+ resolve_opts
32
+ }) {
33
+ const { fetcher, fetched, cookies } = create_fetch({
34
+ event,
35
+ options,
36
+ state,
37
+ route: GENERIC_ERROR
38
+ });
39
+
40
+ try {
41
+ const branch = [];
42
+
43
+ if (resolve_opts.ssr) {
44
+ const default_layout = await options.manifest._.nodes[0](); // 0 is always the root layout
45
+
46
+ const server_data_promise = load_server_data({
47
+ event,
48
+ node: default_layout,
49
+ parent: async () => ({})
50
+ });
51
+
52
+ const server_data = await server_data_promise;
53
+
54
+ const data = await load_data({
55
+ $session,
56
+ event,
57
+ fetcher,
58
+ node: default_layout,
59
+ options,
60
+ parent: async () => ({}),
61
+ server_data_promise,
62
+ state
63
+ });
64
+
65
+ branch.push(
66
+ {
67
+ node: default_layout,
68
+ server_data,
69
+ data
70
+ },
71
+ {
72
+ node: await options.manifest._.nodes[1](), // 1 is always the root error
73
+ data: null,
74
+ server_data: null
75
+ }
76
+ );
77
+ }
78
+
79
+ return await render_response({
80
+ options,
81
+ state,
82
+ $session,
83
+ page_config: {
84
+ hydrate: options.hydrate,
85
+ router: options.router
86
+ },
87
+ status,
88
+ error,
89
+ branch,
90
+ fetched,
91
+ cookies,
92
+ event,
93
+ resolve_opts,
94
+ validation_errors: undefined
95
+ });
96
+ } catch (err) {
97
+ const error = coalesce_to_error(err);
98
+
99
+ options.handle_error(error, event);
100
+
101
+ return new Response(error.stack, {
102
+ status: 500
103
+ });
104
+ }
105
+ }
@@ -0,0 +1,44 @@
1
+ import { JSONValue, ResponseHeaders, SSRNode, CspDirectives } from 'types';
2
+ import { HttpError } from '../../../index/private';
3
+
4
+ export interface Fetched {
5
+ url: string;
6
+ body?: string | null;
7
+ response: {
8
+ status: number;
9
+ statusText: string;
10
+ headers: ResponseHeaders;
11
+ body: string;
12
+ };
13
+ }
14
+
15
+ export interface FetchState {
16
+ fetched: Fetched[];
17
+ cookies: string[];
18
+ new_cookies: string[];
19
+ }
20
+
21
+ export type Loaded = {
22
+ node: SSRNode;
23
+ data: Record<string, any> | null;
24
+ server_data: JSONValue;
25
+ };
26
+
27
+ type CspMode = 'hash' | 'nonce' | 'auto';
28
+
29
+ export interface CspConfig {
30
+ mode: CspMode;
31
+ directives: CspDirectives;
32
+ reportOnly: CspDirectives;
33
+ }
34
+
35
+ export interface CspOpts {
36
+ dev: boolean;
37
+ prerender: boolean;
38
+ }
39
+
40
+ export interface SerializedHttpError extends Pick<HttpError, 'message' | 'status'> {
41
+ name: 'HttpError';
42
+ stack: '';
43
+ __is_http_error: true;
44
+ }
@@ -0,0 +1,116 @@
1
+ import { HttpError } from '../../index/private.js';
2
+
3
+ /** @param {any} body */
4
+ export function is_pojo(body) {
5
+ if (typeof body !== 'object') return false;
6
+
7
+ if (body) {
8
+ if (body instanceof Uint8Array) return false;
9
+ if (body instanceof ReadableStream) return false;
10
+
11
+ // if body is a node Readable, throw an error
12
+ // TODO remove this for 1.0
13
+ if (body._readableState && typeof body.pipe === 'function') {
14
+ throw new Error('Node streams are no longer supported — use a ReadableStream instead');
15
+ }
16
+ }
17
+
18
+ return true;
19
+ }
20
+
21
+ /**
22
+ * Serialize an error into a JSON string through `error_to_pojo`.
23
+ * This is necessary because `JSON.stringify(error) === '{}'`
24
+ *
25
+ * @param {Error | HttpError} error
26
+ * @param {(error: Error) => string | undefined} get_stack
27
+ */
28
+ export function serialize_error(error, get_stack) {
29
+ return JSON.stringify(error_to_pojo(error, get_stack));
30
+ }
31
+
32
+ /**
33
+ * Transform an error into a POJO, by copying its `name`, `message`
34
+ * and (in dev) `stack`, plus any custom properties, plus recursively
35
+ * serialized `cause` properties.
36
+ * Our own HttpError gets a meta property attached so we can identify it on the client.
37
+ *
38
+ * @param {HttpError | Error } error
39
+ * @param {(error: Error) => string | undefined} get_stack
40
+ */
41
+ export function error_to_pojo(error, get_stack) {
42
+ if (error instanceof HttpError) {
43
+ return /** @type {import('./page/types').SerializedHttpError} */ ({
44
+ message: error.message,
45
+ status: error.status,
46
+ __is_http_error: true // TODO we should probably make this unnecessary
47
+ });
48
+ }
49
+
50
+ const {
51
+ name,
52
+ message,
53
+ stack,
54
+ // @ts-expect-error i guess typescript doesn't know about error.cause yet
55
+ cause,
56
+ ...custom
57
+ } = error;
58
+
59
+ /** @type {Record<string, any>} */
60
+ const object = { name, message, stack: get_stack(error) };
61
+
62
+ if (cause) object.cause = error_to_pojo(cause, get_stack);
63
+
64
+ for (const key in custom) {
65
+ // @ts-expect-error
66
+ object[key] = custom[key];
67
+ }
68
+
69
+ return object;
70
+ }
71
+
72
+ // TODO: Remove for 1.0
73
+ /** @param {Record<string, any>} mod */
74
+ export function check_method_names(mod) {
75
+ ['get', 'post', 'put', 'patch', 'del'].forEach((m) => {
76
+ if (m in mod) {
77
+ const replacement = m === 'del' ? 'DELETE' : m.toUpperCase();
78
+ throw Error(
79
+ `Endpoint method "${m}" has changed to "${replacement}". See https://github.com/sveltejs/kit/discussions/5359 for more information.`
80
+ );
81
+ }
82
+ });
83
+ }
84
+
85
+ /** @type {import('types').SSRErrorPage} */
86
+ export const GENERIC_ERROR = {
87
+ id: '__error'
88
+ };
89
+
90
+ /**
91
+ * @param {Partial<Record<import('types').HttpMethod, any>>} mod
92
+ * @param {import('types').HttpMethod} method
93
+ */
94
+ export function method_not_allowed(mod, method) {
95
+ return new Response(`${method} method not allowed`, {
96
+ status: 405,
97
+ headers: {
98
+ // https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/405
99
+ // "The server must generate an Allow header field in a 405 status code response"
100
+ allow: allowed_methods(mod).join(', ')
101
+ }
102
+ });
103
+ }
104
+
105
+ /** @param {Partial<Record<import('types').HttpMethod, any>>} mod */
106
+ export function allowed_methods(mod) {
107
+ const allowed = [];
108
+
109
+ for (const method in ['GET', 'POST', 'PUT', 'PATCH', 'DELETE']) {
110
+ if (method in mod) allowed.push(method);
111
+ }
112
+
113
+ if (mod.GET || mod.HEAD) allowed.push('HEAD');
114
+
115
+ return allowed;
116
+ }
@@ -0,0 +1,22 @@
1
+ import { HttpError, Redirect } from '../index/private.js';
2
+
3
+ /**
4
+ * @param {unknown} err
5
+ * @return {Error}
6
+ */
7
+ export function coalesce_to_error(err) {
8
+ return err instanceof Error ||
9
+ (err && /** @type {any} */ (err).name && /** @type {any} */ (err).message)
10
+ ? /** @type {Error} */ (err)
11
+ : new Error(JSON.stringify(err));
12
+ }
13
+
14
+ /**
15
+ * This is an identity function that exists to make TypeScript less
16
+ * paranoid about people throwing things that aren't errors, which
17
+ * frankly is not something we should care about
18
+ * @param {unknown} error
19
+ */
20
+ export function normalize_error(error) {
21
+ return /** @type {Redirect | HttpError | Error} */ (error);
22
+ }