@sveltejs/kit 2.58.0 → 2.59.1

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,13 +1,19 @@
1
- /** @import { RemoteQuery, RemoteQueryFunction } from '@sveltejs/kit' */
2
- /** @import { RemoteInternals, MaybePromise, RequestState, RemoteQueryBatchInternals, RemoteQueryInternals } from 'types' */
1
+ /** @import { RemoteLiveQuery, RemoteLiveQueryFunction, RemoteQuery, RemoteQueryFunction } from '@sveltejs/kit' */
2
+ /** @import { RemoteInternals, MaybePromise, RequestState, RemoteQueryLiveInternals, RemoteQueryBatchInternals, RemoteQueryInternals, RemoteLiveQueryUserFunctionReturnType } from 'types' */
3
3
  /** @import { StandardSchemaV1 } from '@standard-schema/spec' */
4
4
  import { get_request_store } from '@sveltejs/kit/internal/server';
5
5
  import { create_remote_key, stringify, stringify_remote_arg } from '../../../shared.js';
6
6
  import { prerendering } from '__sveltekit/environment';
7
- import { noop } from '../../../../utils/functions.js';
8
- import { create_validator, get_cache, get_response, run_remote_function } from './shared.js';
7
+ import {
8
+ create_validator,
9
+ get_cache,
10
+ get_response,
11
+ run_remote_function,
12
+ run_remote_generator
13
+ } from './shared.js';
9
14
  import { handle_error_and_jsonify } from '../../../server/utils.js';
10
15
  import { HttpError, SvelteKitError } from '@sveltejs/kit/internal';
16
+ import { noop } from '../../../../utils/functions.js';
11
17
 
