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

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 (195) hide show
  1. package/package.json +62 -36
  2. package/src/cli.js +15 -12
  3. package/src/constants.js +6 -1
  4. package/src/core/adapt/builder.js +66 -72
  5. package/src/core/adapt/index.js +17 -6
  6. package/src/core/config/index.js +134 -80
  7. package/src/core/config/options.js +295 -273
  8. package/src/core/config/types.d.ts +1 -1
  9. package/src/core/env.js +146 -16
  10. package/src/core/generate_manifest/index.js +18 -15
  11. package/src/core/postbuild/analyse.js +8 -20
  12. package/src/core/postbuild/crawl.js +22 -6
  13. package/src/core/postbuild/entities.js +8 -2
  14. package/src/core/postbuild/fallback.js +4 -2
  15. package/src/core/postbuild/prerender.js +222 -70
  16. package/src/core/postbuild/queue.js +2 -1
  17. package/src/core/sync/create_manifest_data/conflict.js +1 -1
  18. package/src/core/sync/create_manifest_data/index.js +82 -62
  19. package/src/core/sync/sync.js +40 -31
  20. package/src/core/sync/ts.js +1 -1
  21. package/src/core/sync/utils.js +22 -2
  22. package/src/core/sync/{write_non_ambient.js → write_app_types.js} +107 -58
  23. package/src/core/sync/write_client_manifest.js +14 -29
  24. package/src/core/sync/write_env.js +7 -5
  25. package/src/core/sync/write_server.js +37 -45
  26. package/src/core/sync/write_tsconfig/index.js +274 -0
  27. package/src/core/sync/write_tsconfig/test-app/package.json +7 -0
  28. package/src/core/sync/write_tsconfig/utils.js +77 -0
  29. package/src/core/sync/write_tsconfig/validate.js +128 -0
  30. package/src/core/sync/write_types/index.js +127 -123
  31. package/src/core/utils.js +30 -5
  32. package/src/exports/env/index.js +77 -0
  33. package/src/exports/env/public.d.ts +55 -0
  34. package/src/exports/hooks/index.js +3 -9
  35. package/src/exports/hooks/public.d.ts +195 -0
  36. package/src/exports/hooks/sequence.js +9 -6
  37. package/src/exports/index.js +52 -29
  38. package/src/exports/internal/client.js +5 -0
  39. package/src/exports/internal/env.js +8 -5
  40. package/src/exports/internal/index.js +1 -90
  41. package/src/exports/internal/{event.js → server/event.js} +2 -3
  42. package/src/exports/internal/server/index.js +37 -0
  43. package/src/exports/internal/server/telemetry.js +95 -0
  44. package/src/exports/internal/shared.js +90 -0
  45. package/src/exports/node/index.js +64 -22
  46. package/src/exports/params/index.js +70 -0
  47. package/src/exports/params/public.d.ts +63 -0
  48. package/src/exports/public.d.ts +50 -1733
  49. package/src/exports/remote/index.js +11 -0
  50. package/src/exports/remote/public.d.ts +519 -0
  51. package/src/exports/url.js +86 -0
  52. package/src/exports/vite/build/build_server.js +54 -65
  53. package/src/exports/vite/build/remote.js +24 -19
  54. package/src/exports/vite/build/utils.js +0 -8
  55. package/src/exports/vite/dev/index.js +218 -146
  56. package/src/exports/vite/index.js +1590 -858
  57. package/src/exports/vite/module_ids.js +2 -2
  58. package/src/exports/vite/preview/index.js +40 -32
  59. package/src/exports/vite/public.d.ts +588 -0
  60. package/src/exports/vite/utils.js +84 -46
  61. package/src/pathname.js +55 -0
  62. package/src/runner.js +15 -0
  63. package/src/runtime/app/env/internal.js +4 -4
  64. package/src/runtime/app/env/types.d.ts +1 -1
  65. package/src/runtime/app/environment/index.js +3 -3
  66. package/src/runtime/app/{forms.js → forms/index.js} +73 -42
  67. package/src/runtime/app/forms/public.d.ts +2 -0
  68. package/src/runtime/app/forms/types.d.ts +56 -0
  69. package/src/runtime/app/internal/transport.js +53 -0
  70. package/src/runtime/app/manifest/index.js +1 -0
  71. package/src/runtime/app/{navigation.js → navigation/index.js} +2 -1
  72. package/src/runtime/app/navigation/public.d.ts +237 -0
  73. package/src/runtime/app/paths/client.js +37 -37
  74. package/src/runtime/app/paths/index.js +1 -1
  75. package/src/runtime/app/paths/internal/client.js +34 -2
  76. package/src/runtime/app/paths/internal/server.js +6 -23
  77. package/src/runtime/app/paths/internal.d.ts +3 -0
  78. package/src/runtime/app/paths/public.d.ts +1 -29
  79. package/src/runtime/app/paths/server.js +36 -17
  80. package/src/runtime/app/paths/types.d.ts +11 -19
  81. package/src/runtime/app/server/index.js +2 -2
  82. package/src/runtime/app/server/public.d.ts +201 -0
  83. package/src/runtime/app/server/remote/command.js +13 -11
  84. package/src/runtime/app/server/remote/form.js +61 -39
  85. package/src/runtime/app/server/remote/prerender.js +45 -45
  86. package/src/runtime/app/server/remote/query.js +106 -108
  87. package/src/runtime/app/server/remote/requested.js +27 -19
  88. package/src/runtime/app/server/remote/shared.js +76 -76
  89. package/src/runtime/app/service-worker/index.js +24 -0
  90. package/src/runtime/app/state/client.js +4 -2
  91. package/src/runtime/app/state/index.js +7 -5
  92. package/src/runtime/app/state/public.d.ts +72 -0
  93. package/src/runtime/app/state/server.js +3 -0
  94. package/src/runtime/app/stores.js +15 -78
  95. package/src/runtime/client/bundle.js +1 -1
  96. package/src/runtime/client/client-entry.js +3 -0
  97. package/src/runtime/client/client.js +1336 -648
  98. package/src/runtime/client/constants.js +3 -6
  99. package/src/runtime/client/entry.js +24 -3
  100. package/src/runtime/client/fetcher.js +25 -25
  101. package/src/runtime/client/ndjson.js +1 -1
  102. package/src/runtime/client/parse.js +1 -1
  103. package/src/runtime/client/payload.js +17 -0
  104. package/src/runtime/client/remote-functions/cache.svelte.js +3 -1
  105. package/src/runtime/client/remote-functions/command.svelte.js +37 -61
  106. package/src/runtime/client/remote-functions/form.svelte.js +267 -178
  107. package/src/runtime/client/remote-functions/prerender.svelte.js +32 -11
  108. package/src/runtime/client/remote-functions/query/index.js +10 -17
  109. package/src/runtime/client/remote-functions/query/instance.svelte.js +64 -18
  110. package/src/runtime/client/remote-functions/query/proxy.js +5 -5
  111. package/src/runtime/client/remote-functions/query-batch.svelte.js +61 -70
  112. package/src/runtime/client/remote-functions/query-live/index.js +1 -1
  113. package/src/runtime/client/remote-functions/query-live/instance.svelte.js +63 -21
  114. package/src/runtime/client/remote-functions/query-live/iterator.js +15 -12
  115. package/src/runtime/client/remote-functions/query-live/proxy.js +2 -12
  116. package/src/runtime/client/remote-functions/shared.svelte.js +90 -65
  117. package/src/runtime/client/snapshots.js +147 -0
  118. package/src/runtime/client/state.svelte.js +94 -55
  119. package/src/runtime/client/stream.js +3 -2
  120. package/src/runtime/client/types.d.ts +13 -9
  121. package/src/runtime/client/utils.js +22 -110
  122. package/src/runtime/components/root.svelte +56 -0
  123. package/src/runtime/env/dynamic/private.js +7 -0
  124. package/src/runtime/env/dynamic/public.js +7 -0
  125. package/src/runtime/env/static/private.js +6 -0
  126. package/src/runtime/env/static/public.js +6 -0
  127. package/src/runtime/form-utils.js +172 -61
  128. package/src/runtime/pathname.js +20 -32
  129. package/src/runtime/props.svelte.js +72 -0
  130. package/src/runtime/server/constants.js +0 -3
  131. package/src/runtime/server/cookie.js +72 -55
  132. package/src/runtime/server/csrf.js +65 -0
  133. package/src/runtime/server/data/index.js +49 -53
  134. package/src/runtime/server/dev.js +22 -0
  135. package/src/runtime/server/endpoint.js +6 -7
  136. package/src/runtime/server/env_module.js +0 -5
  137. package/src/runtime/server/errors.js +160 -0
  138. package/src/runtime/server/fetch.js +32 -39
  139. package/src/runtime/server/index.js +90 -64
  140. package/src/runtime/server/internal.js +71 -0
  141. package/src/runtime/server/page/actions.js +85 -64
  142. package/src/runtime/server/page/crypto.js +2 -2
  143. package/src/runtime/server/page/csp.js +88 -104
  144. package/src/runtime/server/page/data_serializer.js +24 -25
  145. package/src/runtime/server/page/index.js +36 -53
  146. package/src/runtime/server/page/load_data.js +50 -57
  147. package/src/runtime/server/page/render.js +173 -239
  148. package/src/runtime/server/page/respond_with_error.js +17 -31
  149. package/src/runtime/server/page/serialize_data.js +2 -13
  150. package/src/runtime/server/page/server_routing.js +85 -26
  151. package/src/runtime/server/remote-functions.js +640 -0
  152. package/src/runtime/server/respond.js +190 -131
  153. package/src/runtime/server/sourcemaps.js +183 -0
  154. package/src/runtime/server/state.js +53 -0
  155. package/src/runtime/server/utils.js +13 -155
  156. package/src/runtime/shared.js +20 -40
  157. package/src/runtime/utils.js +3 -0
  158. package/src/types/ambient-private.d.ts +11 -1
  159. package/src/types/ambient.d.ts +87 -36
  160. package/src/types/global-private.d.ts +25 -25
  161. package/src/types/internal.d.ts +163 -157
  162. package/src/types/private.d.ts +41 -1
  163. package/src/utils/error.js +28 -4
  164. package/src/utils/escape.js +9 -25
  165. package/src/utils/features.js +1 -1
  166. package/src/utils/filesystem.js +1 -23
  167. package/src/utils/fork.js +7 -2
  168. package/src/utils/hash.js +21 -0
  169. package/src/utils/http.js +8 -7
  170. package/src/utils/import.js +9 -2
  171. package/src/utils/imports.js +83 -0
  172. package/src/utils/mime.js +9 -0
  173. package/src/utils/page_nodes.js +6 -7
  174. package/src/utils/params.js +67 -0
  175. package/src/utils/regex.js +9 -0
  176. package/src/utils/routing.js +145 -73
  177. package/src/utils/shared-iterator.js +5 -0
  178. package/src/utils/streaming.js +14 -4
  179. package/src/utils/url.js +33 -2
  180. package/src/version.js +1 -1
  181. package/types/index.d.ts +2616 -2433
  182. package/types/index.d.ts.map +120 -106
  183. package/src/core/sync/write_ambient.js +0 -18
  184. package/src/core/sync/write_root.js +0 -148
  185. package/src/core/sync/write_tsconfig.js +0 -250
  186. package/src/exports/internal/server.js +0 -22
  187. package/src/exports/node/polyfills.js +0 -30
  188. package/src/runtime/server/app.js +0 -9
  189. package/src/runtime/server/remote.js +0 -457
  190. package/src/runtime/shared-server.js +0 -7
  191. package/src/runtime/telemetry/otel.js +0 -21
  192. package/src/runtime/telemetry/record_span.js +0 -65
  193. package/src/types/synthetic/$lib.md +0 -5
  194. /package/src/exports/internal/{remote-functions.js → server/remote-functions.js} +0 -0
  195. /package/src/{runtime/telemetry/noop.js → telemetry.js} +0 -0
