@sveltejs/kit 2.26.1 → 2.27.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.
Files changed (54) hide show
  1. package/README.md +1 -1
  2. package/package.json +3 -2
  3. package/src/core/adapt/builder.js +6 -1
  4. package/src/core/config/options.js +4 -0
  5. package/src/core/generate_manifest/index.js +4 -1
  6. package/src/core/postbuild/analyse.js +25 -1
  7. package/src/core/postbuild/fallback.js +2 -1
  8. package/src/core/postbuild/prerender.js +41 -10
  9. package/src/core/sync/create_manifest_data/index.js +35 -1
  10. package/src/core/sync/write_server.js +4 -2
  11. package/src/exports/index.js +1 -1
  12. package/src/exports/internal/index.js +3 -1
  13. package/src/exports/internal/remote-functions.js +21 -0
  14. package/src/exports/public.d.ts +162 -2
  15. package/src/exports/vite/build/build_remote.js +129 -0
  16. package/src/exports/vite/dev/index.js +7 -0
  17. package/src/exports/vite/index.js +123 -8
  18. package/src/exports/vite/preview/index.js +3 -1
  19. package/src/runtime/app/navigation.js +1 -0
  20. package/src/runtime/app/server/index.js +2 -0
  21. package/src/runtime/app/server/remote/command.js +91 -0
  22. package/src/runtime/app/server/remote/form.js +124 -0
  23. package/src/runtime/app/server/remote/index.js +4 -0
  24. package/src/runtime/app/server/remote/prerender.js +163 -0
  25. package/src/runtime/app/server/remote/query.js +115 -0
  26. package/src/runtime/app/server/remote/shared.js +153 -0
  27. package/src/runtime/client/client.js +107 -39
  28. package/src/runtime/client/fetcher.js +1 -1
  29. package/src/runtime/client/remote-functions/command.js +71 -0
  30. package/src/runtime/client/remote-functions/form.svelte.js +312 -0
  31. package/src/runtime/client/remote-functions/index.js +4 -0
  32. package/src/runtime/client/remote-functions/prerender.svelte.js +166 -0
  33. package/src/runtime/client/remote-functions/query.svelte.js +219 -0
  34. package/src/runtime/client/remote-functions/shared.svelte.js +143 -0
  35. package/src/runtime/client/types.d.ts +2 -0
  36. package/src/runtime/server/data/index.js +6 -4
  37. package/src/runtime/server/event-state.js +41 -0
  38. package/src/runtime/server/index.js +12 -3
  39. package/src/runtime/server/page/actions.js +1 -1
  40. package/src/runtime/server/page/index.js +10 -3
  41. package/src/runtime/server/page/load_data.js +18 -12
  42. package/src/runtime/server/page/render.js +33 -7
  43. package/src/runtime/server/page/serialize_data.js +1 -1
  44. package/src/runtime/server/remote.js +237 -0
  45. package/src/runtime/server/respond.js +57 -36
  46. package/src/runtime/shared.js +61 -0
  47. package/src/types/global-private.d.ts +2 -0
  48. package/src/types/internal.d.ts +52 -5
  49. package/src/types/synthetic/$env+static+private.md +1 -1
  50. package/src/utils/routing.js +2 -2
  51. package/src/version.js +1 -1
  52. package/types/index.d.ts +271 -8
  53. package/types/index.d.ts.map +14 -1
  54. /package/src/{runtime → utils}/hash.js +0 -0
