@sveltejs/kit 2.58.0 → 2.59.0

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.
@@ -1,16 +1,15 @@
1
1
  /** @import { RemoteQueryFunction } from '@sveltejs/kit' */
2
- /** @import { RemoteFunctionResponse } from 'types' */
3
2
  import { app_dir, base } from '$app/paths/internal/client';
4
- import { app, goto, query_map, query_responses } from '../client.js';
3
+ import { app, query_map, query_responses } from '../client.js';
5
4
  import {
6
5
  get_remote_request_headers,
6
+ is_in_effect,
7
7
  QUERY_FUNCTION_ID,
8
8
  QUERY_OVERRIDE_KEY,
9
9
  QUERY_RESOURCE_KEY,
10
10
  remote_request
11
11
  } from './shared.svelte.js';
12
12
  import * as devalue from 'devalue';
13
- import { HttpError, Redirect } from '@sveltejs/kit/internal';
14
13
  import { DEV } from 'esm-env';
15
14
  import { noop } from '../../../utils/functions.js';
16
15
  import { with_resolvers } from '../../../utils/promise.js';
@@ -26,18 +25,6 @@ import { create_remote_key, stringify_remote_arg, unfriendly_hydratable } from '
26
25
  * }} RemoteQueryCacheEntry
27
26
  */
28
27
 
