@sveltejs/kit 3.0.0-next.24 → 3.0.0-next.25

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 (40) hide show
  1. package/package.json +12 -4
  2. package/src/constants.js +6 -0
  3. package/src/core/adapt/builder.js +1 -2
  4. package/src/core/env.js +3 -6
  5. package/src/core/postbuild/prerender.js +2 -2
  6. package/src/core/sync/write_server.js +3 -17
  7. package/src/core/utils.js +10 -0
  8. package/src/exports/adapter.js +22 -0
  9. package/src/exports/public.d.ts +1 -1
  10. package/src/exports/vite/build/service-worker.js +98 -0
  11. package/src/exports/vite/dev/index.js +17 -3
  12. package/src/exports/vite/index.js +41 -411
  13. package/src/exports/vite/plugins/env-vars.js +42 -0
  14. package/src/exports/vite/plugins/guard.js +205 -0
  15. package/src/exports/vite/utils.js +97 -0
  16. package/src/runtime/app/server/remote/query.js +2 -2
  17. package/src/runtime/client/client.js +4 -4
  18. package/src/runtime/form-utils.js +11 -19
  19. package/src/runtime/server/data/index.js +11 -26
  20. package/src/runtime/server/errors.js +7 -10
  21. package/src/runtime/server/fetch.js +14 -16
  22. package/src/runtime/server/index.js +28 -25
  23. package/src/runtime/server/internal.js +34 -4
  24. package/src/runtime/server/page/actions.js +6 -8
  25. package/src/runtime/server/page/data_serializer.js +6 -10
  26. package/src/runtime/server/page/index.js +9 -14
  27. package/src/runtime/server/page/render.js +16 -29
  28. package/src/runtime/server/page/respond_with_error.js +7 -9
  29. package/src/runtime/server/remote-functions.js +125 -125
  30. package/src/runtime/server/respond.js +53 -28
  31. package/src/runtime/server/state.js +1 -0
  32. package/src/runtime/server/utils.js +0 -7
  33. package/src/runtime/utils.js +41 -0
  34. package/src/types/global-private.d.ts +8 -0
  35. package/src/types/internal.d.ts +7 -11
  36. package/src/utils/filesystem.js +1 -1
  37. package/src/utils/streaming.js +5 -15
  38. package/src/version.js +1 -1
  39. package/types/index.d.ts +20 -1
  40. package/types/index.d.ts.map +4 -1
@@ -1,6 +1,6 @@
1
1
  /** @import { RequestEvent, SSRManifest } from '@sveltejs/kit' */
2
2
  /** @import { RemoteForm } from '$app/server' */
3
- /** @import { RemoteFormInternals, RemoteFunctionData, RemoteFunctionResponse, RemoteInternals, RequestState, ServerActionResult, SSROptions } from 'types' */
3
+ /** @import { RemoteFormInternals, RemoteFunctionData, RemoteFunctionResponse, RemoteInternals, RequestState, ServerActionResult } from 'types' */
4
4
 
5
5
  import { error } from '@sveltejs/kit';
6
6
  import { Redirect, SvelteKitError } from '@sveltejs/kit/internal';
@@ -16,6 +16,7 @@ import {
16
16
  method_not_allowed_result
17
17
  } from './page/actions.js';
18
18
  import { deserialize_binary_form } from '../form-utils.js';
19
+ import { text_encoder } from '../utils.js';
19
20
  import { with_version_header } from './utils.js';
20
21
 
21
22
  /**
@@ -25,8 +26,121 @@ import { with_version_header } from './utils.js';
25
26
  */
26
27
  const KEEP_ALIVE_INTERVAL = 30_000;
27
28
 
