@sveltejs/kit 3.0.0-next.13 → 3.0.0-next.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (86) hide show
  1. package/package.json +7 -4
  2. package/src/cli.js +8 -5
  3. package/src/core/adapt/builder.js +20 -10
  4. package/src/core/config/index.js +4 -5
  5. package/src/core/env.js +3 -3
  6. package/src/core/generate_manifest/index.js +6 -0
  7. package/src/core/postbuild/entities.js +8 -2
  8. package/src/core/postbuild/fallback.js +2 -1
  9. package/src/core/postbuild/prerender.js +18 -13
  10. package/src/core/sync/create_manifest_data/conflict.js +1 -1
  11. package/src/core/sync/create_manifest_data/index.js +33 -2
  12. package/src/core/sync/sync.js +3 -2
  13. package/src/core/sync/utils.js +2 -2
  14. package/src/core/sync/write_app_types.js +72 -27
  15. package/src/core/sync/write_tsconfig/index.js +73 -54
  16. package/src/core/sync/write_tsconfig/utils.js +0 -61
  17. package/src/core/sync/write_tsconfig/validate.js +128 -0
  18. package/src/core/sync/write_types/index.js +7 -4
  19. package/src/exports/node/index.js +2 -7
  20. package/src/exports/public.d.ts +25 -18
  21. package/src/exports/vite/build/build_server.js +2 -3
  22. package/src/exports/vite/dev/index.js +44 -36
  23. package/src/exports/vite/index.js +91 -16
  24. package/src/exports/vite/utils.js +62 -15
  25. package/src/runner.js +4 -2
  26. package/src/runtime/app/forms.js +4 -7
  27. package/src/runtime/app/internal/transport.js +53 -0
  28. package/src/runtime/app/paths/client.js +2 -2
  29. package/src/runtime/app/paths/internal/client.js +2 -2
  30. package/src/runtime/app/server/remote/prerender.js +6 -10
  31. package/src/runtime/app/server/remote/query.js +3 -9
  32. package/src/runtime/app/server/remote/requested.js +2 -2
  33. package/src/runtime/app/server/remote/shared.js +1 -16
  34. package/src/runtime/client/client.js +177 -63
  35. package/src/runtime/client/fetcher.js +2 -13
  36. package/src/runtime/client/parse.js +1 -1
  37. package/src/runtime/client/remote-functions/command.svelte.js +1 -2
  38. package/src/runtime/client/remote-functions/form.svelte.js +3 -7
  39. package/src/runtime/client/remote-functions/prerender.svelte.js +2 -2
  40. package/src/runtime/client/remote-functions/query/index.js +1 -1
  41. package/src/runtime/client/remote-functions/query/proxy.js +2 -2
  42. package/src/runtime/client/remote-functions/query-batch.svelte.js +1 -1
  43. package/src/runtime/client/remote-functions/query-live/proxy.js +2 -12
  44. package/src/runtime/client/remote-functions/shared.svelte.js +1 -1
  45. package/src/runtime/client/utils.js +1 -0
  46. package/src/runtime/form-utils.js +4 -6
  47. package/src/runtime/pathname.js +44 -1
  48. package/src/runtime/server/data/index.js +5 -8
  49. package/src/runtime/server/dev.js +22 -0
  50. package/src/runtime/server/endpoint.js +3 -4
  51. package/src/runtime/server/fetch.js +25 -30
  52. package/src/runtime/server/index.js +64 -46
  53. package/src/runtime/server/internal.js +12 -5
  54. package/src/runtime/server/page/actions.js +18 -43
  55. package/src/runtime/server/page/crypto.js +2 -2
  56. package/src/runtime/server/page/csp.js +2 -1
  57. package/src/runtime/server/page/data_serializer.js +12 -13
  58. package/src/runtime/server/page/index.js +16 -32
  59. package/src/runtime/server/page/load_data.js +28 -44
  60. package/src/runtime/server/page/render.js +28 -12
  61. package/src/runtime/server/page/respond_with_error.js +8 -20
  62. package/src/runtime/server/page/serialize_data.js +2 -13
  63. package/src/runtime/server/page/server_routing.js +58 -9
  64. package/src/runtime/server/remote-functions.js +11 -15
  65. package/src/runtime/server/respond.js +44 -56
  66. package/src/runtime/server/state.js +60 -0
  67. package/src/runtime/server/utils.js +0 -20
  68. package/src/runtime/shared.js +20 -40
  69. package/src/runtime/utils.js +3 -0
  70. package/src/types/ambient-private.d.ts +1 -1
  71. package/src/types/ambient.d.ts +58 -7
  72. package/src/types/global-private.d.ts +1 -1
  73. package/src/types/internal.d.ts +47 -53
  74. package/src/utils/filesystem.js +1 -23
  75. package/src/utils/hash.js +21 -0
  76. package/src/utils/http.js +8 -7
  77. package/src/utils/import.js +2 -1
  78. package/src/utils/params.js +1 -1
  79. package/src/utils/regex.js +9 -0
  80. package/src/utils/routing.js +52 -27
  81. package/src/utils/url.js +1 -0
  82. package/src/version.js +1 -1
  83. package/types/index.d.ts +98 -28
  84. package/types/index.d.ts.map +1 -1
  85. package/src/exports/node/polyfills.js +0 -30
  86. package/src/runtime/server/app.js +0 -9
