react-f0rm 1.4.0 → 1.5.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/README.md +17 -4
- package/dist/array-Bu7W8BSz.d.ts +54 -0
- package/dist/devtools/index.cjs.js +1 -1
- package/dist/devtools/index.cjs.js.map +1 -1
- package/dist/devtools/index.d.cts +8 -18
- package/dist/devtools/index.d.mts +8 -18
- package/dist/devtools/index.d.ts +8 -18
- package/dist/devtools/index.mjs +1 -1
- package/dist/devtools/index.mjs.map +1 -1
- package/dist/errors-DA4ReEd9.mjs +2 -0
- package/dist/errors-DA4ReEd9.mjs.map +1 -0
- package/dist/errors-TzyWwBfw.cjs.js +2 -0
- package/dist/errors-TzyWwBfw.cjs.js.map +1 -0
- package/dist/index.cjs.js +1 -1
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.cts +347 -927
- package/dist/index.d.mts +347 -927
- package/dist/index.d.ts +347 -927
- package/dist/index.mjs +1 -1
- package/dist/index.mjs.map +1 -1
- package/dist/index.umd.js +538 -451
- package/dist/index.umd.js.map +1 -1
- package/dist/index.umd.min.js +2 -2
- package/dist/index.umd.min.js.map +1 -1
- package/dist/persist.cjs.js +1 -1
- package/dist/persist.cjs.js.map +1 -1
- package/dist/persist.d.cts +9 -30
- package/dist/persist.d.mts +9 -30
- package/dist/persist.d.ts +9 -30
- package/dist/persist.mjs +1 -1
- package/dist/persist.mjs.map +1 -1
- package/dist/resolvers/standard-schema.cjs.js +1 -1
- package/dist/resolvers/standard-schema.d.cts +1 -1
- package/dist/resolvers/standard-schema.d.mts +1 -1
- package/dist/resolvers/standard-schema.d.ts +1 -1
- package/dist/resolvers/standard-schema.mjs +1 -1
- package/dist/resolvers/yup.cjs.js +1 -1
- package/dist/resolvers/yup.mjs +1 -1
- package/dist/resolvers/zod.cjs.js +1 -1
- package/dist/resolvers/zod.cjs.js.map +1 -1
- package/dist/resolvers/zod.d.cts +30 -2
- package/dist/resolvers/zod.d.mts +30 -2
- package/dist/resolvers/zod.d.ts +30 -2
- package/dist/resolvers/zod.mjs +1 -1
- package/dist/resolvers/zod.mjs.map +1 -1
- package/dist/server/index.cjs.js +1 -1
- package/dist/server/index.cjs.js.map +1 -1
- package/dist/server/index.d.cts +24 -92
- package/dist/server/index.d.mts +24 -92
- package/dist/server/index.d.ts +24 -92
- package/dist/server/index.mjs +1 -1
- package/dist/server/index.mjs.map +1 -1
- package/dist/standard-schema-BAaTmAHh.d.ts +682 -0
- package/dist/standardSchema-5WezjHlp.mjs +2 -0
- package/dist/standardSchema-5WezjHlp.mjs.map +1 -0
- package/dist/standardSchema-DINHlsYR.cjs.js +2 -0
- package/dist/standardSchema-DINHlsYR.cjs.js.map +1 -0
- package/dist/validate-2pX-N1O6.cjs.js +2 -0
- package/dist/validate-2pX-N1O6.cjs.js.map +1 -0
- package/dist/validate-C0HOsP9v.mjs +2 -0
- package/dist/validate-C0HOsP9v.mjs.map +1 -0
- package/dist/values-BbPnLByD.cjs.js +2 -0
- package/dist/values-BbPnLByD.cjs.js.map +1 -0
- package/dist/values-CHsmcZk4.mjs +2 -0
- package/dist/values-CHsmcZk4.mjs.map +1 -0
- package/package.json +6 -4
- package/dist/array-3hAjl6Bz.d.ts +0 -160
- package/dist/errors-8oPux7GR.cjs.js +0 -2
- package/dist/errors-8oPux7GR.cjs.js.map +0 -1
- package/dist/errors-ClH3eV1R.mjs +0 -2
- package/dist/errors-ClH3eV1R.mjs.map +0 -1
- package/dist/standard-schema-CYbnugL7.d.ts +0 -1184
- package/dist/standardSchema-BpZvg0tZ.mjs +0 -2
- package/dist/standardSchema-BpZvg0tZ.mjs.map +0 -1
- package/dist/standardSchema-CxV_DhBO.cjs.js +0 -2
- package/dist/standardSchema-CxV_DhBO.cjs.js.map +0 -1
- package/dist/validate-BEjNsNvd.mjs +0 -2
- package/dist/validate-BEjNsNvd.mjs.map +0 -1
- package/dist/validate-BvN6hiEG.cjs.js +0 -2
- package/dist/validate-BvN6hiEG.cjs.js.map +0 -1
- package/dist/values-Bod74Kzu.mjs +0 -2
- package/dist/values-Bod74Kzu.mjs.map +0 -1
- package/dist/values-DKpOCD5J.cjs.js +0 -2
- package/dist/values-DKpOCD5J.cjs.js.map +0 -1
package/dist/server/index.d.cts
CHANGED
|
@@ -1,105 +1,37 @@
|
|
|
1
1
|
import { FieldErrorEntry, Options } from '../index.js';
|
|
2
|
-
export {
|
|
3
|
-
export { a as appendValue, i as insertValue, m as moveValue, p as prependValue, r as removeValue, b as replaceValues, s as swapValues, u as updateValue } from '../array-
|
|
2
|
+
export { c as VALIDATION_OUTCOME, d as ValidationOutcome } from '../standard-schema-BAaTmAHh.js';
|
|
3
|
+
export { a as appendValue, i as insertValue, m as moveValue, p as prependValue, r as removeValue, b as replaceValues, s as swapValues, u as updateValue } from '../array-Bu7W8BSz.js';
|
|
4
4
|
import '@for-fun/event-emitter';
|
|
5
5
|
|
|
6
|
-
/** The outcome of {@link validateValues}: the
|
|
7
|
-
*
|
|
8
|
-
* parsed values), and every error the round wrote as flat entries. */
|
|
6
|
+
/** The outcome of {@link validateValues}: `valid`, the (schema-coerced)
|
|
7
|
+
* values, and the round's flat error entries. */
|
|
9
8
|
type ValidateValuesResult<T extends Record<string, any> = any> = {
|
|
10
|
-
/** Whether the round landed no errors
|
|
11
|
-
*
|
|
12
|
-
* `ensureValidate`, server callers learn validity from data instead of
|
|
13
|
-
* catching, because both branches are interesting on the server
|
|
14
|
-
* (persist vs. bounce back to the client). */
|
|
9
|
+
/** Whether the round landed no errors. An invalid payload is data, not
|
|
10
|
+
* a rejection — both branches are interesting server-side. */
|
|
15
11
|
valid: boolean;
|
|
16
|
-
/** The values after the round
|
|
17
|
-
*
|
|
18
|
-
* baseline `getValues` layers over the input — schema coerce/transform
|
|
19
|
-
* output included — so this is the tree to persist or feed onward, not
|
|
20
|
-
* necessarily the object passed in. Deep-equals the input otherwise. */
|
|
12
|
+
/** The values after the round: parsed output when the validator
|
|
13
|
+
* returned a branded outcome, the input otherwise. */
|
|
21
14
|
values: T;
|
|
22
|
-
/** Every error
|
|
23
|
-
*
|
|
24
|
-
* Feed it to `setServerErrors` to land a failed round back on the
|
|
25
|
-
* client form (the Server Actions bridge; see the docs' Server Actions
|
|
26
|
-
* guide). */
|
|
15
|
+
/** Every error flattened to {path, type, message}; feed to
|
|
16
|
+
* `setServerErrors` to land it back on the client form. */
|
|
27
17
|
errors: FieldErrorEntry[];
|
|
28
18
|
};
|
|
29
|
-
/**
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
* `<Form action>` prop and `validateValues`: the validated (schema-coerced)
|
|
33
|
-
* values tree lands in the server action as FormData, files included.
|
|
34
|
-
*
|
|
35
|
-
* Array values become multiple entries under the same key (FormData's
|
|
36
|
-
* native multi-value convention); File values keep their name; Dates
|
|
37
|
-
* become ISO strings; plain objects JSON.stringify; null/undefined are
|
|
38
|
-
* skipped.
|
|
39
|
-
*/
|
|
19
|
+
/** Convert values into FormData (Server Actions/multipart shape). Arrays
|
|
20
|
+
* become multiple entries per key; Files keep names; Dates → ISO; objects
|
|
21
|
+
* JSON.stringify; null/undefined skipped. */
|
|
40
22
|
declare function formDataFromValues(values: Record<string, any>): FormData;
|
|
41
|
-
/**
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
* Multiple entries under one key collect into an array (FormData's
|
|
47
|
-
* multi-value convention, which {@link formDataFromValues} uses for
|
|
48
|
-
* arrays); a single entry stays scalar. String values that look like JSON
|
|
49
|
-
* (`{…}`, `[…]`) parse back into objects/arrays — the shape plain objects
|
|
50
|
-
* take through {@link formDataFromValues} — while everything else stays a
|
|
51
|
-
* string, exactly like a native form submit: scalar types round-trip
|
|
52
|
-
* through String() (numbers, booleans, ISO dates), so let a schema coerce
|
|
53
|
-
* them back (`z.coerce.number()` style). File values pass through
|
|
54
|
-
* unchanged; keys missing from the FormData are omitted, matching the
|
|
55
|
-
* null/undefined skipping {@link formDataFromValues} does.
|
|
56
|
-
*
|
|
57
|
-
* Pairs with {@link validateValues} to close the Server Action loop
|
|
58
|
-
* without hand-rolled `.get()` calls:
|
|
59
|
-
*
|
|
60
|
-
* export async function register(formData: FormData) {
|
|
61
|
-
* const result = await validateValues(valuesFromFormData(formData), {
|
|
62
|
-
* validate: standardSchemaFormValidator(schema)
|
|
63
|
-
* });
|
|
64
|
-
* if (!result.valid) return {errors: result.errors};
|
|
65
|
-
* await db.insert(result.values);
|
|
66
|
-
* }
|
|
67
|
-
*/
|
|
23
|
+
/** Convert FormData back into a values object — the inverse of
|
|
24
|
+
* {@link formDataFromValues}. Multiple entries under a key collect into
|
|
25
|
+
* an array, JSON-looking strings parse back, Files pass through, and
|
|
26
|
+
* missing keys are omitted. */
|
|
68
27
|
declare function valuesFromFormData(formData: FormData): Record<string, any>;
|
|
69
|
-
/**
|
|
70
|
-
*
|
|
71
|
-
*
|
|
72
|
-
*
|
|
73
|
-
*
|
|
74
|
-
*
|
|
75
|
-
*
|
|
76
|
-
* `validateDebounce` window, so a single `await` drains the whole round —
|
|
77
|
-
* the returned `valid`/`errors` are final, not a snapshot mid-flight.
|
|
78
|
-
*
|
|
79
|
-
* Validation comes from `options.validate` — the form-level validator.
|
|
80
|
-
* Field validators register through mounted fields (`useField`), and
|
|
81
|
-
* nothing is mounted on the server, so they cannot participate by
|
|
82
|
-
* construction; pass a schema-backed form validator
|
|
83
|
-
* (`standardSchemaFormValidator(schema)` from
|
|
84
|
-
* `react-f0rm/resolvers/standard-schema`) or a hand-written `validate`
|
|
85
|
-
* instead. `mode`/`reValidateMode` are equally inert here — there are no
|
|
86
|
-
* field events to gate — and may be omitted.
|
|
87
|
-
*
|
|
88
|
-
* When the validator returns a branded {@link ValidationOutcome} whose
|
|
89
|
-
* `values` carry the schema's output, those parsed values become the
|
|
90
|
-
* form's parsedValues baseline, so `result.values` flows coercion and
|
|
91
|
-
* transforms forward (`z.coerce.number()` turning `'42'` into `42`, and
|
|
92
|
-
* friends). Persist that tree; on the client the same schema round runs
|
|
93
|
-
* again on submit, keeping one validation source across the boundary.
|
|
94
|
-
*
|
|
95
|
-
* Safe to call from Node, Server Actions and RSC — the module graph is
|
|
96
|
-
* this file plus the pure core, zero React.
|
|
97
|
-
*
|
|
98
|
-
* @param values the payload to validate; becomes the form's initialValues
|
|
99
|
-
* @param options form options; `validate` is where the rules come from
|
|
100
|
-
* @return the settled round: `valid`, the (possibly parsed) values, and
|
|
101
|
-
* the flat error entries
|
|
102
|
-
*/
|
|
28
|
+
/** Validate a payload server-side — no form instance, no React. Spins up
|
|
29
|
+
* a throwaway form from `options` (initialValues forced to `values`),
|
|
30
|
+
* runs one whole-form `trigger`, and reads the settled round back (a
|
|
31
|
+
* single await drains async validators and debounce windows). Field
|
|
32
|
+
* validators can't participate (nothing is mounted); pass a form-level
|
|
33
|
+
* schema validator. A branded outcome's parsed values become the baseline
|
|
34
|
+
* `getValues` layers over. Safe in Node, Server Actions and RSC. */
|
|
103
35
|
declare function validateValues<T extends Record<string, any> = any>(values: T, options?: Options<T>): Promise<ValidateValuesResult<T>>;
|
|
104
36
|
|
|
105
37
|
export { formDataFromValues, validateValues, valuesFromFormData };
|
package/dist/server/index.d.mts
CHANGED
|
@@ -1,105 +1,37 @@
|
|
|
1
1
|
import { FieldErrorEntry, Options } from '../index.js';
|
|
2
|
-
export {
|
|
3
|
-
export { a as appendValue, i as insertValue, m as moveValue, p as prependValue, r as removeValue, b as replaceValues, s as swapValues, u as updateValue } from '../array-
|
|
2
|
+
export { c as VALIDATION_OUTCOME, d as ValidationOutcome } from '../standard-schema-BAaTmAHh.js';
|
|
3
|
+
export { a as appendValue, i as insertValue, m as moveValue, p as prependValue, r as removeValue, b as replaceValues, s as swapValues, u as updateValue } from '../array-Bu7W8BSz.js';
|
|
4
4
|
import '@for-fun/event-emitter';
|
|
5
5
|
|
|
6
|
-
/** The outcome of {@link validateValues}: the
|
|
7
|
-
*
|
|
8
|
-
* parsed values), and every error the round wrote as flat entries. */
|
|
6
|
+
/** The outcome of {@link validateValues}: `valid`, the (schema-coerced)
|
|
7
|
+
* values, and the round's flat error entries. */
|
|
9
8
|
type ValidateValuesResult<T extends Record<string, any> = any> = {
|
|
10
|
-
/** Whether the round landed no errors
|
|
11
|
-
*
|
|
12
|
-
* `ensureValidate`, server callers learn validity from data instead of
|
|
13
|
-
* catching, because both branches are interesting on the server
|
|
14
|
-
* (persist vs. bounce back to the client). */
|
|
9
|
+
/** Whether the round landed no errors. An invalid payload is data, not
|
|
10
|
+
* a rejection — both branches are interesting server-side. */
|
|
15
11
|
valid: boolean;
|
|
16
|
-
/** The values after the round
|
|
17
|
-
*
|
|
18
|
-
* baseline `getValues` layers over the input — schema coerce/transform
|
|
19
|
-
* output included — so this is the tree to persist or feed onward, not
|
|
20
|
-
* necessarily the object passed in. Deep-equals the input otherwise. */
|
|
12
|
+
/** The values after the round: parsed output when the validator
|
|
13
|
+
* returned a branded outcome, the input otherwise. */
|
|
21
14
|
values: T;
|
|
22
|
-
/** Every error
|
|
23
|
-
*
|
|
24
|
-
* Feed it to `setServerErrors` to land a failed round back on the
|
|
25
|
-
* client form (the Server Actions bridge; see the docs' Server Actions
|
|
26
|
-
* guide). */
|
|
15
|
+
/** Every error flattened to {path, type, message}; feed to
|
|
16
|
+
* `setServerErrors` to land it back on the client form. */
|
|
27
17
|
errors: FieldErrorEntry[];
|
|
28
18
|
};
|
|
29
|
-
/**
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
* `<Form action>` prop and `validateValues`: the validated (schema-coerced)
|
|
33
|
-
* values tree lands in the server action as FormData, files included.
|
|
34
|
-
*
|
|
35
|
-
* Array values become multiple entries under the same key (FormData's
|
|
36
|
-
* native multi-value convention); File values keep their name; Dates
|
|
37
|
-
* become ISO strings; plain objects JSON.stringify; null/undefined are
|
|
38
|
-
* skipped.
|
|
39
|
-
*/
|
|
19
|
+
/** Convert values into FormData (Server Actions/multipart shape). Arrays
|
|
20
|
+
* become multiple entries per key; Files keep names; Dates → ISO; objects
|
|
21
|
+
* JSON.stringify; null/undefined skipped. */
|
|
40
22
|
declare function formDataFromValues(values: Record<string, any>): FormData;
|
|
41
|
-
/**
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
* Multiple entries under one key collect into an array (FormData's
|
|
47
|
-
* multi-value convention, which {@link formDataFromValues} uses for
|
|
48
|
-
* arrays); a single entry stays scalar. String values that look like JSON
|
|
49
|
-
* (`{…}`, `[…]`) parse back into objects/arrays — the shape plain objects
|
|
50
|
-
* take through {@link formDataFromValues} — while everything else stays a
|
|
51
|
-
* string, exactly like a native form submit: scalar types round-trip
|
|
52
|
-
* through String() (numbers, booleans, ISO dates), so let a schema coerce
|
|
53
|
-
* them back (`z.coerce.number()` style). File values pass through
|
|
54
|
-
* unchanged; keys missing from the FormData are omitted, matching the
|
|
55
|
-
* null/undefined skipping {@link formDataFromValues} does.
|
|
56
|
-
*
|
|
57
|
-
* Pairs with {@link validateValues} to close the Server Action loop
|
|
58
|
-
* without hand-rolled `.get()` calls:
|
|
59
|
-
*
|
|
60
|
-
* export async function register(formData: FormData) {
|
|
61
|
-
* const result = await validateValues(valuesFromFormData(formData), {
|
|
62
|
-
* validate: standardSchemaFormValidator(schema)
|
|
63
|
-
* });
|
|
64
|
-
* if (!result.valid) return {errors: result.errors};
|
|
65
|
-
* await db.insert(result.values);
|
|
66
|
-
* }
|
|
67
|
-
*/
|
|
23
|
+
/** Convert FormData back into a values object — the inverse of
|
|
24
|
+
* {@link formDataFromValues}. Multiple entries under a key collect into
|
|
25
|
+
* an array, JSON-looking strings parse back, Files pass through, and
|
|
26
|
+
* missing keys are omitted. */
|
|
68
27
|
declare function valuesFromFormData(formData: FormData): Record<string, any>;
|
|
69
|
-
/**
|
|
70
|
-
*
|
|
71
|
-
*
|
|
72
|
-
*
|
|
73
|
-
*
|
|
74
|
-
*
|
|
75
|
-
*
|
|
76
|
-
* `validateDebounce` window, so a single `await` drains the whole round —
|
|
77
|
-
* the returned `valid`/`errors` are final, not a snapshot mid-flight.
|
|
78
|
-
*
|
|
79
|
-
* Validation comes from `options.validate` — the form-level validator.
|
|
80
|
-
* Field validators register through mounted fields (`useField`), and
|
|
81
|
-
* nothing is mounted on the server, so they cannot participate by
|
|
82
|
-
* construction; pass a schema-backed form validator
|
|
83
|
-
* (`standardSchemaFormValidator(schema)` from
|
|
84
|
-
* `react-f0rm/resolvers/standard-schema`) or a hand-written `validate`
|
|
85
|
-
* instead. `mode`/`reValidateMode` are equally inert here — there are no
|
|
86
|
-
* field events to gate — and may be omitted.
|
|
87
|
-
*
|
|
88
|
-
* When the validator returns a branded {@link ValidationOutcome} whose
|
|
89
|
-
* `values` carry the schema's output, those parsed values become the
|
|
90
|
-
* form's parsedValues baseline, so `result.values` flows coercion and
|
|
91
|
-
* transforms forward (`z.coerce.number()` turning `'42'` into `42`, and
|
|
92
|
-
* friends). Persist that tree; on the client the same schema round runs
|
|
93
|
-
* again on submit, keeping one validation source across the boundary.
|
|
94
|
-
*
|
|
95
|
-
* Safe to call from Node, Server Actions and RSC — the module graph is
|
|
96
|
-
* this file plus the pure core, zero React.
|
|
97
|
-
*
|
|
98
|
-
* @param values the payload to validate; becomes the form's initialValues
|
|
99
|
-
* @param options form options; `validate` is where the rules come from
|
|
100
|
-
* @return the settled round: `valid`, the (possibly parsed) values, and
|
|
101
|
-
* the flat error entries
|
|
102
|
-
*/
|
|
28
|
+
/** Validate a payload server-side — no form instance, no React. Spins up
|
|
29
|
+
* a throwaway form from `options` (initialValues forced to `values`),
|
|
30
|
+
* runs one whole-form `trigger`, and reads the settled round back (a
|
|
31
|
+
* single await drains async validators and debounce windows). Field
|
|
32
|
+
* validators can't participate (nothing is mounted); pass a form-level
|
|
33
|
+
* schema validator. A branded outcome's parsed values become the baseline
|
|
34
|
+
* `getValues` layers over. Safe in Node, Server Actions and RSC. */
|
|
103
35
|
declare function validateValues<T extends Record<string, any> = any>(values: T, options?: Options<T>): Promise<ValidateValuesResult<T>>;
|
|
104
36
|
|
|
105
37
|
export { formDataFromValues, validateValues, valuesFromFormData };
|
package/dist/server/index.d.ts
CHANGED
|
@@ -1,105 +1,37 @@
|
|
|
1
1
|
import { FieldErrorEntry, Options } from '../index.js';
|
|
2
|
-
export {
|
|
3
|
-
export { a as appendValue, i as insertValue, m as moveValue, p as prependValue, r as removeValue, b as replaceValues, s as swapValues, u as updateValue } from '../array-
|
|
2
|
+
export { c as VALIDATION_OUTCOME, d as ValidationOutcome } from '../standard-schema-BAaTmAHh.js';
|
|
3
|
+
export { a as appendValue, i as insertValue, m as moveValue, p as prependValue, r as removeValue, b as replaceValues, s as swapValues, u as updateValue } from '../array-Bu7W8BSz.js';
|
|
4
4
|
import '@for-fun/event-emitter';
|
|
5
5
|
|
|
6
|
-
/** The outcome of {@link validateValues}: the
|
|
7
|
-
*
|
|
8
|
-
* parsed values), and every error the round wrote as flat entries. */
|
|
6
|
+
/** The outcome of {@link validateValues}: `valid`, the (schema-coerced)
|
|
7
|
+
* values, and the round's flat error entries. */
|
|
9
8
|
type ValidateValuesResult<T extends Record<string, any> = any> = {
|
|
10
|
-
/** Whether the round landed no errors
|
|
11
|
-
*
|
|
12
|
-
* `ensureValidate`, server callers learn validity from data instead of
|
|
13
|
-
* catching, because both branches are interesting on the server
|
|
14
|
-
* (persist vs. bounce back to the client). */
|
|
9
|
+
/** Whether the round landed no errors. An invalid payload is data, not
|
|
10
|
+
* a rejection — both branches are interesting server-side. */
|
|
15
11
|
valid: boolean;
|
|
16
|
-
/** The values after the round
|
|
17
|
-
*
|
|
18
|
-
* baseline `getValues` layers over the input — schema coerce/transform
|
|
19
|
-
* output included — so this is the tree to persist or feed onward, not
|
|
20
|
-
* necessarily the object passed in. Deep-equals the input otherwise. */
|
|
12
|
+
/** The values after the round: parsed output when the validator
|
|
13
|
+
* returned a branded outcome, the input otherwise. */
|
|
21
14
|
values: T;
|
|
22
|
-
/** Every error
|
|
23
|
-
*
|
|
24
|
-
* Feed it to `setServerErrors` to land a failed round back on the
|
|
25
|
-
* client form (the Server Actions bridge; see the docs' Server Actions
|
|
26
|
-
* guide). */
|
|
15
|
+
/** Every error flattened to {path, type, message}; feed to
|
|
16
|
+
* `setServerErrors` to land it back on the client form. */
|
|
27
17
|
errors: FieldErrorEntry[];
|
|
28
18
|
};
|
|
29
|
-
/**
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
* `<Form action>` prop and `validateValues`: the validated (schema-coerced)
|
|
33
|
-
* values tree lands in the server action as FormData, files included.
|
|
34
|
-
*
|
|
35
|
-
* Array values become multiple entries under the same key (FormData's
|
|
36
|
-
* native multi-value convention); File values keep their name; Dates
|
|
37
|
-
* become ISO strings; plain objects JSON.stringify; null/undefined are
|
|
38
|
-
* skipped.
|
|
39
|
-
*/
|
|
19
|
+
/** Convert values into FormData (Server Actions/multipart shape). Arrays
|
|
20
|
+
* become multiple entries per key; Files keep names; Dates → ISO; objects
|
|
21
|
+
* JSON.stringify; null/undefined skipped. */
|
|
40
22
|
declare function formDataFromValues(values: Record<string, any>): FormData;
|
|
41
|
-
/**
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
* Multiple entries under one key collect into an array (FormData's
|
|
47
|
-
* multi-value convention, which {@link formDataFromValues} uses for
|
|
48
|
-
* arrays); a single entry stays scalar. String values that look like JSON
|
|
49
|
-
* (`{…}`, `[…]`) parse back into objects/arrays — the shape plain objects
|
|
50
|
-
* take through {@link formDataFromValues} — while everything else stays a
|
|
51
|
-
* string, exactly like a native form submit: scalar types round-trip
|
|
52
|
-
* through String() (numbers, booleans, ISO dates), so let a schema coerce
|
|
53
|
-
* them back (`z.coerce.number()` style). File values pass through
|
|
54
|
-
* unchanged; keys missing from the FormData are omitted, matching the
|
|
55
|
-
* null/undefined skipping {@link formDataFromValues} does.
|
|
56
|
-
*
|
|
57
|
-
* Pairs with {@link validateValues} to close the Server Action loop
|
|
58
|
-
* without hand-rolled `.get()` calls:
|
|
59
|
-
*
|
|
60
|
-
* export async function register(formData: FormData) {
|
|
61
|
-
* const result = await validateValues(valuesFromFormData(formData), {
|
|
62
|
-
* validate: standardSchemaFormValidator(schema)
|
|
63
|
-
* });
|
|
64
|
-
* if (!result.valid) return {errors: result.errors};
|
|
65
|
-
* await db.insert(result.values);
|
|
66
|
-
* }
|
|
67
|
-
*/
|
|
23
|
+
/** Convert FormData back into a values object — the inverse of
|
|
24
|
+
* {@link formDataFromValues}. Multiple entries under a key collect into
|
|
25
|
+
* an array, JSON-looking strings parse back, Files pass through, and
|
|
26
|
+
* missing keys are omitted. */
|
|
68
27
|
declare function valuesFromFormData(formData: FormData): Record<string, any>;
|
|
69
|
-
/**
|
|
70
|
-
*
|
|
71
|
-
*
|
|
72
|
-
*
|
|
73
|
-
*
|
|
74
|
-
*
|
|
75
|
-
*
|
|
76
|
-
* `validateDebounce` window, so a single `await` drains the whole round —
|
|
77
|
-
* the returned `valid`/`errors` are final, not a snapshot mid-flight.
|
|
78
|
-
*
|
|
79
|
-
* Validation comes from `options.validate` — the form-level validator.
|
|
80
|
-
* Field validators register through mounted fields (`useField`), and
|
|
81
|
-
* nothing is mounted on the server, so they cannot participate by
|
|
82
|
-
* construction; pass a schema-backed form validator
|
|
83
|
-
* (`standardSchemaFormValidator(schema)` from
|
|
84
|
-
* `react-f0rm/resolvers/standard-schema`) or a hand-written `validate`
|
|
85
|
-
* instead. `mode`/`reValidateMode` are equally inert here — there are no
|
|
86
|
-
* field events to gate — and may be omitted.
|
|
87
|
-
*
|
|
88
|
-
* When the validator returns a branded {@link ValidationOutcome} whose
|
|
89
|
-
* `values` carry the schema's output, those parsed values become the
|
|
90
|
-
* form's parsedValues baseline, so `result.values` flows coercion and
|
|
91
|
-
* transforms forward (`z.coerce.number()` turning `'42'` into `42`, and
|
|
92
|
-
* friends). Persist that tree; on the client the same schema round runs
|
|
93
|
-
* again on submit, keeping one validation source across the boundary.
|
|
94
|
-
*
|
|
95
|
-
* Safe to call from Node, Server Actions and RSC — the module graph is
|
|
96
|
-
* this file plus the pure core, zero React.
|
|
97
|
-
*
|
|
98
|
-
* @param values the payload to validate; becomes the form's initialValues
|
|
99
|
-
* @param options form options; `validate` is where the rules come from
|
|
100
|
-
* @return the settled round: `valid`, the (possibly parsed) values, and
|
|
101
|
-
* the flat error entries
|
|
102
|
-
*/
|
|
28
|
+
/** Validate a payload server-side — no form instance, no React. Spins up
|
|
29
|
+
* a throwaway form from `options` (initialValues forced to `values`),
|
|
30
|
+
* runs one whole-form `trigger`, and reads the settled round back (a
|
|
31
|
+
* single await drains async validators and debounce windows). Field
|
|
32
|
+
* validators can't participate (nothing is mounted); pass a form-level
|
|
33
|
+
* schema validator. A branded outcome's parsed values become the baseline
|
|
34
|
+
* `getValues` layers over. Safe in Node, Server Actions and RSC. */
|
|
103
35
|
declare function validateValues<T extends Record<string, any> = any>(values: T, options?: Options<T>): Promise<ValidateValuesResult<T>>;
|
|
104
36
|
|
|
105
37
|
export { formDataFromValues, validateValues, valuesFromFormData };
|
package/dist/server/index.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{emit as e,on as t,create as n,setMaxListeners as
|
|
1
|
+
import{emit as e,on as t,create as n,setMaxListeners as r}from"@for-fun/event-emitter";import{h as i,s as o}from"../standardSchema-5WezjHlp.mjs";import{g as a,B as s,o as u,j as l,c,f as d,A as f}from"../errors-DA4ReEd9.mjs";export{V as VALIDATION_OUTCOME}from"../errors-DA4ReEd9.mjs";import{c as m,d as p,h as g,e as v,a as y,f as h,i as b,s as k,g as A}from"../values-CHsmcZk4.mjs";import{s as S,r as M,a as w,b as L,c as q,t as N}from"../validate-C0HOsP9v.mjs";const x=new WeakMap;function O(e,t,n,r){x.get(e)?.get(t.key)?function(e,t,n){p(e,t,n);const r=x.get(e)?.get(t.key);r&&function(e,t,n){D(e,t,n,"onChange",g(e,t)),w(e,t,n),j(e,"onChange"),L(e,t,n)}(e,t,r.mode??e.mode)}(e,t,n):p(e,t,n,r)}function j(e,t){e.validateMode===t&&e.validate&&M(e).catch(()=>{})}function D(e,t,n,r,i){S(n,r,i,()=>s(e,t).length>0,e.reValidateMode)&&e.validators.get(t.key)?.()}function F(e){return void 0!==e.required||void 0!==e.min||void 0!==e.max||void 0!==e.minLength||void 0!==e.maxLength||void 0!==e.pattern||void 0!==e.validate}function B(e,t){switch(e){case"required":return"This field is required";case"min":return`Must be at least ${t}`;case"max":return`Must be at most ${t}`;case"minLength":return`Must be at least ${t} characters`;case"maxLength":return`Must be at most ${t} characters`;case"pattern":return"Invalid format";default:return"Invalid value"}}function C(e,t){return"function"==typeof e?e(t):e?.replace("{bound}",String(t))}function I(e){const t=Number(e);return Number.isNaN(t)?void 0:t}function U(e){return"string"==typeof e||Array.isArray(e)?e.length:void 0}const T=[["min",I,(e,t)=>e<t],["max",I,(e,t)=>e>t],["minLength",U,(e,t)=>e<t],["maxLength",U,(e,t)=>e>t]];function $(e,t){return(n,r)=>{if(e.required&&(""===n||null==n||Array.isArray(n)&&0===n.length))return[{type:"required",message:"string"==typeof e.required?e.required:C(t?.required)??B("required")}];const i=[],o=(n,r)=>e.messages?.[n]??C(t?.[n],r)??B(n,r);for(const[t,r,a]of T){const s=e[t];if(void 0===s)continue;const u=r(n);void 0!==u&&a(u,s)&&i.push({type:t,message:o(t,s)})}if(e.pattern&&!e.pattern.value.test(n)&&i.push({type:"pattern",message:e.messages?.pattern??e.pattern.message??C(t?.pattern)??B("pattern")}),void 0!==e.validate){const t="function"==typeof e.validate?{validate:e.validate}:e.validate;for(const[e,o]of Object.entries(t)){const t=o(n,r);if(void 0!==t)for(const n of Array.isArray(t)?t:[t])i.push("string"==typeof n?{type:e,message:n}:{...n,type:e})}}return i.length?i:void 0}}function W(n,r,i){const o=c(r),{mode:s,shouldUnregister:d,eventToValue:f,valueAsNumber:g,valueAsDate:k,rules:A}=i??{},S=f??(e=>{const t=e?.target;return t?"file"===t.type?t.files:"checkbox"===t.type?t.checked:g?t.valueAsNumber:k?t.valueAsDate:t.value:e});let M=null,w=null,L=null,V=null,N=null,B=null;const C=r=>{if(V&&(!function(t,n,r){const{key:i}=n;r.present?p(t,n,r.value,{shouldDirty:!1}):(t.deleted.delete(i),u(t),e(t.emitter,"change",n)),r.touched&&m(t,n),r.errors&&l(t,n,r.errors)}(n,o,V),V=null),M=r,"file"!==r.type&&void 0===y(n,o)&&(h(n,o,"checkbox"===r.type?r.checked:r.value),b(n,o)),w=function(e,t,n){const r=a(x,e,()=>new Map),i=r.has(t.key),o={};return r.set(t.key,{mode:n,token:o}),{token:o,displaced:i}}(n,o,s).token,A&&F(A)){const{required:e,...t}=A,r=void 0!==e?$({required:e},n.messages):void 0;L=q(n,o,{validate:()=>F(t)?$(t,n.messages):void 0,debounce:()=>0,sync:()=>r})}N=t(n.emitter,"focusError",(e,t)=>{e===o.key&&M&&"function"==typeof M.focus&&(M.focus(),t?.shouldSelect&&"function"==typeof M.select&&M.select())}),B=t(n.emitter,"change",e=>{e||(()=>{if(!M||"file"===M.type)return;const e=y(n,o),t=null==e?"":String(e);M.value!==t&&(M.value=t)})()})},I=()=>{w&&(!function(e,t,n){const r=x.get(e),i=r?.get(t.key);r&&i&&i.token===n&&r.delete(t.key)}(n,o,w),w=null),L&&(L(),L=null),N&&(N(),N=null),B&&(B(),B=null),M=null,!1!==(d??n.shouldUnregister)&&(V=function(e,t){const{key:n}=t,r={present:e.values.has(n),value:e.values.get(n),touched:e.touched.has(n),errors:e.errors.get(n)};return v(e,t),r}(n,o))};return{name:o.key,onChange:e=>O(n,o,S(e)),onBlur:()=>function(e,t){m(e,t);const n=x.get(e)?.get(t.key);n&&(D(e,t,n.mode??e.mode,"onBlur",!0),j(e,"onBlur"))}(n,o),ref:e=>{e?C(e):I()}}}function E(e,t){const n=y(e,t);return Array.isArray(n)?n:[]}function J(e,t,n){!function(e,t,n){const r=E(e,t);p(e,t,[...r,n])}(e,c(t),n)}function z(e,t,n){!function(e,t,n){const r=E(e,t);p(e,t,[n,...r])}(e,c(t),n)}function P(e,t,n,r){return function(e,t,n,r){const i=E(e,t);return!(n<0||n>i.length||(p(e,t,[...i.slice(0,n),r,...i.slice(n)]),0))}(e,c(t),n,r)}function _(e,t,n){return function(e,t,n){const r=E(e,t),i=new Set;for(const e of Array.isArray(n)?n:[n])e>=0&&e<r.length&&i.add(e);if(0===i.size)return[];const o=[...i].sort((e,t)=>t-e);return p(e,t,r.filter((e,t)=>!i.has(t))),o}(e,c(t),n)}function G(e,t,n,r){return function(e,t,n,r){const i=E(e,t);if(n<0||n>=i.length||r<0||r>=i.length)return!1;if(n===r)return!1;const o=[...i],[a]=o.splice(n,1);return o.splice(r,0,a),p(e,t,o),!0}(e,c(t),n,r)}function H(e,t,n,r){return function(e,t,n,r){const i=E(e,t);if(n<0||n>=i.length||r<0||r>=i.length)return!1;if(n===r)return!1;const o=[...i];return[o[n],o[r]]=[o[r],o[n]],p(e,t,o),!0}(e,c(t),n,r)}function K(e,t,n){!function(e,t,n){p(e,t,[...n])}(e,c(t),n)}function Q(e,t,n,r){return function(e,t,n,r){const i=E(e,t);if(n<0||n>=i.length)return!1;const o=[...i];return o[n]=r,p(e,t,o),!0}(e,c(t),n,r)}function R(t){const a=n();r(a,0);const s=t?.initialValues??{},u="function"==typeof s?s():s,l=t?.validate,f=l&&i(l)?o(l):l,m={emitter:a,...t,validate:f,mode:t?.mode??"onSubmit",reValidateMode:t?.reValidateMode??"onChange",validateMode:t?.validateMode??"onSubmit",disabled:t?.disabled??!1,validateOnMount:t?.validateOnMount??!1,asyncAlways:t?.asyncAlways??!1,shouldUseNativeValidation:t?.shouldUseNativeValidation??!0,validateDeps:t?.validateDeps?new Set(t.validateDeps.map(e=>c(e).key)):void 0,initialValues:{},values:new Map,deleted:new Set,errors:new Map,touched:new Set,validators:new Map,validating:new Set,parsedValues:void 0,isSubmitting:!1,isSubmitted:!1,submitCount:0,isSubmitSuccessful:void 0,isLoading:!1,status:void 0,register:(e,t)=>W(m,e,t)};return function(t,n,r){d(r)?(t.isLoading=!0,e(n,"loading"),Promise.resolve(r).then(r=>{k(t,r??{}),t.isLoading=!1,e(n,"loading")},r=>{t.isLoading=!1,e(n,"loading")})):t.initialValues=r}(m,a,u),m}function X(e,t,n){if(null!=n)if(Array.isArray(n))for(const r of n)X(e,t,r);else if("undefined"!=typeof FileList&&n instanceof FileList)for(let r=0;r<n.length;r++)e.append(t,n.item(r));else"undefined"!=typeof File&&n instanceof File?e.append(t,n,n.name):"undefined"!=typeof Blob&&n instanceof Blob?e.append(t,n):n instanceof Date?e.append(t,n.toISOString()):e.append(t,"object"==typeof n?JSON.stringify(n):String(n))}function Y(e){const t=new FormData;for(const n of Object.keys(e))X(t,n,e[n]);return t}function Z(e){return"undefined"!=typeof File&&e instanceof File?e:function(e){const t=e.trim();if(t.startsWith("{")||t.startsWith("["))try{return JSON.parse(t)}catch{return e}return e}(e)}function ee(e){const t={};for(const n of new Set(e.keys())){const r=e.getAll(n);t[n]=1===r.length?Z(r[0]):r.map(Z)}return t}async function te(e,t){const n=R({...t,initialValues:e});return{valid:await N(n),values:A(n),errors:f(n)}}export{J as appendValue,Y as formDataFromValues,P as insertValue,G as moveValue,z as prependValue,_ as removeValue,K as replaceValues,H as swapValues,Q as updateValue,te as validateValues,ee as valuesFromFormData};
|
|
2
2
|
//# sourceMappingURL=index.mjs.map
|