@@ -1,10 +1,12 @@
1
- /** @import { RemotePrerenderFunction } from '@sveltejs/kit' */
2
- import { app_dir, base } from '$app/paths/internal/client';
1
+ /** @import { RemotePrerenderFunction } from '@sveltejs/kit/remote' */
2
+ import { app_dir, base } from '#app/paths';
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, handle_error, 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
+ import { noop } from '../../../utils/functions.js';
9
+ import { HandledHttpError } from '@sveltejs/kit/internal';
8
10
 
9
11
  // Initialize Cache API for prerender functions
10
12
  const CACHE_NAME = __SVELTEKIT_DEV__ ? `sveltekit:${Date.now()}` : `sveltekit:${version}`;
@@ -55,7 +57,7 @@ function put(url, encoded) {
55
57
  */
56
58
  export function prerender(id) {
57
59
  return (arg) => {
58
- const payload = stringify_remote_arg(arg, app.hooks.transport);
60
+ const payload = stringify_remote_arg(arg);
59
61
  const cache_key = create_remote_key(id, payload);
60
62
 
61
63
  let resource = prerender_resources.get(cache_key)?.deref();
@@ -67,7 +69,7 @@ export function prerender(id) {
67
69
  const url = `${base}/${app_dir}/remote/${id}${payload ? `/${payload}` : ''}`;
68
70
 
69
71
  if (Object.hasOwn(prerender_responses, cache_key)) {
70
- const data = prerender_responses[cache_key];
72
+ const data = unwrap_node(prerender_responses[cache_key]);
71
73
 
72
74
  if (prerender_cache) {
73
75
  void put(url, devalue.stringify(data, app.encoders));
@@ -77,6 +79,7 @@ export function prerender(id) {
77
79
  }
78
80
 
79
81
  // Do this here, after await Svelte' reactivity context is gone.
82
+ // TODO we really don't want to be sending these specific headers here?
80
83
  const headers = get_remote_request_headers();
81
84
 
82
85
  // Check the Cache API first
@@ -93,14 +96,22 @@ export function prerender(id) {
93
96
  }
94
97
  }
95
98
 
96
- const encoded = await remote_request(url, headers);
99
+ const result = await remote_request(url, { headers });
100
+
101
+ if (result.redirect) {
102
+ // Use internal version to allow redirects to external URLs
103
+ void _goto(result.redirect);
104
+ return;
105
+ }
106
+
107
+ const data = result._;
97
108
 
98
109
  // For successful prerender requests, save to cache
99
110
  if (prerender_cache) {
100
- void put(url, encoded);
111
+ void put(url, devalue.stringify(data, app.encoders));
101
112
  }
102
113
 
103
- return devalue.parse(encoded, app.decoders);
114
+ return data;
104
115
  });
105
116
 
106
117
  prerender_resources.set(cache_key, new WeakRef(resource));
@@ -138,6 +149,7 @@ class Prerender {
138
149
  /** @type {T | undefined} */
139
150
  #current = $state.raw();
140
151
 
152
+ /** @type {App.Error | undefined} */
141
153
  #error = $state.raw(undefined);
142
154
 
143
155
  /**
@@ -152,12 +164,21 @@ class Prerender {
152
164
  this.#error = undefined;
153
165
  return value;
154
166
  },
155
- (error) => {
167
+ async (e) => {
168
+ const error = await handle_error(e, {
169
+ params: {},
170
+ route: { id: null },
171
+ url: new URL(location.href)
172
+ });
156
173
  this.#loading = false;
157
174
  this.#error = error;
158
- throw error;
175
+ throw new HandledHttpError(error);
159
176
  }
160
177
  );
178
+
179
+ // rejections are surfaced via `.error` for reactive consumers — make sure the
180
+ // stored promise (consumed without `await`) never becomes an unhandled rejection
181
+ this.#promise.catch(noop);
161
182
  }
162
183
 
163
184
  /**
@@ -1,10 +1,8 @@
1
- /** @import { RemoteQueryFunction } from '@sveltejs/kit' */
2
- import { app_dir, base } from '$app/paths/internal/client';
3
- import { app, query_map, query_responses } from '../../client.js';
4
- import { get_remote_request_headers, QUERY_FUNCTION_ID, remote_request } from '../shared.svelte.js';
5
- import * as devalue from 'devalue';
1
+ /** @import { RemoteQueryFunction } from '@sveltejs/kit/remote' */
2
+ import { app_dir, base } from '#app/paths';
3
+ import { _goto, query_map } from '../../client.js';
4
+ import { QUERY_FUNCTION_ID, remote_request } from '../shared.svelte.js';
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,15 @@ 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);
40
30
 
41
- return devalue.parse(serialized, app.decoders);
31
+ if (result.redirect) {
32
+ // Use internal version to allow redirects to external URLs
33
+ await _goto(result.redirect);
34
+ }
42
35
  });
43
36
  };