29
- /**
30
- * @returns {boolean} Returns `true` if we are in an effect
31
- */
32
- function is_in_effect() {
33
- try {
34
- $effect.pre(noop);
35
- return true;
36
- } catch {
37
- return false;
38
- }
39
- }
40
-
41
28
  /**
42
29
  * @param {string} id
43
30
  * @returns {RemoteQueryFunction<any, any>}
@@ -49,8 +36,7 @@ export function query(id) {
49
36
 
50
37
  if (entries) {
51
38
  for (const entry of entries.values()) {
52
- // use optional chaining in case a prerender function was turned into a query
53
- void entry.resource.refresh?.();
39
+ void entry.resource.refresh();
54
40
  }
55
41
  }
56
42
  }
@@ -73,102 +59,6 @@ export function query(id) {
73
59
  return wrapper;
74
60
  }
75
61
 
76
- /**
77
- * @param {string} id
78
- * @returns {RemoteQueryFunction<any, any>}
79
- */
80
- export function query_batch(id) {
81
- /** @type {Map<string, Array<{resolve: (value: any) => void, reject: (error: any) => void}>>} */
82
- let batching = new Map();
83
-
84
- /** @type {RemoteQueryFunction<any, any>} */
85
- const wrapper = (arg) => {
86
- return new QueryProxy(id, arg, async (key, payload) => {
87
- const serialized = await unfriendly_hydratable(key, () => {
88
- return new Promise((resolve, reject) => {
89
- // create_remote_function caches identical calls, but in case a refresh to the same query is called multiple times this function
90
- // is invoked multiple times with the same payload, so we need to deduplicate here
91
- const entry = batching.get(payload) ?? [];
92
- entry.push({ resolve, reject });
93
- batching.set(payload, entry);
94
-
95
- if (batching.size > 1) return;
96
-
97
- // Do this here, after await Svelte' reactivity context is gone.
98
- // TODO is it possible to have batches of the same key
99
- // but in different forks/async contexts and in the same macrotask?
100
- // If so this would potentially be buggy
101
- const headers = {
102
- 'Content-Type': 'application/json',
103
- ...get_remote_request_headers()
104
- };
105
-
106
- // Wait for the next macrotask - don't use microtask as Svelte runtime uses these to collect changes and flush them,
107
- // and flushes could reveal more queries that should be batched.
108
- setTimeout(async () => {
109
- const batched = batching;
110
- batching = new Map();
111
-
112
- try {
113
- const response = await fetch(`${base}/${app_dir}/remote/${id}`, {
114
- method: 'POST',
115
- body: JSON.stringify({
116
- payloads: Array.from(batched.keys())
117
- }),
118
- headers
119
- });
120
-
121
- if (!response.ok) {
122
- throw new Error('Failed to execute batch query');
123
- }
124
-
125
- const result = /** @type {RemoteFunctionResponse} */ (await response.json());
126
- if (result.type === 'error') {
127
- throw new HttpError(result.status ?? 500, result.error);
128
- }
129
-
130
- if (result.type === 'redirect') {
131
- await goto(result.location);
132
- throw new Redirect(307, result.location);
133
- }
134
-
135
- const results = devalue.parse(result.result, app.decoders);
136
-
137
- // Resolve individual queries
138
- // Maps guarantee insertion order so we can do it like this
139
- let i = 0;
140
-
141
- for (const resolvers of batched.values()) {
142
- for (const { resolve, reject } of resolvers) {
143
- if (results[i].type === 'error') {
144
- reject(new HttpError(results[i].status, results[i].error));
145
- } else {
146
- resolve(results[i].data);
147
- }
148
- }
149
- i++;
150
- }
151
- } catch (error) {
152
- // Reject all queries in the batch
153
- for (const resolver of batched.values()) {
154
- for (const { reject } of resolver) {
155
- reject(error);
156
- }
157
- }
158
- }
159
- }, 0);
160
- });
161
- });
162
-
163
- return devalue.parse(serialized, app.decoders);
164
- });
165
- };
166
-
167
- Object.defineProperty(wrapper, QUERY_FUNCTION_ID, { value: id });
168
-
169
- return wrapper;
170
- }
171
-
172
62
  /**
173
63
  * The actual query instance. There should only ever be one active query instance per key.
174
64
  *
@@ -274,6 +164,11 @@ export class Query {
274
164
  resolve(undefined);
275
165
  })
276
166
  .catch((e) => {
167
+ // TODO: Our behavior here could be better:
168
+ // - We should not reject on redirects, but should hook into the router
169
+ // to ensure the query is properly refreshed before the navigation completes
170
+ // - Instead of failing on transport-level errors, we should probably do what
171
+ // LiveQuery does and preserve the last known good value and retry the connection
277
172
  const idx = this.#latest.indexOf(resolve);
278
173
  if (idx === -1) return;
279
174
 
@@ -290,10 +185,14 @@ export class Query {
290
185
  }
291
186
 
292
187
  get then() {
188
+ // TODO this should be unnecessary but due to the bug described
189
+ // in #start, we need to do this in some circumstances
190
+ this.#start();
293
191
  return this.#then;
294
192
  }
295
193
 
296
194
  get catch() {
195
+ this.#start();
297
196
  this.#then;
298
197
  return (/** @type {any} */ reject) => {
299
198
  return this.#then(undefined, reject);
@@ -301,6 +200,7 @@ export class Query {
301
200
  }
302
201
 
303
202
  get finally() {
203
+ this.#start();
304
204
  this.#then;
305
205
  return (/** @type {any} */ fn) => {
306
206
  return this.#then(
@@ -410,7 +310,7 @@ export class Query {
410
310
  * @template T
411
311
  * @implements {Promise<T>}
412
312
  */
413
- class QueryProxy {
313
+ export class QueryProxy {
414
314
  #id;
415
315
  #key;
416
316
  #payload;
@@ -545,7 +445,7 @@ class QueryProxy {
545
445
  /** @type {Query<T>['withOverride']} */
546
446
  withOverride(fn) {
547
447
  const entry = this.#get_or_create_cache_entry();
548
- const override = entry.resource.withOverride(fn);
448
+ const override = /** @type {Query<T>} */ (entry.resource).withOverride(fn);
549
449
 
550
450
  const release = /** @type {(() => void) & { [QUERY_OVERRIDE_KEY]: string }} */ (
551
451
  () => {
@@ -1,11 +1,12 @@
1
- /** @import { RemoteFunctionResponse, RemoteRefreshMap } from 'types' */
1
+ /** @import { RemoteFunctionResponse, RemoteSingleflightMap, RemoteSingleflightEntry } from 'types' */
2
2
  /** @import { RemoteQueryUpdate } from '@sveltejs/kit' */
3
3
  import * as devalue from 'devalue';
4
- import { app, goto, query_map } from '../client.js';
4
+ import { app, goto, live_query_map, query_map } from '../client.js';
5
5
  import { HttpError, Redirect } from '@sveltejs/kit/internal';
6
6
  import { untrack } from 'svelte';
7
7
  import { create_remote_key, split_remote_key } from '../../shared.js';
8
8
  import { navigating, page } from '../state.svelte.js';
9
+ import { noop } from '../../../utils/functions.js';
9
10
 
10
11
  /** Indicates a query function, as opposed to a query instance */
11
12
  export const QUERY_FUNCTION_ID = Symbol('sveltekit.query_function_id');
@@ -14,6 +15,18 @@ export const QUERY_OVERRIDE_KEY = Symbol('sveltekit.query_override_key');
14
15
  /** Indicates a query instance */
15
16
  export const QUERY_RESOURCE_KEY = Symbol('sveltekit.query_resource_key');
16
17
 
18
+ /**
19
+ * @returns {boolean} Returns `true` if we are in an effect
20
+ */
21
+ export function is_in_effect() {
22
+ try {
23
+ $effect.pre(noop);
24
+ return true;
25
+ } catch {
26
+ return false;
27
+ }
28
+ }
29
+
17
30
  /**
18
31
  * @returns {{ 'x-sveltekit-pathname': string, 'x-sveltekit-search': string }}
19
32
  */
@@ -49,16 +62,26 @@ export async function remote_request(url, headers) {
49
62
 
50
63
  const result = /** @type {RemoteFunctionResponse} */ (await response.json());
51
64
 
52
- if (result.type === 'redirect') {
53
- await goto(result.location);
54
- throw new Redirect(307, result.location);
65
+ const resolved = await handle_side_channel_response(result);
66
+
67
+ return resolved.result;
68
+ }
69
+
70
+ /**
71
+ * @param {RemoteFunctionResponse} response
72
+ * @returns {Promise<Extract<RemoteFunctionResponse, { type: 'result' }>>}
73
+ */
74
+ export async function handle_side_channel_response(response) {
75
+ if (response.type === 'redirect') {
76
+ await goto(response.location);
77
+ throw new Redirect(307, response.location);
55
78
  }
56
79
 
57
- if (result.type === 'error') {
58
- throw new HttpError(result.status ?? 500, result.error);
80
+ if (response.type === 'error') {
81
+ throw new HttpError(response.status ?? 500, response.error);
59
82
  }
60
83
 
61
- return result.result;
84
+ return response;
62
85
  }
63
86
 
64
87
  /**
@@ -81,10 +104,10 @@ export function categorize_updates(updates) {
81
104
  if (typeof update === 'function') {
82
105
  if (Object.hasOwn(update, QUERY_FUNCTION_ID)) {
83
106
  // this is a query function (not instance), so we need to find all active instances
84
- // of this functionand request that they be refreshed by the command handler
107
+ // of this function and request that they be refreshed/reconnected by the command handler
85
108
  // @ts-expect-error
86
109
  const id = /** @type {string} */ (update[QUERY_FUNCTION_ID]);
87
- const entries = query_map.get(id);
110
+ const entries = query_map.get(id) ?? live_query_map.get(id);
88
111
 
89
112
  if (entries) {
90
113
  for (const payload of entries.keys()) {
@@ -112,6 +135,10 @@ export function categorize_updates(updates) {
112
135
  overrides.push(/** @type {() => void} */ (update));
113
136
  continue;
114
137
  }
138
+
139
+ // this is just a regular function provided by some user integration, so we can just stash it in the overrides array
140
+ overrides.push(/** @type {() => void} */ (update));
141
+ continue;
115
142
  }
116
143
 
117
144
  if (
@@ -125,31 +152,57 @@ export function categorize_updates(updates) {
125
152
  continue;
126
153
  }
127
154
 
128
- throw new Error('updates() expects a query function, query resource, or query override');
155
+ throw new Error(
156
+ 'updates() expects a query or live query function, query resource, or query override'
157
+ );
129
158
  }
130
159
 
131
160
  return { overrides, refreshes };
132
161
  }
133
162
 
134
163
  /**
135
- * Apply refresh data from the server to the relevant queries
136
- *
137
- * @param {string} stringified_refreshes
164
+ * @template TResource
165
+ * @param {string} stringified_singleflight
166
+ * @param {Map<string, Map<string, { resource: TResource }>>} map
167
+ * @param {(resource: TResource, value: RemoteSingleflightEntry) => void} callback
138
168
  */
139
- export function apply_refreshes(stringified_refreshes) {
140
- const refreshes = Object.entries(
141
- /** @type {RemoteRefreshMap} */ (devalue.parse(stringified_refreshes, app.decoders))
169
+ function apply_singleflight(stringified_singleflight, map, callback) {
170
+ const singleflight = /** @type {RemoteSingleflightMap} */ (
171
+ devalue.parse(stringified_singleflight, app.decoders)
142
172
  );
143
173
 
144
- for (const [key, value] of refreshes) {
174
+ for (const [key, value] of Object.entries(singleflight)) {
145
175
  const parts = split_remote_key(key);
176
+ const entry = map.get(parts.id)?.get(parts.payload);
177
+ if (entry?.resource) {
178
+ callback(entry.resource, value);
179
+ }
180
+ }
181
+ }
146
182
 
147
- const entry = query_map.get(parts.id)?.get(parts.payload);
183
+ /**
184
+ * Apply refresh data from the server to the relevant queries
185
+ *
186
+ * @param {string} stringified_refreshes
187
+ */
188
+ export const apply_refreshes = (stringified_refreshes) => {
189
+ apply_singleflight(stringified_refreshes, query_map, (resource, value) => {
190
+ if (value.type === 'result') {
191
+ resource?.set(value.data);
192
+ } else {
193
+ resource?.fail(new HttpError(value.status ?? 500, value.error));
194
+ }
195
+ });
196
+ };
148
197
 
198
+ /** @param {string} stringified_reconnects */
199
+ export const apply_reconnections = (stringified_reconnects) => {
200
+ apply_singleflight(stringified_reconnects, live_query_map, (resource, value) => {
149
201
  if (value.type === 'result') {
150
- entry?.resource.set(value.data);
202
+ resource?.set(value.data);
203
+ void resource?.reconnect();
151
204
  } else {
152
- entry?.resource.fail(new HttpError(value.status ?? 500, value.error));
205
+ resource?.fail(new HttpError(value.status ?? 500, value.error));
153
206
  }
154
- }
155
- }
207
+ });
208
+ };
@@ -4,9 +4,11 @@
4
4
 
5
5
  import { DEV } from 'esm-env';
6
6
  import * as devalue from 'devalue';
7
- import { text_decoder, text_encoder } from './utils.js';
7
+ import { text_encoder } from './utils.js';
8
8
  import { SvelteKitError } from '@sveltejs/kit/internal';
9
9
 
10
+ const decoder = new TextDecoder();
11
+
10
12
  /**
11
13
  * Sets a value in a nested object using a path string, mutating the original object
12
14
  * @param {Record<string, any>} object
@@ -250,7 +252,7 @@ export async function deserialize_binary_form(request) {
250
252
  const file_offsets_buffer = await get_buffer(HEADER_BYTES + data_length, file_offsets_length);
251
253
  if (!file_offsets_buffer) throw deserialize_error('file offset table too short');
252
254
 
253
- const parsed_offsets = JSON.parse(text_decoder.decode(file_offsets_buffer));
255
+ const parsed_offsets = JSON.parse(decoder.decode(file_offsets_buffer));
254
256
 
255
257
  if (
256
258
  !Array.isArray(parsed_offsets) ||
@@ -265,7 +267,7 @@ export async function deserialize_binary_form(request) {
265
267
 
266
268
  /** @type {Array<{ offset: number, size: number }>} */
267
269
  const file_spans = [];
268
- const [data, meta] = devalue.parse(text_decoder.decode(data_buffer), {
270
+ const [data, meta] = devalue.parse(decoder.decode(data_buffer), {
269
271
  File: ([name, type, size, last_modified, index]) => {
270
272
  if (
271
273
  typeof name !== 'string' ||
@@ -458,7 +460,7 @@ class LazyFile {
458
460
  });
459
461
  }
460
462
  async text() {
461
- return text_decoder.decode(await this.arrayBuffer());
463
+ return decoder.decode(await this.arrayBuffer());
462
464
  }
463
465
  }
464
466
 
@@ -664,7 +666,7 @@ export function create_field_proxy(target, get_input, set_input, get_issues, pat
664
666
  if (prop === 'as') {
665
667
  /**
666
668
  * @param {string} type
667
- * @param {string} [input_value]
669
+ * @param {unknown} [input_value]
668
670
  */
669
671
  const as_func = (type, input_value) => {
670
672
  const is_array =
@@ -732,6 +734,23 @@ export function create_field_proxy(target, get_input, set_input, get_issues, pat
732
734
  }
733
735
  }
734
736
 
737
+ if (type === 'checkbox' && !is_array) {
738
+ return Object.defineProperties(base_props, {
739
+ defaultChecked: {
740
+ enumerable: true,
741
+ get() {
742
+ return input_value;
743
+ }
744
+ },
745
+ checked: {
746
+ enumerable: true,
747
+ get() {
748
+ return get_value() ?? input_value;
749
+ }
750
+ }
751
+ });
752
+ }
753
+
735
754
  return Object.defineProperties(base_props, {
736
755
  value: { value: input_value ?? 'on', enumerable: true },
737
756
  checked: {
@@ -743,11 +762,7 @@ export function create_field_proxy(target, get_input, set_input, get_issues, pat
743
762
  return value === input_value;
744
763
  }
745
764
 
746
- if (is_array) {
747
- return (value ?? []).includes(input_value);
748
- }
749
-
750
- return value;
765
+ return (value ?? []).includes(input_value);
751
766
  }
752
767
  }
753
768
  });
@@ -797,6 +812,12 @@ export function create_field_proxy(target, get_input, set_input, get_issues, pat
797
812
 
798
813
  // Handle all other input types (text, number, etc.)
799
814
  return Object.defineProperties(base_props, {
815
+ defaultValue: {
816
+ enumerable: true,
817
+ get() {
818
+ return input_value;
819
+ }
820
+ },
800
821
  value: {
801
822
  enumerable: true,
802
823
  get() {
@@ -4,7 +4,7 @@ import { disable_search, make_trackable } from '../../../utils/url.js';
4
4
  import { validate_depends, validate_load_response } from '../../shared.js';
5
5
  import { with_request_store, merge_tracing } from '@sveltejs/kit/internal/server';
6
6
  import { record_span } from '../../telemetry/record_span.js';
7
- import { base64_encode, text_decoder } from '../../utils.js';
7
+ import { base64_encode } from '../../utils.js';
8
8
  import { NULL_BODY_STATUS } from '../constants.js';
9
9
  import { get_node_type } from '../utils.js';
10
10
 
@@ -493,12 +493,14 @@ export function create_universal_fetch(event, state, fetched, csr, resolve_opts)
493
493
  async function stream_to_string(stream) {
494
494
  let result = '';
495
495
  const reader = stream.getReader();
496
+ const decoder = new TextDecoder();
496
497
  while (true) {
497
498
  const { done, value } = await reader.read();
498
499
  if (done) {
500
+ result += decoder.decode();
499
501
  break;
500
502
  }
501
- result += text_decoder.decode(value);
503
+ result += decoder.decode(value, { stream: true });
502
504
  }
503
505
  return result;
504
506
  }
@@ -529,7 +529,10 @@ export async function render_response({
529
529
 
530
530
  const store = internals.type === 'prerender' ? prerender : query;
531
531
 
532
- if (event_state.remote.refreshes?.[remote_key] !== undefined) {
532
+ if (
533
+ event_state.remote.refreshes?.has(remote_key) ||
534
+ event_state.remote.reconnects?.has(remote_key)
535
+ ) {
533
536
  // This entry was refreshed/set by a command or form action.
534
537
  // Always await it so the mutation result is serialized.
535
538
  store[remote_key] = await entry.data;
@@ -121,7 +121,12 @@ async function handle_remote_call_internal(event, state, options, manifest, id)
121
121
  /** @type {RemoteFunctionResponse} */ ({
122
122
  type: 'result',
123
123
  result: stringify(result, transport),
124
- refreshes: result.issues ? undefined : await serialize_refreshes()
124
+ refreshes: result.issues
125
+ ? undefined
126
+ : await serialize_singleflight(state.remote.refreshes),
127
+ reconnects: result.issues
128
+ ? undefined
129
+ : await serialize_singleflight(state.remote.reconnects)
125
130
  })
126
131
  );
127
132
  }
@@ -137,11 +142,115 @@ async function handle_remote_call_internal(event, state, options, manifest, id)
137
142
  /** @type {RemoteFunctionResponse} */ ({
138
143
  type: 'result',
139
144
  result: stringify(data, transport),
140
- refreshes: await serialize_refreshes()
145
+ refreshes: await serialize_singleflight(state.remote.refreshes),
146
+ reconnects: await serialize_singleflight(state.remote.reconnects)
141
147
  })
142
148
  );
143
149
  }
144
150
 
151
+ if (internals.type === 'query_live') {
152
+ if (event.request.method !== 'GET') {
153
+ throw new SvelteKitError(
154
+ 405,
155
+ 'Method Not Allowed',
156
+ `\`query.live\` functions must be invoked via GET request, not ${event.request.method}`
157
+ );
158
+ }
159
+
160
+ const payload = /** @type {string} */ (
161
+ new URL(event.request.url).searchParams.get('payload')
162
+ );
163
+
164
+ const generator = internals.run(event, state, parse_remote_arg(payload, transport));
165
+
166
+ const encoder = new TextEncoder();
167
+
168
+ /**
169
+ * @param {ReadableStreamDefaultController} controller
170
+ * @param {any} payload
171
+ */
172
+ function send(controller, payload) {
173
+ controller.enqueue(encoder.encode(JSON.stringify(payload) + '\n'));
174
+ }
175
+
176
+ let closed = false;
177
+
178
+ /** @type {string | undefined} */
179
+ let result = undefined;
180
+
181
+ async function cancel() {
182
+ if (closed) return;
183
+ closed = true;
184
+ await generator.return(undefined);
185
+ }
186
+
187
+ event.request.signal.addEventListener('abort', cancel, { once: true });
188
+
189
+ return new Response(
190
+ new ReadableStream({
191
+ async pull(controller) {
192
+ if (event.request.signal.aborted) {
193
+ await cancel();
194
+ controller.close();
195
+ return;
196
+ }
197
+
198
+ try {
199
+ while (true) {
200
+ const { value, done } = await generator.next();
201
+
202
+ if (done) {
203
+ await cancel();
204
+ controller.close();
205
+ return;
206
+ }
207
+
208
+ // only send changed data
209
+ if (result !== (result = stringify(value, transport))) {
210
+ send(controller, {
211
+ type: 'result',
212
+ result
213
+ });
214
+
215
+ return;
216
+ }
217
+ }
218
+ } catch (error) {
219
+ if (!event.request.signal.aborted) {
220
+ if (error instanceof Redirect) {
221
+ send(controller, {
222
+ type: 'redirect',
223
+ location: error.location
224
+ });
225
+ } else {
226
+ const status =
227
+ error instanceof HttpError || error instanceof SvelteKitError
228
+ ? error.status
229
+ : 500;
230
+
231
+ send(controller, {
232
+ type: 'error',
233
+ error: await handle_error_and_jsonify(event, state, options, error),
234
+ status
235
+ });
236
+ }
237
+ }
238
+
239
+ await cancel();
240
+ controller.close();
241
+ }
242
+ },
243
+ cancel
244
+ }),
245
+ {
246
+ headers: {
247
+ 'cache-control': 'private, no-store',
248
+ 'content-type': 'application/x-ndjson'
249
+ }
250
+ }
251
+ );
252
+ }
253
+
145
254
  const payload =
146
255
  internals.type === 'prerender'
147
256
  ? additional_args
@@ -166,7 +275,8 @@ async function handle_remote_call_internal(event, state, options, manifest, id)
166
275
  /** @type {RemoteFunctionResponse} */ ({
167
276
  type: 'redirect',
168
277
  location: error.location,
169
- refreshes: await serialize_refreshes()
278
+ refreshes: await serialize_singleflight(state.remote.refreshes),
279
+ reconnects: await serialize_singleflight(state.remote.reconnects)
170
280
  })
171
281
  );
172
282
  }
@@ -191,16 +301,14 @@ async function handle_remote_call_internal(event, state, options, manifest, id)
191
301
  );
192
302
  }
193
303
 
194
- async function serialize_refreshes() {
195
- const refreshes = state.remote.refreshes ?? {};
196
-
197
- const entries = Object.entries(refreshes);
198
- if (entries.length === 0) {
304
+ /** @param {Map<string, Promise<any>> | null} map */
305
+ async function serialize_singleflight(map) {
306
+ if (!map || map.size === 0) {
199
307
  return undefined;
200
308
  }
201
309
 
202
310
  const results = await Promise.all(
203
- entries.map(async ([key, promise]) => {
311
+ Array.from(map, async ([key, promise]) => {
204
312
  try {
205
313
  return [key, { type: 'result', data: await promise }];
206
314
  } catch (error) {
@@ -152,6 +152,7 @@ export async function internal_respond(request, options, manifest, state) {
152
152
  forms: null,
153
153
  /** A map of remote function key to corresponding single-flight-mutation promise */
154
154
  refreshes: null,
155
+ reconnects: null,
155
156
  /** A map of remote function ID to payloads requested for refreshing by the client */
156
157
  requested: null
157
158
  },
@@ -1,6 +1,6 @@
1
1
  /** @import { Transport } from '@sveltejs/kit' */
2
2
  import * as devalue from 'devalue';
3
- import { base64_decode, base64_encode, text_decoder, text_encoder } from './utils.js';
3
+ import { base64_decode, base64_encode, text_encoder } from './utils.js';
4
4
  import * as svelte from 'svelte';
5
5
 
6
6
  /**
@@ -273,7 +273,7 @@ export function stringify_remote_arg(value, transport, sort = true) {
273
273
  export function parse_remote_arg(string, transport) {
274
274
  if (!string) return undefined;
275
275
 
276
- const json_string = text_decoder.decode(
276
+ const json_string = new TextDecoder().decode(
277
277
  // no need to add back `=` characters, atob can handle it
278
278
  base64_decode(string.replaceAll('-', '+').replaceAll('_', '/'))
279
279
  );
@@ -1,7 +1,6 @@
1
1
  import { BROWSER } from 'esm-env';
2
2
 
3
3
  export const text_encoder = new TextEncoder();
4
- export const text_decoder = new TextDecoder();
5
4
 
6
5
  /**
7
6
  * Like node's path.relative, but without using node