12
18
  /**
13
19
  * Creates a remote query. When called from the browser, the function will be invoked on the server via a `fetch` call.
@@ -98,6 +104,110 @@ export function query(validate_or_fn, maybe_fn) {
98
104
  return wrapper;
99
105
  }
100
106
 
107
+ /**
108
+ * Creates a live remote query. When called from the browser, the function will be invoked on the server via a streaming `fetch` call.
109
+ *
110
+ * See [Remote functions](https://svelte.dev/docs/kit/remote-functions#query.live) for full documentation.
111
+ *
112
+ * @template Output
113
+ * @overload
114
+ * @param {(arg: void) => RemoteLiveQueryUserFunctionReturnType<Output>} fn
115
+ * @returns {RemoteLiveQueryFunction<void, Output>}
116
+ */
117
+ /**
118
+ * @template Input
119
+ * @template Output
120
+ * @overload
121
+ * @param {'unchecked'} validate
122
+ * @param {(arg: Input) => RemoteLiveQueryUserFunctionReturnType<Output>} fn
123
+ * @returns {RemoteLiveQueryFunction<Input, Output>}
124
+ */
125
+ /**
126
+ * @template {StandardSchemaV1} Schema
127
+ * @template Output
128
+ * @overload
129
+ * @param {Schema} schema
130
+ * @param {(arg: StandardSchemaV1.InferOutput<Schema>) => RemoteLiveQueryUserFunctionReturnType<Output>} fn
131
+ * @returns {RemoteLiveQueryFunction<StandardSchemaV1.InferInput<Schema>, Output, StandardSchemaV1.InferOutput<Schema>>}
132
+ */
133
+ /**
134
+ * @template Input
135
+ * @template Output
136
+ * @param {any} validate_or_fn
137
+ * @param {(args: Input) => RemoteLiveQueryUserFunctionReturnType<Output>} [maybe_fn]
138
+ * @returns {RemoteLiveQueryFunction<Input, Output>}
139
+ */
140
+ /*@__NO_SIDE_EFFECTS__*/
141
+ function live(validate_or_fn, maybe_fn) {
142
+ /** @type {(arg: Input) => RemoteLiveQueryUserFunctionReturnType<Output>} */
143
+ const fn = maybe_fn ?? validate_or_fn;
144
+
145
+ /** @type {(arg?: any) => MaybePromise<Input>} */
146
+ const validate = create_validator(validate_or_fn, maybe_fn);
147
+
148
+ /**
149
+ * @param {any} event
150
+ * @param {any} state
151
+ * @param {any} get_input
152
+ */
153
+ const run = (event, state, get_input) =>
154
+ run_remote_generator(event, state, false, get_input, fn, __.name);
155
+
156
+ /**
157
+ * @param {any} generator
158
+ * @returns {Promise<any>}
159
+ */
160
+ const first_value = async (generator) => {
161
+ try {
162
+ const { value, done } = await generator.next();
163
+
164
+ if (done) {
165
+ throw new Error(`query.live '${__.name}' did not yield a value`);
166
+ }
167
+
168
+ return value;
169
+ } finally {
170
+ await generator.return(undefined);
171
+ }
172
+ };
173
+
174
+ /** @type {RemoteQueryLiveInternals} */
175
+ const __ = {
176
+ type: 'query_live',
177
+ id: '',
178
+ name: '',
179
+ run: (event, state, arg) => run(event, state, () => validate(arg)),
180
+ validate,
181
+ bind(payload, validated_arg) {
182
+ const { event, state } = get_request_store();
183
+
184
+ return create_live_query_resource(__, payload, state, () =>
185
+ first_value(run(event, state, () => validated_arg))
186
+ );
187
+ }
188
+ };
189
+
190
+ /** @type {RemoteLiveQueryFunction<Input, Output> & { __: RemoteQueryLiveInternals }} */
191
+ const wrapper = (arg) => {
192
+ if (prerendering) {
193
+ throw new Error(
194
+ `Cannot call query.live '${__.name}' while prerendering, as prerendered pages need static data. Use 'prerender' from $app/server instead`
195
+ );
196
+ }
197
+
198
+ const { event, state } = get_request_store();
199
+ const payload = stringify_remote_arg(arg, state.transport);
200
+
201
+ return create_live_query_resource(__, payload, state, () =>
202
+ first_value(run(event, state, () => validate(arg)))
203
+ );
204
+ };
205
+
206
+ Object.defineProperty(wrapper, '__', { value: __ });
207
+
208
+ return wrapper;
209
+ }
210
+
101
211
  /**
102
212
  * Creates a batch query function that collects multiple calls and executes them in a single request
103
213
  *
@@ -140,11 +250,81 @@ function batch(validate_or_fn, maybe_fn) {
140
250
  /** @type {(arg?: any) => MaybePromise<Input>} */
141
251
  const validate = create_validator(validate_or_fn, maybe_fn);
142
252
 
253
+ /** @type {Map<string, { get_validated: () => MaybePromise<any>, resolvers: Array<{resolve: (value: any) => void, reject: (error: any) => void}> }>} */
254
+ let batching = new Map();
255
+
256
+ /**
257
+ * Enqueues a single call into the current batch (creating one if necessary)
258
+ * and returns a promise that resolves with the result for this entry.
259
+ *
260
+ * @param {string} payload — the stringified raw argument (cache key)
261
+ * @param {() => MaybePromise<any>} get_validated — produces the validated argument for this entry
262
+ * @returns {Promise<any>}
263
+ */
264
+ const enqueue = (payload, get_validated) => {
265
+ const { event, state } = get_request_store();
266
+
267
+ return new Promise((resolve, reject) => {
268
+ const entry = batching.get(payload);
269
+
270
+ if (entry) {
271
+ entry.resolvers.push({ resolve, reject });
272
+ return;
273
+ }
274
+
275
+ batching.set(payload, {
276
+ get_validated,
277
+ resolvers: [{ resolve, reject }]
278
+ });
279
+
280
+ if (batching.size > 1) return;
281
+
282
+ setTimeout(async () => {
283
+ const batched = batching;
284
+ batching = new Map();
285
+ const entries = Array.from(batched.values());
286
+
287
+ try {
288
+ return await run_remote_function(
289
+ event,
290
+ state,
291
+ false,
292
+ async () => Promise.all(entries.map((entry) => entry.get_validated())),
293
+ async (input) => {
294
+ const get_result = await fn(input);
295
+
296
+ for (let i = 0; i < entries.length; i++) {
297
+ try {
298
+ const result = get_result(input[i], i);
299
+
300
+ for (const resolver of entries[i].resolvers) {
301
+ resolver.resolve(result);
302
+ }
303
+ } catch (error) {
304
+ for (const resolver of entries[i].resolvers) {
305
+ resolver.reject(error);
306
+ }
307
+ }
308
+ }
309
+ }
310
+ );
311
+ } catch (error) {
312
+ for (const entry of batched.values()) {
313
+ for (const resolver of entry.resolvers) {
314
+ resolver.reject(error);
315
+ }
316
+ }
317
+ }
318
+ }, 0);
319
+ });
320
+ };
321
+
143
322
  /** @type {RemoteQueryBatchInternals} */
