@sveltejs/kit 3.0.0-next.2 → 3.0.0-next.3

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 (33) hide show
  1. package/package.json +2 -2
  2. package/src/core/postbuild/analyse.js +0 -8
  3. package/src/core/postbuild/prerender.js +2 -0
  4. package/src/exports/public.d.ts +1 -1
  5. package/src/exports/vite/build/build_server.js +43 -58
  6. package/src/exports/vite/build/remote.js +18 -11
  7. package/src/exports/vite/build/utils.js +0 -8
  8. package/src/exports/vite/index.js +220 -216
  9. package/src/runtime/app/server/remote/command.js +0 -3
  10. package/src/runtime/app/server/remote/form.js +18 -13
  11. package/src/runtime/app/server/remote/prerender.js +28 -34
  12. package/src/runtime/app/server/remote/query.js +105 -94
  13. package/src/runtime/app/server/remote/requested.js +14 -10
  14. package/src/runtime/app/server/remote/shared.js +25 -19
  15. package/src/runtime/client/client.js +19 -13
  16. package/src/runtime/client/remote-functions/command.svelte.js +5 -30
  17. package/src/runtime/client/remote-functions/form.svelte.js +62 -82
  18. package/src/runtime/client/remote-functions/prerender.svelte.js +14 -6
  19. package/src/runtime/client/remote-functions/query/index.js +6 -14
  20. package/src/runtime/client/remote-functions/query/instance.svelte.js +20 -0
  21. package/src/runtime/client/remote-functions/query/proxy.js +3 -3
  22. package/src/runtime/client/remote-functions/query-batch.svelte.js +59 -68
  23. package/src/runtime/client/remote-functions/query-live/instance.svelte.js +21 -6
  24. package/src/runtime/client/remote-functions/shared.svelte.js +76 -59
  25. package/src/runtime/server/page/render.js +20 -80
  26. package/src/runtime/server/page/server_routing.js +20 -15
  27. package/src/runtime/server/remote.js +296 -204
  28. package/src/runtime/server/respond.js +4 -2
  29. package/src/types/global-private.d.ts +3 -3
  30. package/src/types/internal.d.ts +53 -34
  31. package/src/version.js +1 -1
  32. package/types/index.d.ts +6 -5
  33. package/types/index.d.ts.map +1 -1
@@ -2,10 +2,7 @@
2
2
  /** @import { ServerHooks, MaybePromise, RequestState, RemoteInternals, RequestStore, RemoteLiveQueryUserFunctionReturnType } from 'types' */
3
3
  import { parse } from 'devalue';
4
4
  import { error } from '@sveltejs/kit';
5
- import { hydratable } from 'svelte';
6
5
  import { with_request_store, get_request_store } from '@sveltejs/kit/internal/server';
7
- import { create_remote_key, stringify } from '../../../shared.js';
8
- import { noop } from '../../../../utils/functions.js';
9
6
 
10
7
  /**
11
8
  * @param {any} validate_or_fn
@@ -76,24 +73,13 @@ export async function get_response(internals, payload, state, get_result) {
76
73
  await 0;
77
74
 
78
75
  const cache = get_cache(internals, state);
79
- const entry = (cache[payload] ??= {
80
- serialize: false,
81
- data: get_result()
82
- });
83
76
 
84
- entry.serialize ||= !!state.is_in_universal_load;
85
-
86
- if (state.is_in_render && internals.id) {
87
- const remote_key = create_remote_key(internals.id, payload);
88
-
89
- void Promise.resolve(entry.data)
90
- .then((value) => {
91
- void hydratable(remote_key, () => stringify(value, state.transport));
92
- })
93
- .catch(noop);
77
+ if (!state.is_in_remote_query) {
78
+ // if this is a top-level (not nested) `await myQuery()`, include it in the serialized response
79
+ get_implicit_lookup(internals, state)[payload] = get_result;
94
80
  }
95
81
 
96
- return entry.data;
82
+ return (cache[payload] ??= get_result());
97
83
  }
98
84
 
99
85
  /**
@@ -239,10 +225,15 @@ function to_iterator(source, name) {
239
225
  }
240
226
 
241
227
  /**
228
+ * Note that `state` is deliberately not optional: resources that capture the request
229
+ * state at creation must pass it explicitly, because reading it from the request store
230
+ * at call time is only equivalent on runtimes with `AsyncLocalStorage` support.
231
+ * Callers without a captured state (such as the module-level `form` instance getters)
232
+ * should pass `get_request_store().state` themselves.
242
233
  * @param {RemoteInternals} internals
243
234
  * @param {RequestState} state
244
235
  */