@@ -1,4 +1,4 @@
1
- /** @import { RequestState, SSRNode } from 'types' */
1
+ /** @import { SSRNode } from 'types' */
2
2
  import { DEV } from 'esm-env';
3
3
  import { json, text } from '@sveltejs/kit';
4
4
  import { Redirect, SvelteKitError } from '@sveltejs/kit/internal';
@@ -26,13 +26,15 @@ import { validate_server_exports } from '../../utils/exports.js';
26
26
  import { action_json_redirect, is_action_json_request } from './page/actions.js';
27
27
  import { INVALIDATED_PARAM, TRAILING_SLASH_PARAM } from '../shared.js';
28
28
  import { get_public_env } from './env_module.js';
29
- import { resolve_route } from './page/server_routing.js';
29
+ import { resolve_route, resolve_route_by_id } from './page/server_routing.js';
30
30
  import { validateHeaders } from './validate-headers.js';
31
31
  import {
32
32
  add_data_suffix,
33
33
  add_resolution_suffix,
34
+ extract_route_id,
34
35
  has_data_suffix,
35
36
  has_resolution_suffix,
37
+ is_route_id_resolution_path,
36
38
  strip_data_suffix,
37
39
  strip_resolution_suffix
38
40
  } from '../pathname.js';
@@ -82,7 +84,7 @@ export const respond = propagate_context(internal_respond);
82
84
  * @param {Request} request
83
85
  * @param {import('types').SSROptions} options
84
86
  * @param {import('@sveltejs/kit').SSRManifest} manifest
85
- * @param {import('types').SSRState} state
87
+ * @param {import('types').RequestState} state
86
88
  * @returns {Promise<Response>}
87
89
  */
