@sveltejs/kit 1.0.0-next.52 → 1.0.0-next.520

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 (128) hide show
  1. package/README.md +6 -3
  2. package/package.json +93 -67
  3. package/postinstall.js +47 -0
  4. package/scripts/special-types/$env+dynamic+private.md +10 -0
  5. package/scripts/special-types/$env+dynamic+public.md +8 -0
  6. package/scripts/special-types/$env+static+private.md +19 -0
  7. package/scripts/special-types/$env+static+public.md +7 -0
  8. package/scripts/special-types/$lib.md +5 -0
  9. package/src/cli.js +108 -0
  10. package/src/constants.js +7 -0
  11. package/src/core/adapt/builder.js +215 -0
  12. package/src/core/adapt/index.js +31 -0
  13. package/src/core/config/default-error.html +56 -0
  14. package/src/core/config/index.js +110 -0
  15. package/src/core/config/options.js +504 -0
  16. package/src/core/config/types.d.ts +1 -0
  17. package/src/core/env.js +121 -0
  18. package/src/core/generate_manifest/index.js +94 -0
  19. package/src/core/prerender/crawl.js +198 -0
  20. package/src/core/prerender/entities.js +2252 -0
  21. package/src/core/prerender/prerender.js +458 -0
  22. package/src/core/prerender/queue.js +80 -0
  23. package/src/core/sync/create_manifest_data/conflict.js +0 -0
  24. package/src/core/sync/create_manifest_data/index.js +470 -0
  25. package/src/core/sync/create_manifest_data/sort.js +163 -0
  26. package/src/core/sync/create_manifest_data/types.d.ts +37 -0
  27. package/src/core/sync/sync.js +78 -0
  28. package/src/core/sync/utils.js +33 -0
  29. package/src/core/sync/write_ambient.js +53 -0
  30. package/src/core/sync/write_client_manifest.js +106 -0
  31. package/src/core/sync/write_matchers.js +25 -0
  32. package/src/core/sync/write_root.js +91 -0
  33. package/src/core/sync/write_tsconfig.js +195 -0
  34. package/src/core/sync/write_types/index.js +783 -0
  35. package/src/core/utils.js +70 -0
  36. package/src/exports/hooks/index.js +1 -0
  37. package/src/exports/hooks/sequence.js +44 -0
  38. package/src/exports/index.js +45 -0
  39. package/src/exports/node/index.js +161 -0
  40. package/src/exports/node/polyfills.js +28 -0
  41. package/src/exports/vite/build/build_server.js +378 -0
  42. package/src/exports/vite/build/build_service_worker.js +91 -0
  43. package/src/exports/vite/build/utils.js +181 -0
  44. package/src/exports/vite/dev/index.js +581 -0
  45. package/src/exports/vite/graph_analysis/index.js +277 -0
  46. package/src/exports/vite/graph_analysis/types.d.ts +5 -0
  47. package/src/exports/vite/graph_analysis/utils.js +30 -0
  48. package/src/exports/vite/index.js +603 -0
  49. package/src/exports/vite/preview/index.js +189 -0
  50. package/src/exports/vite/types.d.ts +3 -0
  51. package/src/exports/vite/utils.js +157 -0
  52. package/src/runtime/app/env.js +1 -0
  53. package/src/runtime/app/environment.js +11 -0
  54. package/src/runtime/app/forms.js +123 -0
  55. package/src/runtime/app/navigation.js +23 -0
  56. package/src/runtime/app/paths.js +1 -0
  57. package/src/runtime/app/stores.js +102 -0
  58. package/src/runtime/client/ambient.d.ts +30 -0
  59. package/src/runtime/client/client.js +1595 -0
  60. package/src/runtime/client/fetcher.js +107 -0
  61. package/src/runtime/client/parse.js +60 -0
  62. package/src/runtime/client/singletons.js +21 -0
  63. package/src/runtime/client/start.js +37 -0
  64. package/src/runtime/client/types.d.ts +84 -0
  65. package/src/runtime/client/utils.js +159 -0
  66. package/src/runtime/components/error.svelte +16 -0
  67. package/{assets → src/runtime}/components/layout.svelte +0 -0
  68. package/src/runtime/control.js +98 -0
  69. package/src/runtime/env/dynamic/private.js +1 -0
  70. package/src/runtime/env/dynamic/public.js +1 -0
  71. package/src/runtime/env-private.js +6 -0
  72. package/src/runtime/env-public.js +6 -0
  73. package/src/runtime/env.js +6 -0
  74. package/src/runtime/hash.js +20 -0
  75. package/src/runtime/paths.js +11 -0
  76. package/src/runtime/server/cookie.js +166 -0
  77. package/src/runtime/server/data/index.js +131 -0
  78. package/src/runtime/server/endpoint.js +92 -0
  79. package/src/runtime/server/fetch.js +174 -0
  80. package/src/runtime/server/index.js +355 -0
  81. package/src/runtime/server/page/actions.js +256 -0
  82. package/src/runtime/server/page/crypto.js +239 -0
  83. package/src/runtime/server/page/csp.js +250 -0
  84. package/src/runtime/server/page/index.js +304 -0
  85. package/src/runtime/server/page/load_data.js +215 -0
  86. package/src/runtime/server/page/render.js +346 -0
  87. package/src/runtime/server/page/respond_with_error.js +102 -0
  88. package/src/runtime/server/page/serialize_data.js +87 -0
  89. package/src/runtime/server/page/types.d.ts +35 -0
  90. package/src/runtime/server/utils.js +181 -0
  91. package/src/utils/array.js +9 -0
  92. package/src/utils/error.js +22 -0
  93. package/src/utils/escape.js +46 -0
  94. package/src/utils/filesystem.js +142 -0
  95. package/src/utils/functions.js +16 -0
  96. package/src/utils/http.js +72 -0
  97. package/src/utils/misc.js +1 -0
  98. package/src/utils/promises.js +17 -0
  99. package/src/utils/routing.js +130 -0
  100. package/src/utils/unit_test.js +11 -0
  101. package/src/utils/url.js +144 -0
  102. package/svelte-kit.js +1 -1
  103. package/types/ambient.d.ts +431 -0
  104. package/types/index.d.ts +477 -0
  105. package/types/internal.d.ts +380 -0
  106. package/types/private.d.ts +224 -0
  107. package/CHANGELOG.md +0 -496
  108. package/assets/components/error.svelte +0 -13
  109. package/assets/runtime/app/env.js +0 -5
  110. package/assets/runtime/app/navigation.js +0 -44
  111. package/assets/runtime/app/paths.js +0 -1
  112. package/assets/runtime/app/stores.js +0 -93
  113. package/assets/runtime/chunks/utils.js +0 -22
  114. package/assets/runtime/internal/singletons.js +0 -23
  115. package/assets/runtime/internal/start.js +0 -776
  116. package/assets/runtime/paths.js +0 -12
  117. package/dist/chunks/index.js +0 -3537
  118. package/dist/chunks/index2.js +0 -587
  119. package/dist/chunks/index3.js +0 -246
  120. package/dist/chunks/index4.js +0 -568
  121. package/dist/chunks/index5.js +0 -763
  122. package/dist/chunks/index6.js +0 -323
  123. package/dist/chunks/standard.js +0 -99
  124. package/dist/chunks/utils.js +0 -83
  125. package/dist/cli.js +0 -555
  126. package/dist/ssr.js +0 -2604
  127. package/types.d.ts +0 -73
  128. package/types.internal.d.ts +0 -222