245
- export function get_cache(internals, state = get_request_store().state) {
236
+ export function get_cache(internals, state) {
246
237
  let cache = state.remote.data?.get(internals);
247
238
 
248
239
  if (cache === undefined) {
@@ -252,3 +243,18 @@ export function get_cache(internals, state = get_request_store().state) {
252
243
 
253
244
  return cache;
254
245
  }
246
+
247
+ /**
248
+ * @param {RemoteInternals} internals
249
+ * @param {RequestState} state
250
+ */
251
+ export function get_implicit_lookup(internals, state) {
252
+ let cache = state.remote.implicit?.get(internals);
253
+
254
+ if (cache === undefined) {
255
+ cache = {};
256
+ (state.remote.implicit ??= new Map()).set(internals, cache);
257
+ }
258
+
259
+ return cache;
260
+ }
@@ -1,4 +1,4 @@
1
- /** @import { ServerNodesResponse, ServerRedirectNode } from 'types' */
1
+ /** @import { RemoteFunctionDataNode, ServerNodesResponse, ServerRedirectNode } from 'types' */
2
2
  /** @import { CacheEntry } from './remote-functions/cache.svelte.js' */
3
3
  /** @import { Query } from './remote-functions/query/instance.svelte.js' */
4
4
  /** @import { LiveQuery } from './remote-functions/query-live/instance.svelte.js' */
@@ -202,18 +202,20 @@ let target;
202
202
  export let app;
203
203
 
204
204
  /**
205
- * Data that was serialized during SSR for queries/forms/commands.
206
- * This is cleared before client-side loads run.
207
- * @type {Record<string, any>}
205
+ * Data that was serialized during SSR for queries/forms/commands, stored as
206
+ * `{ v }` (value) or `{ e }` (error) nodes so that failed states survive hydration.
207
+ * Entries are deleted as they are consumed (when the corresponding resource is created).
208
+ * @type {Record<string, RemoteFunctionDataNode>}
208
209
  */
209
- export let query_responses = {};
210
+ export const query_responses = {};
210
211
 
211
212
  /**
212
- * Data that was serialized during SSR for prerender functions.
213
+ * Data that was serialized during SSR for prerender functions, stored as
214
+ * `{ v }` (value) or `{ e }` (error) nodes.
213
215
  * This persists across client-side navigations.
214
- * @type {Record<string, any>}
216
+ * @type {Record<string, RemoteFunctionDataNode>}
215
217
  */
216
- export let prerender_responses = {};
218
+ export const prerender_responses = {};
217
219
 
218
220
  /** @type {Array<((url: URL) => boolean)>} */
219
221
  const invalidated = [];
@@ -328,9 +330,15 @@ export async function start(_app, _target, hydrate) {
328
330
  );
329
331
  }
330
332
 
331
- if (__SVELTEKIT_PAYLOAD__) {
332
- query_responses = __SVELTEKIT_PAYLOAD__.query ?? {};
333
- prerender_responses = __SVELTEKIT_PAYLOAD__.prerender ?? {};
333
+ if (__SVELTEKIT_PAYLOAD__.data) {
334
+ const { q = {}, p = {}, l = {}, f = {} } = __SVELTEKIT_PAYLOAD__.data;
335
+
336
+ // store the whole nodes — error records seed the corresponding
337
+ // resources in a failed state when they are created during hydration
338
+ for (const k in q) query_responses[k] = q[k];
339
+ for (const k in l) query_responses[k] = l[k];
340
+ for (const k in f) query_responses[k] = f[k];
341
+ for (const k in p) prerender_responses[k] = p[k];
334
342
  }
335
343
 
336
344
  // detect basic auth credentials in the current URL
@@ -3028,8 +3036,6 @@ async function _hydrate(
3028
3036
 
3029
3037
  target.textContent = '';
3030
3038
  hydrate = false;
3031
- } finally {
3032
- query_responses = {};
3033
3039
  }
3034
3040
 
3035
3041
  if (result.props.page) {
@@ -1,16 +1,8 @@
1
1
  /** @import { RemoteCommand, RemoteQueryUpdate } from '@sveltejs/kit' */
2
- /** @import { RemoteFunctionResponse } from 'types' */
3
2
  import { app_dir, base } from '$app/paths/internal/client';
4
- import * as devalue from 'devalue';
5
- import { HttpError } from '@sveltejs/kit/internal';
6
3
  import { app } from '../client.js';
7
4
  import { stringify_command_arg } from '../../shared.js';
8
- import {
9
- get_remote_request_headers,
10
- apply_refreshes,
11
- categorize_updates,
12
- apply_reconnections
13
- } from './shared.svelte.js';
5
+ import { get_remote_request_headers, categorize_updates, remote_request } from './shared.svelte.js';
14
6
 
15
7
  /**
16
8
  * Client-version of the `command` function from `$app/server`.
@@ -53,7 +45,7 @@ export function command(id) {
53
45
  throw updates_error;
54
46
  }
55
47
 
56
- const response = await fetch(`${base}/${app_dir}/remote/${id}`, {
48
+ const response = await remote_request(`${base}/${app_dir}/remote/${id}`, {
57
49
  method: 'POST',
58
50
  body: JSON.stringify({
59
51
  payload: await stringify_command_arg(arg, app.hooks.transport),
@@ -62,30 +54,13 @@ export function command(id) {
62
54
  headers
63
55
  });
64
56
 
65
- if (!response.ok) {
66
- // We only end up here in case of a network error or if the server has an internal error
67
- // (which shouldn't happen because we handle errors on the server and always send a 200 response)
68
- throw new Error('Failed to execute remote function');
69
- }
70
-
71
- const result = /** @type {RemoteFunctionResponse} */ (await response.json());
72
- if (result.type === 'redirect') {
57
+ if (response.redirect) {
73
58
  throw new Error(
74
59
  'Redirects are not allowed in commands. Return a result instead and use goto on the client'
75
60
  );
76
- } else if (result.type === 'error') {
77
- throw new HttpError(result.status ?? 500, result.error);
78
- } else {
79
- if (result.refreshes) {
80
- apply_refreshes(result.refreshes);
81
- }
82
-
83
- if (result.reconnects) {
84
- apply_reconnections(result.reconnects);
85
- }
86
-
87
- return devalue.parse(result.result, app.decoders);
88
61
  }
62
+
63
+ return response._;
89
64
  } finally {
90
65
  overrides?.forEach((fn) => fn());
91
66
 
@@ -1,13 +1,12 @@
1
1
  /** @import { StandardSchemaV1 } from '@standard-schema/spec' */
2
2
  /** @import { RemoteFormInput, RemoteForm, RemoteQueryUpdate } from '@sveltejs/kit' */
3
- /** @import { InternalRemoteFormIssue, RemoteFunctionResponse } from 'types' */
3
+ /** @import { InternalRemoteFormIssue } from 'types' */
4
4
  import { app_dir, base } from '$app/paths/internal/client';
5
- import * as devalue from 'devalue';
6
5
  import { DEV } from 'esm-env';
7
6
  import { HttpError } from '@sveltejs/kit/internal';
8
- import { app, query_responses, _goto, set_nearest_error_page, invalidateAll } from '../client.js';
7
+ import { query_responses, _goto, set_nearest_error_page, invalidateAll } from '../client.js';
9
8
  import { tick } from 'svelte';
10
- import { apply_refreshes, categorize_updates, apply_reconnections } from './shared.svelte.js';
9
+ import { categorize_updates, remote_request } from './shared.svelte.js';
11
10
  import { createAttachmentKey } from 'svelte/attachments';
12
11
  import {
13
12
  convert_formdata,
@@ -59,18 +58,25 @@ export function form(id) {
59
58
  const action_id = id + (key != undefined ? `/${JSON.stringify(key)}` : '');
60
59
  const action = '?/remote=' + encodeURIComponent(action_id);
61
60
 
61
+ // the output of a non-enhanced submission that resulted in this page —
62
+ // consume it so the form's state survives hydration (form outputs are
63
+ // always value nodes; the server never serializes them as errors)
64
+ /** @type {{ input?: Record<string, any>, issues?: InternalRemoteFormIssue[], result?: any } | undefined} */
65
+ const initial = query_responses[action_id]?.v;
66
+ delete query_responses[action_id];
67
+
62
68
  /**
63
69
  * @type {Record<string, string | string[] | File | File[]>}
64
70
  */
65
- let input = $state({});
71
+ let input = $state(initial?.input ?? {});
66
72
 
67
73
  /** @type {InternalRemoteFormIssue[]} */
68
- let raw_issues = $state.raw([]);
74
+ let raw_issues = $state.raw(initial?.issues ?? []);
69
75
 
70
76
  const issues = $derived(flatten_issues(raw_issues));
71
77
 
72
78
  /** @type {any} */
73
- let result = $state.raw(query_responses[action_id]);
79
+ let result = $state.raw(initial?.result);
74
80
 
75
81
  /** @type {number} */
76
82
  let pending_count = $state(0);
@@ -181,77 +187,54 @@ export function form(id) {
181
187
  remote_refreshes: Array.from(refreshes ?? [])
182
188
  });
183
189
 
184
- const response = await fetch(`${base}/${app_dir}/remote/${action_id_without_key}`, {
185
- method: 'POST',
186
- headers: {
187
- 'Content-Type': BINARY_FORM_CONTENT_TYPE,
188
- // Forms cannot be called during rendering, so it's save to use location here
189
- 'x-sveltekit-pathname': location.pathname,
190
- 'x-sveltekit-search': location.search
191
- },
192
- body: blob
193
- });
194
-
195
- if (!response.ok) {
196
- // We only end up here in case of a network error or if the server has an internal error
197
- // (which shouldn't happen because we handle errors on the server and always send a 200 response)
198
- throw new Error('Failed to execute remote function');
199
- }
200
-
201
- const form_result = /** @type { RemoteFunctionResponse} */ (await response.json());
202
-
203
- // reset issues in case it's a redirect or error (but issues passed in that case)
204
- raw_issues = [];
205
- result = undefined;
206
-
207
- if (form_result.type === 'result') {
208
- ({ issues: raw_issues = [], result } = devalue.parse(form_result.result, app.decoders));
209
- const succeeded = raw_issues.length === 0;
210
-
211
- if (succeeded) {
212
- if (refreshes === null && !form_result.refreshes && !form_result.reconnects) {
213
- void invalidateAll();
214
- } else {
215
- if (form_result.refreshes) {
216
- apply_refreshes(form_result.refreshes);
217
- }
218
- if (form_result.reconnects) {
219
- apply_reconnections(form_result.reconnects);
220
- }
221
- }
222
- } else {
223
- if (DEV) {
224
- warn_on_missing_issue_reads();
225
- }
190
+ const response = await remote_request(
191
+ `${base}/${app_dir}/remote/${action_id_without_key}`,
192
+ {
193
+ method: 'POST',
194
+ headers: {
195
+ 'Content-Type': BINARY_FORM_CONTENT_TYPE,
196
+ // Forms cannot be called during rendering, so it's save to use location here
197
+ 'x-sveltekit-pathname': location.pathname,
198
+ 'x-sveltekit-search': location.search
199
+ },
200
+ body: blob
226
201
  }
202
+ );
227
203
 
228
- return succeeded;
229
- } else if (form_result.type === 'redirect') {
230
- const stringified_refreshes = form_result.refreshes ?? '';
231
- const stringified_reconnects = form_result.reconnects ?? '';
232
- if (stringified_refreshes) {
233
- apply_refreshes(stringified_refreshes);
234
- }
204
+ ({ issues: raw_issues = [], result } = response._ ?? {});
235
205
 
236
- if (stringified_reconnects) {
237
- apply_reconnections(stringified_reconnects);
238
- }
206
+ // if the developer took control of updates via `.updates(...)` (even with
207
+ // no arguments), or the server performed explicit refreshes, don't invalidateAll
208
+ const should_invalidate = refreshes === null && !response.r;
239
209
 
210
+ if (response.redirect) {
240
211
  // Use internal version to allow redirects to external URLs
241
212
  void _goto(
242
- form_result.location,
213
+ response.redirect,
243
214
  {
244
- invalidateAll:
245
- refreshes === null && !stringified_refreshes && !stringified_reconnects
215
+ invalidateAll: should_invalidate
246
216
  },
247
217
  0
248
218
  );
249
219
  return true;
220
+ }
221
+
222
+ const succeeded = raw_issues.length === 0;
223
+
224
+ if (succeeded) {
225
+ if (should_invalidate) {
226
+ void invalidateAll();
227
+ }
250
228
  } else {
251
- throw new HttpError(form_result.status ?? 500, form_result.error);
229
+ if (DEV) {
230
+ warn_on_missing_issue_reads();
231
+ }
252
232
  }
233
+
234
+ return succeeded;
253
235
  } catch (e) {
254
236
  result = undefined;
237
+ raw_issues = [];
255
238
  throw e;
256
239
  } finally {
257
240
  overrides?.forEach((fn) => fn());
@@ -630,30 +613,27 @@ export function form(id) {
630
613
  if (validated?.issues) {
631
614
  array = validated.issues.map((issue) => normalize_issue(issue, false));
632
615
  } else if (!preflightOnly) {
633
- const response = await fetch(`${base}/${app_dir}/remote/${action_id_without_key}`, {
634
- method: 'POST',
635
- headers: {
636
- 'Content-Type': BINARY_FORM_CONTENT_TYPE,
637
- // Validation should not be and will not be called during rendering, so it's save to use location here
638
- 'x-sveltekit-pathname': location.pathname,
639
- 'x-sveltekit-search': location.search
640
- },
641
- body: serialize_binary_form(data, {
642
- validate_only: true
643
- }).blob
644
- });
645
-
646
- const result = await response.json();
616
+ const result = await remote_request(
617
+ `${base}/${app_dir}/remote/${action_id_without_key}`,
618
+ {
619
+ method: 'POST',
620
+ headers: {
621
+ 'Content-Type': BINARY_FORM_CONTENT_TYPE,
622
+ // Validation should not be and will not be called during rendering, so it's save to use location here
623
+ 'x-sveltekit-pathname': location.pathname,
624
+ 'x-sveltekit-search': location.search
625
+ },
626
+ body: serialize_binary_form(data, {
627
+ validate_only: true
628
+ }).blob
629
+ }
630
+ );
647
631
 
648
632
  if (validate_id !== id) {
649
633
  return;
650
634
  }
651
635
 
652
- if (result.type === 'result') {
653
- array = /** @type {InternalRemoteFormIssue[]} */ (
654
- devalue.parse(result.result, app.decoders)
655
- );
656
- }
636
+ array = /** @type {InternalRemoteFormIssue[]} */ (result._);
657
637
  }
658
638
 
659
639
  if (!includeUntouched && !submitted) {
@@ -2,8 +2,8 @@
2
2
  import { app_dir, base } from '$app/paths/internal/client';
3
3
  import { version } from '$app/env';
4
4
  import * as devalue from 'devalue';
5
- import { app, prerender_responses } from '../client.js';
6
- import { get_remote_request_headers, remote_request } from './shared.svelte.js';
5
+ import { app, goto, prerender_responses } from '../client.js';
6
+ import { get_remote_request_headers, remote_request, unwrap_node } from './shared.svelte.js';
7
7
  import { create_remote_key, stringify_remote_arg } from '../../shared.js';
8
8
 
9
9
  // Initialize Cache API for prerender functions
@@ -67,7 +67,7 @@ export function prerender(id) {
67
67
  const url = `${base}/${app_dir}/remote/${id}${payload ? `/${payload}` : ''}`;
68
68
 
69
69
  if (Object.hasOwn(prerender_responses, cache_key)) {
70
- const data = prerender_responses[cache_key];
70
+ const data = unwrap_node(prerender_responses[cache_key]);
71
71
 
72
72
  if (prerender_cache) {
73
73
  void put(url, devalue.stringify(data, app.encoders));
@@ -77,6 +77,7 @@ export function prerender(id) {
77
77
  }
78
78
 
79
79
  // Do this here, after await Svelte' reactivity context is gone.
80
+ // TODO we really don't want to be sending these specific headers here?
80
81
  const headers = get_remote_request_headers();
81
82
 
82
83
  // Check the Cache API first
@@ -93,14 +94,21 @@ export function prerender(id) {
93
94
  }
94
95
  }
95
96
 
96
- const encoded = await remote_request(url, headers);
97
+ const result = await remote_request(url, { headers });
98
+
99
+ if (result.redirect) {
100
+ void goto(result.redirect);
101
+ return;
102
+ }
103
+
104
+ const data = result._;
97
105
 
98
106
  // For successful prerender requests, save to cache
99
107
  if (prerender_cache) {
100
- void put(url, encoded);
108
+ void put(url, devalue.stringify(data, app.encoders));
101
109
  }
102
110
 
103
- return devalue.parse(encoded, app.decoders);
111
+ return data;
104
112
  });
105
113
 
106
114
  prerender_resources.set(cache_key, new WeakRef(resource));
@@ -1,10 +1,8 @@
1
1
  /** @import { RemoteQueryFunction } from '@sveltejs/kit' */
2
2
  import { app_dir, base } from '$app/paths/internal/client';
3
- import { app, query_map, query_responses } from '../../client.js';
3
+ import { goto, query_map } from '../../client.js';
4
4
  import { get_remote_request_headers, QUERY_FUNCTION_ID, remote_request } from '../shared.svelte.js';
5
- import * as devalue from 'devalue';
6
5
  import { DEV } from 'esm-env';
7
- import { hydratable } from 'svelte';
8
6
  import { QueryProxy } from './proxy.js';
9
7
 
10
8
  /**
@@ -25,20 +23,14 @@ export function query(id) {
25
23
 
26
24
  /** @type {RemoteQueryFunction<any, any>} */
27
25
  const wrapper = (arg) => {
28
- return new QueryProxy(id, arg, async (key, payload) => {
29
- if (Object.hasOwn(query_responses, key)) {
30
- const value = query_responses[key];
31
- delete query_responses[key];
32
- return value;
33
- }
34
-
26
+ return new QueryProxy(id, arg, async (payload) => {
35
27
  const url = `${base}/${app_dir}/remote/${id}${payload ? `?payload=${payload}` : ''}`;
36
28
 
37
- const serialized = await hydratable(key, () =>
38
- remote_request(url, get_remote_request_headers())
39
- );
29
+ const result = await remote_request(url, { headers: get_remote_request_headers() });
40
30
 
41
- return devalue.parse(serialized, app.decoders);
31
+ if (result.redirect) {
32
+ await goto(result.redirect);
33
+ }
42
34
  });
43
35
  };
44
36
 
@@ -1,4 +1,5 @@
1
1
  import { query_responses } from '../../client.js';
2
+ import { HttpError } from '@sveltejs/kit/internal';
2
3
  import { QUERY_OVERRIDE_KEY } from '../shared.svelte.js';
3
4
  import { noop } from '../../../../utils/functions.js';
4
5
  import { tick, untrack } from 'svelte';
@@ -63,6 +64,17 @@ export class Query {
63
64
  constructor(key, fn) {
64
65
  this.#key = key;
65
66
  this.#fn = fn;
67
+
68
+ if (Object.hasOwn(query_responses, key)) {
69
+ const node = query_responses[key];
70
+ delete query_responses[key];
71
+
72
+ if (node.e) {
73
+ this.fail(new HttpError(node.e[0] ?? 500, node.e[1]));
74
+ } else {
75
+ this.set(/** @type {T} */ (node.v));
76
+ }
77
+ }
66
78
  }
67
79
 
68
80
  #get_promise() {
@@ -198,6 +210,10 @@ export class Query {
198
210
  * @param {T} value
199
211
  */
200
212
  set(value) {
213
+ // normally consumed in the constructor, but make sure a leftover
214
+ // SSR record can never shadow the newly-set value
215
+ delete query_responses[this.#key];
216
+
201
217
  this.#clear_pending();
202
218
  this.#ready = true;
203
219
  this.#loading = false;
@@ -210,6 +226,10 @@ export class Query {
210
226
  * @param {unknown} error
211
227
  */
212
228
  fail(error) {
229
+ // normally consumed in the constructor, but make sure a leftover
230
+ // SSR record can never shadow the newly-set error
231
+ delete query_responses[this.#key];
232
+
213
233
  this.#clear_pending();
214
234
  this.#loading = false;
215
235
  this.#error = error;
@@ -25,7 +25,7 @@ export class QueryProxy {
25
25
  /**
26
26
  * @param {string} id
27
27
  * @param {any} arg
28
- * @param {(key: string, payload: string) => Promise<T>} fn
28
+ * @param {(payload: string) => Promise<T>} fn
29
29
  */
30
30
  constructor(id, arg, fn) {
31
31
  this.#id = id;
@@ -41,7 +41,7 @@ export class QueryProxy {
41
41
  this.#payload,
42
42
  // IMPORTANT: This cannot close over `this` or it becomes impossible to
43
43
  // garbage collect the QueryProxy and thus impossible to evict cache entries.
44
- () => new Query(key, () => fn(key, payload))
44
+ () => new Query(key, () => fn(payload))
45
45
  );
46
46
 
47
47
  cache.ref(this, entry, this.#id, this.#payload);
@@ -98,7 +98,7 @@ export class QueryProxy {
98
98
  this.#payload,
99
99
  // IMPORTANT: This cannot close over `this` or it becomes impossible to
100
100
  // garbage collect the QueryProxy and thus impossible to evict cache entries.
101
- () => new Query(key_ref, () => fn_ref(key_ref, payload_ref))
101
+ () => new Query(key_ref, () => fn_ref(payload_ref))
102
102
  );
103
103
 
104
104
  const deref = cache.manual_ref(entry, this.#id, this.#payload);