144
323
  const __ = {
145
324
  type: 'query_batch',
146
325
  id: '',
147
326
  name: '',
327
+ validate,
148
328
  run: async (args, options) => {
149
329
  const { event, state } = get_request_store();
150
330
 
@@ -175,12 +355,14 @@ function batch(validate_or_fn, maybe_fn) {
175
355
  );
176
356
  }
177
357
  );
358
+ },
359
+ bind(payload, validated_arg) {
360
+ const { state } = get_request_store();
361
+
362
+ return create_query_resource(__, payload, state, () => enqueue(payload, () => validated_arg));
178
363
  }
179
364
  };
180
365
 
181
- /** @type {Map<string, { arg: any, resolvers: Array<{resolve: (value: any) => void, reject: (error: any) => void}> }>} */
182
- let batching = new Map();
183
-
184
366
  /** @type {RemoteQueryFunction<Input, Output> & { __: RemoteQueryBatchInternals }} */
185
367
  const wrapper = (arg) => {
186
368
  if (prerendering) {
@@ -189,69 +371,14 @@ function batch(validate_or_fn, maybe_fn) {
189
371
  );
190
372
  }
191
373
 
192
- const { event, state } = get_request_store();
193
- // batched queries do not participate in `requested(...)`, so `arg` is
194
- // always the raw user-supplied value and can be used for the cache key directly
374
+ const { state } = get_request_store();
195
375
  const payload = stringify_remote_arg(arg, state.transport);
196
376
 
197
- return create_query_resource(__, payload, state, () => {
377
+ return create_query_resource(__, payload, state, () =>
198
378
  // Collect all the calls to the same query in the same macrotask,
199
379
  // then execute them as one backend request.
200
- return new Promise((resolve, reject) => {
201
- const entry = batching.get(payload);
202
-
203
- if (entry) {
204
- entry.resolvers.push({ resolve, reject });
205
- return;
206
- }
207
-
208
- batching.set(payload, {
209
- arg,
210
- resolvers: [{ resolve, reject }]
211
- });
212
-
213
- if (batching.size > 1) return;
214
-
215
- setTimeout(async () => {
216
- const batched = batching;
217
- batching = new Map();
218
- const entries = Array.from(batched.values());
219
- const args = entries.map((entry) => entry.arg);
220
-
221
- try {
222
- return await run_remote_function(
223
- event,
224
- state,
225
- false,
226
- async () => Promise.all(args.map(validate)),
227
- async (input) => {
228
- const get_result = await fn(input);
229
-
230
- for (let i = 0; i < entries.length; i++) {
231
- try {
232
- const result = get_result(input[i], i);
233
-
234
- for (const resolver of entries[i].resolvers) {
235
- resolver.resolve(result);
236
- }
237
- } catch (error) {
238
- for (const resolver of entries[i].resolvers) {
239
- resolver.reject(error);
240
- }
241
- }
242
- }
243
- }
244
- );
245
- } catch (error) {
246
- for (const entry of batched.values()) {
247
- for (const resolver of entry.resolvers) {
248
- resolver.reject(error);
249
- }
250
- }
251
- }
252
- }, 0);
253
- });
254
- });
380
+ enqueue(payload, () => validate(arg))
381
+ );
255
382
  };