@@ -0,0 +1,355 @@
1
+ import { is_endpoint_request, render_endpoint } from './endpoint.js';
2
+ import { render_page } from './page/index.js';
3
+ import { render_response } from './page/render.js';
4
+ import { respond_with_error } from './page/respond_with_error.js';
5
+ import { coalesce_to_error } from '../../utils/error.js';
6
+ import { is_form_content_type } from '../../utils/http.js';
7
+ import { GENERIC_ERROR, handle_fatal_error } from './utils.js';
8
+ import { decode_params, disable_search, normalize_path } from '../../utils/url.js';
9
+ import { exec } from '../../utils/routing.js';
10
+ import { render_data } from './data/index.js';
11
+ import { DATA_SUFFIX } from '../../constants.js';
12
+ import { add_cookies_to_headers, get_cookies } from './cookie.js';
13
+ import { HttpError } from '../control.js';
14
+ import { create_fetch } from './fetch.js';
15
+
16
+ /* global __SVELTEKIT_ADAPTER_NAME__ */
17
+
18
+ /** @param {{ html: string }} opts */
19
+ const default_transform = ({ html }) => html;
20
+
21
+ const default_filter = () => false;
22
+
23
+ /** @type {import('types').Respond} */
24
+ export async function respond(request, options, state) {
25
+ let url = new URL(request.url);
26
+
27
+ if (options.csrf.check_origin) {
28
+ const forbidden =
29
+ request.method === 'POST' &&
30
+ request.headers.get('origin') !== url.origin &&
31
+ is_form_content_type(request);
32
+
33
+ if (forbidden) {
34
+ return new Response(`Cross-site ${request.method} form submissions are forbidden`, {
35
+ status: 403
36
+ });
37
+ }
38
+ }
39
+
40
+ let decoded;
41
+ try {
42
+ decoded = decodeURI(url.pathname);
43
+ } catch {
44
+ return new Response('Malformed URI', { status: 400 });
45
+ }
46
+
47
+ /** @type {import('types').SSRRoute | null} */
48
+ let route = null;
49
+
50
+ /** @type {Record<string, string>} */
51
+ let params = {};
52
+
53
+ if (options.paths.base && !state.prerendering?.fallback) {
54
+ if (!decoded.startsWith(options.paths.base)) {
55
+ return new Response('Not found', { status: 404 });
56
+ }
57
+ decoded = decoded.slice(options.paths.base.length) || '/';
58
+ }
59
+
60
+ const is_data_request = decoded.endsWith(DATA_SUFFIX);
61
+ if (is_data_request) decoded = decoded.slice(0, -DATA_SUFFIX.length) || '/';
62
+
63
+ if (!state.prerendering?.fallback) {
64
+ const matchers = await options.manifest._.matchers();
65
+
66
+ for (const candidate of options.manifest._.routes) {
67
+ const match = candidate.pattern.exec(decoded);
68
+ if (!match) continue;
69
+
70
+ const matched = exec(match, candidate.names, candidate.types, matchers);
71
+ if (matched) {
72
+ route = candidate;
73
+ params = decode_params(matched);
74
+ break;
75
+ }
76
+ }
77
+ }
78
+
79
+ if (route?.page && !is_data_request) {
80
+ const normalized = normalize_path(url.pathname, options.trailing_slash);
81
+
82
+ if (normalized !== url.pathname && !state.prerendering?.fallback) {
83
+ return new Response(undefined, {
84
+ status: 301,
85
+ headers: {
86
+ 'x-sveltekit-normalize': '1',
87
+ location:
88
+ // ensure paths starting with '//' are not treated as protocol-relative
89
+ (normalized.startsWith('//') ? url.origin + normalized : normalized) +
90
+ (url.search === '?' ? '' : url.search)
91
+ }
92
+ });
93
+ }
94
+ }
95
+
96
+ /** @type {Record<string, string>} */
97
+ const headers = {};
98
+
99
+ const { cookies, new_cookies, get_cookie_header } = get_cookies(request, url);
100
+
101
+ if (state.prerendering) disable_search(url);
102
+
103
+ /** @type {import('types').RequestEvent} */
104
+ const event = {
105
+ cookies,
106
+ // @ts-expect-error this is added in the next step, because `create_fetch` needs a reference to `event`
107
+ fetch: null,
108
+ getClientAddress:
109
+ state.getClientAddress ||
110
+ (() => {
111
+ throw new Error(
112
+ `${__SVELTEKIT_ADAPTER_NAME__} does not specify getClientAddress. Please raise an issue`
113
+ );
114
+ }),
115
+ locals: {},
116
+ params,
117
+ platform: state.platform,
118
+ request,
119
+ routeId: route && route.id,
120
+ setHeaders: (new_headers) => {
121
+ for (const key in new_headers) {
122
+ const lower = key.toLowerCase();
123
+ const value = new_headers[key];
124
+
125
+ if (lower === 'set-cookie') {
126
+ throw new Error(
127
+ `Use \`event.cookies.set(name, value, options)\` instead of \`event.setHeaders\` to set cookies`
128
+ );
129
+ } else if (lower in headers) {
130
+ throw new Error(`"${key}" header is already set`);
131
+ } else {
132
+ headers[lower] = value;
133
+
134
+ if (state.prerendering && lower === 'cache-control') {
135
+ state.prerendering.cache = /** @type {string} */ (value);
136
+ }
137
+ }
138
+ }
139
+ },
140
+ url
141
+ };
142
+
143
+ event.fetch = create_fetch({ event, options, state, get_cookie_header });
144
+
145
+ // TODO remove this for 1.0
146
+ /**
147
+ * @param {string} property
148
+ * @param {string} replacement
149
+ * @param {string} suffix
150
+ */
151
+ const removed = (property, replacement, suffix = '') => ({
152
+ get: () => {
153
+ throw new Error(`event.${property} has been replaced by event.${replacement}` + suffix);
154
+ }
155
+ });
156
+
157
+ const details = '. See https://github.com/sveltejs/kit/pull/3384 for details';
158
+
159
+ const body_getter = {
160
+ get: () => {
161
+ throw new Error(
162
+ 'To access the request body use the text/json/arrayBuffer/formData methods, e.g. `body = await request.json()`' +
163
+ details
164
+ );
165
+ }
166
+ };
167
+
168
+ Object.defineProperties(event, {
169
+ clientAddress: removed('clientAddress', 'getClientAddress'),
170
+ method: removed('method', 'request.method', details),
171
+ headers: removed('headers', 'request.headers', details),
172
+ origin: removed('origin', 'url.origin'),
173
+ path: removed('path', 'url.pathname'),
174
+ query: removed('query', 'url.searchParams'),
175
+ body: body_getter,
176
+ rawBody: body_getter
177
+ });
178
+
179
+ /** @type {import('types').RequiredResolveOptions} */
180
+ let resolve_opts = {
181
+ transformPageChunk: default_transform,
182
+ filterSerializedResponseHeaders: default_filter
183
+ };
184
+
185
+ /**
186
+ *
187
+ * @param {import('types').RequestEvent} event
188
+ * @param {import('types').ResolveOptions} [opts]
189
+ */
190
+ async function resolve(event, opts) {
191
+ try {
192
+ if (opts) {
193
+ // TODO remove for 1.0
194
+ if ('transformPage' in opts) {
195
+ throw new Error(
196
+ 'transformPage has been replaced by transformPageChunk — see https://github.com/sveltejs/kit/pull/5657 for more information'
197
+ );
198
+ }
199
+
200
+ if ('ssr' in opts) {
201
+ throw new Error(
202
+ 'ssr has been removed, set it in the appropriate +layout.js instead. See the PR for more information: https://github.com/sveltejs/kit/pull/6197'
203
+ );
204
+ }
205
+
206
+ resolve_opts = {
207
+ transformPageChunk: opts.transformPageChunk || default_transform,
208
+ filterSerializedResponseHeaders: opts.filterSerializedResponseHeaders || default_filter
209
+ };
210
+ }
211
+
212
+ if (state.prerendering?.fallback) {
213
+ return await render_response({
214
+ event,
215
+ options,
216
+ state,
217
+ page_config: { ssr: false, csr: true },
218
+ status: 200,
219
+ error: null,
220
+ branch: [],
221
+ fetched: [],
222
+ resolve_opts
223
+ });
224
+ }
225
+
226
+ if (route) {
227
+ /** @type {Response} */
228
+ let response;
229
+
230
+ if (is_data_request) {
231
+ response = await render_data(event, route, options, state);
232
+ } else if (route.endpoint && (!route.page || is_endpoint_request(event))) {
233
+ response = await render_endpoint(event, await route.endpoint(), state);
234
+ } else if (route.page) {
235
+ response = await render_page(event, route, route.page, options, state, resolve_opts);
236
+ } else {
237
+ // a route will always have a page or an endpoint, but TypeScript
238
+ // doesn't know that
239
+ throw new Error('This should never happen');
240
+ }
241
+
242
+ return response;
243
+ }
244
+
245
+ if (state.initiator === GENERIC_ERROR) {
246
+ return new Response('Internal Server Error', {
247
+ status: 500
248
+ });
249
+ }
250
+
251
+ // if this request came direct from the user, rather than
252
+ // via a `fetch` in a `load`, render a 404 page
253
+ if (!state.initiator) {
254
+ return await respond_with_error({
255
+ event,
256
+ options,
257
+ state,
258
+ status: 404,
259
+ error: new Error(`Not found: ${event.url.pathname}`),
260
+ resolve_opts
261
+ });
262
+ }
263
+
264
+ if (state.prerendering) {
265
+ return new Response('not found', { status: 404 });
266
+ }
267
+
268
+ // we can't load the endpoint from our own manifest,
269
+ // so we need to make an actual HTTP request
270
+ return await fetch(request);
271
+ } catch (e) {
272
+ // HttpError can come from endpoint - TODO should it be handled there instead?
273
+ const error = e instanceof HttpError ? e : coalesce_to_error(e);
274
+ return handle_fatal_error(event, options, error);
275
+ } finally {
276
+ event.cookies.set = () => {
277
+ throw new Error('Cannot use `cookies.set(...)` after the response has been generated');
278
+ };
279
+
280
+ event.setHeaders = () => {
281
+ throw new Error('Cannot use `setHeaders(...)` after the response has been generated');
282
+ };
283
+ }
284
+ }
285
+
286
+ try {
287
+ const response = await options.hooks.handle({
288
+ event,
289
+ resolve: (event, opts) =>
290
+ resolve(event, opts).then((response) => {
291
+ // add headers/cookies here, rather than inside `resolve`, so that we
292
+ // can do it once for all responses instead of once per `return`
293
+ if (!is_data_request) {
294
+ // we only want to set cookies on __data.json requests, we don't
295
+ // want to cache stuff erroneously etc
296
+ for (const key in headers) {
297
+ const value = headers[key];
298
+ response.headers.set(key, /** @type {string} */ (value));
299
+ }
300
+ }
301
+ add_cookies_to_headers(response.headers, Object.values(new_cookies));
302
+
303
+ if (state.prerendering && event.routeId !== null) {
304
+ response.headers.set('x-sveltekit-routeid', encodeURI(event.routeId));
305
+ }
306
+
307
+ return response;
308
+ }),
309
+ // TODO remove for 1.0
310
+ // @ts-expect-error
311
+ get request() {
312
+ throw new Error('request in handle has been replaced with event' + details);
313
+ }
314
+ });
315
+
316
+ // respond with 304 if etag matches
317
+ if (response.status === 200 && response.headers.has('etag')) {
318
+ let if_none_match_value = request.headers.get('if-none-match');
319
+
320
+ // ignore W/ prefix https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/If-None-Match#directives
321
+ if (if_none_match_value?.startsWith('W/"')) {
322
+ if_none_match_value = if_none_match_value.substring(2);
323
+ }
324
+
325
+ const etag = /** @type {string} */ (response.headers.get('etag'));
326
+
327
+ if (if_none_match_value === etag) {
328
+ const headers = new Headers({ etag });
329
+
330
+ // https://datatracker.ietf.org/doc/html/rfc7232#section-4.1 + set-cookie
331
+ for (const key of [
332
+ 'cache-control',
333
+ 'content-location',
334
+ 'date',
335
+ 'expires',
336
+ 'vary',
337
+ 'set-cookie'
338
+ ]) {
339
+ const value = response.headers.get(key);
340
+ if (value) headers.set(key, value);
341
+ }
342
+
343
+ return new Response(undefined, {
344
+ status: 304,
345
+ headers
346
+ });
347
+ }
348
+ }
349
+
350
+ return response;
351
+ } catch (/** @type {unknown} */ e) {
352
+ const error = coalesce_to_error(e);
353
+ return handle_fatal_error(event, options, error);
354
+ }
355
+ }
@@ -0,0 +1,256 @@
1
+ import { error, json } from '../../../exports/index.js';
2
+ import { normalize_error } from '../../../utils/error.js';
3
+ import { is_form_content_type, negotiate } from '../../../utils/http.js';
4
+ import { HttpError, Redirect, ValidationError } from '../../control.js';
5
+ import { handle_error_and_jsonify } from '../utils.js';
6
+
7
+ /** @param {import('types').RequestEvent} event */
8
+ export function is_action_json_request(event) {
9
+ const accept = negotiate(event.request.headers.get('accept') ?? '*/*', [
10
+ 'application/json',
11
+ 'text/html'
12
+ ]);
13
+
14
+ return accept === 'application/json' && event.request.method === 'POST';
15
+ }
16
+
17
+ /**
18
+ * @param {import('types').RequestEvent} event
19
+ * @param {import('types').SSROptions} options
20
+ * @param {import('types').SSRNode['server']} server
21
+ */
22
+ export async function handle_action_json_request(event, options, server) {
23
+ const actions = server.actions;
24
+
25
+ if (!actions) {
26
+ maybe_throw_migration_error(server);
27
+ // TODO should this be a different error altogether?
28
+ return new Response('POST method not allowed. No actions exist for this page', {
29
+ status: 405,
30
+ headers: {
31
+ // https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/405
32
+ // "The server must generate an Allow header field in a 405 status code response"
33
+ allow: 'GET'
34
+ }
35
+ });
36
+ }
37
+
38
+ check_named_default_separate(actions);
39
+
40
+ try {
41
+ const data = await call_action(event, actions);
42
+
43
+ if (data instanceof ValidationError) {
44
+ check_serializability(data.data, /** @type {string} */ (event.routeId), 'data');
45
+ return action_json({ type: 'invalid', status: data.status, data: data.data });
46
+ } else {
47
+ check_serializability(data, /** @type {string} */ (event.routeId), 'data');
48
+ return action_json({
49
+ type: 'success',
50
+ status: data ? 200 : 204,
51
+ data: /** @type {Record<string, any> | undefined} */ (data)
52
+ });
53
+ }
54
+ } catch (e) {
55
+ const error = normalize_error(e);
56
+
57
+ if (error instanceof Redirect) {
58
+ return action_json({
59
+ type: 'redirect',
60
+ status: error.status,
61
+ location: error.location
62
+ });
63
+ }
64
+
65
+ return action_json(
66
+ {
67
+ type: 'error',
68
+ error: handle_error_and_jsonify(event, options, check_incorrect_invalid_use(error))
69
+ },
70
+ {
71
+ status: error instanceof HttpError ? error.status : 500
72
+ }
73
+ );
74
+ }
75
+ }
76
+
77
+ /**
78
+ * @param {HttpError | Error} error
79
+ */
80
+ function check_incorrect_invalid_use(error) {
81
+ return error instanceof ValidationError
82
+ ? new Error(`Cannot "throw invalid()". Use "return invalid()"`)
83
+ : error;
84
+ }
85
+
86
+ /**
87
+ * @param {import('types').ActionResult} data
88
+ * @param {ResponseInit} [init]
89
+ */
90
+ function action_json(data, init) {
91
+ return json(data, init);
92
+ }
93
+
94
+ /**
95
+ * @param {import('types').RequestEvent} event
96
+ * @param {import('types').SSRNode} leaf_node
97
+ */
98
+ export function is_action_request(event, leaf_node) {
99
+ return leaf_node.server && event.request.method !== 'GET' && event.request.method !== 'HEAD';
100
+ }
101
+
102
+ /**
103
+ * @param {import('types').RequestEvent} event
104
+ * @param {import('types').SSRNode['server']} server
105
+ * @returns {Promise<import('types').ActionResult>}
106
+ */
107
+ export async function handle_action_request(event, server) {
108
+ const actions = server.actions;
109
+
110
+ if (!actions) {
111
+ maybe_throw_migration_error(server);
112
+ // TODO should this be a different error altogether?
113
+ event.setHeaders({
114
+ // https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/405
115
+ // "The server must generate an Allow header field in a 405 status code response"
116
+ allow: 'GET'
117
+ });
118
+ return {
119
+ type: 'error',
120
+ error: error(405, 'POST method not allowed. No actions exist for this page')
121
+ };
122
+ }
123
+
124
+ check_named_default_separate(actions);
125
+
126
+ try {
127
+ const data = await call_action(event, actions);
128
+
129
+ if (data instanceof ValidationError) {
130
+ return { type: 'invalid', status: data.status, data: data.data };
131
+ } else {
132
+ return {
133
+ type: 'success',
134
+ status: 200,
135
+ data: /** @type {Record<string, any> | undefined} */ (data)
136
+ };
137
+ }
138
+ } catch (e) {
139
+ const error = normalize_error(e);
140
+
141
+ if (error instanceof Redirect) {
142
+ return {
143
+ type: 'redirect',
144
+ status: error.status,
145
+ location: error.location
146
+ };
147
+ }
148
+
149
+ return {
150
+ type: 'error',
151
+ error: check_incorrect_invalid_use(error)
152
+ };
153
+ }
154
+ }
155
+
156
+ /**
157
+ * @param {import('types').Actions} actions
158
+ */
159
+ function check_named_default_separate(actions) {
160
+ if (actions.default && Object.keys(actions).length > 1) {
161
+ throw new Error(
162
+ `When using named actions, the default action cannot be used. See the docs for more info: https://kit.svelte.dev/docs/form-actions#named-actions`
163
+ );
164
+ }
165
+ }
166
+
167
+ /**
168
+ * @param {import('types').RequestEvent} event
169
+ * @param {NonNullable<import('types').SSRNode['server']['actions']>} actions
170
+ * @throws {Redirect | ValidationError | HttpError | Error}
171
+ */
172
+ export async function call_action(event, actions) {
173
+ const url = new URL(event.request.url);
174
+
175
+ let name = 'default';
176
+ for (const param of url.searchParams) {
177
+ if (param[0].startsWith('/')) {
178
+ name = param[0].slice(1);
179
+ if (name === 'default') {
180
+ throw new Error('Cannot use reserved action name "default"');
181
+ }
182
+ break;
183
+ }
184
+ }
185
+
186
+ const action = actions[name];
187
+ if (!action) {
188
+ throw new Error(`No action with name '${name}' found`);
189
+ }
190
+
191
+ if (!is_form_content_type(event.request)) {
192
+ throw new Error(
193
+ `Actions expect form-encoded data (received ${event.request.headers.get('content-type')}`
194
+ );
195
+ }
196
+
197
+ return action(event);
198
+ }
199
+
200
+ /**
201
+ * @param {import('types').SSRNode['server']} server
202
+ */
203
+ function maybe_throw_migration_error(server) {
204
+ for (const method of ['POST', 'PUT', 'PATCH', 'DELETE']) {
205
+ if (/** @type {any} */ (server)[method]) {
206
+ throw new Error(
207
+ `${method} method no longer allowed in +page.server, use actions instead. See the PR for more info: https://github.com/sveltejs/kit/pull/6469`
208
+ );
209
+ }
210
+ }
211
+ }
212
+
213
+ /**
214
+ * Check that the data can safely be serialized to JSON
215
+ * @param {any} value
216
+ * @param {string} id
217
+ * @param {string} path
218
+ */
219
+ function check_serializability(value, id, path) {
220
+ const type = typeof value;
221
+
222
+ if (type === 'string' || type === 'boolean' || type === 'number' || type === 'undefined') {
223
+ // primitives are fine
224
+ return;
225
+ }
226
+
227
+ if (type === 'object') {
228
+ // nulls are fine...
229
+ if (!value) return;
230
+
231
+ // ...so are plain arrays...
232
+ if (Array.isArray(value)) {
233
+ value.forEach((child, i) => {
234
+ check_serializability(child, id, `${path}[${i}]`);
235
+ });
236
+ return;
237
+ }
238
+
239
+ // ...and objects
240
+ // This simple check might potentially run into some weird edge cases
241
+ // Refer to https://github.com/lodash/lodash/blob/2da024c3b4f9947a48517639de7560457cd4ec6c/isPlainObject.js?rgh-link-date=2022-07-20T12%3A48%3A07Z#L30
242
+ // if that ever happens
243
+ if (Object.getPrototypeOf(value) === Object.prototype) {
244
+ for (const key in value) {
245
+ check_serializability(value[key], id, `${path}.${key}`);
246
+ }
247
+ return;
248
+ }
249
+ }
250
+
251
+ throw new Error(
252
+ `${path} returned from action in ${id} cannot be serialized as JSON without losing its original type` +
253
+ // probably the most common case, so let's give a hint
254
+ (value instanceof Date ? ' (Date objects are serialized as strings)' : '')
255
+ );
256
+ }