88
90
  export async function internal_respond(request, options, manifest, state) {
@@ -138,12 +140,16 @@ export async function internal_respond(request, options, manifest, state) {
138
140
 
139
141
  let skip_route_resolution = false;
140
142
 
143
+ /** Whether this is a `/${app_dir}/routes/<route_id>/__route.js` request, used by `preloadCode` */
144
+ let is_route_id_resolution_request = false;
145
+
141
146
  if (is_route_resolution_request) {
142
147
  /**
143
148
  * If the request is for a route resolution, first modify the URL, then continue as normal
144
149
  * for path resolution, then return the route object as a JS file.
145
150
  */
146
151
  url.pathname = strip_resolution_suffix(url.pathname);
152
+ is_route_id_resolution_request = is_route_id_resolution_path(url.pathname, base, app_dir);
147
153
  } else if (is_data_request) {
148
154
  url.pathname =
149
155
  strip_data_suffix(url.pathname) +
@@ -174,31 +180,6 @@ export async function internal_respond(request, options, manifest, state) {
174
180
  url
175
181
  );
176
182
 
177
- /** @type {RequestState} */
178
- const event_state = {
179
- prerendering: state.prerendering,
180
- transport: options.hooks.transport,
181
- handleValidationError: options.hooks.handleValidationError,
182
- tracing: {
183
- record_span
184
- },
185
- remote: {
186
- data: null,
187
- explicit: null,
188
- implicit: null,
189
- forms: null,
190
- requested: null,
191
- batches: null,
192
- live_iterators: null
193
- },
194
- is_in_remote_function: false,
195
- is_in_remote_form_or_command: false,
196
- is_in_remote_query: false,
197
- is_in_remote_prerender: false,
198
- is_in_render: false,
199
- is_in_universal_load: false
200
- };
201
-
202
183
  /** @type {import('@sveltejs/kit').RequestEvent} */
203
184
  const event = {
204
185
  cookies,
@@ -213,7 +194,12 @@ export async function internal_respond(request, options, manifest, state) {
213
194
  }),
214
195
  locals: {},
215
196
  params: {},
216
- platform: state.platform,
197
+ platform: state.emulator?.platform
198
+ ? await state.emulator.platform({
199
+ config: {},
200
+ prerender: !!state.prerendering?.fallback
201
+ })
202
+ : state.platform,
217
203
  request,
218
204
  route: { id: null },
219
205
  setHeaders: (new_headers) => {
@@ -251,6 +237,7 @@ export async function internal_respond(request, options, manifest, state) {
251
237
  isRemoteRequest: !!remote_id
252
238
  };
253
239
 
240
+ // @ts-expect-error this has to be assigned lazily
254
241
  event.fetch = create_fetch({
255
242
  event,
256
243
  options,
@@ -260,17 +247,11 @@ export async function internal_respond(request, options, manifest, state) {
260
247
  set_internal
261
248
  });
262
249
 
263
- if (state.emulator?.platform) {
264
- event.platform = await state.emulator.platform({
265
- config: {},
266
- prerender: !!state.prerendering?.fallback
267
- });
268
- }
269
-
270
250
  /** @type {string | null} */
271
251
  let resolved_path = url.pathname;
272
252
 
273
- if (!remote_id) {
253
+ // `reroute` hooks receive pathnames, so they must not run for route-ID resolution requests
254
+ if (!remote_id && !is_route_id_resolution_request) {
274
255
  const prerendering_reroute_state = state.prerendering?.inside_reroute;
275
256
  try {
276
257
  // For the duration or a reroute, disable the prerendering state as reroute could call API endpoints
@@ -339,7 +320,7 @@ export async function internal_respond(request, options, manifest, state) {
339
320
  statusText: response.statusText
340
321
  });
341
322
  } catch (error) {
342
- return await handle_fatal_error(event, event_state, options, error);
323
+ return await handle_fatal_error(event, state, options, error);
343
324
  }
344
325
  }
345
326
 
@@ -354,6 +335,14 @@ export async function internal_respond(request, options, manifest, state) {
354
335
  }
355
336
 
356
337
  if (is_route_resolution_request) {
338
+ if (is_route_id_resolution_request) {
339
+ return resolve_route_by_id(
340
+ extract_route_id(resolved_path, app_dir),
341
+ new URL(request.url),
342
+ manifest
343
+ );
344
+ }
345
+
357
346
  return resolve_route(resolved_path, new URL(request.url), manifest);
358
347
  }
359
348
 
@@ -375,11 +364,13 @@ export async function internal_respond(request, options, manifest, state) {
375
364
 
376
365
  if (result) {
377
366
  route = result.route;
367
+ // @ts-expect-error this has to be assigned lazily
378
368
  event.route = { id: route.id };
369
+ // @ts-expect-error this has to be assigned lazily
379
370
  event.params = result.params;
380
371
  }
381
372
  } catch (e) {
382
- return await handle_fatal_error(event, event_state, options, e);
373
+ return await handle_fatal_error(event, state, options, e);
383
374
  }
384
375
  }
385
376
 
@@ -439,6 +430,7 @@ export async function internal_respond(request, options, manifest, state) {
439
430
  }
440
431
 
441
432
  if (state.emulator?.platform) {
433
+ // @ts-expect-error this has to be assigned lazily
442
434
  event.platform = await state.emulator.platform({ config, prerender });
443
435
  }
444
436
 
@@ -461,10 +453,10 @@ export async function internal_respond(request, options, manifest, state) {
461
453
  add_cookies_to_headers(response.headers, new_cookies.values());
462
454
  return response;
463
455
  } catch (err) {
464
- return await handle_fatal_error(event, event_state, options, err);
456
+ return await handle_fatal_error(event, state, options, err);
465
457
  }
466
458
  }
467
- return await handle_fatal_error(event, event_state, options, e);
459
+ return await handle_fatal_error(event, state, options, e);
468
460
  }
469
461
 
470
462
  async function handle() {
@@ -493,7 +485,7 @@ export async function internal_respond(request, options, manifest, state) {
493
485
  }
494
486
  };
495
487
 
496
- return await with_request_store({ event: traced_event, state: event_state }, () =>
488
+ return await with_request_store({ event: traced_event, state }, () =>
497
489
  options.hooks.handle({
498
490
  event: traced_event,
499
491
  resolve: (event, opts) => {
@@ -600,10 +592,9 @@ export async function internal_respond(request, options, manifest, state) {
600
592
  if (resolved_path === null) {
601
593
  return await respond_with_error({
602
594
  event,
603
- event_state,
595
+ state,
604
596
  options,
605
597
  manifest,
606
- state,
607
598
  error: new SvelteKitError(
608
599
  400,
609
600
  'Malformed URI',
@@ -616,10 +607,9 @@ export async function internal_respond(request, options, manifest, state) {
616
607
  if (options.hash_routing || state.prerendering?.fallback) {
617
608
  return await render_response({
618
609
  event,
619
- event_state,
610
+ state,
620
611
  options,
621
612
  manifest,
622
- state,
623
613
  page_config: { ssr: false, csr: true },
624
614
  status: 200,
625
615
  error: null,
@@ -633,12 +623,12 @@ export async function internal_respond(request, options, manifest, state) {
633
623
  ],
634
624
  fetched: [],
635
625
  resolve_opts,
636
- data_serializer: server_data_serializer(event, event_state, options)
626
+ data_serializer: server_data_serializer(event, state, options)
637
627
  });
638
628
  }
639
629
 
640
630
  if (remote_id) {
641
- return await handle_remote_call(event, event_state, options, manifest, remote_id);
631
+ return await handle_remote_call(event, state, options, manifest, remote_id);
642
632
  }
643
633
 
644
634
  if (route) {
@@ -650,11 +640,10 @@ export async function internal_respond(request, options, manifest, state) {
650
640
  if (is_data_request) {
651
641
  response = await render_data(
652
642
  event,
653
- event_state,
643
+ state,
654
644
  route,
655
645
  options,
656
646
  manifest,
657
- state,
658
647
  invalidated_data_nodes,
659
648
  trailing_slash
660
649
  );
@@ -679,18 +668,17 @@ export async function internal_respond(request, options, manifest, state) {
679
668
  }
680
669
 
681
670
  if (endpoint) {
682
- response = await render_endpoint(event, event_state, endpoint, state);
671
+ response = await render_endpoint(event, state, endpoint);
683
672
  } else if (route.page) {
684
673
  if (!page_nodes) {
685
674
  throw new Error('page_nodes not found. This should never happen');
686
675
  } else if (page_methods.has(method)) {
687
676
  response = await render_page(
688
677
  event,
689
- event_state,
678
+ state,
690
679
  route.page,
691
680
  options,
692
681
  manifest,
693
- state,
694
682
  page_nodes,
695
683
  resolve_opts
696
684
  );
@@ -776,10 +764,9 @@ export async function internal_respond(request, options, manifest, state) {
776
764
 
777
765
  return await respond_with_error({
778
766
  event,
779
- event_state,
767
+ state,
780
768
  options,
781
769
  manifest,
782
- state,
783
770
  error: new SvelteKitError(404, 'Not Found', `Not found: ${event.url.pathname}`),
784
771
  resolve_opts
785
772
  });
@@ -800,12 +787,13 @@ export async function internal_respond(request, options, manifest, state) {
800
787
  // and I don't even know how to describe it. need to investigate at some point
801
788
 
802
789
  // HttpError from endpoint can end up here - TODO should it be handled there instead?
803
- return await handle_fatal_error(event, event_state, options, e);
790
+ return await handle_fatal_error(event, state, options, e);
804
791
  } finally {
805
792
  event.cookies.set = () => {
806
793
  throw new Error('Cannot use `cookies.set(...)` after the response has been generated');
807
794
  };
808
795
 
796
+ // @ts-expect-error this has to be assigned lazily
809
797
  event.setHeaders = () => {
810
798
  throw new Error('Cannot use `setHeaders(...)` after the response has been generated');
811
799
  };
@@ -0,0 +1,60 @@
1
+ /** @import { InternalRequestOptions, RequestState, ServerHooks } from 'types' */
2
+ import { record_span } from '../telemetry/record_span.js';
3
+
4
+ /** Per-request caches and context flags — never carried into a fork. */
5
+ function transient_fields() {
6
+ return {
7
+ remote: {
8
+ data: null,
9
+ explicit: null,
10
+ implicit: null,
11
+ forms: null,
12
+ requested: null,
13
+ batches: null,
14
+ live_iterators: null
15
+ },
16
+ is_in_remote_function: false,
17
+ is_in_remote_form_or_command: false,
18
+ is_in_remote_query: false,
19
+ is_in_remote_prerender: false,
20
+ is_in_render: false,
21
+ original_event: undefined
22
+ };
23
+ }
24
+
25
+ /**
26
+ * @param {InternalRequestOptions} options
27
+ * @param {ServerHooks} hooks
28
+ * @returns {RequestState}
29
+ */
30
+ export function create_request_state(options, hooks) {
31
+ // every field is initialized up front so the object shape stays stable
32
+ return {
33
+ getClientAddress: options.getClientAddress,
34
+ platform: options.platform,
35
+ read: options.read,
36
+ before_handle: options.before_handle,
37
+ emulator: options.emulator,
38
+ prerendering: options.prerendering,
39
+ prerender_default: undefined,
40
+ error: false,
41
+ depth: 0,
42
+ handleValidationError: hooks.handleValidationError,
43
+ tracing: {
44
+ record_span
45
+ },
46
+ ...transient_fields()
47
+ };
48
+ }
49
+
50
+ /**
51
+ * @param {RequestState} state
52
+ * @returns {RequestState}
53
+ */
54
+ export function fork_state_for_subrequest(state) {
55
+ return {
56
+ ...state,
57
+ ...transient_fields(),
58
+ depth: state.depth + 1
59
+ };
60
+ }
@@ -1,5 +1,3 @@
1
- /** @import { ServerHooks } from 'types' */
2
- import * as devalue from 'devalue';
3
1
  import { text } from '@sveltejs/kit';
4
2
  import { ENDPOINT_METHODS } from '../../constants.js';
5
3
 
@@ -139,21 +137,3 @@ export function get_node_type(node_id) {
139
137
  export function count_non_ssi_comments(str) {
140
138
  return (str.match(/<!--(?!#)/g) ?? []).length;
141
139
  }
142
-
143
- /**
144
- * Creates a serialiser for non-arbitrary POJOs using the app's transport hook
145
- * @param {ServerHooks['transport']} transport
146
- * @returns {(thing: unknown) => string | undefined}
147
- */
148
- export function create_replacer(transport) {
149
- /** @param {unknown} thing */
150
- const replacer = (thing) => {
151
- for (const key in transport) {
152
- const encoded = transport[key].encode(thing);
153
- if (encoded) {
154
- return `app.decode('${key}', ${devalue.uneval(encoded, replacer)})`;
155
- }
156
- }
157
- };
158
- return replacer;
159
- }
@@ -1,6 +1,6 @@
1
- /** @import { Transport } from '@sveltejs/kit' */
2
1
  import * as devalue from 'devalue';
3
- import { base64_decode, base64_encode, text_encoder } from './utils.js';
2
+ import { base64_decode, base64_encode, text_decoder, text_encoder } from './utils.js';
3
+ import { decoders, encoders } from '#app/internal/transport';
4
4
 
5
5
  /**
6
6
  * @param {string} route_id
@@ -39,17 +39,6 @@ export function validate_load_response(data, location_description) {
39
39
  }
40
40
  }
41
41
 
42
- /**
43
- * Try to `devalue.stringify` the data object using the provided transport encoders.
44
- * @param {any} data
45
- * @param {Transport} transport
46
- */
47
- export function stringify(data, transport) {
48
- const encoders = Object.fromEntries(Object.entries(transport).map(([k, v]) => [k, v.encode]));
49
-
50
- return devalue.stringify(data, encoders);
51
- }
52
-
53
42
  const object_proto_names = /* @__PURE__ */ Object.getOwnPropertyNames(Object.prototype)
54
43
  .sort()
55
44
  .join('\0');
@@ -102,11 +91,9 @@ const remote_regex_guard = '__skrag';
102
91
  const remote_arg_marker = Symbol(remote_object);
103
92
 
104
93
  /**
105
- * @param {Transport} transport
106
94
  * @param {boolean} sort
107
- * @param {Map<any, any>} remote_arg_clones
108
95
  */
109
- function create_remote_arg_reducers(transport, sort, remote_arg_clones) {
96
+ function create_remote_arg_reducers(sort) {
110
97
  /** @type {Record<string, (value: unknown) => unknown>} */
111
98
  const remote_fns_reducers = {
112
99
  /** @param {unknown} value */
@@ -118,6 +105,8 @@ function create_remote_arg_reducers(transport, sort, remote_arg_clones) {
118
105
  };
119
106
 
120
107
  if (sort) {
108
+ const clones = new Map();
109
+
121
110
  /** @type {(value: unknown) => Array<[unknown, unknown]> | undefined} */
122
111
  remote_fns_reducers[remote_map] = (value) => {
123
112
  if (!(value instanceof Map)) {
@@ -167,18 +156,15 @@ function create_remote_arg_reducers(transport, sort, remote_arg_clones) {
167
156
  return;
168
157
  }
169
158
 
170
- if (remote_arg_clones.has(value)) {
171
- return remote_arg_clones.get(value);
159
+ if (clones.has(value)) {
160
+ return clones.get(value);
172
161
  }
173
162
 
174
- return to_sorted(value, remote_arg_clones);
163
+ return to_sorted(value, clones);
175
164
  };
176
165
  }
177
166
 
178
- const user_reducers = Object.fromEntries(
179
- Object.entries(transport).map(([k, v]) => [k, v.encode])
180
- );
181
- const all_reducers = { ...user_reducers, ...remote_fns_reducers };
167
+ const all_reducers = { ...encoders, ...remote_fns_reducers };
182
168
 
183
169
  /** @type {(value: unknown) => string} */
184
170
  const stringify = (value) => devalue.stringify(value, all_reducers);
@@ -186,8 +172,7 @@ function create_remote_arg_reducers(transport, sort, remote_arg_clones) {
186
172
  return all_reducers;
187
173
  }
188
174
 
189
- /** @param {Transport} transport */
190
- function create_remote_arg_revivers(transport) {
175
+ function create_remote_arg_revivers() {
191
176
  const remote_fns_revivers = {
192
177
  /** @type {(value: unknown) => unknown} */
193
178
  [remote_object]: (value) => value,
@@ -251,11 +236,7 @@ function create_remote_arg_revivers(transport) {
251
236
  }
252
237
  };
253
238
 
254
- const user_revivers = Object.fromEntries(
255
- Object.entries(transport).map(([k, v]) => [k, v.decode])
256
- );
257
-
258
- const all_revivers = { ...user_revivers, ...remote_fns_revivers };
239
+ const all_revivers = { ...decoders, ...remote_fns_revivers };
259
240
 
260
241
  /** @type {(data: string) => unknown} */
261
242
  const parse = (data) => devalue.parse(data, all_revivers);
@@ -267,13 +248,12 @@ function create_remote_arg_revivers(transport) {
267
248
  * Stringifies the argument (if any) for a remote function in such a way that
268
249
  * it is both a valid URL and a valid file name (necessary for prerendering).
269
250
  * @param {any} value
270
- * @param {Transport} transport
271
251
  */
272
- export function stringify_remote_arg(value, transport) {
252
+ export function stringify_remote_arg(value) {
273
253
  if (value === undefined) return '';
274
254
 
275
255
  // If people hit file/url size limits, we can look into using something like compress_and_encode_text from svelte.dev beyond a certain size
276
- const json = devalue.stringify(value, create_remote_arg_reducers(transport, true, new Map()));
256
+ const json = devalue.stringify(value, create_remote_arg_reducers(true));
277
257
 
278
258
  return url_friendly_base64_encode(json);
279
259
  }
@@ -281,12 +261,11 @@ export function stringify_remote_arg(value, transport) {
281
261
  /**
282
262
  * Stringifies command arguments, including `File` objects.
283
263
  * @param {any} value
284
- * @param {Transport} transport
285
264
  */
286
- export async function stringify_command_arg(value, transport) {
265
+ export async function stringify_command_arg(value) {
287
266
  if (value === undefined) return '';
288
267
 
289
- const reducers = create_remote_arg_reducers(transport, false, new Map());
268
+ const reducers = create_remote_arg_reducers(false);
290
269
 
291
270
  /** @type {Set<Promise<any>>} */
292
271
  const allowed_promises = new Set();
@@ -331,23 +310,24 @@ export async function stringify_command_arg(value, transport) {
331
310
  */
332
311
  function url_friendly_base64_encode(string) {
333
312
  const bytes = text_encoder.encode(string);
313
+ // TODO replace with `bytes.toBase64({ alphabet: 'base64url', omitPadding: true })` when we require Node >= 25
334
314
  return base64_encode(bytes).replaceAll('=', '').replaceAll('+', '-').replaceAll('/', '_');
335
315
  }
336
316
 
337
317
  /**
338
318
  * Parses the argument (if any) for a remote function
339
319
  * @param {string} string
340
- * @param {Transport} transport
341
320
  */
342
- export function parse_remote_arg(string, transport) {
321
+ export function parse_remote_arg(string) {
343
322
  if (!string) return undefined;
344
323
 
345
- const json_string = new TextDecoder().decode(
324
+ const json_string = text_decoder.decode(
325
+ // TODO replace with `Uint8Array.fromBase64(string, { alphabet: 'base64url' })` when we require Node >= 25
346
326
  // no need to add back `=` characters, atob can handle it
347
327
  base64_decode(string.replaceAll('-', '+').replaceAll('_', '/'))
348
328
  );
349
329
 
350
- return devalue.parse(json_string, create_remote_arg_revivers(transport));
330
+ return devalue.parse(json_string, create_remote_arg_revivers());
351
331
  }
352
332
 
353
333
  /**
@@ -1,6 +1,7 @@
1
1
  import { BROWSER } from 'esm-env';
2
2
 
3
3
  export const text_encoder = new TextEncoder();
4
+ export const text_decoder = new TextDecoder();
4
5
 
5
6
  /**
6
7
  * Like node's path.relative, but without using node
@@ -28,6 +29,7 @@ export function get_relative_path(from, to) {
28
29
  * @returns {string}
29
30
  */
30
31
  export function base64_encode(bytes) {
32
+ // TODO replace with `bytes.toBase64()` when we require Node >= 25
31
33
  // Using `Buffer` is faster than iterating
32
34
  if (!BROWSER && globalThis.Buffer) {
33
35
  return globalThis.Buffer.from(bytes).toString('base64');
@@ -47,6 +49,7 @@ export function base64_encode(bytes) {
47
49
  * @returns {Uint8Array}
48
50
  */
49
51
  export function base64_decode(encoded) {
52
+ // TODO replace with `Uint8Array.fromBase64(encoded)` when we require Node >= 25
50
53
  // Using `Buffer` is faster than iterating
51
54
  if (!BROWSER && globalThis.Buffer) {
52
55
  const buffer = globalThis.Buffer.from(encoded, 'base64');
@@ -51,5 +51,5 @@ declare module '__sveltekit/manifest-data' {
51
51
  export const immutable: Array<{ path: string }>;
52
52
  export const assets: Array<{ path: string }>;
53
53
  export const prerendered: Array<{ path: string }>;
54
- export const routes: Array<{ id: string }>;
54
+ export const routes: Array<{ id: string; page: boolean; endpoint: boolean }>;
55
55
  }
@@ -78,9 +78,41 @@ declare module '$app/manifest' {
78
78
  */
79
79
  export const prerendered: Array<{ path: import('$app/types').Path }>;
80
80
  /**
81
- * An array of objects with an `id` property representing the routes in your app.
82
- */
83
- export const routes: Array<{ id: import('$app/types').RouteId }>;
81
+ * A route in your app, along with its capabilities. `page` indicates the presence of a `+page`,
82
+ * while `endpoint` indicates the presence of a `+server`. Both are `true` when both files exist.
83
+ */
84
+ export type ManifestRoute =
85
+ | {
86
+ id: Exclude<import('$app/types').PageRouteId, import('$app/types').EndpointRouteId>;
87
+ page: true;
88
+ endpoint: false;
89
+ }
90
+ | {
91
+ id: Exclude<import('$app/types').EndpointRouteId, import('$app/types').PageRouteId>;
92
+ page: false;
93
+ endpoint: true;
94
+ }
95
+ | {
96
+ id: Extract<import('$app/types').PageRouteId, import('$app/types').EndpointRouteId>;
97
+ page: true;
98
+ endpoint: true;
99
+ };
100
+ /**
101
+ * An array of objects representing the routes in your app. Only routes that the router can match
102
+ * are included — directories that merely hold a `+layout` are not routes of their own.
103
+ *
104
+ * Each object has an `id`, plus `page` and `endpoint` booleans describing whether the route has a
105
+ * `+page` and/or a `+server`. Both are `true` for a route that has both, so the capabilities can
106
+ * be filtered independently:
107
+ *
108
+ * ```js
109
+ * import { routes } from '$app/manifest';
110
+ *
111
+ * const pages = routes.filter((route) => route.page);
112
+ * const endpoints = routes.filter((route) => route.endpoint);
113
+ * ```
114
+ */
115
+ export const routes: ManifestRoute[];
84
116
  }
85
117
 
86
118
  /**
@@ -94,6 +126,8 @@ declare module '$app/types' {
94
126
  // These are all functions so that we can leverage function overloads to get the correct type.
95
127
  // Using the return types directly would error with a "not the same type" error.
96
128
  // https://www.typescriptlang.org/docs/handbook/declaration-merging.html#merging-interfaces
129
+ PageRouteId(): string;
130
+ EndpointRouteId(): string;
97
131
  RouteId(): string;
98
132
  RouteParams(): Record<string, Record<string, string>>;
99
133
  LayoutParams(): Record<string, Record<string, string>>;
@@ -103,7 +137,21 @@ declare module '$app/types' {
103
137
  }
104
138
 
105
139
  /**
106
- * A union of all the route IDs in your app. Used for `page.route.id` and `event.route.id`.
140
+ * A union of the route IDs in your app that have a `+page`.
141
+ *
142
+ * A route ID can be in both `PageRouteId` and `EndpointRouteId`, if its directory contains both a `+page` and a `+server`.
143
+ */
144
+ export type PageRouteId = ReturnType<AppTypes['PageRouteId']>;
145
+
146
+ /**
147
+ * A union of the route IDs in your app that have a `+server`.
148
+ *
149
+ * A route ID can be in both `PageRouteId` and `EndpointRouteId`, if its directory contains both a `+page` and a `+server`.
150
+ */
151
+ export type EndpointRouteId = ReturnType<AppTypes['EndpointRouteId']>;
152
+
153
+ /**
154
+ * A union of all the route IDs in your app — the union of `PageRouteId` and `EndpointRouteId`. Used for `page.route.id` and `event.route.id`.
107
155
  */
108
156
  export type RouteId = ReturnType<AppTypes['RouteId']>;
109
157
 
@@ -119,12 +167,15 @@ declare module '$app/types' {
119
167
  ? ReturnType<AppTypes['RouteParams']>[T]
120
168
  : Record<string, never>;
121
169
 
170
+ /**
171
+ * The route IDs accepted by `LayoutParams`. Like `RouteId`, these preserve route groups and `[param]` syntax, but they identify directories containing layouts rather than matchable routes.
172
+ */
173
+ type LayoutParamsId = keyof ReturnType<AppTypes['LayoutParams']>;
174
+
122
175
  /**
123
176
  * A utility for getting the parameters associated with a given layout, which is similar to `RouteParams` but also includes optional parameters for any child route.
124
177
  */
125
- export type LayoutParams<T extends RouteId> = T extends keyof ReturnType<AppTypes['LayoutParams']>
126
- ? ReturnType<AppTypes['LayoutParams']>[T]
127
- : Record<string, never>;
178
+ export type LayoutParams<T extends LayoutParamsId> = ReturnType<AppTypes['LayoutParams']>[T];
128
179
 
129
180
  /**
130
181
  * A union of all valid paths in your app, relative to the `base` path.
@@ -53,7 +53,7 @@ declare global {
53
53
  const __SVELTEKIT_MANIFEST_IMMUTABLE__: string[];
54
54
  const __SVELTEKIT_MANIFEST_ASSETS__: string[];
55
55
  const __SVELTEKIT_MANIFEST_PRERENDERED__: string[];
56
- const __SVELTEKIT_MANIFEST_ROUTES__: { id: string }[];
56
+ const __SVELTEKIT_MANIFEST_ROUTES__: Array<{ id: string }>;
57
57
  /**
58
58
  * This makes the use of specific features visible at both dev and build time, in such a
59
59
  * way that we can error when they are not supported by the target platform.