package/README.md CHANGED
@@ -4,7 +4,7 @@ This is the [SvelteKit](https://svelte.dev/docs/kit) framework and CLI.
4
4
 
5
5
  The quickest way to get started is via the [sv](https://npmjs.com/package/sv) package:
6
6
 
7
- ```bash
7
+ ```sh
8
8
  npx sv create my-app
9
9
  cd my-app
10
10
  npm install
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sveltejs/kit",
3
- "version": "2.26.1",
3
+ "version": "2.27.1",
4
4
  "description": "SvelteKit is the fastest way to build Svelte apps",
5
5
  "keywords": [
6
6
  "framework",
@@ -18,6 +18,7 @@
18
18
  "homepage": "https://svelte.dev",
19
19
  "type": "module",
20
20
  "dependencies": {
21
+ "@standard-schema/spec": "^1.0.0",
21
22
  "@sveltejs/acorn-typescript": "^1.0.5",
22
23
  "@types/cookie": "^0.6.0",
23
24
  "acorn": "^8.14.1",
@@ -37,7 +38,7 @@
37
38
  "@types/connect": "^3.4.38",
38
39
  "@types/node": "^18.19.119",
39
40
  "@types/set-cookie-parser": "^2.4.7",
40
- "dts-buddy": "^0.6.1",
41
+ "dts-buddy": "^0.6.2",
41
42
  "rollup": "^4.14.2",
42
43
  "svelte": "^5.35.5",
43
44
  "svelte-preprocess": "^6.0.0",
@@ -219,7 +219,12 @@ export function create_builder({
219
219
 
220
220
  writePrerendered(dest) {
221
221
  const source = `${config.kit.outDir}/output/prerendered`;
222
- return [...copy(`${source}/pages`, dest), ...copy(`${source}/dependencies`, dest)];
222
+
223
+ return [
224
+ ...copy(`${source}/pages`, dest),
225
+ ...copy(`${source}/dependencies`, dest),
226
+ ...copy(`${source}/data`, dest)
227
+ ];
223
228
  },
224
229
 
225
230
  writeServer(dest) {
@@ -120,6 +120,10 @@ const options = object(
120
120
  privatePrefix: string('')
121
121
  }),
122
122
 
123
+ experimental: object({
124
+ remoteFunctions: boolean(false)
125
+ }),
126
+
123
127
  files: object({
124
128
  assets: string('static'),
125
129
  hooks: object({
@@ -59,7 +59,7 @@ export function generate_manifest({ build_data, prerendered, relative_path, rout
59
59
  assets.push(build_data.service_worker);
60
60
  }
61
61
 
62
- // In case of server side route resolution, we need to include all matchers. Prerendered routes are not part
62
+ // In case of server-side route resolution, we need to include all matchers. Prerendered routes are not part
63
63
  // of the server manifest, and they could reference matchers that then would not be included.
64
64
  const matchers = new Set(
65
65
  build_data.client?.nodes ? Object.keys(build_data.manifest_data.matchers) : undefined
@@ -100,6 +100,9 @@ export function generate_manifest({ build_data, prerendered, relative_path, rout
100
100
  nodes: [
101
101
  ${(node_paths).map(loader).join(',\n')}
102
102
  ],
103
+ remotes: {
104
+ ${build_data.manifest_data.remotes.map((remote) => `'${remote.hash}': ${loader(join_relative(relative_path, resolve_symlinks(build_data.server_manifest, remote.file).chunk.file))}`).join(',\n')}
105
+ },
103
106
  routes: [
104
107
  ${routes.map(route => {
105
108
  if (!route.page && !route.endpoint) return;
@@ -11,6 +11,7 @@ import { check_feature } from '../../utils/features.js';
11
11
  import { createReadableStream } from '@sveltejs/kit/node';
12
12
  import { PageNodes } from '../../utils/page_nodes.js';
13
13
  import { build_server_nodes } from '../../exports/vite/build/build_server.js';
14
+ import { validate_remote_functions } from '@sveltejs/kit/internal';
14
15
 
15
16
  export default forked(import.meta.url, analyse);
16
17
 
@@ -82,7 +83,8 @@ async function analyse({
82
83
  /** @type {import('types').ServerMetadata} */
83
84
  const metadata = {
84
85
  nodes: [],
85
- routes: new Map()
86
+ routes: new Map(),
87
+ remotes: new Map()
86
88
  };
87
89
 
88
90
  const nodes = await Promise.all(manifest._.nodes.map((loader) => loader()));
@@ -164,6 +166,28 @@ async function analyse({
164
166
  });
165
167
  }
166
168
 
169
+ // analyse remotes
170
+ for (const remote of manifest_data.remotes) {
171
+ const loader = manifest._.remotes[remote.hash];
172
+ const module = await loader();
173
+
174
+ validate_remote_functions(module, remote.file);
175
+
176
+ const exports = new Map();
177
+
178
+ for (const name in module) {
179
+ const info = /** @type {import('types').RemoteInfo} */ (module[name].__);
180
+ const type = info.type;
181
+
182
+ exports.set(name, {
183
+ type,
184
+ dynamic: type !== 'prerender' || info.dynamic
185
+ });
186
+ }
187
+
188
+ metadata.remotes.set(remote.hash, exports);
189
+ }
190
+
167
191
  return { metadata, static_exports };
168
192
  }
169
193
 
@@ -41,7 +41,8 @@ async function generate_fallback({ manifest_path, env }) {
41
41
  },
42
42
  prerendering: {
43
43
  fallback: true,
44
- dependencies: new Map()
44
+ dependencies: new Map(),
45
+ remote_responses: new Map()
45
46
  },
46
47
  read: (file) => readFileSync(join(config.files.assets, file))
47
48
  });
@@ -14,6 +14,7 @@ import { forked } from '../../utils/fork.js';
14
14
  import * as devalue from 'devalue';
15
15
  import { createReadableStream } from '@sveltejs/kit/node';
16
16
  import generate_fallback from './fallback.js';
17
+ import { stringify_remote_arg } from '../../runtime/shared.js';
17
18
 
18
19
  export default forked(import.meta.url, prerender);
19
20
 
@@ -184,8 +185,12 @@ async function prerender({ hash, out, manifest_path, metadata, verbose, env }) {
184
185
  files.add(posixify(`${config.appDir}/immutable/${file}`));
185
186
  }
186
187
  }
188
+
189
+ const remote_prefix = `${config.paths.base}/${config.appDir}/remote/`;
190
+
187
191
  const seen = new Set();
188
192
  const written = new Set();
193
+ const remote_responses = new Map();
189
194
 
190
195
  /** @type {Map<string, Set<string>>} */
191
196
  const expected_hashlinks = new Map();
@@ -229,7 +234,8 @@ async function prerender({ hash, out, manifest_path, metadata, verbose, env }) {
229
234
  throw new Error('Cannot read clientAddress during prerendering');
230
235
  },
231
236
  prerendering: {
232
- dependencies
237
+ dependencies,
238
+ remote_responses
233
239
  },
234
240
  read: (file) => {
235
241
  // stuff we just wrote
@@ -258,7 +264,8 @@ async function prerender({ hash, out, manifest_path, metadata, verbose, env }) {
258
264
 
259
265
  const body = Buffer.from(await response.arrayBuffer());
260
266
 
261
- save('pages', response, body, decoded, encoded, referrer, 'linked');
267
+ const category = decoded.startsWith(remote_prefix) ? 'data' : 'pages';
268
+ save(category, response, body, decoded, encoded, referrer, 'linked');
262
269
 
263
270
  for (const [dependency_path, result] of dependencies) {
264
271
  // this seems circuitous, but using new URL allows us to not care
@@ -282,8 +289,10 @@ async function prerender({ hash, out, manifest_path, metadata, verbose, env }) {
282
289
 
283
290
  const body = result.body ?? new Uint8Array(await result.response.arrayBuffer());
284
291
 
292
+ const category = decoded_dependency_path.startsWith(remote_prefix) ? 'data' : 'dependencies';
293
+
285
294
  save(
286
- 'dependencies',
295
+ category,
287
296
  result.response,
288
297
  body,
289
298
  decoded_dependency_path,
@@ -336,7 +345,7 @@ async function prerender({ hash, out, manifest_path, metadata, verbose, env }) {
336
345
  }
337
346
 
338
347
  /**
339
- * @param {'pages' | 'dependencies'} category
348
+ * @param {'pages' | 'dependencies' | 'data'} category
340
349
  * @param {Response} response
341
350
  * @param {string | Uint8Array} body
342
351
  * @param {string} decoded
@@ -451,19 +460,30 @@ async function prerender({ hash, out, manifest_path, metadata, verbose, env }) {
451
460
  }
452
461
  }
453
462
 
454
- let has_prerenderable_routes = false;
463
+ let should_prerender = false;
455
464
 
456
465
  for (const value of prerender_map.values()) {
457
466
  if (value) {
458
- has_prerenderable_routes = true;
467
+ should_prerender = true;
459
468
  break;
460
469
  }
461
470
  }
462
471
 
463
- if (
464
- (config.prerender.entries.length === 0 && route_level_entries.length === 0) ||
465
- !has_prerenderable_routes
466
- ) {
472
+ /** @type {Array<import('types').RemoteInfo & { type: 'prerender'}>} */
473
+ const prerender_functions = [];
474
+
475
+ for (const loader of Object.values(manifest._.remotes)) {
476
+ const module = await loader();
477
+
478
+ for (const fn of Object.values(module)) {
479
+ if (fn?.__?.type === 'prerender') {
480
+ prerender_functions.push(fn.__);
481
+ should_prerender = true;
482
+ }
483
+ }
484
+ }
485
+
486
+ if (!should_prerender) {
467
487
  return { prerendered, prerender_map };
468
488
  }
469
489
 
@@ -499,6 +519,17 @@ async function prerender({ hash, out, manifest_path, metadata, verbose, env }) {
499
519
  }
500
520
  }
501
521
 
522
+ const transport = (await internal.get_hooks()).transport ?? {};
523
+ for (const info of prerender_functions) {
524
+ if (info.has_arg) {
525
+ for (const arg of (await info.inputs?.()) ?? []) {
526
+ void enqueue(null, remote_prefix + info.id + '/' + stringify_remote_arg(arg, transport));
527
+ }
528
+ } else {
529
+ void enqueue(null, remote_prefix + info.id);
530
+ }
531
+ }
532
+
502
533
  await q.done();
503
534
 
504
535
  // handle invalid fragment links
@@ -4,10 +4,11 @@ import process from 'node:process';
4
4
  import colors from 'kleur';
5
5
  import { lookup } from 'mrmime';
6
6
  import { list_files, runtime_directory } from '../../utils.js';
7
- import { posixify, resolve_entry } from '../../../utils/filesystem.js';
7
+ import { posixify, resolve_entry, walk } from '../../../utils/filesystem.js';
8
8
  import { parse_route_id } from '../../../utils/routing.js';
9
9
  import { sort_routes } from './sort.js';
10
10
  import { isSvelte5Plus } from '../utils.js';
11
+ import { hash } from '../../../utils/hash.js';
11
12
 
12
13
  /**
13
14
  * Generates the manifest data used for the client-side manifest and types generation.
@@ -27,6 +28,7 @@ export default function create_manifest_data({
27
28
  const hooks = create_hooks(config, cwd);
28
29
  const matchers = create_matchers(config, cwd);
29
30
  const { nodes, routes } = create_routes_and_nodes(cwd, config, fallback);
31
+ const remotes = create_remotes(config, cwd);
30
32
 
31
33
  for (const route of routes) {
32
34
  for (const param of route.params) {
@@ -41,6 +43,7 @@ export default function create_manifest_data({
41
43
  hooks,
42
44
  matchers,
43
45
  nodes,
46
+ remotes,
44
47
  routes
45
48
  };
46
49
  }
@@ -465,6 +468,37 @@ function create_routes_and_nodes(cwd, config, fallback) {
465
468
  };
466
469
  }
467
470
 
471
+ /**
472
+ * @param {import('types').ValidatedConfig} config
473
+ * @param {string} cwd
474
+ */
475
+ function create_remotes(config, cwd) {
476
+ if (!config.kit.experimental.remoteFunctions) return [];
477
+
478
+ const extensions = config.kit.moduleExtensions.map((ext) => `.remote${ext}`);
479
+
480
+ /** @type {import('types').ManifestData['remotes']} */
481
+ const remotes = [];
482
+
483
+ // TODO could files live in other directories, including node_modules?
484
+ for (const dir of [config.kit.files.lib, config.kit.files.routes]) {
485
+ if (!fs.existsSync(dir)) continue;
486
+
487
+ for (const file of walk(dir)) {
488
+ if (extensions.some((ext) => file.endsWith(ext))) {
489
+ const posixified = posixify(path.relative(cwd, `${dir}/${file}`));
490
+
491
+ remotes.push({
492
+ hash: hash(posixified),
493
+ file: posixified
494
+ });
495
+ }
496
+ }
497
+ }
498
+
499
+ return remotes;
500
+ }
501
+
468
502
  /**
469
503
  * @param {string} project_relative
470
504
  * @param {string} file
@@ -1,6 +1,6 @@
1
1
  import path from 'node:path';
2
2
  import process from 'node:process';
3
- import { hash } from '../../runtime/hash.js';
3
+ import { hash } from '../../utils/hash.js';
4
4
  import { posixify, resolve_entry } from '../../utils/filesystem.js';
5
5
  import { s } from '../../utils/misc.js';
6
6
  import { load_error_page, load_template } from '../config/index.js';
@@ -67,8 +67,9 @@ export async function get_hooks() {
67
67
  let handle;
68
68
  let handleFetch;
69
69
  let handleError;
70
+ let handleValidationError;
70
71
  let init;
71
- ${server_hooks ? `({ handle, handleFetch, handleError, init } = await import(${s(server_hooks)}));` : ''}
72
+ ${server_hooks ? `({ handle, handleFetch, handleError, handleValidationError, init } = await import(${s(server_hooks)}));` : ''}
72
73
 
73
74
  let reroute;
74
75
  let transport;
@@ -78,6 +79,7 @@ export async function get_hooks() {
78
79
  handle,
79
80
  handleFetch,
80
81
  handleError,
82
+ handleValidationError,
81
83
  init,
82
84
  reroute,
83
85
  transport
@@ -188,7 +188,7 @@ export function text(body, init) {
188
188
  */
189
189
  /**
190
190
  * Create an `ActionFailure` object. Call when form submission fails.
191
- * @template {Record<string, unknown> | undefined} [T=undefined]
191
+ * @template [T=undefined]
192
192
  * @param {number} status The [HTTP status code](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status#client_error_responses). Must be in the range 400-599.
193
193
  * @param {T} data Data associated with the failure (e.g. validation errors)
194
194
  * @overload
@@ -49,7 +49,7 @@ export class SvelteKitError extends Error {
49
49
  }
50
50
 
51
51
  /**
52
- * @template {Record<string, unknown> | undefined} [T=undefined]
52
+ * @template [T=undefined]
53
53
  */
54
54
  export class ActionFailure {
55
55
  /**
@@ -61,3 +61,5 @@ export class ActionFailure {
61
61
  this.data = data;
62
62
  }
63
63
  }
64
+
65
+ export { validate_remote_functions } from './remote-functions.js';
@@ -0,0 +1,21 @@
1
+ /**
2
+ * @param {Record<string, any>} module
3
+ * @param {string} file
4
+ */
5
+ export function validate_remote_functions(module, file) {
6
+ if (module.default) {
7
+ throw new Error(
8
+ `Cannot export \`default\` from a remote module (${file}) — please use named exports instead`
9
+ );
10
+ }
11
+
12
+ for (const name in module) {
13
+ const type = module[name]?.__?.type;
14
+
15
+ if (type !== 'form' && type !== 'command' && type !== 'query' && type !== 'prerender') {
16
+ throw new Error(
17
+ `\`${name}\` exported from ${file} is invalid — all exports from this file must be remote functions`
18
+ );
19
+ }
20
+ }
21
+ }
@@ -17,7 +17,8 @@ import {
17
17
  RouteSegment
18
18
  } from '../types/private.js';
19
19
  import { BuildData, SSRNodeLoader, SSRRoute, ValidatedConfig } from 'types';
20
- import type { SvelteConfig, PluginOptions } from '@sveltejs/vite-plugin-svelte';
20
+ import type { SvelteConfig } from '@sveltejs/vite-plugin-svelte';
21
+ import type { StandardSchemaV1 } from '@standard-schema/spec';
21
22
  import {
22
23
  RouteId as AppRouteId,
23
24
  LayoutParams as AppLayoutParams,
@@ -78,7 +79,7 @@ type OptionalUnion<
78
79
 
79
80
  declare const uniqueSymbol: unique symbol;
80
81
 
81
- export interface ActionFailure<T extends Record<string, unknown> | undefined = undefined> {
82
+ export interface ActionFailure<T = undefined> {
82
83
  status: number;
83
84
  data: T;
84
85
  [uniqueSymbol]: true; // necessary or else UnpackValidationError could wrongly unpack objects with the same shape as ActionFailure
@@ -407,6 +408,16 @@ export interface KitConfig {
407
408
  */
408
409
  privatePrefix?: string;
409
410
  };
411
+ /**
412
+ * Experimental features which are exempt from semantic versioning. These features may be changed or removed at any time.
413
+ */
414
+ experimental?: {
415
+ /**
416
+ * Whether to enable the experimental remote functions feature. This feature is not yet stable and may be changed or removed at any time.
417
+ * @default false
418
+ */
419
+ remoteFunctions?: boolean;
420
+ };
410
421
  /**
411
422
  * Where to find various files within your project.
412
423
  */
@@ -774,6 +785,14 @@ export type HandleServerError = (input: {
774
785
  message: string;
775
786
  }) => MaybePromise<void | App.Error>;
776
787
 
788
+ /**
789
+ * The [`handleValidationError`](https://svelte.dev/docs/kit/hooks#Server-hooks-handleValidationError) hook runs when the argument to a remote function fails validation.
790
+ *
791
+ * It will be called with the validation issues and the event, and must return an object shape that matches `App.Error`.
792
+ */
793
+ export type HandleValidationError<Issue extends StandardSchemaV1.Issue = StandardSchemaV1.Issue> =
794
+ (input: { issues: Issue[]; event: RequestEvent }) => MaybePromise<App.Error>;
795
+
777
796
  /**
778
797
  * The client-side [`handleError`](https://svelte.dev/docs/kit/hooks#Shared-hooks-handleError) hook runs when an unexpected error is thrown while navigating.
779
798
  *
@@ -1248,6 +1267,11 @@ export interface RequestEvent<
1248
1267
  * `true` for `+server.js` calls coming from SvelteKit without the overhead of actually making an HTTP request. This happens when you make same-origin `fetch` requests on the server.
1249
1268
  */
1250
1269
  isSubRequest: boolean;
1270
+ /**
1271
+ * `true` if the request comes from the client via a remote function. The `url` property will be stripped of the internal information
1272
+ * related to the data request in this case. Use this property instead if the distinction is important to you.
1273
+ */
1274
+ isRemoteRequest: boolean;
1251
1275
  }
1252
1276
 
1253
1277
  /**
@@ -1322,6 +1346,8 @@ export interface SSRManifest {
1322
1346
  _: {
1323
1347
  client: NonNullable<BuildData['client']>;
1324
1348
  nodes: SSRNodeLoader[];
1349
+ /** hashed filename -> import to that file */
1350
+ remotes: Record<string, () => Promise<any>>;
1325
1351
  routes: SSRRoute[];
1326
1352
  prerendered_routes: Set<string>;
1327
1353
  matchers: () => Promise<Record<string, ParamMatcher>>;
@@ -1499,4 +1525,138 @@ export interface Snapshot<T = any> {
1499
1525
  restore: (snapshot: T) => void;
1500
1526
  }
1501
1527
 
1528
+ /**
1529
+ * The return value of a remote `form` function. See [Remote functions](https://svelte.dev/docs/kit/remote-functions#form) for full documentation.
1530
+ */
1531
+ export type RemoteForm<Result> = {
1532
+ method: 'POST';
1533
+ /** The URL to send the form to. */
1534
+ action: string;
1535
+ /** Event handler that intercepts the form submission on the client to prevent a full page reload */
1536
+ onsubmit: (event: SubmitEvent) => void;
1537
+ /** Use the `enhance` method to influence what happens when the form is submitted. */
1538
+ enhance(
1539
+ callback: (opts: {
1540
+ form: HTMLFormElement;
1541
+ data: FormData;
1542
+ submit: () => Promise<void> & {
1543
+ updates: (...queries: Array<RemoteQuery<any> | RemoteQueryOverride>) => Promise<void>;
1544
+ };
1545
+ }) => void
1546
+ ): {
1547
+ method: 'POST';
1548
+ action: string;
1549
+ onsubmit: (event: SubmitEvent) => void;
1550
+ };
1551
+ /**
1552
+ * Create an instance of the form for the given key.
1553
+ * The key is stringified and used for deduplication to potentially reuse existing instances.
1554
+ * Useful when you have multiple forms that use the same remote form action, for example in a loop.
1555
+ * ```svelte
1556
+ * {#each todos as todo}
1557
+ * {@const todoForm = updateTodo.for(todo.id)}
1558
+ * <form {...todoForm}>
1559
+ * {#if todoForm.result?.invalid}<p>Invalid data</p>{/if}
1560
+ * ...
1561
+ * </form>
1562
+ * {/each}
1563
+ * ```
1564
+ */
1565
+ for(key: string | number | boolean): Omit<RemoteForm<Result>, 'for'>;
1566
+ /** The result of the form submission */
1567
+ get result(): Result | undefined;
1568
+ /** Spread this onto a `<button>` or `<input type="submit">` */
1569
+ buttonProps: {
1570
+ type: 'submit';
1571
+ formmethod: 'POST';
1572
+ formaction: string;
1573
+ onclick: (event: Event) => void;
1574
+ /** Use the `enhance` method to influence what happens when the form is submitted. */
1575
+ enhance(
1576
+ callback: (opts: {
1577
+ form: HTMLFormElement;
1578
+ data: FormData;
1579
+ submit: () => Promise<void> & {
1580
+ updates: (...queries: Array<RemoteQuery<any> | RemoteQueryOverride>) => Promise<void>;
1581
+ };
1582
+ }) => void
1583
+ ): {
1584
+ type: 'submit';
1585
+ formmethod: 'POST';
1586
+ formaction: string;
1587
+ onclick: (event: Event) => void;
1588
+ };
1589
+ };
1590
+ };
1591
+
1592
+ /**
1593
+ * The return value of a remote `command` function. See [Remote functions](https://svelte.dev/docs/kit/remote-functions#command) for full documentation.
1594
+ */
1595
+ export type RemoteCommand<Input, Output> = (arg: Input) => Promise<Awaited<Output>> & {
1596
+ updates(...queries: Array<RemoteQuery<any> | RemoteQueryOverride>): Promise<Awaited<Output>>;
1597
+ };
1598
+
1599
+ export type RemoteResource<T> = Promise<Awaited<T>> & {
1600
+ /** The error in case the query fails. Most often this is a [`HttpError`](https://svelte.dev/docs/kit/@sveltejs-kit#HttpError) but it isn't guaranteed to be. */
1601
+ get error(): any;
1602
+ /** `true` before the first result is available and during refreshes */
1603
+ get loading(): boolean;
1604
+ } & (
1605
+ | {
1606
+ /** The current value of the query. Undefined until `ready` is `true` */
1607
+ get current(): undefined;
1608
+ ready: false;
1609
+ }
1610
+ | {
1611
+ /** The current value of the query. Undefined until `ready` is `true` */
1612
+ get current(): Awaited<T>;
1613
+ ready: true;
1614
+ }
1615
+ );
1616
+
1617
+ export type RemoteQuery<T> = RemoteResource<T> & {
1618
+ /**
1619
+ * On the client, this function will re-fetch the query from the server.
1620
+ *
1621
+ * On the server, this can be called in the context of a `command` or `form` and the refreshed data will accompany the action response back to the client.
1622
+ * This prevents SvelteKit needing to refresh all queries on the page in a second server round-trip.
1623
+ */
1624
+ refresh(): Promise<void>;
1625
+ /**
1626
+ * Temporarily override the value of a query. This is used with the `updates` method of a [command](https://svelte.dev/docs/kit/remote-functions#command-Single-flight-mutations) or [enhanced form submission](https://svelte.dev/docs/kit/remote-functions#form-enhance) to provide optimistic updates.
1627
+ *
1628
+ * ```svelte
1629
+ * <script>
1630
+ * import { getTodos, addTodo } from './todos.remote.js';
1631
+ * const todos = getTodos();
1632
+ * </script>
1633
+ *
1634
+ * <form {...addTodo.enhance(async ({ data, submit }) => {
1635
+ * await submit().updates(
1636
+ * todos.withOverride((todos) => [...todos, { text: data.get('text') }])
1637
+ * );
1638
+ * }}>
1639
+ * <input type="text" name="text" />
1640
+ * <button type="submit">Add Todo</button>
1641
+ * </form>
1642
+ * ```
1643
+ */
1644
+ withOverride(update: (current: Awaited<T>) => Awaited<T>): RemoteQueryOverride;
1645
+ };
1646
+
1647
+ export interface RemoteQueryOverride {
1648
+ _key: string;
1649
+ release(): void;
1650
+ }
1651
+
1652
+ /**
1653
+ * The return value of a remote `prerender` function. See [Remote functions](https://svelte.dev/docs/kit/remote-functions#prerender) for full documentation.
1654
+ */
1655
+ export type RemotePrerenderFunction<Input, Output> = (arg: Input) => RemoteResource<Output>;
1656
+
1657
+ /**
1658
+ * The return value of a remote `query` function. See [Remote functions](https://svelte.dev/docs/kit/remote-functions#query) for full documentation.
1659
+ */
1660
+ export type RemoteQueryFunction<Input, Output> = (arg: Input) => RemoteQuery<Output>;
1661
+
1502
1662
  export * from './index.js';