29
+ /**
30
+ * @param {RequestEvent} event
31
+ * @param {RequestState} state
32
+ * @param {import('types').RemoteQueryLiveInternals} internals
33
+ * @param {any} arg
34
+ */
35
+ export function create_live_query_response(event, state, internals, arg) {
36
+ const cancellation = new AbortController();
37
+ const live_event = {
38
+ ...event,
39
+ request: new Request(event.request, {
40
+ signal: AbortSignal.any([event.request.signal, cancellation.signal])
41
+ })
42
+ };
43
+
44
+ const generator = internals.run(live_event, state, arg);
45
+
46
+ let open = true;
47
+ let pulling = false;
48
+ /** @type {ReadableStreamDefaultController<Uint8Array>} */
49
+ let stream_controller;
50
+ /** @type {ReturnType<typeof setTimeout> | undefined} */
51
+ let keep_alive;
52
+ /** @type {string | undefined} */
53
+ let result;
54
+
55
+ function schedule_keep_alive() {
56
+ clearTimeout(keep_alive);
57
+ keep_alive = setTimeout(() => {
58
+ if (!open) return;
59
+ if ((stream_controller.desiredSize ?? 0) > 0) {
60
+ stream_controller.enqueue(text_encoder.encode(': keep-alive\n\n'));
61
+ }
62
+ schedule_keep_alive();
63
+ }, KEEP_ALIVE_INTERVAL);
64
+ }
65
+
66
+ /** @param {any} data */
67
+ function send(data) {
68
+ if (!open) return;
69
+ stream_controller.enqueue(text_encoder.encode('data: ' + JSON.stringify(data) + '\n\n'));
70
+ schedule_keep_alive();
71
+ }
72
+
73
+ /** @param {boolean} cancelled */
74
+ function teardown(cancelled) {
75
+ if (!open) return;
76
+ open = false;
77
+ clearTimeout(keep_alive);
78
+ cancellation.abort();
79
+ if (!cancelled) stream_controller.close();
80
+ // AsyncGenerator.return() cannot interrupt a pending next(). Cleanup is
81
+ // cooperative via request.signal, so stream cancellation must not await it.
82
+ void generator.return(undefined).catch(() => {});
83
+ }
84
+
85
+ event.request.signal.addEventListener('abort', () => teardown(true), { once: true });
86
+
87
+ return new Response(
88
+ new ReadableStream({
89
+ start(controller) {
90
+ stream_controller = controller;
91
+ schedule_keep_alive();
92
+ },
93
+ async pull() {
94
+ if (!open || pulling) return;
95
+ pulling = true;
96
+
97
+ try {
98
+ while (open) {
99
+ const { value, done } = await generator.next();
100
+
101
+ if (!open) return;
102
+
103
+ if (done) {
104
+ teardown(false);
105
+ return;
106
+ }
107
+
108
+ if (result !== (result = stringify(value))) {
109
+ send({ type: 'result', result });
110
+ return;
111
+ }
112
+ }
113
+ } catch (error) {
114
+ if (!open) return;
115
+
116
+ if (error instanceof Redirect) {
117
+ send({ type: 'redirect', location: error.location });
118
+ } else {
119
+ const transformed = await handle_error_and_jsonify(event, state, error);
120
+
121
+ send({ type: 'error', error: transformed });
122
+ }
123
+
124
+ teardown(false);
125
+ } finally {
126
+ pulling = false;
127
+ }
128
+ },
129
+ cancel() {
130
+ teardown(true);
131
+ }
132
+ }),
133
+ {
134
+ headers: {
135
+ 'cache-control': 'private, no-store',
136
+ 'content-type': 'text/event-stream'
137
+ }
138
+ }
139
+ );
140
+ }
141
+
28
142
  /** @type {typeof handle_remote_call_internal} */