256
383
 
257
384
  Object.defineProperty(wrapper, '__', { value: __ });
@@ -274,19 +401,38 @@ function create_query_resource(__, payload, state, fn) {
274
401
  return (promise ??= get_response(__, payload, state, fn));
275
402
  };
276
403
 
404
+ const populate_hydratable = () => {
405
+ // accessing data properties needs to kick off the work
406
+ // so that it gets seeded in the hydration cache
407
+ // and becomes available on the client
408
+ void (__.id && state.is_in_render && get_promise());
409
+ };
410
+
277
411
  return {
278
412
  /** @type {Promise<any>['catch']} */
279
413
  catch(onrejected) {
280
414
  return get_promise().catch(onrejected);
281
415
  },
282
- current: undefined,
283
- error: undefined,
416
+ get current() {
417
+ populate_hydratable();
418
+ return undefined;
419
+ },
420
+ get error() {
421
+ populate_hydratable();
422
+ return undefined;
423
+ },
284
424
  /** @type {Promise<any>['finally']} */
285
425
  finally(onfinally) {
286
426
  return get_promise().finally(onfinally);
287
427
  },
288
- loading: true,
289
- ready: false,
428
+ get loading() {
429
+ populate_hydratable();
430
+ return true;
431
+ },
432
+ get ready() {
433
+ populate_hydratable();
434
+ return false;
435
+ },
290
436
  refresh() {
291
437
  const refresh_context = get_refresh_context(__, 'refresh', payload);
292
438
  const is_immediate_refresh = !refresh_context.cache[refresh_context.payload];
@@ -321,14 +467,92 @@ function create_query_resource(__, payload, state, fn) {
321
467
  };
322
468
  }
323
469
 
470
+ /**
471
+ * @param {RemoteQueryLiveInternals} __
472
+ * @param {string} payload — the stringified raw argument (i.e. the cache key the client will use)
473
+ * @param {RequestState} state
474
+ * @param {() => Promise<any>} get_first_value
475
+ * @returns {RemoteLiveQuery<any>}
476
+ */
477
+ function create_live_query_resource(__, payload, state, get_first_value) {
478
+ /** @type {Promise<any> | null} */
479
+ let promise = null;
480
+
481
+ const get_promise = () => {
482
+ return (promise ??= get_response(__, payload, state, get_first_value));
483
+ };
484
+
485
+ const populate_hydratable = () => {
486
+ void (__.id && state.is_in_render && get_promise());
487
+ };
488
+
489
+ return {
490
+ /** @type {Promise<any>['catch']} */
491
+ catch(onrejected) {
492
+ return get_promise().catch(onrejected);
493
+ },
494
+ get current() {
495
+ populate_hydratable();
496
+ return undefined;
497
+ },
498
+ get error() {
499
+ populate_hydratable();
500
+ return undefined;
501
+ },
502
+ /** @type {Promise<any>['finally']} */
503
+ finally(onfinally) {
504
+ return get_promise().finally(onfinally);
505
+ },
506
+ get done() {
507
+ populate_hydratable();
508
+ return false;
509
+ },
510
+ get loading() {
511
+ populate_hydratable();
512
+ return true;
513
+ },
514
+ get ready() {
515
+ populate_hydratable();
516
+ return false;
517
+ },
518
+ get connected() {
519
+ populate_hydratable();
520
+ return false;
521
+ },
522
+ reconnect() {
523
+ const reconnects = state.remote.reconnects;
524
+
525
+ if (!reconnects) {
526
+ throw new Error(
527
+ `Cannot call reconnect on query.live '${__.name}' because it is not executed in the context of a command/form remote function`
528
+ );
529
+ }
530
+
531
+ reconnects.set(create_remote_key(__.id, payload), get_promise());
532
+ return Promise.resolve();
533
+ },
534
+ run() {
535
+ throw new Error('Cannot call .run() on a live query on the server');
536
+ },
537
+ /** @type {Promise<any>['then']} */
538
+ then(onfulfilled, onrejected) {
539
+ return get_promise().then(onfulfilled, onrejected);
540
+ },
541
+ get [Symbol.toStringTag]() {
542
+ return 'LiveQueryResource';
543
+ }
544
+ };
545
+ }
546
+
324
547
  // Add batch as a property to the query function
325
548
  Object.defineProperty(query, 'batch', { value: batch, enumerable: true });
549
+ Object.defineProperty(query, 'live', { value: live, enumerable: true });
326
550
 
327
551
  /**
328
552
  * @param {RemoteInternals} __
329
553
  * @param {'set' | 'refresh'} action
330
- * @param {string} payload — the stringified raw argument
331
- * @returns {{ __: RemoteInternals; state: any; refreshes: Record<string, Promise<any>>; cache: Record<string, { serialize: boolean; data: any }>; refreshes_key: string; payload: string }}
554
+ * @param {string} payload — the stringified raw argument (i.e. the cache key the client will use)
555
+ * @returns {{ __: RemoteInternals; state: any; refreshes: Map<string, Promise<any>>; cache: Record<string, { serialize: boolean; data: any }>; refreshes_key: string; payload: string }}
332
556
  */
333
557
  function get_refresh_context(__, action, payload) {
334
558
  const { state } = get_request_store();
@@ -348,7 +572,7 @@ function get_refresh_context(__, action, payload) {
348
572
  }
349
573
 
350
574
  /**
351
- * @param {{ __: RemoteInternals; refreshes: Record<string, Promise<any>>; cache: Record<string, { serialize: boolean; data: any }>; refreshes_key: string; payload: string }} context
575
+ * @param {{ __: RemoteInternals; refreshes: Map<string, Promise<any>>; cache: Record<string, { serialize: boolean; data: any }>; refreshes_key: string; payload: string }} context
352
576
  * @param {any} value
353
577
  * @param {boolean} [is_immediate_refresh=false]
354
578
  * @returns {Promise<void>}
@@ -365,8 +589,13 @@ function update_refresh_value(
365
589
  }
366
590
 
367
591
  if (__.id) {
368
- refreshes[refreshes_key] = promise;
592
+ refreshes.set(refreshes_key, promise);
369
593
  }
370
594
 
371
- return promise.then(noop, noop);
595
+ promise.catch(noop);
596
+
597
+ // we return an immediately-resolving promise so that the `refresh()` signature is consistent,
598
+ // but it doesn't delay anything if awaited inside a command. this way, people aren't
599
+ // penalised if they do `await q1.refresh(); await q2.refresh()`
600
+ return Promise.resolve();
372
601
  }
@@ -1,5 +1,5 @@
1
- /** @import { RemoteQueryFunction, RequestedResult } from '@sveltejs/kit' */
2
- /** @import { MaybePromise, RemoteQueryInternals } from 'types' */
1
+ /** @import { RemoteLiveQuery, RemoteLiveQueryFunction, RemoteQuery, RemoteQueryFunction, RequestedResult, QueryRequestedResult, LiveQueryRequestedResult } from '@sveltejs/kit' */
2
+ /** @import { MaybePromise, RemoteAnyQueryInternals } from 'types' */
3
3
  import { get_request_store } from '@sveltejs/kit/internal/server';
4
4
  import { create_remote_key, parse_remote_arg } from '../../../shared.js';
5
5
  import { noop } from '../../../../utils/functions.js';
@@ -30,30 +30,104 @@ import { noop } from '../../../../utils/functions.js';
30
30
  *
31
31
  * As a shorthand for the above, you can also call `refreshAll` on the result:
32
32
  *
33
+ * @example
33
34
  * ```ts
34
35
  * import { requested } from '$app/server';
35
36
  *
36
37
  * await requested(getPost, 5).refreshAll();
37
38
  * ```
38
39
  *
40
+ * Works with `query.batch` as well — refreshes for individual entries are
41
+ * collected into a single batched call.
42
+ *
43
+ * For live queries, the same applies, but with `reconnect` and `reconnectAll`.
44
+ *
39
45
  * @template Input
40
46
  * @template Output
41
47
  * @template [Validated=Input]
48
+ * @overload
42
49
  * @param {RemoteQueryFunction<Input, Output, Validated>} query
43
50
  * @param {number} limit
51
+ * @returns {QueryRequestedResult<Validated, Output>}
52
+ */
53
+ /**
54
+ * In the context of a remote `command` or `form` request, returns an iterable
55
+ * of `{ arg, query }` entries for the reconnects requested by the client, up to
56
+ * the supplied `limit`. Each `query` is a `RemoteLiveQuery` bound to the original
57
+ * client-side cache key, so `reconnect()` propagates correctly even when
58
+ * the query's schema transforms the input. `arg` is the *validated* argument.
59
+ *
60
+ * Arguments that fail validation or exceed `limit` are recorded as failures in
61
+ * the response to the client.
62
+ *
63
+ * @example
64
+ * ```ts
65
+ * import { requested } from '$app/server';
66
+ *
67
+ * for (const { query } of requested(getPost, 5)) {
68
+ * void query.reconnect();
69
+ * }
70
+ * ```
71
+ *
72
+ * As a shorthand, you can also call `reconnectAll` on the result:
73
+ *
74
+ * @example
75
+ * ```ts
76
+ * import { requested } from '$app/server';
77
+ *
78
+ * await requested(getPost, 5).reconnectAll();
79
+ * ```
80
+ *
81
+ * @template Input
82
+ * @template Output
83
+ * @template [Validated=Input]
84
+ * @overload
85
+ * @param {RemoteLiveQueryFunction<Input, Output, Validated>} query
86
+ * @param {number} limit
87
+ * @returns {LiveQueryRequestedResult<Validated, Output>}
88
+ */
89
+ /**
90
+ * @template Input
91
+ * @template Output
92
+ * @template [Validated=Input]
93
+ * @param {RemoteQueryFunction<Input, Output, Validated> | RemoteLiveQueryFunction<Input, Output, Validated>} query
94
+ * @param {number} limit
44
95
  * @returns {RequestedResult<Validated, Output>}
45
96
  */
46
97
  export function requested(query, limit) {
47
98
  const { state } = get_request_store();
48
- const internals = /** @type {RemoteQueryInternals | undefined} */ (/** @type {any} */ (query).__);
99
+ const internals = /** @type {RemoteAnyQueryInternals | undefined} */ (
100
+ /** @type {any} */ (query).__
101
+ );
49
102
 
50
- if (!internals || internals.type !== 'query') {
51
- throw new Error('requested(...) expects a query function created with query(...)');
103
+ if (
104
+ internals?.type !== 'query' &&
105
+ internals?.type !== 'query_batch' &&
106
+ internals?.type !== 'query_live'
107
+ ) {
108
+ throw new Error(
109
+ 'requested(...) expects a query function created with query(...), query.batch(...), or query.live(...)'
110
+ );
52
111
  }
53
112
 
113
+ // narrow-stable alias so generator closures below don't lose the narrowing
114
+ const __ = internals;
115
+
54
116
  const requested = state.remote.requested;
55
- const payloads = requested?.get(internals.id) ?? [];
56
- const refreshes = (state.remote.refreshes ??= {});
117
+ const payloads = requested?.get(__.id) ?? [];
118
+ // note: don't initialize these maps here -- they will be initialized by the
119
+ // command/form wrapper when we enter them, and if we initialize them here
120
+ // we will enable requested(...) in contexts where it shouldn't be allowed,
121
+ // such as load functions or other server functions
122
+ const refreshes = state.remote.refreshes;
123
+ const reconnects = state.remote.reconnects;
124
+ const store = __.type === 'query_live' ? reconnects : refreshes;
125
+
126
+ if (!store) {
127
+ throw new Error(
128
+ 'requested(...) can only be called in the context of a command/form remote function'
129
+ );
130
+ }
57
131
  const [selected, skipped] = split_limit(payloads, limit);
58
132
 
59
133
  /**
@@ -64,34 +138,34 @@ export function requested(query, limit) {
64
138
  const promise = Promise.reject(error);
65
139
  promise.catch(noop);
66
140
 
67
- const key = create_remote_key(internals.id, payload);
68
- refreshes[key] = promise;
141
+ const key = create_remote_key(__.id, payload);
142
+ store.set(key, promise);
69
143
  };
70
144
 
71
145
  for (const payload of skipped) {
72
146
  record_failure(
73
147
  payload,
74
148
  new Error(
75
- `Requested refresh was rejected because it exceeded requested(${internals.name}, ${limit}) limit`
149
+ `Requested refresh was rejected because it exceeded requested(${__.name}, ${limit}) limit`
76
150
  )
77
151
  );
78
152
  }
79
153
 
80
- return {
154
+ const result = {
81
155
  *[Symbol.iterator]() {
82
156
  for (const payload of selected) {
83
157
  try {
84
158
  const parsed = parse_remote_arg(payload, state.transport);
85
- const validated = internals.validate(parsed);
159
+ const validated = __.validate(parsed);
86
160
 
87
161
  if (is_thenable(validated)) {
88
162
  throw new Error(
89
163
  // TODO improve
90
- `requested(${internals.name}, ${limit}) cannot be used with synchronous iteration because the query validator is async. Use \`for await ... of\` instead`
164
+ `requested(${__.name}, ${limit}) cannot be used with synchronous iteration because the query validator is async. Use \`for await ... of\` instead`
91
165
  );
92
166
  }
93
167
 
94
- yield { arg: validated, query: internals.bind(payload, validated) };
168
+ yield { arg: validated, query: __.bind(payload, validated) };
95
169
  } catch (error) {
96
170
  record_failure(payload, error);
97
171
  continue;
@@ -102,20 +176,35 @@ export function requested(query, limit) {
102
176
  yield* race_all(selected, async (payload) => {
103
177
  try {
104
178
  const parsed = parse_remote_arg(payload, state.transport);
105
- const validated = await internals.validate(parsed);
106
- return { arg: validated, query: internals.bind(payload, validated) };
179
+ const validated = await __.validate(parsed);
180
+ return { arg: validated, query: __.bind(payload, validated) };
107
181
  } catch (error) {
108
182
  record_failure(payload, error);
109
- throw new Error(`Skipping ${internals.name}(${payload})`, { cause: error });
183
+ throw new Error(`Skipping ${__.name}(${payload})`, { cause: error });
110
184
  }
111
185
  });
112
186
  },
113
187
  async refreshAll() {
114
- for await (const { query } of this) {
115
- void query.refresh();
188
+ if (__.type === 'query_live') {
189
+ throw new Error('refreshAll() is invalid for live queries. Use reconnectAll() instead.');
190
+ }
191
+
192
+ for await (const { query } of result) {
193
+ void (/** @type {RemoteQuery<Output>} */ (query).refresh());
194
+ }
195
+ },
196
+ async reconnectAll() {
197
+ if (__.type !== 'query_live') {
198
+ throw new Error('reconnectAll() is invalid for regular queries. Use refreshAll() instead.');
199
+ }
200
+
201
+ for await (const { query } of result) {
202
+ void (/** @type {RemoteLiveQuery<Output>} */ (query).reconnect());
116
203
  }
117
204
  }
118
205
  };
206
+
207
+ return /** @type {RequestedResult<Validated, Output>} */ (/** @type {unknown} */ (result));
119
208
  }
120
209
 
121
210
  /**
@@ -163,7 +252,7 @@ async function* race_all(array, fn) {
163
252
  value: result
164
253
  }));
165
254
 
166
- promise.catch(noop);
255
+ promise.catch(() => pending.delete(promise));
167
256
  pending.add(promise);
168
257
  }
169
258