server-act 0.0.5 → 0.0.7
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/.turbo/turbo-build.log +11 -10
- package/CHANGELOG.md +12 -0
- package/README.md +27 -3
- package/dist/index.d.mts +56 -0
- package/dist/index.d.ts +18 -5
- package/dist/index.js +40 -9
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +40 -9
- package/dist/index.mjs.map +1 -1
- package/package.json +10 -10
- package/src/index.test.ts +85 -38
- package/src/index.ts +38 -7
- package/tsconfig.json +5 -2
package/.turbo/turbo-build.log
CHANGED
|
@@ -1,21 +1,22 @@
|
|
|
1
1
|
|
|
2
|
-
> server-act@0.0.
|
|
2
|
+
> server-act@0.0.7 build /home/runner/work/server-act/server-act/packages/server-act
|
|
3
3
|
> tsup
|
|
4
4
|
|
|
5
5
|
[34mCLI[39m Building entry: ./src/index.ts
|
|
6
6
|
[34mCLI[39m Using tsconfig: tsconfig.json
|
|
7
|
-
[34mCLI[39m tsup
|
|
7
|
+
[34mCLI[39m tsup v7.2.0
|
|
8
8
|
[34mCLI[39m Using tsup config: /home/runner/work/server-act/server-act/packages/server-act/tsup.config.ts
|
|
9
|
-
[34mCLI[39m Target:
|
|
9
|
+
[34mCLI[39m Target: node16
|
|
10
10
|
[34mCLI[39m Cleaning output folder
|
|
11
11
|
[34mESM[39m Build start
|
|
12
12
|
[34mCJS[39m Build start
|
|
13
|
-
[
|
|
14
|
-
[
|
|
15
|
-
[32mCJS[39m ⚡️ Build success in 29ms
|
|
16
|
-
[32mESM[39m [1mdist/index.mjs [22m[32m3.57 KB[39m
|
|
17
|
-
[32mESM[39m [1mdist/index.mjs.map [22m[32m8.63 KB[39m
|
|
13
|
+
[32mESM[39m [1mdist/index.mjs [22m[32m4.66 KB[39m
|
|
14
|
+
[32mESM[39m [1mdist/index.mjs.map [22m[32m11.81 KB[39m
|
|
18
15
|
[32mESM[39m ⚡️ Build success in 30ms
|
|
16
|
+
[32mCJS[39m [1mdist/index.js [22m[32m6.24 KB[39m
|
|
17
|
+
[32mCJS[39m [1mdist/index.js.map [22m[32m11.86 KB[39m
|
|
18
|
+
[32mCJS[39m ⚡️ Build success in 31ms
|
|
19
19
|
[34mDTS[39m Build start
|
|
20
|
-
[32mDTS[39m ⚡️ Build success in
|
|
21
|
-
[32mDTS[39m [1mdist/index.d.
|
|
20
|
+
[32mDTS[39m ⚡️ Build success in 1055ms
|
|
21
|
+
[32mDTS[39m [1mdist/index.d.mts [22m[32m2.08 KB[39m
|
|
22
|
+
[32mDTS[39m [1mdist/index.d.ts [22m[32m2.08 KB[39m
|
package/CHANGELOG.md
CHANGED
package/README.md
CHANGED
|
@@ -25,14 +25,14 @@ pnpm add server-act zod
|
|
|
25
25
|
|
|
26
26
|
import { serverAct } from "server-act";
|
|
27
27
|
|
|
28
|
-
const sayHelloAction = serverAct
|
|
28
|
+
export const sayHelloAction = serverAct
|
|
29
29
|
.input(
|
|
30
30
|
z.object({
|
|
31
31
|
name: z.string(),
|
|
32
32
|
})
|
|
33
33
|
)
|
|
34
|
-
.action(async ({
|
|
35
|
-
return `Hello, ${name}`;
|
|
34
|
+
.action(async ({ input }) => {
|
|
35
|
+
return `Hello, ${input.name}`;
|
|
36
36
|
});
|
|
37
37
|
```
|
|
38
38
|
|
|
@@ -55,3 +55,27 @@ export const ClientComponent = () => {
|
|
|
55
55
|
);
|
|
56
56
|
};
|
|
57
57
|
```
|
|
58
|
+
|
|
59
|
+
### With Middleware
|
|
60
|
+
|
|
61
|
+
```ts
|
|
62
|
+
// action.ts
|
|
63
|
+
"use server";
|
|
64
|
+
|
|
65
|
+
import { serverAct } from "server-act";
|
|
66
|
+
|
|
67
|
+
export const sayHelloAction = serverAct
|
|
68
|
+
.middleware(() => {
|
|
69
|
+
const userId = "...";
|
|
70
|
+
return { userId };
|
|
71
|
+
})
|
|
72
|
+
.input(
|
|
73
|
+
z.object({
|
|
74
|
+
name: z.string(),
|
|
75
|
+
})
|
|
76
|
+
)
|
|
77
|
+
.action(async ({ ctx, input }) => {
|
|
78
|
+
console.log("User ID", ctx.userId);
|
|
79
|
+
return `Hello, ${input.name}`;
|
|
80
|
+
});
|
|
81
|
+
```
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
|
|
3
|
+
declare const unsetMarker: unique symbol;
|
|
4
|
+
type UnsetMarker = typeof unsetMarker;
|
|
5
|
+
type OptionalizeUndefined<T> = undefined extends T ? [param?: T] : [param: T];
|
|
6
|
+
type InferParserType<TParser, TType extends 'in' | 'out'> = TParser extends UnsetMarker ? undefined : TParser extends z.ZodType ? TParser[TType extends 'in' ? '_input' : '_output'] : never;
|
|
7
|
+
type InferContextType<T> = T extends UnsetMarker ? undefined : T;
|
|
8
|
+
interface ActionParams<TInput = unknown, TContext = unknown> {
|
|
9
|
+
_input: TInput;
|
|
10
|
+
_context: TContext;
|
|
11
|
+
}
|
|
12
|
+
interface ActionBuilder<TParams extends ActionParams> {
|
|
13
|
+
/**
|
|
14
|
+
* Middleware allows you to run code before the action, its return value will pass as context to the action.
|
|
15
|
+
*/
|
|
16
|
+
middleware: <TContext>(middleware: () => Promise<TContext> | TContext) => ActionBuilder<{
|
|
17
|
+
_input: TParams['_input'];
|
|
18
|
+
_context: TContext;
|
|
19
|
+
}>;
|
|
20
|
+
/**
|
|
21
|
+
* Input validation for the action.
|
|
22
|
+
*/
|
|
23
|
+
input: <TParser extends z.ZodType>(input: TParser) => ActionBuilder<{
|
|
24
|
+
_input: TParser;
|
|
25
|
+
_context: TParams['_context'];
|
|
26
|
+
}>;
|
|
27
|
+
/**
|
|
28
|
+
* Create an action.
|
|
29
|
+
*/
|
|
30
|
+
action: <TOutput>(action: (params: {
|
|
31
|
+
ctx: InferContextType<TParams['_context']>;
|
|
32
|
+
input: InferParserType<TParams['_input'], 'out'>;
|
|
33
|
+
}) => Promise<TOutput>) => (...[input]: OptionalizeUndefined<InferParserType<TParams['_input'], 'in'>>) => Promise<TOutput>;
|
|
34
|
+
/**
|
|
35
|
+
* ***Experimental*** - Create an action for React `useFormState`
|
|
36
|
+
*/
|
|
37
|
+
experimental_formAction: <TState>(action: (params: {
|
|
38
|
+
ctx: InferContextType<TParams['_context']>;
|
|
39
|
+
prevState: any;
|
|
40
|
+
} & ({
|
|
41
|
+
input: InferParserType<TParams['_input'], 'out'>;
|
|
42
|
+
formErrors?: undefined;
|
|
43
|
+
} | {
|
|
44
|
+
input?: undefined;
|
|
45
|
+
formErrors: z.ZodError<InferParserType<TParams['_input'], 'in'>>['formErrors']['fieldErrors'];
|
|
46
|
+
})) => Promise<TState>) => (prevState: TState, formData: FormData) => Promise<TState>;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Server action builder
|
|
50
|
+
*/
|
|
51
|
+
declare const serverAct: ActionBuilder<{
|
|
52
|
+
_input: UnsetMarker;
|
|
53
|
+
_context: UnsetMarker;
|
|
54
|
+
}>;
|
|
55
|
+
|
|
56
|
+
export { serverAct };
|
package/dist/index.d.ts
CHANGED
|
@@ -5,13 +5,13 @@ type UnsetMarker = typeof unsetMarker;
|
|
|
5
5
|
type OptionalizeUndefined<T> = undefined extends T ? [param?: T] : [param: T];
|
|
6
6
|
type InferParserType<TParser, TType extends 'in' | 'out'> = TParser extends UnsetMarker ? undefined : TParser extends z.ZodType ? TParser[TType extends 'in' ? '_input' : '_output'] : never;
|
|
7
7
|
type InferContextType<T> = T extends UnsetMarker ? undefined : T;
|
|
8
|
-
|
|
8
|
+
interface ActionParams<TInput = unknown, TContext = unknown> {
|
|
9
9
|
_input: TInput;
|
|
10
10
|
_context: TContext;
|
|
11
|
-
}
|
|
12
|
-
|
|
11
|
+
}
|
|
12
|
+
interface ActionBuilder<TParams extends ActionParams> {
|
|
13
13
|
/**
|
|
14
|
-
* Middleware allows you to run code before the action,
|
|
14
|
+
* Middleware allows you to run code before the action, its return value will pass as context to the action.
|
|
15
15
|
*/
|
|
16
16
|
middleware: <TContext>(middleware: () => Promise<TContext> | TContext) => ActionBuilder<{
|
|
17
17
|
_input: TParams['_input'];
|
|
@@ -31,7 +31,20 @@ type ActionBuilder<TParams extends ActionParams> = {
|
|
|
31
31
|
ctx: InferContextType<TParams['_context']>;
|
|
32
32
|
input: InferParserType<TParams['_input'], 'out'>;
|
|
33
33
|
}) => Promise<TOutput>) => (...[input]: OptionalizeUndefined<InferParserType<TParams['_input'], 'in'>>) => Promise<TOutput>;
|
|
34
|
-
|
|
34
|
+
/**
|
|
35
|
+
* ***Experimental*** - Create an action for React `useFormState`
|
|
36
|
+
*/
|
|
37
|
+
experimental_formAction: <TState>(action: (params: {
|
|
38
|
+
ctx: InferContextType<TParams['_context']>;
|
|
39
|
+
prevState: any;
|
|
40
|
+
} & ({
|
|
41
|
+
input: InferParserType<TParams['_input'], 'out'>;
|
|
42
|
+
formErrors?: undefined;
|
|
43
|
+
} | {
|
|
44
|
+
input?: undefined;
|
|
45
|
+
formErrors: z.ZodError<InferParserType<TParams['_input'], 'in'>>['formErrors']['fieldErrors'];
|
|
46
|
+
})) => Promise<TState>) => (prevState: TState, formData: FormData) => Promise<TState>;
|
|
47
|
+
}
|
|
35
48
|
/**
|
|
36
49
|
* Server action builder
|
|
37
50
|
*/
|
package/dist/index.js
CHANGED
|
@@ -34,10 +34,10 @@ __export(src_exports, {
|
|
|
34
34
|
});
|
|
35
35
|
module.exports = __toCommonJS(src_exports);
|
|
36
36
|
|
|
37
|
-
// ../../node_modules/.pnpm/zod-validation-error@1.
|
|
37
|
+
// ../../node_modules/.pnpm/zod-validation-error@1.5.0_zod@3.22.2/node_modules/zod-validation-error/dist/esm/ValidationError.js
|
|
38
38
|
var zod = __toESM(require("zod"));
|
|
39
39
|
|
|
40
|
-
// ../../node_modules/.pnpm/zod-validation-error@1.
|
|
40
|
+
// ../../node_modules/.pnpm/zod-validation-error@1.5.0_zod@3.22.2/node_modules/zod-validation-error/dist/esm/utils/joinPath.js
|
|
41
41
|
var identifierRegex = /[$_\p{ID_Start}][$\u200c\u200d\p{ID_Continue}]*/u;
|
|
42
42
|
function joinPath(path) {
|
|
43
43
|
if (path.length === 1) {
|
|
@@ -61,12 +61,17 @@ function escapeQuotes(str) {
|
|
|
61
61
|
return str.replace(/"/g, '\\"');
|
|
62
62
|
}
|
|
63
63
|
|
|
64
|
-
// ../../node_modules/.pnpm/zod-validation-error@1.
|
|
64
|
+
// ../../node_modules/.pnpm/zod-validation-error@1.5.0_zod@3.22.2/node_modules/zod-validation-error/dist/esm/utils/NonEmptyArray.js
|
|
65
65
|
function isNonEmptyArray(value) {
|
|
66
66
|
return value.length !== 0;
|
|
67
67
|
}
|
|
68
68
|
|
|
69
|
-
// ../../node_modules/.pnpm/zod-validation-error@1.
|
|
69
|
+
// ../../node_modules/.pnpm/zod-validation-error@1.5.0_zod@3.22.2/node_modules/zod-validation-error/dist/esm/ValidationError.js
|
|
70
|
+
var MAX_ISSUES_IN_MESSAGE = 99;
|
|
71
|
+
var ISSUE_SEPARATOR = "; ";
|
|
72
|
+
var UNION_SEPARATOR = ", or ";
|
|
73
|
+
var PREFIX = "Validation error";
|
|
74
|
+
var PREFIX_SEPARATOR = ": ";
|
|
70
75
|
var ValidationError = class extends Error {
|
|
71
76
|
details;
|
|
72
77
|
name;
|
|
@@ -79,10 +84,10 @@ var ValidationError = class extends Error {
|
|
|
79
84
|
return this.message;
|
|
80
85
|
}
|
|
81
86
|
};
|
|
82
|
-
function
|
|
87
|
+
function getMessageFromZodIssue(issue, issueSeparator, unionSeparator) {
|
|
83
88
|
if (issue.code === "invalid_union") {
|
|
84
89
|
return issue.unionErrors.reduce((acc, zodError) => {
|
|
85
|
-
const newIssues = zodError.issues.map((issue2) =>
|
|
90
|
+
const newIssues = zodError.issues.map((issue2) => getMessageFromZodIssue(issue2, issueSeparator, unionSeparator)).join(issueSeparator);
|
|
86
91
|
if (!acc.includes(newIssues)) {
|
|
87
92
|
acc.push(newIssues);
|
|
88
93
|
}
|
|
@@ -100,10 +105,22 @@ function fromZodIssue(issue, issueSeparator, unionSeparator) {
|
|
|
100
105
|
}
|
|
101
106
|
return issue.message;
|
|
102
107
|
}
|
|
108
|
+
function conditionallyPrefixMessage(reason, prefix, prefixSeparator) {
|
|
109
|
+
if (prefix !== null) {
|
|
110
|
+
if (reason.length > 0) {
|
|
111
|
+
return [prefix, reason].join(prefixSeparator);
|
|
112
|
+
}
|
|
113
|
+
return prefix;
|
|
114
|
+
}
|
|
115
|
+
if (reason.length > 0) {
|
|
116
|
+
return reason;
|
|
117
|
+
}
|
|
118
|
+
return PREFIX;
|
|
119
|
+
}
|
|
103
120
|
function fromZodError(zodError, options = {}) {
|
|
104
|
-
const { maxIssuesInMessage =
|
|
105
|
-
const reason = zodError.errors.slice(0, maxIssuesInMessage).map((issue) =>
|
|
106
|
-
const message = reason
|
|
121
|
+
const { maxIssuesInMessage = MAX_ISSUES_IN_MESSAGE, issueSeparator = ISSUE_SEPARATOR, unionSeparator = UNION_SEPARATOR, prefixSeparator = PREFIX_SEPARATOR, prefix = PREFIX } = options;
|
|
122
|
+
const reason = zodError.errors.slice(0, maxIssuesInMessage).map((issue) => getMessageFromZodIssue(issue, issueSeparator, unionSeparator)).join(issueSeparator);
|
|
123
|
+
const message = conditionallyPrefixMessage(reason, prefix, prefixSeparator);
|
|
107
124
|
return new ValidationError(message, zodError.errors);
|
|
108
125
|
}
|
|
109
126
|
|
|
@@ -133,6 +150,20 @@ var createServerActionBuilder = (initDef = {}) => {
|
|
|
133
150
|
}
|
|
134
151
|
return await action({ ctx, input });
|
|
135
152
|
};
|
|
153
|
+
},
|
|
154
|
+
experimental_formAction: (action) => {
|
|
155
|
+
return async (prevState, formData) => {
|
|
156
|
+
var _a;
|
|
157
|
+
const ctx = await ((_a = _def.middleware) == null ? void 0 : _a.call(_def));
|
|
158
|
+
if (_def.input) {
|
|
159
|
+
const result = _def.input.safeParse(Object.fromEntries(formData.entries()));
|
|
160
|
+
if (!result.success) {
|
|
161
|
+
return await action({ ctx, prevState, formErrors: result.error.formErrors.fieldErrors });
|
|
162
|
+
}
|
|
163
|
+
return await action({ ctx, prevState, input: result.data });
|
|
164
|
+
}
|
|
165
|
+
return await action({ ctx, prevState, input: void 0 });
|
|
166
|
+
};
|
|
136
167
|
}
|
|
137
168
|
};
|
|
138
169
|
};
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../../../node_modules/.pnpm/zod-validation-error@1.3.0_zod@3.21.4/node_modules/zod-validation-error/dist/esm/ValidationError.js","../../../node_modules/.pnpm/zod-validation-error@1.3.0_zod@3.21.4/node_modules/zod-validation-error/dist/esm/utils/joinPath.js","../../../node_modules/.pnpm/zod-validation-error@1.3.0_zod@3.21.4/node_modules/zod-validation-error/dist/esm/utils/NonEmptyArray.js"],"sourcesContent":["/* eslint-disable @typescript-eslint/no-explicit-any */\nimport {type z} from 'zod';\nimport {fromZodError} from 'zod-validation-error';\n\nconst unsetMarker = Symbol('unsetMarker');\ntype UnsetMarker = typeof unsetMarker;\n\ntype OptionalizeUndefined<T> = undefined extends T ? [param?: T] : [param: T];\n\ntype InferParserType<TParser, TType extends 'in' | 'out'> = TParser extends UnsetMarker\n ? undefined\n : TParser extends z.ZodType\n ? TParser[TType extends 'in' ? '_input' : '_output']\n : never;\n\ntype InferContextType<T> = T extends UnsetMarker ? undefined : T;\n\ntype ActionParams<TInput = unknown, TContext = unknown> = {\n _input: TInput;\n _context: TContext;\n};\n\ntype ActionBuilder<TParams extends ActionParams> = {\n /**\n * Middleware allows you to run code before the action, and return context to the action.\n */\n middleware: <TContext>(\n middleware: () => Promise<TContext> | TContext,\n ) => ActionBuilder<{_input: TParams['_input']; _context: TContext}>;\n /**\n * Input validation for the action.\n */\n input: <TParser extends z.ZodType>(input: TParser) => ActionBuilder<{_input: TParser; _context: TParams['_context']}>;\n /**\n * Create an action.\n */\n action: <TOutput>(\n action: (params: {\n ctx: InferContextType<TParams['_context']>;\n input: InferParserType<TParams['_input'], 'out'>;\n }) => Promise<TOutput>,\n ) => (...[input]: OptionalizeUndefined<InferParserType<TParams['_input'], 'in'>>) => Promise<TOutput>;\n};\ntype AnyActionBuilder = ActionBuilder<any>;\n\ntype ActionBuilderDef<TParams extends ActionParams<any>> = {\n input: TParams['_input'];\n middleware: (() => Promise<TParams['_context']> | TParams['_context']) | undefined;\n};\ntype AnyActionBuilderDef = ActionBuilderDef<any>;\n\nconst createNewServerActionBuilder = (def: Partial<AnyActionBuilderDef>) => {\n return createServerActionBuilder(def);\n};\n\nconst createServerActionBuilder = (\n initDef: Partial<AnyActionBuilderDef> = {},\n): ActionBuilder<{\n _input: UnsetMarker;\n _context: UnsetMarker;\n}> => {\n const _def: ActionBuilderDef<{_input: z.ZodType | undefined; _context: undefined}> = {\n input: undefined,\n middleware: undefined,\n ...initDef,\n };\n return {\n middleware: (middleware) => createServerActionBuilder({..._def, middleware}) as AnyActionBuilder,\n input: (input) => createNewServerActionBuilder({..._def, input}) as AnyActionBuilder,\n action: (action) => {\n return async (input) => {\n const ctx = await _def.middleware?.();\n if (_def.input) {\n const result = _def.input.safeParse(input);\n if (!result.success) {\n throw fromZodError(result.error);\n }\n }\n return await action({ctx, input});\n };\n },\n };\n};\n\n/**\n * Server action builder\n */\nexport const serverAct = createServerActionBuilder();\n","import * as zod from 'zod';\nimport { joinPath } from './utils/joinPath';\nimport { isNonEmptyArray } from './utils/NonEmptyArray';\nexport class ValidationError extends Error {\n details;\n name;\n constructor(message, details = []) {\n super(message);\n this.details = details;\n this.name = 'ZodValidationError';\n }\n toString() {\n return this.message;\n }\n}\nfunction fromZodIssue(issue, issueSeparator, unionSeparator) {\n if (issue.code === 'invalid_union') {\n return issue.unionErrors\n .reduce((acc, zodError) => {\n const newIssues = zodError.issues\n .map((issue) => fromZodIssue(issue, issueSeparator, unionSeparator))\n .join(issueSeparator);\n if (!acc.includes(newIssues)) {\n acc.push(newIssues);\n }\n return acc;\n }, [])\n .join(unionSeparator);\n }\n if (isNonEmptyArray(issue.path)) {\n if (issue.path.length === 1) {\n const identifier = issue.path[0];\n if (typeof identifier === 'number') {\n return `${issue.message} at index ${identifier}`;\n }\n }\n return `${issue.message} at \"${joinPath(issue.path)}\"`;\n }\n return issue.message;\n}\nexport function fromZodError(zodError, options = {}) {\n const { maxIssuesInMessage = 99, issueSeparator = '; ', unionSeparator = ', or ', prefixSeparator = ': ', prefix = 'Validation error', } = options;\n const reason = zodError.errors\n .slice(0, maxIssuesInMessage)\n .map((issue) => fromZodIssue(issue, issueSeparator, unionSeparator))\n .join(issueSeparator);\n const message = reason ? [prefix, reason].join(prefixSeparator) : prefix;\n return new ValidationError(message, zodError.errors);\n}\nexport const toValidationError = (options = {}) => (err) => {\n if (err instanceof zod.ZodError) {\n return fromZodError(err, options);\n }\n if (err instanceof Error) {\n return err;\n }\n return new Error('Unknown error');\n};\nexport function isValidationError(err) {\n return err instanceof ValidationError;\n}\nexport function isValidationErrorLike(err) {\n return err instanceof Error && err.name === 'ZodValidationError';\n}\n","const identifierRegex = /[$_\\p{ID_Start}][$\\u200c\\u200d\\p{ID_Continue}]*/u;\nexport function joinPath(path) {\n if (path.length === 1) {\n return path[0].toString();\n }\n return path.reduce((acc, item) => {\n if (typeof item === 'number') {\n return acc + '[' + item.toString() + ']';\n }\n if (item.includes('\"')) {\n return acc + '[\"' + escapeQuotes(item) + '\"]';\n }\n if (!identifierRegex.test(item)) {\n return acc + '[\"' + item + '\"]';\n }\n const separator = acc.length === 0 ? '' : '.';\n return acc + separator + item;\n }, '');\n}\nfunction escapeQuotes(str) {\n return str.replace(/\"/g, '\\\\\"');\n}\n","export function isNonEmptyArray(value) {\n return value.length !== 0;\n}\n"],"mappings":"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","names":["issue"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../../../node_modules/.pnpm/zod-validation-error@1.5.0_zod@3.22.2/node_modules/zod-validation-error/dist/esm/ValidationError.js","../../../node_modules/.pnpm/zod-validation-error@1.5.0_zod@3.22.2/node_modules/zod-validation-error/dist/esm/utils/joinPath.js","../../../node_modules/.pnpm/zod-validation-error@1.5.0_zod@3.22.2/node_modules/zod-validation-error/dist/esm/utils/NonEmptyArray.js"],"sourcesContent":["/* eslint-disable @typescript-eslint/no-unsafe-assignment */\n/* eslint-disable @typescript-eslint/no-explicit-any */\nimport {type z} from 'zod';\nimport {fromZodError} from 'zod-validation-error';\n\nconst unsetMarker = Symbol('unsetMarker');\ntype UnsetMarker = typeof unsetMarker;\n\ntype OptionalizeUndefined<T> = undefined extends T ? [param?: T] : [param: T];\n\ntype InferParserType<TParser, TType extends 'in' | 'out'> = TParser extends UnsetMarker\n ? undefined\n : TParser extends z.ZodType\n ? TParser[TType extends 'in' ? '_input' : '_output']\n : never;\n\ntype InferContextType<T> = T extends UnsetMarker ? undefined : T;\n\ninterface ActionParams<TInput = unknown, TContext = unknown> {\n _input: TInput;\n _context: TContext;\n}\n\ninterface ActionBuilder<TParams extends ActionParams> {\n /**\n * Middleware allows you to run code before the action, its return value will pass as context to the action.\n */\n middleware: <TContext>(\n middleware: () => Promise<TContext> | TContext,\n ) => ActionBuilder<{_input: TParams['_input']; _context: TContext}>;\n /**\n * Input validation for the action.\n */\n input: <TParser extends z.ZodType>(input: TParser) => ActionBuilder<{_input: TParser; _context: TParams['_context']}>;\n /**\n * Create an action.\n */\n action: <TOutput>(\n action: (params: {\n ctx: InferContextType<TParams['_context']>;\n input: InferParserType<TParams['_input'], 'out'>;\n }) => Promise<TOutput>,\n ) => (...[input]: OptionalizeUndefined<InferParserType<TParams['_input'], 'in'>>) => Promise<TOutput>;\n /**\n * ***Experimental*** - Create an action for React `useFormState`\n */\n experimental_formAction: <TState>(\n action: (\n params: {\n ctx: InferContextType<TParams['_context']>;\n prevState: any; // FIXME: This supposes to be `TState`, but we can't, as it will break the type.\n } & (\n | {input: InferParserType<TParams['_input'], 'out'>; formErrors?: undefined}\n | {\n input?: undefined;\n formErrors: z.ZodError<InferParserType<TParams['_input'], 'in'>>['formErrors']['fieldErrors'];\n }\n ),\n ) => Promise<TState>,\n ) => (prevState: TState, formData: FormData) => Promise<TState>;\n}\ntype AnyActionBuilder = ActionBuilder<any>;\n\ninterface ActionBuilderDef<TParams extends ActionParams<any>> {\n input: TParams['_input'];\n middleware: (() => Promise<TParams['_context']> | TParams['_context']) | undefined;\n}\ntype AnyActionBuilderDef = ActionBuilderDef<any>;\n\nconst createNewServerActionBuilder = (def: Partial<AnyActionBuilderDef>) => {\n return createServerActionBuilder(def);\n};\n\nconst createServerActionBuilder = (\n initDef: Partial<AnyActionBuilderDef> = {},\n): ActionBuilder<{\n _input: UnsetMarker;\n _context: UnsetMarker;\n}> => {\n const _def: ActionBuilderDef<{_input: z.ZodType | undefined; _context: undefined}> = {\n input: undefined,\n middleware: undefined,\n ...initDef,\n };\n return {\n middleware: (middleware) => createServerActionBuilder({..._def, middleware}) as AnyActionBuilder,\n input: (input) => createNewServerActionBuilder({..._def, input}) as AnyActionBuilder,\n action: (action) => {\n return async (input) => {\n const ctx = await _def.middleware?.();\n if (_def.input) {\n const result = _def.input.safeParse(input);\n if (!result.success) {\n throw fromZodError(result.error);\n }\n }\n return await action({ctx, input});\n };\n },\n experimental_formAction: (action) => {\n return async (prevState, formData) => {\n const ctx = await _def.middleware?.();\n if (_def.input) {\n const result = _def.input.safeParse(Object.fromEntries(formData.entries()));\n if (!result.success) {\n return await action({ctx, prevState, formErrors: result.error.formErrors.fieldErrors});\n }\n return await action({ctx, prevState, input: result.data});\n }\n return await action({ctx, prevState, input: undefined});\n };\n },\n };\n};\n\n/**\n * Server action builder\n */\nexport const serverAct = createServerActionBuilder();\n","import * as zod from 'zod';\nimport { joinPath } from './utils/joinPath';\nimport { isNonEmptyArray } from './utils/NonEmptyArray';\nconst MAX_ISSUES_IN_MESSAGE = 99;\nconst ISSUE_SEPARATOR = '; ';\nconst UNION_SEPARATOR = ', or ';\nconst PREFIX = 'Validation error';\nconst PREFIX_SEPARATOR = ': ';\nexport class ValidationError extends Error {\n details;\n name;\n constructor(message, details = []) {\n super(message);\n this.details = details;\n this.name = 'ZodValidationError';\n }\n toString() {\n return this.message;\n }\n}\nfunction getMessageFromZodIssue(issue, issueSeparator, unionSeparator) {\n if (issue.code === 'invalid_union') {\n return issue.unionErrors\n .reduce((acc, zodError) => {\n const newIssues = zodError.issues\n .map((issue) => getMessageFromZodIssue(issue, issueSeparator, unionSeparator))\n .join(issueSeparator);\n if (!acc.includes(newIssues)) {\n acc.push(newIssues);\n }\n return acc;\n }, [])\n .join(unionSeparator);\n }\n if (isNonEmptyArray(issue.path)) {\n if (issue.path.length === 1) {\n const identifier = issue.path[0];\n if (typeof identifier === 'number') {\n return `${issue.message} at index ${identifier}`;\n }\n }\n return `${issue.message} at \"${joinPath(issue.path)}\"`;\n }\n return issue.message;\n}\nfunction conditionallyPrefixMessage(reason, prefix, prefixSeparator) {\n if (prefix !== null) {\n if (reason.length > 0) {\n return [prefix, reason].join(prefixSeparator);\n }\n return prefix;\n }\n if (reason.length > 0) {\n return reason;\n }\n return PREFIX;\n}\nexport function fromZodIssue(issue, options = {}) {\n const { issueSeparator = ISSUE_SEPARATOR, unionSeparator = UNION_SEPARATOR, prefixSeparator = PREFIX_SEPARATOR, prefix = PREFIX, } = options;\n const reason = getMessageFromZodIssue(issue, issueSeparator, unionSeparator);\n const message = conditionallyPrefixMessage(reason, prefix, prefixSeparator);\n return new ValidationError(message, [issue]);\n}\nexport function fromZodError(zodError, options = {}) {\n const { maxIssuesInMessage = MAX_ISSUES_IN_MESSAGE, issueSeparator = ISSUE_SEPARATOR, unionSeparator = UNION_SEPARATOR, prefixSeparator = PREFIX_SEPARATOR, prefix = PREFIX, } = options;\n const reason = zodError.errors\n .slice(0, maxIssuesInMessage)\n .map((issue) => getMessageFromZodIssue(issue, issueSeparator, unionSeparator))\n .join(issueSeparator);\n const message = conditionallyPrefixMessage(reason, prefix, prefixSeparator);\n return new ValidationError(message, zodError.errors);\n}\nexport const toValidationError = (options = {}) => (err) => {\n if (err instanceof zod.ZodError) {\n return fromZodError(err, options);\n }\n if (err instanceof Error) {\n return err;\n }\n return new Error('Unknown error');\n};\nexport function isValidationError(err) {\n return err instanceof ValidationError;\n}\nexport function isValidationErrorLike(err) {\n return err instanceof Error && err.name === 'ZodValidationError';\n}\nexport const errorMap = (issue, ctx) => {\n const error = fromZodIssue({\n ...issue,\n message: issue.message ?? ctx.defaultError,\n });\n return {\n message: error.message,\n };\n};\n","const identifierRegex = /[$_\\p{ID_Start}][$\\u200c\\u200d\\p{ID_Continue}]*/u;\nexport function joinPath(path) {\n if (path.length === 1) {\n return path[0].toString();\n }\n return path.reduce((acc, item) => {\n if (typeof item === 'number') {\n return acc + '[' + item.toString() + ']';\n }\n if (item.includes('\"')) {\n return acc + '[\"' + escapeQuotes(item) + '\"]';\n }\n if (!identifierRegex.test(item)) {\n return acc + '[\"' + item + '\"]';\n }\n const separator = acc.length === 0 ? '' : '.';\n return acc + separator + item;\n }, '');\n}\nfunction escapeQuotes(str) {\n return str.replace(/\"/g, '\\\\\"');\n}\n","export function isNonEmptyArray(value) {\n return value.length !== 0;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,UAAqB;;;ACArB,IAAM,kBAAkB;AACjB,SAAS,SAAS,MAAM;AAC3B,MAAI,KAAK,WAAW,GAAG;AACnB,WAAO,KAAK,CAAC,EAAE,SAAS;AAAA,EAC5B;AACA,SAAO,KAAK,OAAO,CAAC,KAAK,SAAS;AAC9B,QAAI,OAAO,SAAS,UAAU;AAC1B,aAAO,MAAM,MAAM,KAAK,SAAS,IAAI;AAAA,IACzC;AACA,QAAI,KAAK,SAAS,GAAG,GAAG;AACpB,aAAO,MAAM,OAAO,aAAa,IAAI,IAAI;AAAA,IAC7C;AACA,QAAI,CAAC,gBAAgB,KAAK,IAAI,GAAG;AAC7B,aAAO,MAAM,OAAO,OAAO;AAAA,IAC/B;AACA,UAAM,YAAY,IAAI,WAAW,IAAI,KAAK;AAC1C,WAAO,MAAM,YAAY;AAAA,EAC7B,GAAG,EAAE;AACT;AACA,SAAS,aAAa,KAAK;AACvB,SAAO,IAAI,QAAQ,MAAM,KAAK;AAClC;;;ACrBO,SAAS,gBAAgB,OAAO;AACnC,SAAO,MAAM,WAAW;AAC5B;;;AFCA,IAAM,wBAAwB;AAC9B,IAAM,kBAAkB;AACxB,IAAM,kBAAkB;AACxB,IAAM,SAAS;AACf,IAAM,mBAAmB;AAClB,IAAM,kBAAN,cAA8B,MAAM;AAAA,EACvC;AAAA,EACA;AAAA,EACA,YAAY,SAAS,UAAU,CAAC,GAAG;AAC/B,UAAM,OAAO;AACb,SAAK,UAAU;AACf,SAAK,OAAO;AAAA,EAChB;AAAA,EACA,WAAW;AACP,WAAO,KAAK;AAAA,EAChB;AACJ;AACA,SAAS,uBAAuB,OAAO,gBAAgB,gBAAgB;AACnE,MAAI,MAAM,SAAS,iBAAiB;AAChC,WAAO,MAAM,YACR,OAAO,CAAC,KAAK,aAAa;AAC3B,YAAM,YAAY,SAAS,OACtB,IAAI,CAACA,WAAU,uBAAuBA,QAAO,gBAAgB,cAAc,CAAC,EAC5E,KAAK,cAAc;AACxB,UAAI,CAAC,IAAI,SAAS,SAAS,GAAG;AAC1B,YAAI,KAAK,SAAS;AAAA,MACtB;AACA,aAAO;AAAA,IACX,GAAG,CAAC,CAAC,EACA,KAAK,cAAc;AAAA,EAC5B;AACA,MAAI,gBAAgB,MAAM,IAAI,GAAG;AAC7B,QAAI,MAAM,KAAK,WAAW,GAAG;AACzB,YAAM,aAAa,MAAM,KAAK,CAAC;AAC/B,UAAI,OAAO,eAAe,UAAU;AAChC,eAAO,GAAG,MAAM,OAAO,aAAa,UAAU;AAAA,MAClD;AAAA,IACJ;AACA,WAAO,GAAG,MAAM,OAAO,QAAQ,SAAS,MAAM,IAAI,CAAC;AAAA,EACvD;AACA,SAAO,MAAM;AACjB;AACA,SAAS,2BAA2B,QAAQ,QAAQ,iBAAiB;AACjE,MAAI,WAAW,MAAM;AACjB,QAAI,OAAO,SAAS,GAAG;AACnB,aAAO,CAAC,QAAQ,MAAM,EAAE,KAAK,eAAe;AAAA,IAChD;AACA,WAAO;AAAA,EACX;AACA,MAAI,OAAO,SAAS,GAAG;AACnB,WAAO;AAAA,EACX;AACA,SAAO;AACX;AAOO,SAAS,aAAa,UAAU,UAAU,CAAC,GAAG;AACjD,QAAM,EAAE,qBAAqB,uBAAuB,iBAAiB,iBAAiB,iBAAiB,iBAAiB,kBAAkB,kBAAkB,SAAS,OAAQ,IAAI;AACjL,QAAM,SAAS,SAAS,OACnB,MAAM,GAAG,kBAAkB,EAC3B,IAAI,CAAC,UAAU,uBAAuB,OAAO,gBAAgB,cAAc,CAAC,EAC5E,KAAK,cAAc;AACxB,QAAM,UAAU,2BAA2B,QAAQ,QAAQ,eAAe;AAC1E,SAAO,IAAI,gBAAgB,SAAS,SAAS,MAAM;AACvD;;;ADlEA,IAAM,cAAc,OAAO,aAAa;AAgExC,IAAM,+BAA+B,CAAC,QAAsC;AAC1E,SAAO,0BAA0B,GAAG;AACtC;AAEA,IAAM,4BAA4B,CAChC,UAAwC,CAAC,MAIrC;AACJ,QAAM,OAA+E;AAAA,IACnF,OAAO;AAAA,IACP,YAAY;AAAA,IACZ,GAAG;AAAA,EACL;AACA,SAAO;AAAA,IACL,YAAY,CAAC,eAAe,0BAA0B,EAAC,GAAG,MAAM,WAAU,CAAC;AAAA,IAC3E,OAAO,CAAC,UAAU,6BAA6B,EAAC,GAAG,MAAM,MAAK,CAAC;AAAA,IAC/D,QAAQ,CAAC,WAAW;AAClB,aAAO,OAAO,UAAU;AAxF9B;AAyFQ,cAAM,MAAM,QAAM,UAAK,eAAL;AAClB,YAAI,KAAK,OAAO;AACd,gBAAM,SAAS,KAAK,MAAM,UAAU,KAAK;AACzC,cAAI,CAAC,OAAO,SAAS;AACnB,kBAAM,aAAa,OAAO,KAAK;AAAA,UACjC;AAAA,QACF;AACA,eAAO,MAAM,OAAO,EAAC,KAAK,MAAK,CAAC;AAAA,MAClC;AAAA,IACF;AAAA,IACA,yBAAyB,CAAC,WAAW;AACnC,aAAO,OAAO,WAAW,aAAa;AApG5C;AAqGQ,cAAM,MAAM,QAAM,UAAK,eAAL;AAClB,YAAI,KAAK,OAAO;AACd,gBAAM,SAAS,KAAK,MAAM,UAAU,OAAO,YAAY,SAAS,QAAQ,CAAC,CAAC;AAC1E,cAAI,CAAC,OAAO,SAAS;AACnB,mBAAO,MAAM,OAAO,EAAC,KAAK,WAAW,YAAY,OAAO,MAAM,WAAW,YAAW,CAAC;AAAA,UACvF;AACA,iBAAO,MAAM,OAAO,EAAC,KAAK,WAAW,OAAO,OAAO,KAAI,CAAC;AAAA,QAC1D;AACA,eAAO,MAAM,OAAO,EAAC,KAAK,WAAW,OAAO,OAAS,CAAC;AAAA,MACxD;AAAA,IACF;AAAA,EACF;AACF;AAKO,IAAM,YAAY,0BAA0B;","names":["issue"]}
|
package/dist/index.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
// ../../node_modules/.pnpm/zod-validation-error@1.
|
|
1
|
+
// ../../node_modules/.pnpm/zod-validation-error@1.5.0_zod@3.22.2/node_modules/zod-validation-error/dist/esm/ValidationError.js
|
|
2
2
|
import * as zod from "zod";
|
|
3
3
|
|
|
4
|
-
// ../../node_modules/.pnpm/zod-validation-error@1.
|
|
4
|
+
// ../../node_modules/.pnpm/zod-validation-error@1.5.0_zod@3.22.2/node_modules/zod-validation-error/dist/esm/utils/joinPath.js
|
|
5
5
|
var identifierRegex = /[$_\p{ID_Start}][$\u200c\u200d\p{ID_Continue}]*/u;
|
|
6
6
|
function joinPath(path) {
|
|
7
7
|
if (path.length === 1) {
|
|
@@ -25,12 +25,17 @@ function escapeQuotes(str) {
|
|
|
25
25
|
return str.replace(/"/g, '\\"');
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
-
// ../../node_modules/.pnpm/zod-validation-error@1.
|
|
28
|
+
// ../../node_modules/.pnpm/zod-validation-error@1.5.0_zod@3.22.2/node_modules/zod-validation-error/dist/esm/utils/NonEmptyArray.js
|
|
29
29
|
function isNonEmptyArray(value) {
|
|
30
30
|
return value.length !== 0;
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
-
// ../../node_modules/.pnpm/zod-validation-error@1.
|
|
33
|
+
// ../../node_modules/.pnpm/zod-validation-error@1.5.0_zod@3.22.2/node_modules/zod-validation-error/dist/esm/ValidationError.js
|
|
34
|
+
var MAX_ISSUES_IN_MESSAGE = 99;
|
|
35
|
+
var ISSUE_SEPARATOR = "; ";
|
|
36
|
+
var UNION_SEPARATOR = ", or ";
|
|
37
|
+
var PREFIX = "Validation error";
|
|
38
|
+
var PREFIX_SEPARATOR = ": ";
|
|
34
39
|
var ValidationError = class extends Error {
|
|
35
40
|
details;
|
|
36
41
|
name;
|
|
@@ -43,10 +48,10 @@ var ValidationError = class extends Error {
|
|
|
43
48
|
return this.message;
|
|
44
49
|
}
|
|
45
50
|
};
|
|
46
|
-
function
|
|
51
|
+
function getMessageFromZodIssue(issue, issueSeparator, unionSeparator) {
|
|
47
52
|
if (issue.code === "invalid_union") {
|
|
48
53
|
return issue.unionErrors.reduce((acc, zodError) => {
|
|
49
|
-
const newIssues = zodError.issues.map((issue2) =>
|
|
54
|
+
const newIssues = zodError.issues.map((issue2) => getMessageFromZodIssue(issue2, issueSeparator, unionSeparator)).join(issueSeparator);
|
|
50
55
|
if (!acc.includes(newIssues)) {
|
|
51
56
|
acc.push(newIssues);
|
|
52
57
|
}
|
|
@@ -64,10 +69,22 @@ function fromZodIssue(issue, issueSeparator, unionSeparator) {
|
|
|
64
69
|
}
|
|
65
70
|
return issue.message;
|
|
66
71
|
}
|
|
72
|
+
function conditionallyPrefixMessage(reason, prefix, prefixSeparator) {
|
|
73
|
+
if (prefix !== null) {
|
|
74
|
+
if (reason.length > 0) {
|
|
75
|
+
return [prefix, reason].join(prefixSeparator);
|
|
76
|
+
}
|
|
77
|
+
return prefix;
|
|
78
|
+
}
|
|
79
|
+
if (reason.length > 0) {
|
|
80
|
+
return reason;
|
|
81
|
+
}
|
|
82
|
+
return PREFIX;
|
|
83
|
+
}
|
|
67
84
|
function fromZodError(zodError, options = {}) {
|
|
68
|
-
const { maxIssuesInMessage =
|
|
69
|
-
const reason = zodError.errors.slice(0, maxIssuesInMessage).map((issue) =>
|
|
70
|
-
const message = reason
|
|
85
|
+
const { maxIssuesInMessage = MAX_ISSUES_IN_MESSAGE, issueSeparator = ISSUE_SEPARATOR, unionSeparator = UNION_SEPARATOR, prefixSeparator = PREFIX_SEPARATOR, prefix = PREFIX } = options;
|
|
86
|
+
const reason = zodError.errors.slice(0, maxIssuesInMessage).map((issue) => getMessageFromZodIssue(issue, issueSeparator, unionSeparator)).join(issueSeparator);
|
|
87
|
+
const message = conditionallyPrefixMessage(reason, prefix, prefixSeparator);
|
|
71
88
|
return new ValidationError(message, zodError.errors);
|
|
72
89
|
}
|
|
73
90
|
|
|
@@ -97,6 +114,20 @@ var createServerActionBuilder = (initDef = {}) => {
|
|
|
97
114
|
}
|
|
98
115
|
return await action({ ctx, input });
|
|
99
116
|
};
|
|
117
|
+
},
|
|
118
|
+
experimental_formAction: (action) => {
|
|
119
|
+
return async (prevState, formData) => {
|
|
120
|
+
var _a;
|
|
121
|
+
const ctx = await ((_a = _def.middleware) == null ? void 0 : _a.call(_def));
|
|
122
|
+
if (_def.input) {
|
|
123
|
+
const result = _def.input.safeParse(Object.fromEntries(formData.entries()));
|
|
124
|
+
if (!result.success) {
|
|
125
|
+
return await action({ ctx, prevState, formErrors: result.error.formErrors.fieldErrors });
|
|
126
|
+
}
|
|
127
|
+
return await action({ ctx, prevState, input: result.data });
|
|
128
|
+
}
|
|
129
|
+
return await action({ ctx, prevState, input: void 0 });
|
|
130
|
+
};
|
|
100
131
|
}
|
|
101
132
|
};
|
|
102
133
|
};
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../node_modules/.pnpm/zod-validation-error@1.3.0_zod@3.21.4/node_modules/zod-validation-error/dist/esm/ValidationError.js","../../../node_modules/.pnpm/zod-validation-error@1.3.0_zod@3.21.4/node_modules/zod-validation-error/dist/esm/utils/joinPath.js","../../../node_modules/.pnpm/zod-validation-error@1.3.0_zod@3.21.4/node_modules/zod-validation-error/dist/esm/utils/NonEmptyArray.js","../src/index.ts"],"sourcesContent":["import * as zod from 'zod';\nimport { joinPath } from './utils/joinPath';\nimport { isNonEmptyArray } from './utils/NonEmptyArray';\nexport class ValidationError extends Error {\n details;\n name;\n constructor(message, details = []) {\n super(message);\n this.details = details;\n this.name = 'ZodValidationError';\n }\n toString() {\n return this.message;\n }\n}\nfunction fromZodIssue(issue, issueSeparator, unionSeparator) {\n if (issue.code === 'invalid_union') {\n return issue.unionErrors\n .reduce((acc, zodError) => {\n const newIssues = zodError.issues\n .map((issue) => fromZodIssue(issue, issueSeparator, unionSeparator))\n .join(issueSeparator);\n if (!acc.includes(newIssues)) {\n acc.push(newIssues);\n }\n return acc;\n }, [])\n .join(unionSeparator);\n }\n if (isNonEmptyArray(issue.path)) {\n if (issue.path.length === 1) {\n const identifier = issue.path[0];\n if (typeof identifier === 'number') {\n return `${issue.message} at index ${identifier}`;\n }\n }\n return `${issue.message} at \"${joinPath(issue.path)}\"`;\n }\n return issue.message;\n}\nexport function fromZodError(zodError, options = {}) {\n const { maxIssuesInMessage = 99, issueSeparator = '; ', unionSeparator = ', or ', prefixSeparator = ': ', prefix = 'Validation error', } = options;\n const reason = zodError.errors\n .slice(0, maxIssuesInMessage)\n .map((issue) => fromZodIssue(issue, issueSeparator, unionSeparator))\n .join(issueSeparator);\n const message = reason ? [prefix, reason].join(prefixSeparator) : prefix;\n return new ValidationError(message, zodError.errors);\n}\nexport const toValidationError = (options = {}) => (err) => {\n if (err instanceof zod.ZodError) {\n return fromZodError(err, options);\n }\n if (err instanceof Error) {\n return err;\n }\n return new Error('Unknown error');\n};\nexport function isValidationError(err) {\n return err instanceof ValidationError;\n}\nexport function isValidationErrorLike(err) {\n return err instanceof Error && err.name === 'ZodValidationError';\n}\n","const identifierRegex = /[$_\\p{ID_Start}][$\\u200c\\u200d\\p{ID_Continue}]*/u;\nexport function joinPath(path) {\n if (path.length === 1) {\n return path[0].toString();\n }\n return path.reduce((acc, item) => {\n if (typeof item === 'number') {\n return acc + '[' + item.toString() + ']';\n }\n if (item.includes('\"')) {\n return acc + '[\"' + escapeQuotes(item) + '\"]';\n }\n if (!identifierRegex.test(item)) {\n return acc + '[\"' + item + '\"]';\n }\n const separator = acc.length === 0 ? '' : '.';\n return acc + separator + item;\n }, '');\n}\nfunction escapeQuotes(str) {\n return str.replace(/\"/g, '\\\\\"');\n}\n","export function isNonEmptyArray(value) {\n return value.length !== 0;\n}\n","/* eslint-disable @typescript-eslint/no-explicit-any */\nimport {type z} from 'zod';\nimport {fromZodError} from 'zod-validation-error';\n\nconst unsetMarker = Symbol('unsetMarker');\ntype UnsetMarker = typeof unsetMarker;\n\ntype OptionalizeUndefined<T> = undefined extends T ? [param?: T] : [param: T];\n\ntype InferParserType<TParser, TType extends 'in' | 'out'> = TParser extends UnsetMarker\n ? undefined\n : TParser extends z.ZodType\n ? TParser[TType extends 'in' ? '_input' : '_output']\n : never;\n\ntype InferContextType<T> = T extends UnsetMarker ? undefined : T;\n\ntype ActionParams<TInput = unknown, TContext = unknown> = {\n _input: TInput;\n _context: TContext;\n};\n\ntype ActionBuilder<TParams extends ActionParams> = {\n /**\n * Middleware allows you to run code before the action, and return context to the action.\n */\n middleware: <TContext>(\n middleware: () => Promise<TContext> | TContext,\n ) => ActionBuilder<{_input: TParams['_input']; _context: TContext}>;\n /**\n * Input validation for the action.\n */\n input: <TParser extends z.ZodType>(input: TParser) => ActionBuilder<{_input: TParser; _context: TParams['_context']}>;\n /**\n * Create an action.\n */\n action: <TOutput>(\n action: (params: {\n ctx: InferContextType<TParams['_context']>;\n input: InferParserType<TParams['_input'], 'out'>;\n }) => Promise<TOutput>,\n ) => (...[input]: OptionalizeUndefined<InferParserType<TParams['_input'], 'in'>>) => Promise<TOutput>;\n};\ntype AnyActionBuilder = ActionBuilder<any>;\n\ntype ActionBuilderDef<TParams extends ActionParams<any>> = {\n input: TParams['_input'];\n middleware: (() => Promise<TParams['_context']> | TParams['_context']) | undefined;\n};\ntype AnyActionBuilderDef = ActionBuilderDef<any>;\n\nconst createNewServerActionBuilder = (def: Partial<AnyActionBuilderDef>) => {\n return createServerActionBuilder(def);\n};\n\nconst createServerActionBuilder = (\n initDef: Partial<AnyActionBuilderDef> = {},\n): ActionBuilder<{\n _input: UnsetMarker;\n _context: UnsetMarker;\n}> => {\n const _def: ActionBuilderDef<{_input: z.ZodType | undefined; _context: undefined}> = {\n input: undefined,\n middleware: undefined,\n ...initDef,\n };\n return {\n middleware: (middleware) => createServerActionBuilder({..._def, middleware}) as AnyActionBuilder,\n input: (input) => createNewServerActionBuilder({..._def, input}) as AnyActionBuilder,\n action: (action) => {\n return async (input) => {\n const ctx = await _def.middleware?.();\n if (_def.input) {\n const result = _def.input.safeParse(input);\n if (!result.success) {\n throw fromZodError(result.error);\n }\n }\n return await action({ctx, input});\n };\n },\n };\n};\n\n/**\n * Server action builder\n */\nexport const serverAct = createServerActionBuilder();\n"],"mappings":";AAAA,YAAY,SAAS;;;ACArB,IAAM,kBAAkB;AACjB,SAAS,SAAS,MAAM;AAC3B,MAAI,KAAK,WAAW,GAAG;AACnB,WAAO,KAAK,CAAC,EAAE,SAAS;AAAA,EAC5B;AACA,SAAO,KAAK,OAAO,CAAC,KAAK,SAAS;AAC9B,QAAI,OAAO,SAAS,UAAU;AAC1B,aAAO,MAAM,MAAM,KAAK,SAAS,IAAI;AAAA,IACzC;AACA,QAAI,KAAK,SAAS,GAAG,GAAG;AACpB,aAAO,MAAM,OAAO,aAAa,IAAI,IAAI;AAAA,IAC7C;AACA,QAAI,CAAC,gBAAgB,KAAK,IAAI,GAAG;AAC7B,aAAO,MAAM,OAAO,OAAO;AAAA,IAC/B;AACA,UAAM,YAAY,IAAI,WAAW,IAAI,KAAK;AAC1C,WAAO,MAAM,YAAY;AAAA,EAC7B,GAAG,EAAE;AACT;AACA,SAAS,aAAa,KAAK;AACvB,SAAO,IAAI,QAAQ,MAAM,KAAK;AAClC;;;ACrBO,SAAS,gBAAgB,OAAO;AACnC,SAAO,MAAM,WAAW;AAC5B;;;AFCO,IAAM,kBAAN,cAA8B,MAAM;AAAA,EACvC;AAAA,EACA;AAAA,EACA,YAAY,SAAS,UAAU,CAAC,GAAG;AAC/B,UAAM,OAAO;AACb,SAAK,UAAU;AACf,SAAK,OAAO;AAAA,EAChB;AAAA,EACA,WAAW;AACP,WAAO,KAAK;AAAA,EAChB;AACJ;AACA,SAAS,aAAa,OAAO,gBAAgB,gBAAgB;AACzD,MAAI,MAAM,SAAS,iBAAiB;AAChC,WAAO,MAAM,YACR,OAAO,CAAC,KAAK,aAAa;AAC3B,YAAM,YAAY,SAAS,OACtB,IAAI,CAACA,WAAU,aAAaA,QAAO,gBAAgB,cAAc,CAAC,EAClE,KAAK,cAAc;AACxB,UAAI,CAAC,IAAI,SAAS,SAAS,GAAG;AAC1B,YAAI,KAAK,SAAS;AAAA,MACtB;AACA,aAAO;AAAA,IACX,GAAG,CAAC,CAAC,EACA,KAAK,cAAc;AAAA,EAC5B;AACA,MAAI,gBAAgB,MAAM,IAAI,GAAG;AAC7B,QAAI,MAAM,KAAK,WAAW,GAAG;AACzB,YAAM,aAAa,MAAM,KAAK,CAAC;AAC/B,UAAI,OAAO,eAAe,UAAU;AAChC,eAAO,GAAG,MAAM,oBAAoB;AAAA,MACxC;AAAA,IACJ;AACA,WAAO,GAAG,MAAM,eAAe,SAAS,MAAM,IAAI;AAAA,EACtD;AACA,SAAO,MAAM;AACjB;AACO,SAAS,aAAa,UAAU,UAAU,CAAC,GAAG;AACjD,QAAM,EAAE,qBAAqB,IAAI,iBAAiB,MAAM,iBAAiB,SAAS,kBAAkB,MAAM,SAAS,mBAAoB,IAAI;AAC3I,QAAM,SAAS,SAAS,OACnB,MAAM,GAAG,kBAAkB,EAC3B,IAAI,CAAC,UAAU,aAAa,OAAO,gBAAgB,cAAc,CAAC,EAClE,KAAK,cAAc;AACxB,QAAM,UAAU,SAAS,CAAC,QAAQ,MAAM,EAAE,KAAK,eAAe,IAAI;AAClE,SAAO,IAAI,gBAAgB,SAAS,SAAS,MAAM;AACvD;;;AG5CA,IAAM,cAAc,OAAO,aAAa;AA+CxC,IAAM,+BAA+B,CAAC,QAAsC;AAC1E,SAAO,0BAA0B,GAAG;AACtC;AAEA,IAAM,4BAA4B,CAChC,UAAwC,CAAC,MAIrC;AACJ,QAAM,OAA+E;AAAA,IACnF,OAAO;AAAA,IACP,YAAY;AAAA,IACZ,GAAG;AAAA,EACL;AACA,SAAO;AAAA,IACL,YAAY,CAAC,eAAe,0BAA0B,EAAC,GAAG,MAAM,WAAU,CAAC;AAAA,IAC3E,OAAO,CAAC,UAAU,6BAA6B,EAAC,GAAG,MAAM,MAAK,CAAC;AAAA,IAC/D,QAAQ,CAAC,WAAW;AAClB,aAAO,OAAO,UAAU;AAtE9B;AAuEQ,cAAM,MAAM,QAAM,UAAK,eAAL;AAClB,YAAI,KAAK,OAAO;AACd,gBAAM,SAAS,KAAK,MAAM,UAAU,KAAK;AACzC,cAAI,CAAC,OAAO,SAAS;AACnB,kBAAM,aAAa,OAAO,KAAK;AAAA,UACjC;AAAA,QACF;AACA,eAAO,MAAM,OAAO,EAAC,KAAK,MAAK,CAAC;AAAA,MAClC;AAAA,IACF;AAAA,EACF;AACF;AAKO,IAAM,YAAY,0BAA0B;","names":["issue"]}
|
|
1
|
+
{"version":3,"sources":["../../../node_modules/.pnpm/zod-validation-error@1.5.0_zod@3.22.2/node_modules/zod-validation-error/dist/esm/ValidationError.js","../../../node_modules/.pnpm/zod-validation-error@1.5.0_zod@3.22.2/node_modules/zod-validation-error/dist/esm/utils/joinPath.js","../../../node_modules/.pnpm/zod-validation-error@1.5.0_zod@3.22.2/node_modules/zod-validation-error/dist/esm/utils/NonEmptyArray.js","../src/index.ts"],"sourcesContent":["import * as zod from 'zod';\nimport { joinPath } from './utils/joinPath';\nimport { isNonEmptyArray } from './utils/NonEmptyArray';\nconst MAX_ISSUES_IN_MESSAGE = 99;\nconst ISSUE_SEPARATOR = '; ';\nconst UNION_SEPARATOR = ', or ';\nconst PREFIX = 'Validation error';\nconst PREFIX_SEPARATOR = ': ';\nexport class ValidationError extends Error {\n details;\n name;\n constructor(message, details = []) {\n super(message);\n this.details = details;\n this.name = 'ZodValidationError';\n }\n toString() {\n return this.message;\n }\n}\nfunction getMessageFromZodIssue(issue, issueSeparator, unionSeparator) {\n if (issue.code === 'invalid_union') {\n return issue.unionErrors\n .reduce((acc, zodError) => {\n const newIssues = zodError.issues\n .map((issue) => getMessageFromZodIssue(issue, issueSeparator, unionSeparator))\n .join(issueSeparator);\n if (!acc.includes(newIssues)) {\n acc.push(newIssues);\n }\n return acc;\n }, [])\n .join(unionSeparator);\n }\n if (isNonEmptyArray(issue.path)) {\n if (issue.path.length === 1) {\n const identifier = issue.path[0];\n if (typeof identifier === 'number') {\n return `${issue.message} at index ${identifier}`;\n }\n }\n return `${issue.message} at \"${joinPath(issue.path)}\"`;\n }\n return issue.message;\n}\nfunction conditionallyPrefixMessage(reason, prefix, prefixSeparator) {\n if (prefix !== null) {\n if (reason.length > 0) {\n return [prefix, reason].join(prefixSeparator);\n }\n return prefix;\n }\n if (reason.length > 0) {\n return reason;\n }\n return PREFIX;\n}\nexport function fromZodIssue(issue, options = {}) {\n const { issueSeparator = ISSUE_SEPARATOR, unionSeparator = UNION_SEPARATOR, prefixSeparator = PREFIX_SEPARATOR, prefix = PREFIX, } = options;\n const reason = getMessageFromZodIssue(issue, issueSeparator, unionSeparator);\n const message = conditionallyPrefixMessage(reason, prefix, prefixSeparator);\n return new ValidationError(message, [issue]);\n}\nexport function fromZodError(zodError, options = {}) {\n const { maxIssuesInMessage = MAX_ISSUES_IN_MESSAGE, issueSeparator = ISSUE_SEPARATOR, unionSeparator = UNION_SEPARATOR, prefixSeparator = PREFIX_SEPARATOR, prefix = PREFIX, } = options;\n const reason = zodError.errors\n .slice(0, maxIssuesInMessage)\n .map((issue) => getMessageFromZodIssue(issue, issueSeparator, unionSeparator))\n .join(issueSeparator);\n const message = conditionallyPrefixMessage(reason, prefix, prefixSeparator);\n return new ValidationError(message, zodError.errors);\n}\nexport const toValidationError = (options = {}) => (err) => {\n if (err instanceof zod.ZodError) {\n return fromZodError(err, options);\n }\n if (err instanceof Error) {\n return err;\n }\n return new Error('Unknown error');\n};\nexport function isValidationError(err) {\n return err instanceof ValidationError;\n}\nexport function isValidationErrorLike(err) {\n return err instanceof Error && err.name === 'ZodValidationError';\n}\nexport const errorMap = (issue, ctx) => {\n const error = fromZodIssue({\n ...issue,\n message: issue.message ?? ctx.defaultError,\n });\n return {\n message: error.message,\n };\n};\n","const identifierRegex = /[$_\\p{ID_Start}][$\\u200c\\u200d\\p{ID_Continue}]*/u;\nexport function joinPath(path) {\n if (path.length === 1) {\n return path[0].toString();\n }\n return path.reduce((acc, item) => {\n if (typeof item === 'number') {\n return acc + '[' + item.toString() + ']';\n }\n if (item.includes('\"')) {\n return acc + '[\"' + escapeQuotes(item) + '\"]';\n }\n if (!identifierRegex.test(item)) {\n return acc + '[\"' + item + '\"]';\n }\n const separator = acc.length === 0 ? '' : '.';\n return acc + separator + item;\n }, '');\n}\nfunction escapeQuotes(str) {\n return str.replace(/\"/g, '\\\\\"');\n}\n","export function isNonEmptyArray(value) {\n return value.length !== 0;\n}\n","/* eslint-disable @typescript-eslint/no-unsafe-assignment */\n/* eslint-disable @typescript-eslint/no-explicit-any */\nimport {type z} from 'zod';\nimport {fromZodError} from 'zod-validation-error';\n\nconst unsetMarker = Symbol('unsetMarker');\ntype UnsetMarker = typeof unsetMarker;\n\ntype OptionalizeUndefined<T> = undefined extends T ? [param?: T] : [param: T];\n\ntype InferParserType<TParser, TType extends 'in' | 'out'> = TParser extends UnsetMarker\n ? undefined\n : TParser extends z.ZodType\n ? TParser[TType extends 'in' ? '_input' : '_output']\n : never;\n\ntype InferContextType<T> = T extends UnsetMarker ? undefined : T;\n\ninterface ActionParams<TInput = unknown, TContext = unknown> {\n _input: TInput;\n _context: TContext;\n}\n\ninterface ActionBuilder<TParams extends ActionParams> {\n /**\n * Middleware allows you to run code before the action, its return value will pass as context to the action.\n */\n middleware: <TContext>(\n middleware: () => Promise<TContext> | TContext,\n ) => ActionBuilder<{_input: TParams['_input']; _context: TContext}>;\n /**\n * Input validation for the action.\n */\n input: <TParser extends z.ZodType>(input: TParser) => ActionBuilder<{_input: TParser; _context: TParams['_context']}>;\n /**\n * Create an action.\n */\n action: <TOutput>(\n action: (params: {\n ctx: InferContextType<TParams['_context']>;\n input: InferParserType<TParams['_input'], 'out'>;\n }) => Promise<TOutput>,\n ) => (...[input]: OptionalizeUndefined<InferParserType<TParams['_input'], 'in'>>) => Promise<TOutput>;\n /**\n * ***Experimental*** - Create an action for React `useFormState`\n */\n experimental_formAction: <TState>(\n action: (\n params: {\n ctx: InferContextType<TParams['_context']>;\n prevState: any; // FIXME: This supposes to be `TState`, but we can't, as it will break the type.\n } & (\n | {input: InferParserType<TParams['_input'], 'out'>; formErrors?: undefined}\n | {\n input?: undefined;\n formErrors: z.ZodError<InferParserType<TParams['_input'], 'in'>>['formErrors']['fieldErrors'];\n }\n ),\n ) => Promise<TState>,\n ) => (prevState: TState, formData: FormData) => Promise<TState>;\n}\ntype AnyActionBuilder = ActionBuilder<any>;\n\ninterface ActionBuilderDef<TParams extends ActionParams<any>> {\n input: TParams['_input'];\n middleware: (() => Promise<TParams['_context']> | TParams['_context']) | undefined;\n}\ntype AnyActionBuilderDef = ActionBuilderDef<any>;\n\nconst createNewServerActionBuilder = (def: Partial<AnyActionBuilderDef>) => {\n return createServerActionBuilder(def);\n};\n\nconst createServerActionBuilder = (\n initDef: Partial<AnyActionBuilderDef> = {},\n): ActionBuilder<{\n _input: UnsetMarker;\n _context: UnsetMarker;\n}> => {\n const _def: ActionBuilderDef<{_input: z.ZodType | undefined; _context: undefined}> = {\n input: undefined,\n middleware: undefined,\n ...initDef,\n };\n return {\n middleware: (middleware) => createServerActionBuilder({..._def, middleware}) as AnyActionBuilder,\n input: (input) => createNewServerActionBuilder({..._def, input}) as AnyActionBuilder,\n action: (action) => {\n return async (input) => {\n const ctx = await _def.middleware?.();\n if (_def.input) {\n const result = _def.input.safeParse(input);\n if (!result.success) {\n throw fromZodError(result.error);\n }\n }\n return await action({ctx, input});\n };\n },\n experimental_formAction: (action) => {\n return async (prevState, formData) => {\n const ctx = await _def.middleware?.();\n if (_def.input) {\n const result = _def.input.safeParse(Object.fromEntries(formData.entries()));\n if (!result.success) {\n return await action({ctx, prevState, formErrors: result.error.formErrors.fieldErrors});\n }\n return await action({ctx, prevState, input: result.data});\n }\n return await action({ctx, prevState, input: undefined});\n };\n },\n };\n};\n\n/**\n * Server action builder\n */\nexport const serverAct = createServerActionBuilder();\n"],"mappings":";AAAA,YAAY,SAAS;;;ACArB,IAAM,kBAAkB;AACjB,SAAS,SAAS,MAAM;AAC3B,MAAI,KAAK,WAAW,GAAG;AACnB,WAAO,KAAK,CAAC,EAAE,SAAS;AAAA,EAC5B;AACA,SAAO,KAAK,OAAO,CAAC,KAAK,SAAS;AAC9B,QAAI,OAAO,SAAS,UAAU;AAC1B,aAAO,MAAM,MAAM,KAAK,SAAS,IAAI;AAAA,IACzC;AACA,QAAI,KAAK,SAAS,GAAG,GAAG;AACpB,aAAO,MAAM,OAAO,aAAa,IAAI,IAAI;AAAA,IAC7C;AACA,QAAI,CAAC,gBAAgB,KAAK,IAAI,GAAG;AAC7B,aAAO,MAAM,OAAO,OAAO;AAAA,IAC/B;AACA,UAAM,YAAY,IAAI,WAAW,IAAI,KAAK;AAC1C,WAAO,MAAM,YAAY;AAAA,EAC7B,GAAG,EAAE;AACT;AACA,SAAS,aAAa,KAAK;AACvB,SAAO,IAAI,QAAQ,MAAM,KAAK;AAClC;;;ACrBO,SAAS,gBAAgB,OAAO;AACnC,SAAO,MAAM,WAAW;AAC5B;;;AFCA,IAAM,wBAAwB;AAC9B,IAAM,kBAAkB;AACxB,IAAM,kBAAkB;AACxB,IAAM,SAAS;AACf,IAAM,mBAAmB;AAClB,IAAM,kBAAN,cAA8B,MAAM;AAAA,EACvC;AAAA,EACA;AAAA,EACA,YAAY,SAAS,UAAU,CAAC,GAAG;AAC/B,UAAM,OAAO;AACb,SAAK,UAAU;AACf,SAAK,OAAO;AAAA,EAChB;AAAA,EACA,WAAW;AACP,WAAO,KAAK;AAAA,EAChB;AACJ;AACA,SAAS,uBAAuB,OAAO,gBAAgB,gBAAgB;AACnE,MAAI,MAAM,SAAS,iBAAiB;AAChC,WAAO,MAAM,YACR,OAAO,CAAC,KAAK,aAAa;AAC3B,YAAM,YAAY,SAAS,OACtB,IAAI,CAACA,WAAU,uBAAuBA,QAAO,gBAAgB,cAAc,CAAC,EAC5E,KAAK,cAAc;AACxB,UAAI,CAAC,IAAI,SAAS,SAAS,GAAG;AAC1B,YAAI,KAAK,SAAS;AAAA,MACtB;AACA,aAAO;AAAA,IACX,GAAG,CAAC,CAAC,EACA,KAAK,cAAc;AAAA,EAC5B;AACA,MAAI,gBAAgB,MAAM,IAAI,GAAG;AAC7B,QAAI,MAAM,KAAK,WAAW,GAAG;AACzB,YAAM,aAAa,MAAM,KAAK,CAAC;AAC/B,UAAI,OAAO,eAAe,UAAU;AAChC,eAAO,GAAG,MAAM,OAAO,aAAa,UAAU;AAAA,MAClD;AAAA,IACJ;AACA,WAAO,GAAG,MAAM,OAAO,QAAQ,SAAS,MAAM,IAAI,CAAC;AAAA,EACvD;AACA,SAAO,MAAM;AACjB;AACA,SAAS,2BAA2B,QAAQ,QAAQ,iBAAiB;AACjE,MAAI,WAAW,MAAM;AACjB,QAAI,OAAO,SAAS,GAAG;AACnB,aAAO,CAAC,QAAQ,MAAM,EAAE,KAAK,eAAe;AAAA,IAChD;AACA,WAAO;AAAA,EACX;AACA,MAAI,OAAO,SAAS,GAAG;AACnB,WAAO;AAAA,EACX;AACA,SAAO;AACX;AAOO,SAAS,aAAa,UAAU,UAAU,CAAC,GAAG;AACjD,QAAM,EAAE,qBAAqB,uBAAuB,iBAAiB,iBAAiB,iBAAiB,iBAAiB,kBAAkB,kBAAkB,SAAS,OAAQ,IAAI;AACjL,QAAM,SAAS,SAAS,OACnB,MAAM,GAAG,kBAAkB,EAC3B,IAAI,CAAC,UAAU,uBAAuB,OAAO,gBAAgB,cAAc,CAAC,EAC5E,KAAK,cAAc;AACxB,QAAM,UAAU,2BAA2B,QAAQ,QAAQ,eAAe;AAC1E,SAAO,IAAI,gBAAgB,SAAS,SAAS,MAAM;AACvD;;;AGlEA,IAAM,cAAc,OAAO,aAAa;AAgExC,IAAM,+BAA+B,CAAC,QAAsC;AAC1E,SAAO,0BAA0B,GAAG;AACtC;AAEA,IAAM,4BAA4B,CAChC,UAAwC,CAAC,MAIrC;AACJ,QAAM,OAA+E;AAAA,IACnF,OAAO;AAAA,IACP,YAAY;AAAA,IACZ,GAAG;AAAA,EACL;AACA,SAAO;AAAA,IACL,YAAY,CAAC,eAAe,0BAA0B,EAAC,GAAG,MAAM,WAAU,CAAC;AAAA,IAC3E,OAAO,CAAC,UAAU,6BAA6B,EAAC,GAAG,MAAM,MAAK,CAAC;AAAA,IAC/D,QAAQ,CAAC,WAAW;AAClB,aAAO,OAAO,UAAU;AAxF9B;AAyFQ,cAAM,MAAM,QAAM,UAAK,eAAL;AAClB,YAAI,KAAK,OAAO;AACd,gBAAM,SAAS,KAAK,MAAM,UAAU,KAAK;AACzC,cAAI,CAAC,OAAO,SAAS;AACnB,kBAAM,aAAa,OAAO,KAAK;AAAA,UACjC;AAAA,QACF;AACA,eAAO,MAAM,OAAO,EAAC,KAAK,MAAK,CAAC;AAAA,MAClC;AAAA,IACF;AAAA,IACA,yBAAyB,CAAC,WAAW;AACnC,aAAO,OAAO,WAAW,aAAa;AApG5C;AAqGQ,cAAM,MAAM,QAAM,UAAK,eAAL;AAClB,YAAI,KAAK,OAAO;AACd,gBAAM,SAAS,KAAK,MAAM,UAAU,OAAO,YAAY,SAAS,QAAQ,CAAC,CAAC;AAC1E,cAAI,CAAC,OAAO,SAAS;AACnB,mBAAO,MAAM,OAAO,EAAC,KAAK,WAAW,YAAY,OAAO,MAAM,WAAW,YAAW,CAAC;AAAA,UACvF;AACA,iBAAO,MAAM,OAAO,EAAC,KAAK,WAAW,OAAO,OAAO,KAAI,CAAC;AAAA,QAC1D;AACA,eAAO,MAAM,OAAO,EAAC,KAAK,WAAW,OAAO,OAAS,CAAC;AAAA,MACxD;AAAA,IACF;AAAA,EACF;AACF;AAKO,IAAM,YAAY,0BAA0B;","names":["issue"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "server-act",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.7",
|
|
4
4
|
"homepage": "https://github.com/chungweileong94/server-act#readme",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -34,17 +34,17 @@
|
|
|
34
34
|
"author": "chungweileong94",
|
|
35
35
|
"license": "MIT",
|
|
36
36
|
"devDependencies": {
|
|
37
|
-
"eslint": "^8.
|
|
38
|
-
"eslint-config-whiteroom": "^3.
|
|
39
|
-
"prettier": "^
|
|
40
|
-
"tsup": "^
|
|
41
|
-
"typescript": "^5.
|
|
42
|
-
"zod": "^3.
|
|
43
|
-
"zod-validation-error": "^1.
|
|
37
|
+
"eslint": "^8.49.0",
|
|
38
|
+
"eslint-config-whiteroom": "^3.3.0",
|
|
39
|
+
"prettier": "^3.0.3",
|
|
40
|
+
"tsup": "^7.2.0",
|
|
41
|
+
"typescript": "^5.2.2",
|
|
42
|
+
"zod": "^3.22.2",
|
|
43
|
+
"zod-validation-error": "^1.5.0"
|
|
44
44
|
},
|
|
45
45
|
"peerDependencies": {
|
|
46
|
-
"typescript": "^5.
|
|
47
|
-
"zod": "^3.
|
|
46
|
+
"typescript": "^5.2.2",
|
|
47
|
+
"zod": "^3.22.2"
|
|
48
48
|
},
|
|
49
49
|
"scripts": {
|
|
50
50
|
"build": "tsup",
|
package/src/index.test.ts
CHANGED
|
@@ -3,59 +3,106 @@ import z from 'zod';
|
|
|
3
3
|
|
|
4
4
|
import {serverAct} from '.';
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
describe.concurrent('action', () => {
|
|
7
|
+
test('should able to create action without input', async () => {
|
|
8
|
+
const action = serverAct.action(async () => Promise.resolve('bar'));
|
|
8
9
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
});
|
|
10
|
+
expectTypeOf(action).parameter(0).toBeUndefined();
|
|
11
|
+
expectTypeOf(action).returns.resolves.toBeString();
|
|
12
|
+
await expect(action()).resolves.toBe('bar');
|
|
13
|
+
});
|
|
13
14
|
|
|
14
|
-
test('should able to create action with input', async () => {
|
|
15
|
-
|
|
15
|
+
test('should able to create action with input', async () => {
|
|
16
|
+
const action = serverAct.input(z.string()).action(async () => Promise.resolve('bar'));
|
|
16
17
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
});
|
|
18
|
+
expectTypeOf(action).parameter(0).toBeString();
|
|
19
|
+
expectTypeOf(action).returns.resolves.toBeString();
|
|
20
|
+
await expect(action('foo')).resolves.toBe('bar');
|
|
21
|
+
});
|
|
21
22
|
|
|
22
|
-
test('should throw error if the input is invalid', async () => {
|
|
23
|
-
|
|
23
|
+
test('should throw error if the input is invalid', async () => {
|
|
24
|
+
const action = serverAct.input(z.string()).action(async () => Promise.resolve('bar'));
|
|
24
25
|
|
|
25
|
-
|
|
26
|
-
|
|
26
|
+
expectTypeOf(action).parameter(0).toBeString();
|
|
27
|
+
expectTypeOf(action).returns.resolves.toBeString();
|
|
27
28
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
});
|
|
29
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
30
|
+
// @ts-ignore
|
|
31
|
+
await expect(action(1)).rejects.toThrowError();
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
describe('middleware should be called once', () => {
|
|
35
|
+
const middlewareSpy = vi.fn(() => {
|
|
36
|
+
return {prefix: 'best'};
|
|
37
|
+
});
|
|
32
38
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
39
|
+
beforeEach(() => {
|
|
40
|
+
vi.restoreAllMocks();
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
test('without input', async () => {
|
|
44
|
+
const action = serverAct.middleware(middlewareSpy).action(async ({ctx}) => Promise.resolve(`${ctx.prefix}-bar`));
|
|
45
|
+
|
|
46
|
+
expectTypeOf(action).returns.resolves.toBeString();
|
|
47
|
+
await expect(action()).resolves.toBe('best-bar');
|
|
48
|
+
expect(middlewareSpy).toBeCalledTimes(1);
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
test('with input', async () => {
|
|
52
|
+
const actionWithInput = serverAct
|
|
53
|
+
.middleware(middlewareSpy)
|
|
54
|
+
.input(z.string())
|
|
55
|
+
.action(async ({ctx, input}) => Promise.resolve(`${ctx.prefix}-${input}-bar`));
|
|
56
|
+
|
|
57
|
+
expectTypeOf(actionWithInput).parameter(0).toBeString();
|
|
58
|
+
expectTypeOf(actionWithInput).returns.resolves.toBeString();
|
|
59
|
+
await expect(actionWithInput('foo')).resolves.toBe('best-foo-bar');
|
|
60
|
+
expect(middlewareSpy).toBeCalledTimes(1);
|
|
61
|
+
});
|
|
36
62
|
});
|
|
63
|
+
});
|
|
37
64
|
|
|
38
|
-
|
|
39
|
-
|
|
65
|
+
describe.concurrent('experimental_formAction', () => {
|
|
66
|
+
test('should able to create form action without input', async () => {
|
|
67
|
+
const action = serverAct.experimental_formAction(async () => Promise.resolve('bar'));
|
|
68
|
+
|
|
69
|
+
expectTypeOf(action).parameter(0).toBeString();
|
|
70
|
+
expectTypeOf(action).parameter(1).toEqualTypeOf<FormData>();
|
|
71
|
+
expectTypeOf(action).returns.resolves.toBeString();
|
|
72
|
+
|
|
73
|
+
const formData = new FormData();
|
|
74
|
+
await expect(action('foo', formData)).resolves.toMatchObject('bar');
|
|
40
75
|
});
|
|
41
76
|
|
|
42
|
-
test('
|
|
43
|
-
const action = serverAct
|
|
77
|
+
test('should able to create form action with input', async () => {
|
|
78
|
+
const action = serverAct
|
|
79
|
+
.input(z.object({foo: z.string()}))
|
|
80
|
+
.experimental_formAction(async () => Promise.resolve('bar'));
|
|
44
81
|
|
|
82
|
+
expectTypeOf(action).parameter(0).toBeString();
|
|
83
|
+
expectTypeOf(action).parameter(1).toEqualTypeOf<FormData>();
|
|
45
84
|
expectTypeOf(action).returns.resolves.toBeString();
|
|
46
|
-
|
|
47
|
-
|
|
85
|
+
|
|
86
|
+
const formData = new FormData();
|
|
87
|
+
formData.append('foo', 'bar');
|
|
88
|
+
await expect(action('foo', formData)).resolves.toMatchObject('bar');
|
|
48
89
|
});
|
|
49
90
|
|
|
50
|
-
test('
|
|
51
|
-
const
|
|
52
|
-
.
|
|
53
|
-
.
|
|
54
|
-
|
|
91
|
+
test('should return form errors if the input is invalid', async () => {
|
|
92
|
+
const action = serverAct
|
|
93
|
+
.input(z.object({foo: z.string({required_error: 'Required'})}))
|
|
94
|
+
.experimental_formAction(async ({formErrors}) => {
|
|
95
|
+
if (formErrors) {
|
|
96
|
+
return formErrors;
|
|
97
|
+
}
|
|
98
|
+
return Promise.resolve('bar');
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
expectTypeOf(action).parameter(0).toMatchTypeOf<string | {foo?: string[]}>();
|
|
102
|
+
expectTypeOf(action).parameter(1).toEqualTypeOf<FormData>();
|
|
55
103
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
await expect(
|
|
59
|
-
expect(middlewareSpy).toBeCalledTimes(1);
|
|
104
|
+
const formData = new FormData();
|
|
105
|
+
formData.append('bar', 'foo');
|
|
106
|
+
await expect(action('foo', formData)).resolves.toMatchObject({foo: ['Required']});
|
|
60
107
|
});
|
|
61
108
|
});
|
package/src/index.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
|
|
1
2
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
3
|
import {type z} from 'zod';
|
|
3
4
|
import {fromZodError} from 'zod-validation-error';
|
|
@@ -15,14 +16,14 @@ type InferParserType<TParser, TType extends 'in' | 'out'> = TParser extends Unse
|
|
|
15
16
|
|
|
16
17
|
type InferContextType<T> = T extends UnsetMarker ? undefined : T;
|
|
17
18
|
|
|
18
|
-
|
|
19
|
+
interface ActionParams<TInput = unknown, TContext = unknown> {
|
|
19
20
|
_input: TInput;
|
|
20
21
|
_context: TContext;
|
|
21
|
-
}
|
|
22
|
+
}
|
|
22
23
|
|
|
23
|
-
|
|
24
|
+
interface ActionBuilder<TParams extends ActionParams> {
|
|
24
25
|
/**
|
|
25
|
-
* Middleware allows you to run code before the action,
|
|
26
|
+
* Middleware allows you to run code before the action, its return value will pass as context to the action.
|
|
26
27
|
*/
|
|
27
28
|
middleware: <TContext>(
|
|
28
29
|
middleware: () => Promise<TContext> | TContext,
|
|
@@ -40,13 +41,30 @@ type ActionBuilder<TParams extends ActionParams> = {
|
|
|
40
41
|
input: InferParserType<TParams['_input'], 'out'>;
|
|
41
42
|
}) => Promise<TOutput>,
|
|
42
43
|
) => (...[input]: OptionalizeUndefined<InferParserType<TParams['_input'], 'in'>>) => Promise<TOutput>;
|
|
43
|
-
|
|
44
|
+
/**
|
|
45
|
+
* ***Experimental*** - Create an action for React `useFormState`
|
|
46
|
+
*/
|
|
47
|
+
experimental_formAction: <TState>(
|
|
48
|
+
action: (
|
|
49
|
+
params: {
|
|
50
|
+
ctx: InferContextType<TParams['_context']>;
|
|
51
|
+
prevState: any; // FIXME: This supposes to be `TState`, but we can't, as it will break the type.
|
|
52
|
+
} & (
|
|
53
|
+
| {input: InferParserType<TParams['_input'], 'out'>; formErrors?: undefined}
|
|
54
|
+
| {
|
|
55
|
+
input?: undefined;
|
|
56
|
+
formErrors: z.ZodError<InferParserType<TParams['_input'], 'in'>>['formErrors']['fieldErrors'];
|
|
57
|
+
}
|
|
58
|
+
),
|
|
59
|
+
) => Promise<TState>,
|
|
60
|
+
) => (prevState: TState, formData: FormData) => Promise<TState>;
|
|
61
|
+
}
|
|
44
62
|
type AnyActionBuilder = ActionBuilder<any>;
|
|
45
63
|
|
|
46
|
-
|
|
64
|
+
interface ActionBuilderDef<TParams extends ActionParams<any>> {
|
|
47
65
|
input: TParams['_input'];
|
|
48
66
|
middleware: (() => Promise<TParams['_context']> | TParams['_context']) | undefined;
|
|
49
|
-
}
|
|
67
|
+
}
|
|
50
68
|
type AnyActionBuilderDef = ActionBuilderDef<any>;
|
|
51
69
|
|
|
52
70
|
const createNewServerActionBuilder = (def: Partial<AnyActionBuilderDef>) => {
|
|
@@ -79,6 +97,19 @@ const createServerActionBuilder = (
|
|
|
79
97
|
return await action({ctx, input});
|
|
80
98
|
};
|
|
81
99
|
},
|
|
100
|
+
experimental_formAction: (action) => {
|
|
101
|
+
return async (prevState, formData) => {
|
|
102
|
+
const ctx = await _def.middleware?.();
|
|
103
|
+
if (_def.input) {
|
|
104
|
+
const result = _def.input.safeParse(Object.fromEntries(formData.entries()));
|
|
105
|
+
if (!result.success) {
|
|
106
|
+
return await action({ctx, prevState, formErrors: result.error.formErrors.fieldErrors});
|
|
107
|
+
}
|
|
108
|
+
return await action({ctx, prevState, input: result.data});
|
|
109
|
+
}
|
|
110
|
+
return await action({ctx, prevState, input: undefined});
|
|
111
|
+
};
|
|
112
|
+
},
|
|
82
113
|
};
|
|
83
114
|
};
|
|
84
115
|
|
package/tsconfig.json
CHANGED
|
@@ -4,9 +4,12 @@
|
|
|
4
4
|
"_version": "2.0.0",
|
|
5
5
|
"compilerOptions": {
|
|
6
6
|
"lib": [
|
|
7
|
-
"ES2020"
|
|
7
|
+
"ES2020",
|
|
8
|
+
"DOM",
|
|
9
|
+
"DOM.Iterable"
|
|
8
10
|
],
|
|
9
|
-
"
|
|
11
|
+
"module": "NodeNext",
|
|
12
|
+
"moduleResolution": "NodeNext",
|
|
10
13
|
"outDir": "./dist",
|
|
11
14
|
"strict": true,
|
|
12
15
|
"allowUnusedLabels": false,
|