@sveltejs/kit 2.48.7 → 2.49.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sveltejs/kit",
3
- "version": "2.48.7",
3
+ "version": "2.49.0",
4
4
  "description": "SvelteKit is the fastest way to build Svelte apps",
5
5
  "keywords": [
6
6
  "framework",
@@ -1,4 +1,6 @@
1
- import { HttpError, Redirect, ActionFailure } from './internal/index.js';
1
+ /** @import { StandardSchemaV1 } from '@standard-schema/spec' */
2
+
3
+ import { HttpError, Redirect, ActionFailure, ValidationError } from './internal/index.js';
2
4
  import { BROWSER, DEV } from 'esm-env';
3
5
  import {
4
6
  add_data_suffix,
@@ -215,6 +217,49 @@ export function isActionFailure(e) {
215
217
  return e instanceof ActionFailure;
216
218
  }
217
219
 
220
+ /**
221
+ * Use this to throw a validation error to imperatively fail form validation.
222
+ * Can be used in combination with `issue` passed to form actions to create field-specific issues.
223
+ *
224
+ * @example
225
+ * ```ts
226
+ * import { invalid } from '@sveltejs/kit';
227
+ * import { form } from '$app/server';
228
+ * import { tryLogin } from '$lib/server/auth';
229
+ * import * as v from 'valibot';
230
+ *
231
+ * export const login = form(
232
+ * v.object({ name: v.string(), _password: v.string() }),
233
+ * async ({ name, _password }) => {
234
+ * const success = tryLogin(name, _password);
235
+ * if (!success) {
236
+ * invalid('Incorrect username or password');
237
+ * }
238
+ *
239
+ * // ...
240
+ * }
241
+ * );
242
+ * ```
243
+ * @param {...(StandardSchemaV1.Issue | string)} issues
244
+ * @returns {never}
245
+ * @since 2.47.3
246
+ */
247
+ export function invalid(...issues) {
248
+ throw new ValidationError(
249
+ issues.map((issue) => (typeof issue === 'string' ? { message: issue } : issue))
250
+ );
251
+ }
252
+
253
+ /**
254
+ * Checks whether this is an validation error thrown by {@link invalid}.
255
+ * @param {unknown} e The object to check.
256
+ * @return {e is import('./public.js').ActionFailure}
257
+ * @since 2.47.3
258
+ */
259
+ export function isValidationError(e) {
260
+ return e instanceof ValidationError;
261
+ }
262
+
218
263
  /**
219
264
  * Strips possible SvelteKit-internal suffixes and trailing slashes from the URL pathname.
220
265
  * Returns the normalized URL as well as a method for adding the potential suffix back
@@ -1,3 +1,5 @@
1
+ /** @import { StandardSchemaV1 } from '@standard-schema/spec' */
2
+
1
3
  export class HttpError {
2
4
  /**
3
5
  * @param {number} status
@@ -62,4 +64,18 @@ export class ActionFailure {
62
64
  }
63
65
  }
64
66
 
67
+ /**
68
+ * Error thrown when form validation fails imperatively
69
+ */
70
+ export class ValidationError extends Error {
71
+ /**
72
+ * @param {StandardSchemaV1.Issue[]} issues
73
+ */
74
+ constructor(issues) {
75
+ super('Validation failed');
76
+ this.name = 'ValidationError';
77
+ this.issues = issues;
78
+ }
79
+ }
80
+
65
81
  export { init_remote_functions } from './remote-functions.js';
@@ -1992,10 +1992,13 @@ type ExtractId<Input> = Input extends { id: infer Id }
1992
1992
  : string | number;
1993
1993
 
1994
1994
  /**
1995
- * Recursively maps an input type to a structure where each field can create a validation issue.
1996
- * This mirrors the runtime behavior of the `invalid` proxy passed to form handlers.
1995
+ * A function and proxy object used to imperatively create validation errors in form handlers.
1996
+ *
1997
+ * Access properties to create field-specific issues: `issue.fieldName('message')`.
1998
+ * The type structure mirrors the input data structure for type-safe field access.
1999
+ * Call `invalid(issue.foo(...), issue.nested.bar(...))` to throw a validation error.
1997
2000
  */
1998
- type InvalidField<T> =
2001
+ export type InvalidField<T> =
1999
2002
  WillRecurseIndefinitely<T> extends true
2000
2003
  ? Record<string | number, any>
2001
2004
  : NonNullable<T> extends string | number | boolean | File
@@ -2011,15 +2014,12 @@ type InvalidField<T> =
2011
2014
  : Record<string, never>;
2012
2015
 
2013
2016
  /**
2014
- * A function and proxy object used to imperatively create validation errors in form handlers.
2015
- *
2016
- * Call `invalid(issue1, issue2, ...issueN)` to throw a validation error.
2017
- * If an issue is a `string`, it applies to the form as a whole (and will show up in `fields.allIssues()`)
2018
- * Access properties to create field-specific issues: `invalid.fieldName('message')`.
2019
- * The type structure mirrors the input data structure for type-safe field access.
2017
+ * A validation error thrown by `invalid`.
2020
2018
  */
2021
- export type Invalid<Input = any> = ((...issues: Array<string | StandardSchemaV1.Issue>) => never) &
2022
- InvalidField<Input>;
2019
+ export interface ValidationError {
2020
+ /** The validation issues */
2021
+ issues: StandardSchemaV1.Issue[];
2022
+ }
2023
2023
 
2024
2024
  /**
2025
2025
  * The return value of a remote `form` function. See [Remote functions](https://svelte.dev/docs/kit/remote-functions#form) for full documentation.
@@ -2067,8 +2067,6 @@ export type RemoteForm<Input extends RemoteFormInput | void, Output> = {
2067
2067
  includeUntouched?: boolean;
2068
2068
  /** Set this to `true` to only run the `preflight` validation. */
2069
2069
  preflightOnly?: boolean;
2070
- /** Perform validation as if the form was submitted by the given button. */
2071
- submitter?: HTMLButtonElement | HTMLInputElement;
2072
2070
  }): Promise<void>;
2073
2071
  /** The result of the form submission */
2074
2072
  get result(): Output | undefined;
@@ -1,10 +1,9 @@
1
- /** @import { RemoteFormInput, RemoteForm } from '@sveltejs/kit' */
1
+ /** @import { RemoteFormInput, RemoteForm, InvalidField } from '@sveltejs/kit' */
2
2
  /** @import { InternalRemoteFormIssue, MaybePromise, RemoteInfo } from 'types' */
3
3
  /** @import { StandardSchemaV1 } from '@standard-schema/spec' */
4
4
  import { get_request_store } from '@sveltejs/kit/internal/server';
5
5
  import { DEV } from 'esm-env';
6
6
  import {
7
- convert_formdata,
8
7
  create_field_proxy,
9
8
  set_nested_value,
10
9
  throw_on_old_property_access,
@@ -13,6 +12,7 @@ import {
13
12
  flatten_issues
14
13
  } from '../../../form-utils.js';
15
14
  import { get_cache, run_remote_function } from './shared.js';
15
+ import { ValidationError } from '@sveltejs/kit/internal';
16
16
 
17
17
  /**
18
18
  * Creates a form object that can be spread onto a `<form>` element.
@@ -21,7 +21,7 @@ import { get_cache, run_remote_function } from './shared.js';
21
21
  *
22
22
  * @template Output
23
23
  * @overload
24
- * @param {(invalid: import('@sveltejs/kit').Invalid<void>) => MaybePromise<Output>} fn
24
+ * @param {() => MaybePromise<Output>} fn
25
25
  * @returns {RemoteForm<void, Output>}
26
26
  * @since 2.27
27
27
  */
@@ -34,7 +34,7 @@ import { get_cache, run_remote_function } from './shared.js';
34
34
  * @template Output
35
35
  * @overload
36
36
  * @param {'unchecked'} validate
37
- * @param {(data: Input, invalid: import('@sveltejs/kit').Invalid<Input>) => MaybePromise<Output>} fn
37
+ * @param {(data: Input, issue: InvalidField<Input>) => MaybePromise<Output>} fn
38
38
  * @returns {RemoteForm<Input, Output>}
39
39
  * @since 2.27
40
40
  */
@@ -47,7 +47,7 @@ import { get_cache, run_remote_function } from './shared.js';
47
47
  * @template Output
48
48
  * @overload
49
49
  * @param {Schema} validate
50
- * @param {(data: StandardSchemaV1.InferOutput<Schema>, invalid: import('@sveltejs/kit').Invalid<StandardSchemaV1.InferInput<Schema>>) => MaybePromise<Output>} fn
50
+ * @param {(data: StandardSchemaV1.InferOutput<Schema>, issue: InvalidField<StandardSchemaV1.InferInput<Schema>>) => MaybePromise<Output>} fn
51
51
  * @returns {RemoteForm<StandardSchemaV1.InferInput<Schema>, Output>}
52
52
  * @since 2.27
53
53
  */
@@ -55,7 +55,7 @@ import { get_cache, run_remote_function } from './shared.js';
55
55
  * @template {RemoteFormInput} Input
56
56
  * @template Output
57
57
  * @param {any} validate_or_fn
58
- * @param {(data_or_invalid: any, invalid?: any) => MaybePromise<Output>} [maybe_fn]
58
+ * @param {(data_or_issue: any, issue?: any) => MaybePromise<Output>} [maybe_fn]
59
59
  * @returns {RemoteForm<Input, Output>}
60
60
  * @since 2.27
61
61
  */
@@ -104,19 +104,7 @@ export function form(validate_or_fn, maybe_fn) {
104
104
  type: 'form',
105
105
  name: '',
106
106
  id: '',
107
- /** @param {FormData} form_data */
108
- fn: async (form_data) => {
109
- const validate_only = form_data.get('sveltekit:validate_only') === 'true';
110
-
111
- let data = maybe_fn ? convert_formdata(form_data) : undefined;
112
-
113
- if (data && data.id === undefined) {
114
- const id = form_data.get('sveltekit:id');
115
- if (typeof id === 'string') {
116
- data.id = JSON.parse(id);
117
- }
118
- }
119
-
107
+ fn: async (data, meta, form_data) => {
120
108
  // TODO 3.0 remove this warning
121
109
  if (DEV && !data) {
122
110
  const error = () => {
@@ -152,12 +140,12 @@ export function form(validate_or_fn, maybe_fn) {
152
140
  const { event, state } = get_request_store();
153
141
  const validated = await schema?.['~standard'].validate(data);
154
142
 
155
- if (validate_only) {
143
+ if (meta.validate_only) {
156
144
  return validated?.issues?.map((issue) => normalize_issue(issue, true)) ?? [];
157
145
  }
158
146
 
159
147
  if (validated?.issues !== undefined) {
160
- handle_issues(output, validated.issues, event.isRemoteRequest, form_data);
148
+ handle_issues(output, validated.issues, form_data);
161
149
  } else {
162
150
  if (validated !== undefined) {
163
151
  data = validated.value;
@@ -165,7 +153,7 @@ export function form(validate_or_fn, maybe_fn) {
165
153
 
166
154
  state.refreshes ??= {};
167
155
 
168
- const invalid = create_invalid();
156
+ const issue = create_issues();
169
157
 
170
158
  try {
171
159
  output.result = await run_remote_function(
@@ -174,11 +162,11 @@ export function form(validate_or_fn, maybe_fn) {
174
162
  true,
175
163
  data,
176
164
  (d) => d,
177
- (data) => (!maybe_fn ? fn(invalid) : fn(data, invalid))
165
+ (data) => (!maybe_fn ? fn() : fn(data, issue))
178
166
  );
179
167
  } catch (e) {
180
168
  if (e instanceof ValidationError) {
181
- handle_issues(output, e.issues, event.isRemoteRequest, form_data);
169
+ handle_issues(output, e.issues, form_data);
182
170
  } else {
183
171
  throw e;
184
172
  }
@@ -297,15 +285,14 @@ export function form(validate_or_fn, maybe_fn) {
297
285
  /**
298
286
  * @param {{ issues?: InternalRemoteFormIssue[], input?: Record<string, any>, result: any }} output
299
287
  * @param {readonly StandardSchemaV1.Issue[]} issues
300
- * @param {boolean} is_remote_request
301
- * @param {FormData} form_data
288
+ * @param {FormData | null} form_data - null if the form is progressively enhanced
302
289
  */
303
- function handle_issues(output, issues, is_remote_request, form_data) {
290
+ function handle_issues(output, issues, form_data) {
304
291
  output.issues = issues.map((issue) => normalize_issue(issue, true));
305
292
 
306
293
  // if it was a progressively-enhanced submission, we don't need
307
294
  // to return the input — it's already there
308
- if (!is_remote_request) {
295
+ if (form_data) {
309
296
  output.input = {};
310
297
 
311
298
  for (let key of form_data.keys()) {
@@ -328,89 +315,72 @@ function handle_issues(output, issues, is_remote_request, form_data) {
328
315
 
329
316
  /**
330
317
  * Creates an invalid function that can be used to imperatively mark form fields as invalid
331
- * @returns {import('@sveltejs/kit').Invalid}
318
+ * @returns {InvalidField<any>}
332
319
  */
333
- function create_invalid() {
334
- /**
335
- * @param {...(string | StandardSchemaV1.Issue)} issues
336
- * @returns {never}
337
- */
338
- function invalid(...issues) {
339
- throw new ValidationError(
340
- issues.map((issue) => {
341
- if (typeof issue === 'string') {
342
- return {
343
- path: [],
344
- message: issue
345
- };
320
+ function create_issues() {
321
+ return /** @type {InvalidField<any>} */ (
322
+ new Proxy(
323
+ /** @param {string} message */
324
+ (message) => {
325
+ // TODO 3.0 remove
326
+ if (typeof message !== 'string') {
327
+ throw new Error(
328
+ '`invalid` should now be imported from `@sveltejs/kit` to throw validation issues. ' +
329
+ "The second parameter provided to the form function (renamed to `issue`) is still used to construct issues, e.g. `invalid(issue.field('message'))`. " +
330
+ 'For more info see https://github.com/sveltejs/kit/pulls/14768'
331
+ );
346
332
  }
347
333
 
348
- return issue;
349
- })
350
- );
351
- }
334
+ return create_issue(message);
335
+ },
336
+ {
337
+ get(target, prop) {
338
+ if (typeof prop === 'symbol') return /** @type {any} */ (target)[prop];
352
339
 
353
- return /** @type {import('@sveltejs/kit').Invalid} */ (
354
- new Proxy(invalid, {
355
- get(target, prop) {
356
- if (typeof prop === 'symbol') return /** @type {any} */ (target)[prop];
357
-
358
- /**
359
- * @param {string} message
360
- * @param {(string | number)[]} path
361
- * @returns {StandardSchemaV1.Issue}
362
- */
363
- const create_issue = (message, path = []) => ({
364
- message,
365
- path
366
- });
367
-
368
- return create_issue_proxy(prop, create_issue, []);
340
+ return create_issue_proxy(prop, []);
341
+ }
369
342
  }
370
- })
343
+ )
371
344
  );
372
- }
373
345
 
374
- /**
375
- * Error thrown when form validation fails imperatively
376
- */
377
- class ValidationError extends Error {
378
346
  /**
379
- * @param {StandardSchemaV1.Issue[]} issues
347
+ * @param {string} message
348
+ * @param {(string | number)[]} path
349
+ * @returns {StandardSchemaV1.Issue}
380
350
  */
381
- constructor(issues) {
382
- super('Validation failed');
383
- this.name = 'ValidationError';
384
- this.issues = issues;
351
+ function create_issue(message, path = []) {
352
+ return {
353
+ message,
354
+ path
355
+ };
385
356
  }
386
- }
387
-
388
- /**
389
- * Creates a proxy that builds up a path and returns a function to create an issue
390
- * @param {string | number} key
391
- * @param {(message: string, path: (string | number)[]) => StandardSchemaV1.Issue} create_issue
392
- * @param {(string | number)[]} path
393
- */
394
- function create_issue_proxy(key, create_issue, path) {
395
- const new_path = [...path, key];
396
357
 
397
358
  /**
398
- * @param {string} message
399
- * @returns {StandardSchemaV1.Issue}
359
+ * Creates a proxy that builds up a path and returns a function to create an issue
360
+ * @param {string | number} key
361
+ * @param {(string | number)[]} path
400
362
  */
401
- const issue_func = (message) => create_issue(message, new_path);
363
+ function create_issue_proxy(key, path) {
364
+ const new_path = [...path, key];
402
365
 
403
- return new Proxy(issue_func, {
404
- get(target, prop) {
405
- if (typeof prop === 'symbol') return /** @type {any} */ (target)[prop];
366
+ /**
367
+ * @param {string} message
368
+ * @returns {StandardSchemaV1.Issue}
369
+ */
370
+ const issue_func = (message) => create_issue(message, new_path);
406
371
 
407
- // Handle array access like invalid.items[0]
408
- if (/^\d+$/.test(prop)) {
409
- return create_issue_proxy(parseInt(prop, 10), create_issue, new_path);
410
- }
372
+ return new Proxy(issue_func, {
373
+ get(target, prop) {
374
+ if (typeof prop === 'symbol') return /** @type {any} */ (target)[prop];
411
375
 
412
- // Handle property access like invalid.field.nested
413
- return create_issue_proxy(prop, create_issue, new_path);
414
- }
415
- });
376
+ // Handle array access like invalid.items[0]
377
+ if (/^\d+$/.test(prop)) {
378
+ return create_issue_proxy(parseInt(prop, 10), new_path);
379
+ }
380
+
381
+ // Handle property access like invalid.field.nested
382
+ return create_issue_proxy(prop, new_path);
383
+ }
384
+ });
385
+ }
416
386
  }
@@ -18,7 +18,9 @@ import {
18
18
  set_nested_value,
19
19
  throw_on_old_property_access,
20
20
  build_path_string,
21
- normalize_issue
21
+ normalize_issue,
22
+ serialize_binary_form,
23
+ BINARY_FORM_CONTENT_TYPE
22
24
  } from '../../form-utils.js';
23
25
 
24
26
  /**
@@ -55,6 +57,7 @@ export function form(id) {
55
57
 
56
58
  /** @param {string | number | boolean} [key] */
57
59
  function create_instance(key) {
60
+ const action_id_without_key = id;
58
61
  const action_id = id + (key != undefined ? `/${JSON.stringify(key)}` : '');
59
62
  const action = '?/remote=' + encodeURIComponent(action_id);
60
63
 
@@ -182,17 +185,18 @@ export function form(id) {
182
185
  try {
183
186
  await Promise.resolve();
184
187
 
185
- if (updates.length > 0) {
186
- data.set('sveltekit:remote_refreshes', JSON.stringify(updates.map((u) => u._key)));
187
- }
188
+ const { blob } = serialize_binary_form(convert(data), {
189
+ remote_refreshes: updates.map((u) => u._key)
190
+ });
188
191
 
189
- const response = await fetch(`${base}/${app_dir}/remote/${action_id}`, {
192
+ const response = await fetch(`${base}/${app_dir}/remote/${action_id_without_key}`, {
190
193
  method: 'POST',
191
- body: data,
192
194
  headers: {
195
+ 'Content-Type': BINARY_FORM_CONTENT_TYPE,
193
196
  'x-sveltekit-pathname': location.pathname,
194
197
  'x-sveltekit-search': location.search
195
- }
198
+ },
199
+ body: blob
196
200
  });
197
201
 
198
202
  if (!response.ok) {
@@ -522,7 +526,7 @@ export function form(id) {
522
526
  },
523
527
  validate: {
524
528
  /** @type {RemoteForm<any, any>['validate']} */
525
- value: async ({ includeUntouched = false, preflightOnly = false, submitter } = {}) => {
529
+ value: async ({ includeUntouched = false, preflightOnly = false } = {}) => {
526
530
  if (!element) return;
527
531
 
528
532
  const id = ++validate_id;
@@ -530,12 +534,18 @@ export function form(id) {
530
534
  // wait a tick in case the user is calling validate() right after set() which takes time to propagate
531
535
  await tick();
532
536
 
533
- const form_data = new FormData(element, submitter);
537
+ const default_submitter = /** @type {HTMLElement | undefined} */ (
538
+ element.querySelector('button:not([type]), [type="submit"]')
539
+ );
540
+
541
+ const form_data = new FormData(element, default_submitter);
534
542
 
535
543
  /** @type {InternalRemoteFormIssue[]} */
536
544
  let array = [];
537
545
 
538
- const validated = await preflight_schema?.['~standard'].validate(convert(form_data));
546
+ const data = convert(form_data);
547
+
548
+ const validated = await preflight_schema?.['~standard'].validate(data);
539
549
 
540
550
  if (validate_id !== id) {
541
551
  return;
@@ -544,11 +554,16 @@ export function form(id) {
544
554
  if (validated?.issues) {
545
555
  array = validated.issues.map((issue) => normalize_issue(issue, false));
546
556
  } else if (!preflightOnly) {
547
- form_data.set('sveltekit:validate_only', 'true');
548
-
549
- const response = await fetch(`${base}/${app_dir}/remote/${action_id}`, {
557
+ const response = await fetch(`${base}/${app_dir}/remote/${action_id_without_key}`, {
550
558
  method: 'POST',
551
- body: form_data
559
+ headers: {
560
+ 'Content-Type': BINARY_FORM_CONTENT_TYPE,
561
+ 'x-sveltekit-pathname': location.pathname,
562
+ 'x-sveltekit-search': location.search
563
+ },
564
+ body: serialize_binary_form(data, {
565
+ validate_only: true
566
+ }).blob
552
567
  });
553
568
 
554
569
  const result = await response.json();
@@ -640,12 +655,6 @@ function clone(element) {
640
655
  */
641
656
  function validate_form_data(form_data, enctype) {
642
657
  for (const key of form_data.keys()) {
643
- if (key.startsWith('sveltekit:')) {
644
- throw new Error(
645
- 'FormData keys starting with `sveltekit:` are reserved for internal use and should not be set manually'
646
- );
647
- }
648
-
649
658
  if (/^\$[.[]?/.test(key)) {
650
659
  throw new Error(
651
660
  '`$` is used to collect all FormData validation issues and cannot be used as the `name` of a form control'
@@ -1,8 +1,10 @@
1
1
  /** @import { RemoteForm } from '@sveltejs/kit' */
2
- /** @import { InternalRemoteFormIssue } from 'types' */
2
+ /** @import { BinaryFormMeta, InternalRemoteFormIssue } from 'types' */
3
3
  /** @import { StandardSchemaV1 } from '@standard-schema/spec' */
4
4
 
5
5
  import { DEV } from 'esm-env';
6
+ import * as devalue from 'devalue';
7
+ import { text_decoder, text_encoder } from './utils.js';
6
8
 
7
9
  /**
8
10
  * Sets a value in a nested object using a path string, mutating the original object
@@ -31,10 +33,6 @@ export function convert_formdata(data) {
31
33
  const result = {};
32
34
 
33
35
  for (let key of data.keys()) {
34
- if (key.startsWith('sveltekit:')) {
35
- continue;
36
- }
37
-
38
36
  const is_array = key.endsWith('[]');
39
37
  /** @type {any[]} */
40
38
  let values = data.getAll(key);
@@ -64,6 +62,344 @@ export function convert_formdata(data) {
64
62
  return result;
65
63
  }
66
64
 
65
+ export const BINARY_FORM_CONTENT_TYPE = 'application/x-sveltekit-formdata';
66
+ const BINARY_FORM_VERSION = 0;
67
+
68
+ /**
69
+ * The binary format is as follows:
70
+ * - 1 byte: Format version
71
+ * - 4 bytes: Length of the header (u32)
72
+ * - 2 bytes: Length of the file offset table (u16)
73
+ * - header: devalue.stringify([data, meta])
74
+ * - file offset table: JSON.stringify([offset1, offset2, ...]) (empty if no files) (offsets start from the end of the table)
75
+ * - file1, file2, ...
76
+ * @param {Record<string, any>} data
77
+ * @param {BinaryFormMeta} meta
78
+ */
79
+ export function serialize_binary_form(data, meta) {
80
+ /** @type {Array<BlobPart>} */
81
+ const blob_parts = [new Uint8Array([BINARY_FORM_VERSION])];
82
+
83
+ /** @type {Array<[file: File, index: number]>} */
84
+ const files = [];
85
+
86
+ if (!meta.remote_refreshes?.length) {
87
+ delete meta.remote_refreshes;
88
+ }
89
+
90
+ const encoded_header = devalue.stringify([data, meta], {
91
+ File: (file) => {
92
+ if (!(file instanceof File)) return;
93
+
94
+ files.push([file, files.length]);
95
+ return [file.name, file.type, file.size, file.lastModified, files.length - 1];
96
+ }
97
+ });
98
+
99
+ const encoded_header_buffer = text_encoder.encode(encoded_header);
100
+
101
+ let encoded_file_offsets = '';
102
+ if (files.length) {
103
+ // Sort small files to the front
104
+ files.sort(([a], [b]) => a.size - b.size);
105
+
106
+ /** @type {Array<number>} */
107
+ const file_offsets = new Array(files.length);
108
+ let start = 0;
109
+ for (const [file, index] of files) {
110
+ file_offsets[index] = start;
111
+ start += file.size;
112
+ }
113
+ encoded_file_offsets = JSON.stringify(file_offsets);
114
+ }
115
+
116
+ const length_buffer = new Uint8Array(4);
117
+ const length_view = new DataView(length_buffer.buffer);
118
+
119
+ length_view.setUint32(0, encoded_header_buffer.byteLength, true);
120
+ blob_parts.push(length_buffer.slice());
121
+
122
+ length_view.setUint16(0, encoded_file_offsets.length, true);
123
+ blob_parts.push(length_buffer.slice(0, 2));
124
+
125
+ blob_parts.push(encoded_header_buffer);
126
+ blob_parts.push(encoded_file_offsets);
127
+
128
+ for (const [file] of files) {
129
+ blob_parts.push(file);
130
+ }
131
+
132
+ return {
133
+ blob: new Blob(blob_parts)
134
+ };
135
+ }
136
+
137
+ /**
138
+ * @param {Request} request
139
+ * @returns {Promise<{ data: Record<string, any>; meta: BinaryFormMeta; form_data: FormData | null }>}
140
+ */
141
+ export async function deserialize_binary_form(request) {
142
+ if (request.headers.get('content-type') !== BINARY_FORM_CONTENT_TYPE) {
143
+ const form_data = await request.formData();
144
+ return { data: convert_formdata(form_data), meta: {}, form_data };
145
+ }
146
+ if (!request.body) {
147
+ throw new Error('Could not deserialize binary form: no body');
148
+ }
149
+
150
+ const reader = request.body.getReader();
151
+
152
+ /** @type {Array<Promise<Uint8Array<ArrayBuffer> | undefined>>} */
153
+ const chunks = [];
154
+
155
+ /**
156
+ * @param {number} index
157
+ * @returns {Promise<Uint8Array<ArrayBuffer> | undefined>}
158
+ */
159
+ async function get_chunk(index) {
160
+ if (index in chunks) return chunks[index];
161
+
162
+ let i = chunks.length;
163
+ while (i <= index) {
164
+ chunks[i] = reader.read().then((chunk) => chunk.value);
165
+ i++;
166
+ }
167
+ return chunks[index];
168
+ }
169
+
170
+ /**
171
+ * @param {number} offset
172
+ * @param {number} length
173
+ * @returns {Promise<Uint8Array | null>}
174
+ */
175
+ async function get_buffer(offset, length) {
176
+ /** @type {Uint8Array} */
177
+ let start_chunk;
178
+ let chunk_start = 0;
179
+ /** @type {number} */
180
+ let chunk_index;
181
+ for (chunk_index = 0; ; chunk_index++) {
182
+ const chunk = await get_chunk(chunk_index);
183
+ if (!chunk) return null;
184
+
185
+ const chunk_end = chunk_start + chunk.byteLength;
186
+ // If this chunk contains the target offset
187
+ if (offset >= chunk_start && offset < chunk_end) {
188
+ start_chunk = chunk;
189
+ break;
190
+ }
191
+ chunk_start = chunk_end;
192
+ }
193
+ // If the buffer is completely contained in one chunk, do a subarray
194
+ if (offset + length <= chunk_start + start_chunk.byteLength) {
195
+ return start_chunk.subarray(offset - chunk_start, offset + length - chunk_start);
196
+ }
197
+ // Otherwise, copy the data into a new buffer
198
+ const buffer = new Uint8Array(length);
199
+ buffer.set(start_chunk.subarray(offset - chunk_start));
200
+ let cursor = start_chunk.byteLength - offset + chunk_start;
201
+ while (cursor < length) {
202
+ chunk_index++;
203
+ let chunk = await get_chunk(chunk_index);
204
+ if (!chunk) return null;
205
+ if (chunk.byteLength > length - cursor) {
206
+ chunk = chunk.subarray(0, length - cursor);
207
+ }
208
+ buffer.set(chunk, cursor);
209
+ cursor += chunk.byteLength;
210
+ }
211
+
212
+ return buffer;
213
+ }
214
+
215
+ const header = await get_buffer(0, 1 + 4 + 2);
216
+ if (!header) throw new Error('Could not deserialize binary form: too short');
217
+
218
+ if (header[0] !== BINARY_FORM_VERSION) {
219
+ throw new Error(
220
+ `Could not deserialize binary form: got version ${header[0]}, expected version ${BINARY_FORM_VERSION}`
221
+ );
222
+ }
223
+ const header_view = new DataView(header.buffer);
224
+ const data_length = header_view.getUint32(1, true);
225
+ const file_offsets_length = header_view.getUint16(5, true);
226
+
227
+ // Read the form data
228
+ const data_buffer = await get_buffer(1 + 4 + 2, data_length);
229
+ if (!data_buffer) throw new Error('Could not deserialize binary form: data too short');
230
+
231
+ /** @type {Array<number>} */
232
+ let file_offsets;
233
+ /** @type {number} */
234
+ let files_start_offset;
235
+ if (file_offsets_length > 0) {
236
+ // Read the file offset table
237
+ const file_offsets_buffer = await get_buffer(1 + 4 + 2 + data_length, file_offsets_length);
238
+ if (!file_offsets_buffer)
239
+ throw new Error('Could not deserialize binary form: file offset table too short');
240
+
241
+ file_offsets = /** @type {Array<number>} */ (
242
+ JSON.parse(text_decoder.decode(file_offsets_buffer))
243
+ );
244
+ files_start_offset = 1 + 4 + 2 + data_length + file_offsets_length;
245
+ }
246
+
247
+ const [data, meta] = devalue.parse(text_decoder.decode(data_buffer), {
248
+ File: ([name, type, size, last_modified, index]) => {
249
+ return new Proxy(
250
+ new LazyFile(
251
+ name,
252
+ type,
253
+ size,
254
+ last_modified,
255
+ get_chunk,
256
+ files_start_offset + file_offsets[index]
257
+ ),
258
+ {
259
+ getPrototypeOf() {
260
+ // Trick validators into thinking this is a normal File
261
+ return File.prototype;
262
+ }
263
+ }
264
+ );
265
+ }
266
+ });
267
+
268
+ // Read the request body asyncronously so it doesn't stall
269
+ void (async () => {
270
+ let has_more = true;
271
+ while (has_more) {
272
+ const chunk = await get_chunk(chunks.length);
273
+ has_more = !!chunk;
274
+ }
275
+ })();
276
+
277
+ return { data, meta, form_data: null };
278
+ }
279
+
280
+ /** @implements {File} */
281
+ class LazyFile {
282
+ /** @type {(index: number) => Promise<Uint8Array<ArrayBuffer> | undefined>} */
283
+ #get_chunk;
284
+ /** @type {number} */
285
+ #offset;
286
+ /**
287
+ * @param {string} name
288
+ * @param {string} type
289
+ * @param {number} size
290
+ * @param {number} last_modified
291
+ * @param {(index: number) => Promise<Uint8Array<ArrayBuffer> | undefined>} get_chunk
292
+ * @param {number} offset
293
+ */
294
+ constructor(name, type, size, last_modified, get_chunk, offset) {
295
+ this.name = name;
296
+ this.type = type;
297
+ this.size = size;
298
+ this.lastModified = last_modified;
299
+ this.webkitRelativePath = '';
300
+ this.#get_chunk = get_chunk;
301
+ this.#offset = offset;
302
+
303
+ // TODO - hacky, required for private members to be accessed on proxy
304
+ this.arrayBuffer = this.arrayBuffer.bind(this);
305
+ this.bytes = this.bytes.bind(this);
306
+ this.slice = this.slice.bind(this);
307
+ this.stream = this.stream.bind(this);
308
+ this.text = this.text.bind(this);
309
+ }
310
+ /** @type {ArrayBuffer | undefined} */
311
+ #buffer;
312
+ async arrayBuffer() {
313
+ this.#buffer ??= await new Response(this.stream()).arrayBuffer();
314
+ return this.#buffer;
315
+ }
316
+ async bytes() {
317
+ return new Uint8Array(await this.arrayBuffer());
318
+ }
319
+ /**
320
+ * @param {number=} start
321
+ * @param {number=} end
322
+ * @param {string=} contentType
323
+ */
324
+ slice(start = 0, end = this.size, contentType = this.type) {
325
+ // https://github.com/nodejs/node/blob/a5f3cd8cb5ba9e7911d93c5fd3ebc6d781220dd8/lib/internal/blob.js#L240
326
+ if (start < 0) {
327
+ start = Math.max(this.size + start, 0);
328
+ } else {
329
+ start = Math.min(start, this.size);
330
+ }
331
+
332
+ if (end < 0) {
333
+ end = Math.max(this.size + end, 0);
334
+ } else {
335
+ end = Math.min(end, this.size);
336
+ }
337
+ const size = Math.max(end - start, 0);
338
+ const file = new LazyFile(
339
+ this.name,
340
+ contentType,
341
+ size,
342
+ this.lastModified,
343
+ this.#get_chunk,
344
+ this.#offset + start
345
+ );
346
+
347
+ return file;
348
+ }
349
+ stream() {
350
+ let cursor = 0;
351
+ let chunk_index = 0;
352
+ return new ReadableStream({
353
+ start: async (controller) => {
354
+ let chunk_start = 0;
355
+ let start_chunk = null;
356
+ for (chunk_index = 0; ; chunk_index++) {
357
+ const chunk = await this.#get_chunk(chunk_index);
358
+ if (!chunk) return null;
359
+
360
+ const chunk_end = chunk_start + chunk.byteLength;
361
+ // If this chunk contains the target offset
362
+ if (this.#offset >= chunk_start && this.#offset < chunk_end) {
363
+ start_chunk = chunk;
364
+ break;
365
+ }
366
+ chunk_start = chunk_end;
367
+ }
368
+ // If the buffer is completely contained in one chunk, do a subarray
369
+ if (this.#offset + this.size <= chunk_start + start_chunk.byteLength) {
370
+ controller.enqueue(
371
+ start_chunk.subarray(this.#offset - chunk_start, this.#offset + this.size - chunk_start)
372
+ );
373
+ controller.close();
374
+ } else {
375
+ controller.enqueue(start_chunk.subarray(this.#offset - chunk_start));
376
+ cursor = start_chunk.byteLength - this.#offset + chunk_start;
377
+ }
378
+ },
379
+ pull: async (controller) => {
380
+ chunk_index++;
381
+ let chunk = await this.#get_chunk(chunk_index);
382
+ if (!chunk) {
383
+ controller.error('Could not deserialize binary form: incomplete file data');
384
+ controller.close();
385
+ return;
386
+ }
387
+ if (chunk.byteLength > this.size - cursor) {
388
+ chunk = chunk.subarray(0, this.size - cursor);
389
+ }
390
+ controller.enqueue(chunk);
391
+ cursor += chunk.byteLength;
392
+ if (cursor >= this.size) {
393
+ controller.close();
394
+ }
395
+ }
396
+ });
397
+ }
398
+ async text() {
399
+ return text_decoder.decode(await this.arrayBuffer());
400
+ }
401
+ }
402
+
67
403
  const path_regex = /^[a-zA-Z_$]\w*(\.[a-zA-Z_$]\w*|\[\d+\])*$/;
68
404
 
69
405
  /**
@@ -12,6 +12,7 @@ import { normalize_error } from '../../utils/error.js';
12
12
  import { check_incorrect_fail_use } from './page/actions.js';
13
13
  import { DEV } from 'esm-env';
14
14
  import { record_span } from '../telemetry/record_span.js';
15
+ import { deserialize_binary_form } from '../form-utils.js';
15
16
 
16
17
  /** @type {typeof handle_remote_call_internal} */
17
18
  export async function handle_remote_call(event, state, options, manifest, id) {
@@ -116,25 +117,22 @@ async function handle_remote_call_internal(event, state, options, manifest, id)
116
117
  );
117
118
  }
118
119
 
119
- const form_data = await event.request.formData();
120
- form_client_refreshes = /** @type {string[]} */ (
121
- JSON.parse(/** @type {string} */ (form_data.get('sveltekit:remote_refreshes')) ?? '[]')
122
- );
123
- form_data.delete('sveltekit:remote_refreshes');
120
+ const { data, meta, form_data } = await deserialize_binary_form(event.request);
124
121
 
125
122
  // If this is a keyed form instance (created via form.for(key)), add the key to the form data (unless already set)
126
- if (additional_args) {
127
- form_data.set('sveltekit:id', decodeURIComponent(additional_args));
123
+ // Note that additional_args will only be set if the form is not enhanced, as enhanced forms transfer the key inside `data`.
124
+ if (additional_args && !('id' in data)) {
125
+ data.id = JSON.parse(decodeURIComponent(additional_args));
128
126
  }
129
127
 
130
128
  const fn = info.fn;
131
- const data = await with_request_store({ event, state }, () => fn(form_data));
129
+ const result = await with_request_store({ event, state }, () => fn(data, meta, form_data));
132
130
 
133
131
  return json(
134
132
  /** @type {RemoteFunctionResponse} */ ({
135
133
  type: 'result',
136
- result: stringify(data, transport),
137
- refreshes: data.issues ? {} : await serialize_refreshes(form_client_refreshes)
134
+ result: stringify(result, transport),
135
+ refreshes: result.issues ? undefined : await serialize_refreshes(meta.remote_refreshes)
138
136
  })
139
137
  );
140
138
  }
@@ -178,7 +176,7 @@ async function handle_remote_call_internal(event, state, options, manifest, id)
178
176
  /** @type {RemoteFunctionResponse} */ ({
179
177
  type: 'redirect',
180
178
  location: error.location,
181
- refreshes: await serialize_refreshes(form_client_refreshes ?? [])
179
+ refreshes: await serialize_refreshes(form_client_refreshes)
182
180
  })
183
181
  );
184
182
  }
@@ -204,24 +202,26 @@ async function handle_remote_call_internal(event, state, options, manifest, id)
204
202
  }
205
203
 
206
204
  /**
207
- * @param {string[]} client_refreshes
205
+ * @param {string[]=} client_refreshes
208
206
  */
209
207
  async function serialize_refreshes(client_refreshes) {
210
208
  const refreshes = state.refreshes ?? {};
211
209
 
212
- for (const key of client_refreshes) {
213
- if (refreshes[key] !== undefined) continue;
210
+ if (client_refreshes) {
211
+ for (const key of client_refreshes) {
212
+ if (refreshes[key] !== undefined) continue;
214
213
 
215
- const [hash, name, payload] = key.split('/');
214
+ const [hash, name, payload] = key.split('/');
216
215
 
217
- const loader = manifest._.remotes[hash];
218
- const fn = (await loader?.())?.default?.[name];
216
+ const loader = manifest._.remotes[hash];
217
+ const fn = (await loader?.())?.default?.[name];
219
218
 
220
- if (!fn) error(400, 'Bad Request');
219
+ if (!fn) error(400, 'Bad Request');
221
220
 
222
- refreshes[key] = with_request_store({ event, state }, () =>
223
- fn(parse_remote_arg(payload, transport))
224
- );
221
+ refreshes[key] = with_request_store({ event, state }, () =>
222
+ fn(parse_remote_arg(payload, transport))
223
+ );
224
+ }
225
225
  }
226
226
 
227
227
  if (Object.keys(refreshes).length === 0) {
@@ -291,16 +291,14 @@ async function handle_remote_form_post_internal(event, state, manifest, id) {
291
291
  }
292
292
 
293
293
  try {
294
- const form_data = await event.request.formData();
295
294
  const fn = /** @type {RemoteInfo & { type: 'form' }} */ (/** @type {any} */ (form).__).fn;
296
295
 
297
- // If this is a keyed form instance (created via form.for(key)), add the key to the form data (unless already set)
298
- if (action_id && !form_data.has('id')) {
299
- // The action_id is URL-encoded JSON, decode and parse it
300
- form_data.set('sveltekit:id', decodeURIComponent(action_id));
296
+ const { data, meta, form_data } = await deserialize_binary_form(event.request);
297
+ if (action_id && !('id' in data)) {
298
+ data.id = JSON.parse(decodeURIComponent(action_id));
301
299
  }
302
300
 
303
- await with_request_store({ event, state }, () => fn(form_data));
301
+ await with_request_store({ event, state }, () => fn(data, meta, form_data));
304
302
 
305
303
  // We don't want the data to appear on `let { form } = $props()`, which is why we're not returning it.
306
304
  // It is instead available on `myForm.result`, setting of which happens within the remote `form` function.
@@ -552,6 +552,11 @@ export type ValidatedKitConfig = Omit<RecursiveRequired<KitConfig>, 'adapter'> &
552
552
  adapter?: Adapter;
553
553
  };
554
554
 
555
+ export type BinaryFormMeta = {
556
+ remote_refreshes?: string[];
557
+ validate_only?: boolean;
558
+ };
559
+
555
560
  export type RemoteInfo =
556
561
  | {
557
562
  type: 'query' | 'command';
@@ -572,7 +577,11 @@ export type RemoteInfo =
572
577
  type: 'form';
573
578
  id: string;
574
579
  name: string;
575
- fn: (data: FormData) => Promise<any>;
580
+ fn: (
581
+ body: Record<string, any>,
582
+ meta: BinaryFormMeta,
583
+ form_data: FormData | null
584
+ ) => Promise<any>;
576
585
  }
577
586
  | {
578
587
  type: 'prerender';
package/src/utils/http.js CHANGED
@@ -1,3 +1,5 @@
1
+ import { BINARY_FORM_CONTENT_TYPE } from '../runtime/form-utils.js';
2
+
1
3
  /**
2
4
  * Given an Accept header and a list of possible content types, pick
3
5
  * the most suitable one to respond with
@@ -74,6 +76,7 @@ export function is_form_content_type(request) {
74
76
  request,
75
77
  'application/x-www-form-urlencoded',
76
78
  'multipart/form-data',
77
- 'text/plain'
79
+ 'text/plain',
80
+ BINARY_FORM_CONTENT_TYPE
78
81
  );
79
82
  }
package/src/version.js CHANGED
@@ -1,4 +1,4 @@
1
1
  // generated during release, do not modify
2
2
 
3
3
  /** @type {string} */
4
- export const VERSION = '2.48.7';
4
+ export const VERSION = '2.49.0';
package/types/index.d.ts CHANGED
@@ -1968,10 +1968,13 @@ declare module '@sveltejs/kit' {
1968
1968
  : string | number;
1969
1969
 
1970
1970
  /**
1971
- * Recursively maps an input type to a structure where each field can create a validation issue.
1972
- * This mirrors the runtime behavior of the `invalid` proxy passed to form handlers.
1971
+ * A function and proxy object used to imperatively create validation errors in form handlers.
1972
+ *
1973
+ * Access properties to create field-specific issues: `issue.fieldName('message')`.
1974
+ * The type structure mirrors the input data structure for type-safe field access.
1975
+ * Call `invalid(issue.foo(...), issue.nested.bar(...))` to throw a validation error.
1973
1976
  */
1974
- type InvalidField<T> =
1977
+ export type InvalidField<T> =
1975
1978
  WillRecurseIndefinitely<T> extends true
1976
1979
  ? Record<string | number, any>
1977
1980
  : NonNullable<T> extends string | number | boolean | File
@@ -1987,15 +1990,12 @@ declare module '@sveltejs/kit' {
1987
1990
  : Record<string, never>;
1988
1991
 
1989
1992
  /**
1990
- * A function and proxy object used to imperatively create validation errors in form handlers.
1991
- *
1992
- * Call `invalid(issue1, issue2, ...issueN)` to throw a validation error.
1993
- * If an issue is a `string`, it applies to the form as a whole (and will show up in `fields.allIssues()`)
1994
- * Access properties to create field-specific issues: `invalid.fieldName('message')`.
1995
- * The type structure mirrors the input data structure for type-safe field access.
1993
+ * A validation error thrown by `invalid`.
1996
1994
  */
1997
- export type Invalid<Input = any> = ((...issues: Array<string | StandardSchemaV1.Issue>) => never) &
1998
- InvalidField<Input>;
1995
+ export interface ValidationError {
1996
+ /** The validation issues */
1997
+ issues: StandardSchemaV1.Issue[];
1998
+ }
1999
1999
 
2000
2000
  /**
2001
2001
  * The return value of a remote `form` function. See [Remote functions](https://svelte.dev/docs/kit/remote-functions#form) for full documentation.
@@ -2043,8 +2043,6 @@ declare module '@sveltejs/kit' {
2043
2043
  includeUntouched?: boolean;
2044
2044
  /** Set this to `true` to only run the `preflight` validation. */
2045
2045
  preflightOnly?: boolean;
2046
- /** Perform validation as if the form was submitted by the given button. */
2047
- submitter?: HTMLButtonElement | HTMLInputElement;
2048
2046
  }): Promise<void>;
2049
2047
  /** The result of the form submission */
2050
2048
  get result(): Output | undefined;
@@ -2702,6 +2700,38 @@ declare module '@sveltejs/kit' {
2702
2700
  * @param e The object to check.
2703
2701
  * */
2704
2702
  export function isActionFailure(e: unknown): e is ActionFailure;
2703
+ /**
2704
+ * Use this to throw a validation error to imperatively fail form validation.
2705
+ * Can be used in combination with `issue` passed to form actions to create field-specific issues.
2706
+ *
2707
+ * @example
2708
+ * ```ts
2709
+ * import { invalid } from '@sveltejs/kit';
2710
+ * import { form } from '$app/server';
2711
+ * import { tryLogin } from '$lib/server/auth';
2712
+ * import * as v from 'valibot';
2713
+ *
2714
+ * export const login = form(
2715
+ * v.object({ name: v.string(), _password: v.string() }),
2716
+ * async ({ name, _password }) => {
2717
+ * const success = tryLogin(name, _password);
2718
+ * if (!success) {
2719
+ * invalid('Incorrect username or password');
2720
+ * }
2721
+ *
2722
+ * // ...
2723
+ * }
2724
+ * );
2725
+ * ```
2726
+ * @since 2.47.3
2727
+ */
2728
+ export function invalid(...issues: (StandardSchemaV1.Issue | string)[]): never;
2729
+ /**
2730
+ * Checks whether this is an validation error thrown by {@link invalid}.
2731
+ * @param e The object to check.
2732
+ * @since 2.47.3
2733
+ */
2734
+ export function isValidationError(e: unknown): e is ActionFailure;
2705
2735
  /**
2706
2736
  * Strips possible SvelteKit-internal suffixes and trailing slashes from the URL pathname.
2707
2737
  * Returns the normalized URL as well as a method for adding the potential suffix back
@@ -3134,7 +3164,7 @@ declare module '$app/paths' {
3134
3164
  }
3135
3165
 
3136
3166
  declare module '$app/server' {
3137
- import type { RequestEvent, RemoteCommand, RemoteForm, RemoteFormInput, RemotePrerenderFunction, RemoteQueryFunction } from '@sveltejs/kit';
3167
+ import type { RequestEvent, RemoteCommand, RemoteForm, RemoteFormInput, InvalidField, RemotePrerenderFunction, RemoteQueryFunction } from '@sveltejs/kit';
3138
3168
  import type { StandardSchemaV1 } from '@standard-schema/spec';
3139
3169
  /**
3140
3170
  * Read the contents of an imported asset from the filesystem
@@ -3188,7 +3218,7 @@ declare module '$app/server' {
3188
3218
  *
3189
3219
  * @since 2.27
3190
3220
  */
3191
- export function form<Output>(fn: (invalid: import("@sveltejs/kit").Invalid<void>) => MaybePromise<Output>): RemoteForm<void, Output>;
3221
+ export function form<Output>(fn: () => MaybePromise<Output>): RemoteForm<void, Output>;
3192
3222
  /**
3193
3223
  * Creates a form object that can be spread onto a `<form>` element.
3194
3224
  *
@@ -3196,7 +3226,7 @@ declare module '$app/server' {
3196
3226
  *
3197
3227
  * @since 2.27
3198
3228
  */
3199
- export function form<Input extends RemoteFormInput, Output>(validate: "unchecked", fn: (data: Input, invalid: import("@sveltejs/kit").Invalid<Input>) => MaybePromise<Output>): RemoteForm<Input, Output>;
3229
+ export function form<Input extends RemoteFormInput, Output>(validate: "unchecked", fn: (data: Input, issue: InvalidField<Input>) => MaybePromise<Output>): RemoteForm<Input, Output>;
3200
3230
  /**
3201
3231
  * Creates a form object that can be spread onto a `<form>` element.
3202
3232
  *
@@ -3204,7 +3234,7 @@ declare module '$app/server' {
3204
3234
  *
3205
3235
  * @since 2.27
3206
3236
  */
3207
- export function form<Schema extends StandardSchemaV1<RemoteFormInput, Record<string, any>>, Output>(validate: Schema, fn: (data: StandardSchemaV1.InferOutput<Schema>, invalid: import("@sveltejs/kit").Invalid<StandardSchemaV1.InferInput<Schema>>) => MaybePromise<Output>): RemoteForm<StandardSchemaV1.InferInput<Schema>, Output>;
3237
+ export function form<Schema extends StandardSchemaV1<RemoteFormInput, Record<string, any>>, Output>(validate: Schema, fn: (data: StandardSchemaV1.InferOutput<Schema>, issue: InvalidField<StandardSchemaV1.InferInput<Schema>>) => MaybePromise<Output>): RemoteForm<StandardSchemaV1.InferInput<Schema>, Output>;
3208
3238
  /**
3209
3239
  * Creates a remote prerender function. When called from the browser, the function will be invoked on the server via a `fetch` call.
3210
3240
  *
@@ -75,7 +75,7 @@
75
75
  "RemoteFormIssue",
76
76
  "ExtractId",
77
77
  "InvalidField",
78
- "Invalid",
78
+ "ValidationError",
79
79
  "RemoteForm",
80
80
  "RemoteCommand",
81
81
  "RemoteResource",
@@ -128,6 +128,8 @@
128
128
  "json",
129
129
  "text",
130
130
  "isActionFailure",
131
+ "invalid",
132
+ "isValidationError",
131
133
  "normalizeUrl",
132
134
  "VERSION",
133
135
  "sequence",
@@ -213,6 +215,6 @@
213
215
  null,
214
216
  null
215
217
  ],
216
- "mappings": "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",
218
+ "mappings": "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",
217
219
  "ignoreList": []
218
220
  }