44
37
 
@@ -1,4 +1,6 @@
1
- import { query_responses } from '../../client.js';
1
+ /** @import { HttpError } from '@sveltejs/kit' */
2
+ import { query_responses, handle_error } from '../../client.js';
3
+ import { HandledHttpError } from '@sveltejs/kit/internal';
2
4
  import { QUERY_OVERRIDE_KEY } from '../shared.svelte.js';
3
5
  import { noop } from '../../../../utils/functions.js';
4
6
  import { tick, untrack } from 'svelte';
@@ -36,7 +38,7 @@ export class Query {
36
38
  return this.#overrides.reduce((v, r) => r(v), /** @type {T} */ (this.#raw));
37
39
  });
38
40
 
39
- /** @type {any} */
41
+ /** @type {App.Error | undefined} */
40
42
  #error = $state.raw(undefined);
41
43
 
42
44
  /** @type {Promise<T>['then']} */
@@ -63,6 +65,17 @@ export class Query {
63
65
  constructor(key, fn) {
64
66
  this.#key = key;
65
67
  this.#fn = fn;
68
+
69
+ if (Object.hasOwn(query_responses, key)) {
70
+ const node = query_responses[key];
71
+ delete query_responses[key];
72
+
73
+ if (node.e) {
74
+ this.fail(new HandledHttpError(node.e));
75
+ } else {
76
+ this.set(/** @type {T} */ (node.v));
77
+ }
78
+ }
66
79
  }
67
80
 
68
81
  #get_promise() {
@@ -70,12 +83,14 @@ export class Query {
70
83
  return /** @type {Promise<T>} */ (this.#promise);
71
84
  }
72
85
 
73
- #start() {
86
+ start() {
74
87
  // there is a really weird bug with untrack and writes and initializations
75
88
  // every time you see this comment, try removing the `tick.then` here and see
76
89
  // if all the tests still pass with the latest svelte version
77
90
  // if they do, congrats, you can remove tick.then
78
- void tick().then(() => this.#get_promise());
91
+ void tick()
92
+ .then(() => this.#get_promise())
93
+ .catch(noop);
79
94
  }
80
95
 
81
96
  #clear_pending() {
@@ -88,6 +103,11 @@ export class Query {
88
103
 
89
104
  const { promise, resolve, reject } = Promise.withResolvers();
90
105
 
106
+ // the rejection is surfaced via `.error` / the `then` getter for awaiting
107
+ // consumers — a purely reactive consumer (`.current`) attaches no handler,
108
+ // so make sure the stored promise can never become an unhandled rejection
109
+ promise.catch(noop);
110
+
91
111
  this.#latest.push(resolve);
92
112
 
93
113
  Promise.resolve(this.#fn())
@@ -107,22 +127,33 @@ export class Query {
107
127
 
108
128
  resolve(undefined);
109
129
  })
110
- .catch((e) => {
130
+ .catch(async (e) => {
111
131
  // TODO: Our behavior here could be better:
112
132
  // - We should not reject on redirects, but should hook into the router
113
133
  // to ensure the query is properly refreshed before the navigation completes
114
134
  // - Instead of failing on transport-level errors, we should probably do what
115
135
  // LiveQuery does and preserve the last known good value and retry the connection
136
+ if (this.#latest.indexOf(resolve) === -1) return;
137
+
138
+ const error = await handle_error(e, {
139
+ params: {},
140
+ route: { id: null },
141
+ url: new URL(location.href)
142
+ });
143
+
144
+ // Re-check after the async `handle_error` gap: a later request may have
145
+ // resolved/rejected while we were awaiting and superseded this one, so
146
+ // recompute the index and bail out if this request is no longer current
116
147
  const idx = this.#latest.indexOf(resolve);
117
148
  if (idx === -1) return;
118
149
 
119
150
  untrack(() => {
120
151
  this.#latest.splice(0, idx).forEach((r) => r(undefined));
121
- this.#error = e;
152
+ this.#error = error;
122
153
  this.#loading = false;
123
154
  });
124
155
 
125
- reject(e);
156
+ reject(new HandledHttpError(error));
126
157
  });
127
158
 
128
159
  return promise;
@@ -131,12 +162,12 @@ export class Query {
131
162
  get then() {
132
163
  // TODO this should be unnecessary but due to the bug described
133
164
  // in #start, we need to do this in some circumstances
134
- this.#start();
165
+ this.start();
135
166
  return this.#then;
136
167
  }
137
168
 
138
169
  get catch() {
139
- this.#start();
170
+ this.start();
140
171
  this.#then;
141
172
  return (/** @type {any} */ reject) => {
142
173
  return this.#then(undefined, reject);
@@ -144,7 +175,7 @@ export class Query {
144
175
  }
145
176
 
146
177
  get finally() {
147
- this.#start();
178
+ this.start();
148
179
  this.#then;
149
180
  return (/** @type {any} */ fn) => {
150
181
  return this.#then(
@@ -161,12 +192,12 @@ export class Query {
161
192
  }
162
193
 
163
194
  get current() {
164
- this.#start();
195
+ this.start();
165
196
  return this.#current;
166
197
  }
167
198
 
168
199
  get error() {
169
- this.#start();
200
+ this.start();
170
201
  return this.#error;
171
202
  }
172
203
 
@@ -174,7 +205,7 @@ export class Query {
174
205
  * Returns true if the resource is loading or reloading.
175
206
  */
176
207
  get loading() {
177
- this.#start();
208
+ this.start();
178
209
  return this.#loading;
179
210
  }
180
211
 
@@ -182,7 +213,7 @@ export class Query {
182
213
  * Returns true once the resource has been loaded for the first time.
183
214
  */
184
215
  get ready() {
185
- this.#start();
216
+ this.start();
186
217
  return this.#ready;
187
218
  }
188
219
 
@@ -198,6 +229,10 @@ export class Query {
198
229
  * @param {T} value
199
230
  */
200
231
  set(value) {
232
+ // normally consumed in the constructor, but make sure a leftover
233
+ // SSR record can never shadow the newly-set value
234
+ delete query_responses[this.#key];
235
+
201
236
  this.#clear_pending();
202
237
  this.#ready = true;
203
238
  this.#loading = false;
@@ -206,13 +241,15 @@ export class Query {
206
241
  this.#promise = Promise.resolve();
207
242
  }
208
243
 
209
- /**
210
- * @param {unknown} error
211
- */
244
+ /** @param {HttpError} error */
212
245
  fail(error) {
246
+ // normally consumed in the constructor, but make sure a leftover
247
+ // SSR record can never shadow the newly-set error
248
+ delete query_responses[this.#key];
249
+
213
250
  this.#clear_pending();
214
251
  this.#loading = false;
215
- this.#error = error;
252
+ this.#error = error.body;
216
253
 
217
254
  const promise = Promise.reject(error);
218
255
 
@@ -242,6 +279,15 @@ export class Query {
242
279
  return release;
243
280
  }
244
281
 
282
+ /**
283
+ * Reset ahead of a navigation that invalidates all, to force newly
284
+ * rendered queries to get fresh data
285
+ */
286
+ reset() {
287
+ this.#promise = null;
288
+ delete query_responses[this.#key];
289
+ }
290
+
245
291
  get [Symbol.toStringTag]() {
246
292
  return 'Query';
247
293
  }
@@ -1,4 +1,4 @@
1
- import { app, query_map } from '../../client.js';
1
+ import { query_map } from '../../client.js';
2
2
  import {
3
3
  pin_in_effect,
4
4
  pin_while_resolving,
@@ -25,11 +25,11 @@ 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;
32
- this.#payload = stringify_remote_arg(arg, app.hooks.transport);
32
+ this.#payload = stringify_remote_arg(arg);
33
33
  this.#key = create_remote_key(id, this.#payload);
34
34
  Object.defineProperty(this, QUERY_RESOURCE_KEY, { value: this.#key });
35
35
  this.#fn = fn;
@@ -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);
@@ -1,12 +1,9 @@
1
- /** @import { RemoteQueryFunction } from '@sveltejs/kit' */
2
- /** @import { RemoteFunctionResponse } from 'types' */
3
- import { app_dir, base } from '$app/paths/internal/client';
4
- import { app, goto } from '../client.js';
5
- import { get_remote_request_headers, QUERY_FUNCTION_ID } from './shared.svelte.js';
1
+ /** @import { RemoteQueryFunction } from '@sveltejs/kit/remote' */
2
+ import { app_dir, base } from '#app/paths';
3
+ import { _goto } from '../client.js';
4
+ import { QUERY_FUNCTION_ID, remote_request } from './shared.svelte.js';
6
5
  import { QueryProxy } from './query/proxy.js';
7
- import * as devalue from 'devalue';
8
- import { HttpError, Redirect } from '@sveltejs/kit/internal';
9
- import { hydratable } from 'svelte';
6
+ import { HandledHttpError } from '@sveltejs/kit/internal';
10
7
 
11
8
  /**
12
9
  * @param {string} id
@@ -18,84 +15,78 @@ export function query_batch(id) {
18
15
 
19
16
  /** @type {RemoteQueryFunction<any, any>} */
20
17
  const wrapper = (arg) => {
21
- return new QueryProxy(id, arg, async (key, payload) => {
22
- const serialized = await hydratable(key, () => {
23
- return new Promise((resolve, reject) => {
24
- // create_remote_function caches identical calls, but in case a refresh to the same query is called multiple times this function
25
- // is invoked multiple times with the same payload, so we need to deduplicate here
26
- const entry = batching.get(payload) ?? [];
27
- entry.push({ resolve, reject });
28
- batching.set(payload, entry);
18
+ return new QueryProxy(id, arg, async (payload) => {
19
+ return await new Promise((resolve, reject) => {
20
+ // create_remote_function caches identical calls, but in case a refresh to the same query is called multiple times this function
21
+ // is invoked multiple times with the same payload, so we need to deduplicate here
22
+ const entry = batching.get(payload) ?? [];
23
+ entry.push({ resolve, reject });
24
+ batching.set(payload, entry);
29
25
 
30
- if (batching.size > 1) return;
26
+ if (batching.size > 1) return;
31
27
 
32
- // Do this here, after await Svelte' reactivity context is gone.
33
- // TODO is it possible to have batches of the same key
34
- // but in different forks/async contexts and in the same macrotask?
35
- // If so this would potentially be buggy
36
- const headers = {
37
- 'Content-Type': 'application/json',
38
- ...get_remote_request_headers()
39
- };
28
+ // Do this here, after await Svelte' reactivity context is gone.
29
+ // TODO is it possible to have batches of the same key
30
+ // but in different forks/async contexts and in the same macrotask?
31
+ // If so this would potentially be buggy
32
+ const headers = {
33
+ 'Content-Type': 'application/json'
34
+ };
40
35
 
41
- // Wait for the next macrotask - don't use microtask as Svelte runtime uses these to collect changes and flush them,
42
- // and flushes could reveal more queries that should be batched.
43
- setTimeout(async () => {
44
- const batched = batching;
45
- batching = new Map();
36
+ // Wait for the next macrotask - don't use microtask as Svelte runtime uses these to collect changes and flush them,
37
+ // and flushes could reveal more queries that should be batched.
38
+ setTimeout(async () => {
39
+ const batched = batching;
40
+ batching = new Map();
46
41
 
47
- try {
48
- const response = await fetch(`${base}/${app_dir}/remote/${id}`, {
49
- method: 'POST',
50
- body: JSON.stringify({
51
- payloads: Array.from(batched.keys())
52
- }),
53
- headers
54
- });
42
+ try {
43
+ const response = await remote_request(`${base}/${app_dir}/remote/${id}`, {
44
+ method: 'POST',
45
+ body: JSON.stringify({
46
+ payloads: Array.from(batched.keys())
47
+ }),
48
+ headers
49
+ });
55
50
 
56
- if (!response.ok) {
57
- throw new Error('Failed to execute batch query');
58
- }
51
+ if (response.redirect) {
52
+ // Use internal version to allow redirects to external URLs
53
+ await _goto(response.redirect);
59
54
 
60
- const result = /** @type {RemoteFunctionResponse} */ (await response.json());
61
- if (result.type === 'error') {
62
- throw new HttpError(result.status ?? 500, result.error);
55
+ // settle all batched promises (with `undefined`, like a redirect
56
+ // from a non-batched query) so that callers don't hang forever
57
+ for (const resolvers of batched.values()) {
58
+ for (const { resolve } of resolvers) {
59
+ resolve(undefined);
60
+ }
63
61
  }
64
62
 
65
- if (result.type === 'redirect') {
66
- await goto(result.location);
67
- throw new Redirect(307, result.location);
68
- }
63
+ return;
64
+ }
69
65
 
70
- const results = devalue.parse(result.result, app.decoders);
66
+ const results = response._;
67
+ let i = 0;
71
68
 
72
- // Resolve individual queries
73
- // Maps guarantee insertion order so we can do it like this
74
- let i = 0;
69
+ for (const resolvers of batched.values()) {
70
+ const result = results[i];
75
71
 
76
- for (const resolvers of batched.values()) {
77
- for (const { resolve, reject } of resolvers) {
78
- if (results[i].type === 'error') {
79
- reject(new HttpError(results[i].status, results[i].error));
80
- } else {
81
- resolve(results[i].data);
82
- }
72
+ for (const { resolve, reject } of resolvers) {
73
+ if (result.type === 'error') {
74
+ reject(new HandledHttpError(result.error));
75
+ } else {
76
+ resolve(result.data);
83
77
  }
84
- i++;
85
78
  }
86
- } catch (error) {
87
- // Reject all queries in the batch
88
- for (const resolver of batched.values()) {
89
- for (const { reject } of resolver) {
90
- reject(error);
91
- }
79
+ i++;
80
+ }
81
+ } catch (e) {
82
+ for (const resolvers of batched.values()) {
83
+ for (const { reject } of resolvers) {
84
+ reject(e);
92
85
  }
93
86
  }
94
- }, 0);
95
- });
87
+ }
88
+ }, 0);
96
89
  });
97
-
98
- return devalue.parse(serialized, app.decoders);
99
90
  });
100
91
  };
101
92
 
@@ -1,4 +1,4 @@
1
- /** @import { RemoteLiveQuery, RemoteLiveQueryFunction } from '@sveltejs/kit' */
1
+ /** @import { RemoteLiveQuery, RemoteLiveQueryFunction } from '@sveltejs/kit/remote' */
2
2
  import { live_query_map } from '../../client.js';
3
3
  import { QUERY_FUNCTION_ID } from '../shared.svelte.js';
4
4
  import { DEV } from 'esm-env';