29
- export async function handle_remote_call(event, state, options, manifest, id) {
143
+ export async function handle_remote_call(event, state, manifest, id) {
30
144
  return record_span({
31
145
  name: 'sveltekit.remote.call',
32
146
  attributes: {
@@ -35,7 +149,7 @@ export async function handle_remote_call(event, state, options, manifest, id) {
35
149
  fn: async (current) => {
36
150
  const traced_event = merge_tracing(event, current);
37
151
  const response = await with_request_store({ event: traced_event, state }, () =>
38
- handle_remote_call_internal(traced_event, state, options, manifest, id)
152
+ handle_remote_call_internal(traced_event, state, manifest, id)
39
153
  );
40
154
  return with_version_header(response);
41
155
  }
@@ -45,11 +159,10 @@ export async function handle_remote_call(event, state, options, manifest, id) {
45
159
  /**
46
160
  * @param {RequestEvent} event
47
161
  * @param {RequestState} state
48
- * @param {SSROptions} options
49
162
  * @param {SSRManifest} manifest
50
163
  * @param {string} id
51
164
  */
52
- async function handle_remote_call_internal(event, state, options, manifest, id) {
165
+ async function handle_remote_call_internal(event, state, manifest, id) {
53
166
  const [hash, name, additional_args] = id.split('/');
54
167
  const remotes = manifest._.remotes;
55
168
 
@@ -89,119 +202,7 @@ async function handle_remote_call_internal(event, state, options, manifest, id)
89
202
  new URL(event.request.url).searchParams.get('payload')
90
203
  );
91
204
 
92
- const generator = internals.run(event, state, parse_remote_arg(payload));
93
-
94
- const encoder = new TextEncoder();
95
-
96
- let closed = false;
97
-
98
- /** @type {ReturnType<typeof setTimeout> | undefined} */
99
- let keep_alive;
100
-
101
- /**
102
- * (Re)schedule the keep-alive comment. Called whenever a message is sent, so
103
- * that a keep-alive is only emitted once `KEEP_ALIVE_INTERVAL` has elapsed
104
- * without any other activity.
105
- * @param {ReadableStreamDefaultController} controller
106
- */
107
- function schedule_keep_alive(controller) {
108
- clearTimeout(keep_alive);
109
- keep_alive = setTimeout(() => {
110
- if (closed || event.request.signal.aborted) return;
111
- // SSE comments (lines starting with `:`) are ignored by the client
112
- controller.enqueue(encoder.encode(': keep-alive\n\n'));
113
- schedule_keep_alive(controller);
114
- }, KEEP_ALIVE_INTERVAL);
115
- }
116
-
117
- /**
118
- * @param {ReadableStreamDefaultController} controller
119
- * @param {any} payload
120
- */
121
- function send(controller, payload) {
122
- controller.enqueue(encoder.encode('data: ' + JSON.stringify(payload) + '\n\n'));
123
- schedule_keep_alive(controller);
124
- }
125
-
126
- /** @type {string | undefined} */
127
- let result = undefined;
128
-
129
- async function cancel() {
130
- if (closed) return;
131
- closed = true;
132
- clearTimeout(keep_alive);
133
- await generator.return(undefined);
134
- }
135
-
136
- event.request.signal.addEventListener('abort', cancel, { once: true });
137
-
138
- return new Response(
139
- new ReadableStream({
140
- start(controller) {
141
- schedule_keep_alive(controller);
142
- },
143
- async pull(controller) {
144
- if (event.request.signal.aborted) {
145
- await cancel();
146
- controller.close();
147
- return;
148
- }
149
-
150
- try {
151
- while (true) {
152
- const { value, done } = await generator.next();
153
-
154
- if (done) {
155
- await cancel();
156
- controller.close();
157
- return;
158
- }
159
-
160
- // only send changed data
161
- if (result !== (result = stringify(value))) {
162
- send(controller, {
163
- type: 'result',
164
- result
165
- });
166
-
167
- return;
168
- }
169
- }
170
- } catch (error) {
171
- if (!event.request.signal.aborted) {
172
- if (error instanceof Redirect) {
173
- send(controller, {
174
- type: 'redirect',
175
- location: error.location
176
- });
177
- } else {
178
- const transformed = await handle_error_and_jsonify(
179
- event,
180
- state,
181
- options,
182
- error
183
- );
184
-
185
- send(controller, {
186
- type: 'error',
187
- error: transformed
188
- });
189
- }
190
- }
191
-
192
- await cancel();
193
- controller.close();
194
- }
195
- },
196
- cancel
197
- }),
198
- {
199
- headers: {
200
- 'cache-control': 'private, no-store',
201
- 'content-type': 'text/event-stream'
202
- }
203
- }
204
- );
205
+ return create_live_query_response(event, state, internals, parse_remote_arg(payload));
205
206
  }
206
207
 
207
208
  case 'query_batch': {
@@ -218,7 +219,7 @@ async function handle_remote_call_internal(event, state, options, manifest, id)
218
219
 
219
220
  const args = await Promise.all(payloads.map((payload) => parse_remote_arg(payload)));
220
221
 
221
- data._ = await with_request_store({ event, state }, () => internals.run(args, options));
222
+ data._ = await with_request_store({ event, state }, () => internals.run(args));
222
223
 
223
224
  break;
224
225
  }
@@ -309,7 +310,7 @@ async function handle_remote_call_internal(event, state, options, manifest, id)
309
310
  }
310
311
  }
311
312
 
312
- await collect_remote_data(data, event, state, options);
313
+ await collect_remote_data(data, event, state);
313
314
 
314
315
  return Response.json(
315
316
  /** @type {RemoteFunctionResponse} */ ({
@@ -320,7 +321,7 @@ async function handle_remote_call_internal(event, state, options, manifest, id)
320
321
  );
321
322
  } catch (error) {
322
323
  if (error instanceof Redirect) {
323
- const data = await collect_remote_data({ redirect: error.location }, event, state, options);
324
+ const data = await collect_remote_data({ redirect: error.location }, event, state);
324
325
 
325
326
  return Response.json(
326
327
  /** @type {RemoteFunctionResponse} */ ({
@@ -331,7 +332,7 @@ async function handle_remote_call_internal(event, state, options, manifest, id)
331
332
  );
332
333
  }
333
334
 
334
- const transformed = await handle_error_and_jsonify(event, state, options, error);
335
+ const transformed = await handle_error_and_jsonify(event, state, error);
335
336
 
336
337
  return Response.json(
337
338
  /** @type {RemoteFunctionResponse} */ ({
@@ -356,9 +357,8 @@ async function handle_remote_call_internal(event, state, options, manifest, id)
356
357
  * @param {RemoteFunctionData} data
357
358
  * @param {RequestEvent} event
358
359
  * @param {RequestState} state
359
- * @param {SSROptions} options
360
360
  */
361
- export async function collect_remote_data(data, event, state, options) {
361
+ export async function collect_remote_data(data, event, state) {
362
362
  /**
363
363
  *
364
364
  * @param {unknown} error
@@ -366,7 +366,7 @@ export async function collect_remote_data(data, event, state, options) {
366
366
  */
367
367
  function convert_error(error) {
368
368
  // TODO 4.0 remove the `Promise.resolve(...)`
369
- return Promise.resolve(handle_error_and_jsonify(event, state, options, error));
369
+ return Promise.resolve(handle_error_and_jsonify(event, state, error));
370
370
  }
371
371
 
372
372
  /** @type {Promise<any>[]} */
@@ -45,6 +45,7 @@ import {
45
45
  } from '../pathname.js';
46
46
  import { server_data_serializer } from './page/data_serializer.js';
47
47
  import { get_remote_id, handle_remote_call } from './remote-functions.js';
48
+ import { hooks, options } from './internal.js';
48
49
 
49
50
  /** @type {import('types').RequiredResolveOptions['transformPageChunk']} */
50
51
  const default_transform = ({ html }) => html;
@@ -85,12 +86,11 @@ export const respond = propagate_context(internal_respond);
85
86
 
86
87
  /**
87
88
  * @param {Request} request
88
- * @param {import('types').SSROptions} options
89
89
  * @param {import('@sveltejs/kit').SSRManifest} manifest
90
90
  * @param {import('types').RequestState} state
91
91
  * @returns {Promise<Response>}
92
92
  */
93
- export async function internal_respond(request, options, manifest, state) {
93
+ export async function internal_respond(request, manifest, state) {
94
94
  /** URL but stripped from the potential `/__data.json` suffix and its search param */
95
95
  const url = new URL(request.url);
96
96
 
@@ -100,7 +100,7 @@ export async function internal_respond(request, options, manifest, state) {
100
100
 
101
101
  if (!__SVELTEKIT_DEV__) {
102
102
  const request_origin = request.headers.get('origin');
103
- const self_origin = get_self_origin(options.paths_origin, url.origin);
103
+ const self_origin = get_self_origin(__SVELTEKIT_PATHS_ORIGIN__, url.origin);
104
104
 
105
105
  if (remote_id) {
106
106
  if (
@@ -113,7 +113,7 @@ export async function internal_respond(request, options, manifest, state) {
113
113
  const message = 'Cross-site remote requests are forbidden';
114
114
  return Response.json({ message }, { status: 403 });
115
115
  }
116
- } else if (options.csrf_check_origin) {
116
+ } else if (__SVELTEKIT_CSRF_CHECK_ORIGIN__) {
117
117
  const forbidden = is_csrf_forbidden({
118
118
  request,
119
119
  request_origin,
@@ -134,7 +134,7 @@ export async function internal_respond(request, options, manifest, state) {
134
134
  }
135
135
  }
136
136
 
137
- if (options.hash_routing && url.pathname !== base + '/' && url.pathname !== '/[fallback]') {
137
+ if (__SVELTEKIT_HASH_ROUTING__ && url.pathname !== base + '/' && url.pathname !== '/[fallback]') {
138
138
  return text('Not found', { status: 404 });
139
139
  }
140
140
 
@@ -243,7 +243,6 @@ export async function internal_respond(request, options, manifest, state) {
243
243
  // @ts-expect-error this has to be assigned lazily
244
244
  event.fetch = create_fetch({
245
245
  event,
246
- options,
247
246
  manifest,
248
247
  state,
249
248
  get_cookie_header,
@@ -263,7 +262,16 @@ export async function internal_respond(request, options, manifest, state) {
263
262
 
264
263
  // reroute could alter the given URL, so we pass a copy
265
264
  resolved_path =
266
- (await options.hooks.reroute({ url: new URL(url), fetch: event.fetch })) ?? url.pathname;
265
+ (await hooks.reroute({ url: new URL(url), fetch: event.fetch })) ?? url.pathname;
266
+
267
+ if (!manifest._.routes.length && resolved_path !== url.pathname) {
268
+ state.rerouted_url = denormalise_url({
269
+ request_url: request.url,
270
+ resolved_path,
271
+ is_data_request,
272
+ is_route_resolution_request
273
+ }).toString();
274
+ }
267
275
  } catch {
268
276
  return text('Internal Server Error', {
269
277
  status: 500
@@ -300,12 +308,12 @@ export async function internal_respond(request, options, manifest, state) {
300
308
  !state.prerendering?.fallback &&
301
309
  has_prerendered_path(manifest, resolved_path)
302
310
  ) {
303
- const url = new URL(request.url);
304
- url.pathname = is_data_request
305
- ? add_data_suffix(resolved_path)
306
- : is_route_resolution_request
307
- ? add_resolution_suffix(resolved_path)
308
- : resolved_path;
311
+ const url = denormalise_url({
312
+ request_url: request.url,
313
+ resolved_path,
314
+ is_data_request,
315
+ is_route_resolution_request
316
+ });
309
317
 
310
318
  try {
311
319
  // `fetch` automatically decodes the body, so we need to delete the related headers to not break the response
@@ -323,7 +331,7 @@ export async function internal_respond(request, options, manifest, state) {
323
331
  statusText: response.statusText
324
332
  });
325
333
  } catch (error) {
326
- return await handle_fatal_error(event, state, options, error);
334
+ return await handle_fatal_error(event, state, error);
327
335
  }
328
336
  }
329
337
 
@@ -369,7 +377,7 @@ export async function internal_respond(request, options, manifest, state) {
369
377
  event.params = result.params;
370
378
  }
371
379
  } catch (e) {
372
- return await handle_fatal_error(event, state, options, e);
380
+ return await handle_fatal_error(event, state, e);
373
381
  }
374
382
  }
375
383
 
@@ -452,10 +460,10 @@ export async function internal_respond(request, options, manifest, state) {
452
460
  add_cookies_to_headers(response.headers, new_cookies.values());
453
461
  return response;
454
462
  } catch (err) {
455
- return await handle_fatal_error(event, state, options, err);
463
+ return await handle_fatal_error(event, state, err);
456
464
  }
457
465
  }
458
- return await handle_fatal_error(event, state, options, e);
466
+ return await handle_fatal_error(event, state, e);
459
467
  }
460
468
 
461
469
  async function handle() {
@@ -485,7 +493,7 @@ export async function internal_respond(request, options, manifest, state) {
485
493
  };
486
494
 
487
495
  return await with_request_store({ event: traced_event, state }, () =>
488
- options.hooks.handle({
496
+ hooks.handle({
489
497
  event: traced_event,
490
498
  resolve: (event, opts) => {
491
499
  return record_span({
@@ -592,7 +600,6 @@ export async function internal_respond(request, options, manifest, state) {
592
600
  return await respond_with_error({
593
601
  event,
594
602
  state,
595
- options,
596
603
  manifest,
597
604
  error: new SvelteKitError(
598
605
  400,
@@ -603,11 +610,10 @@ export async function internal_respond(request, options, manifest, state) {
603
610
  });
604
611
  }
605
612
 
606
- if (options.hash_routing || state.prerendering?.fallback) {
613
+ if (__SVELTEKIT_HASH_ROUTING__ || state.prerendering?.fallback) {
607
614
  return await render_response({
608
615
  event,
609
616
  state,
610
- options,
611
617
  manifest,
612
618
  page_config: { ssr: false, csr: true },
613
619
  status: 200,
@@ -622,12 +628,12 @@ export async function internal_respond(request, options, manifest, state) {
622
628
  ],
623
629
  fetched: [],
624
630
  resolve_opts,
625
- data_serializer: server_data_serializer(event, state, options)
631
+ data_serializer: server_data_serializer(event, state)
626
632
  });
627
633
  }
628
634
 
629
635
  if (remote_id) {
630
- return await handle_remote_call(event, state, options, manifest, remote_id);
636
+ return await handle_remote_call(event, state, manifest, remote_id);
631
637
  }
632
638
 
633
639
  if (route) {
@@ -641,7 +647,6 @@ export async function internal_respond(request, options, manifest, state) {
641
647
  event,
642
648
  state,
643
649
  route,
644
- options,
645
650
  manifest,
646
651
  invalidated_data_nodes,
647
652
  trailing_slash
@@ -676,7 +681,6 @@ export async function internal_respond(request, options, manifest, state) {
676
681
  event,
677
682
  state,
678
683
  route.page,
679
- options,
680
684
  manifest,
681
685
  page_nodes,
682
686
  resolve_opts
@@ -765,7 +769,6 @@ export async function internal_respond(request, options, manifest, state) {
765
769
  event,
766
770
  state,
767
771
  { page: { layouts: [], leaf: 0 } },
768
- options,
769
772
  manifest,
770
773
  invalidated_data_nodes,
771
774
  // there is no route to take a trailing slash option from, and the
@@ -784,7 +787,6 @@ export async function internal_respond(request, options, manifest, state) {
784
787
  return await respond_with_error({
785
788
  event,
786
789
  state,
787
- options,
788
790
  manifest,
789
791
  error: new SvelteKitError(404, 'Not Found', `Not found: ${event.url.pathname}`),
790
792
  resolve_opts
@@ -806,7 +808,7 @@ export async function internal_respond(request, options, manifest, state) {
806
808
  // and I don't even know how to describe it. need to investigate at some point
807
809
 
808
810
  // HttpError from endpoint can end up here - TODO should it be handled there instead?
809
- return await handle_fatal_error(event, state, options, e);
811
+ return await handle_fatal_error(event, state, e);
810
812
  } finally {
811
813
  event.cookies.set = () => {
812
814
  throw new Error('Cannot use `cookies.set(...)` after the response has been generated');
@@ -853,3 +855,26 @@ function propagate_context(fn) {
853
855
  });
854
856
  };
855
857
  }
858
+
859
+ /**
860
+ * @param {object} opts
861
+ * @param {string} opts.request_url - The original request URL
862
+ * @param {string} opts.resolved_path - The resolved pathname
863
+ * @param {boolean} opts.is_data_request - Whether the request is a data request
864
+ * @param {boolean} opts.is_route_resolution_request -
865
+ * @returns {URL}
866
+ */
867
+ function denormalise_url({
868
+ request_url,
869
+ resolved_path,
870
+ is_data_request,
871
+ is_route_resolution_request
872
+ }) {
873
+ const url = new URL(request_url);
874
+ url.pathname = is_data_request
875
+ ? add_data_suffix(resolved_path)
876
+ : is_route_resolution_request
877
+ ? add_resolution_suffix(resolved_path)
878
+ : resolved_path;
879
+ return url;
880
+ }
@@ -36,6 +36,7 @@ export function create_request_state(options) {
36
36
  prerender_default: undefined,
37
37
  error: false,
38
38
  depth: 0,
39
+ rerouted_url: null,
39
40
  ...transient_fields()
40
41
  };
41
42
  }
@@ -29,13 +29,6 @@ export function allowed_methods(mod) {
29
29
  return allowed;
30
30
  }
31
31
 
32
- /**
33
- * @param {import('types').SSROptions} options
34
- */
35
- export function get_global_name(options) {
36
- return __SVELTEKIT_DEV__ ? '__sveltekit_dev' : `__sveltekit_${options.version_hash}`;
37
- }
38
-
39
32
  /**
40
33
  * @param {number} status
41
34
  * @param {string} location
@@ -1,6 +1,47 @@
1
1
  import { BROWSER } from 'esm-env';
2
2
 
3
3
  export const text_encoder = new TextEncoder();
4
+
5
+ /**
6
+ * `ReadableStream.from`, for runtimes that don't support it (as of writing, every Bun release)
7
+ * @template T
8
+ * @param {AsyncIterable<T>} iterable
9
+ * @returns {ReadableStream<T>}
10
+ */
11
+ export function stream_from_iterable(iterable) {
12
+ // TODO remove the casts once TypeScript's lib includes `ReadableStream.from`
13
+ if (/** @type {any} */ (ReadableStream).from) {
14
+ return /** @type {any} */ (ReadableStream).from(iterable);
15
+ }
16
+
17
+ const iterator = iterable[Symbol.asyncIterator]();
18
+ return new ReadableStream({
19
+ async pull(controller) {
20
+ const { value, done } = await iterator.next();
21
+ if (done) controller.close();
22
+ else controller.enqueue(value);
23
+ },
24
+ async cancel(reason) {
25
+ await iterator.return?.(reason);
26
+ }
27
+ });
28
+ }
29
+
30
+ /**
31
+ * @param {string} head
32
+ * @param {AsyncIterable<string>} chunks
33
+ * @returns {ReadableStream<Uint8Array>} `head` followed by each non-empty chunk, encoded
34
+ */
35
+ export function stream_text(head, chunks) {
36
+ return stream_from_iterable(
37
+ (async function* () {
38
+ yield text_encoder.encode(head);
39
+ for await (const chunk of chunks) {
40
+ if (chunk) yield text_encoder.encode(chunk);
41
+ }
42
+ })()
43
+ );
44
+ }
4
45
  export const text_decoder = new TextDecoder();
5
46
 
6
47
  /**
@@ -13,7 +13,15 @@ declare global {
13
13
  * it is influenced by `NODE_ENV` which can still be true during `vite preview`
14
14
  */
15
15
  const __SVELTEKIT_DEV__: boolean;
16
+ const __SVELTEKIT_CSRF_CHECK_ORIGIN__: boolean;
16
17
  const __SVELTEKIT_EMBEDDED__: boolean;
18
+ /** True if `config.output.linkHeaderPreload` is `true` */
19
+ const __SVELTEKIT_LINK_HEADER_PRELOAD__: boolean;
20
+ const __SVELTEKIT_PATHS_ORIGIN__: string | undefined;
21
+ /** True if the app has a service worker and `config.serviceWorker.register` is `true` */
22
+ const __SVELTEKIT_SERVICE_WORKER__: boolean;
23
+ /** The `__sveltekit_xxx` name the payload object is attached to, without `globalThis.` */
24
+ const __SVELTEKIT_GLOBAL_NAME__: string;
17
25
  const __SVELTEKIT_PATHS_ASSETS__: string;
18
26
  const __SVELTEKIT_PATHS_BASE__: string;
19
27
  const __SVELTEKIT_PATHS_RELATIVE__: boolean;