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.
@@ -1,21 +1,22 @@
1
1
 
2
- > server-act@0.0.5 build /home/runner/work/server-act/server-act/packages/server-act
2
+ > server-act@0.0.7 build /home/runner/work/server-act/server-act/packages/server-act
3
3
  > tsup
4
4
 
5
5
  CLI Building entry: ./src/index.ts
6
6
  CLI Using tsconfig: tsconfig.json
7
- CLI tsup v6.7.0
7
+ CLI tsup v7.2.0
8
8
  CLI Using tsup config: /home/runner/work/server-act/server-act/packages/server-act/tsup.config.ts
9
- CLI Target: node14
9
+ CLI Target: node16
10
10
  CLI Cleaning output folder
11
11
  ESM Build start
12
12
  CJS Build start
13
- CJS dist/index.js 5.16 KB
14
- CJS dist/index.js.map 8.68 KB
15
- CJS ⚡️ Build success in 29ms
16
- ESM dist/index.mjs 3.57 KB
17
- ESM dist/index.mjs.map 8.63 KB
13
+ ESM dist/index.mjs 4.66 KB
14
+ ESM dist/index.mjs.map 11.81 KB
18
15
  ESM ⚡️ Build success in 30ms
16
+ CJS dist/index.js 6.24 KB
17
+ CJS dist/index.js.map 11.86 KB
18
+ CJS ⚡️ Build success in 31ms
19
19
  DTS Build start
20
- DTS ⚡️ Build success in 713ms
21
- DTS dist/index.d.ts 1.52 KB
20
+ DTS ⚡️ Build success in 1055ms
21
+ DTS dist/index.d.mts 2.08 KB
22
+ DTS dist/index.d.ts 2.08 KB
package/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # server-act
2
2
 
3
+ ## 0.0.7
4
+
5
+ ### Patch Changes
6
+
7
+ - 50e2853: New experimental form action
8
+
9
+ ## 0.0.6
10
+
11
+ ### Patch Changes
12
+
13
+ - fedd1d4: Update README
14
+
3
15
  ## 0.0.5
4
16
 
5
17
  ### Patch Changes
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 ({ name }) => {
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
+ ```
@@ -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
- type ActionParams<TInput = unknown, TContext = unknown> = {
8
+ interface ActionParams<TInput = unknown, TContext = unknown> {
9
9
  _input: TInput;
10
10
  _context: TContext;
11
- };
12
- type ActionBuilder<TParams extends ActionParams> = {
11
+ }
12
+ interface ActionBuilder<TParams extends ActionParams> {
13
13
  /**
14
- * Middleware allows you to run code before the action, and return context to 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.3.0_zod@3.21.4/node_modules/zod-validation-error/dist/esm/ValidationError.js
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.3.0_zod@3.21.4/node_modules/zod-validation-error/dist/esm/utils/joinPath.js
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.3.0_zod@3.21.4/node_modules/zod-validation-error/dist/esm/utils/NonEmptyArray.js
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.3.0_zod@3.21.4/node_modules/zod-validation-error/dist/esm/ValidationError.js
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 fromZodIssue(issue, issueSeparator, unionSeparator) {
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) => fromZodIssue(issue2, issueSeparator, unionSeparator)).join(issueSeparator);
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 = 99, issueSeparator = "; ", unionSeparator = ", or ", prefixSeparator = ": ", prefix = "Validation error" } = options;
105
- const reason = zodError.errors.slice(0, maxIssuesInMessage).map((issue) => fromZodIssue(issue, issueSeparator, unionSeparator)).join(issueSeparator);
106
- const message = reason ? [prefix, reason].join(prefixSeparator) : prefix;
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":"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","names":["issue"]}
package/dist/index.mjs CHANGED
@@ -1,7 +1,7 @@
1
- // ../../node_modules/.pnpm/zod-validation-error@1.3.0_zod@3.21.4/node_modules/zod-validation-error/dist/esm/ValidationError.js
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.3.0_zod@3.21.4/node_modules/zod-validation-error/dist/esm/utils/joinPath.js
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.3.0_zod@3.21.4/node_modules/zod-validation-error/dist/esm/utils/NonEmptyArray.js
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.3.0_zod@3.21.4/node_modules/zod-validation-error/dist/esm/ValidationError.js
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 fromZodIssue(issue, issueSeparator, unionSeparator) {
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) => fromZodIssue(issue2, issueSeparator, unionSeparator)).join(issueSeparator);
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 = 99, issueSeparator = "; ", unionSeparator = ", or ", prefixSeparator = ": ", prefix = "Validation error" } = options;
69
- const reason = zodError.errors.slice(0, maxIssuesInMessage).map((issue) => fromZodIssue(issue, issueSeparator, unionSeparator)).join(issueSeparator);
70
- const message = reason ? [prefix, reason].join(prefixSeparator) : prefix;
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
  };
@@ -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":"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","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":"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","names":["issue"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "server-act",
3
- "version": "0.0.5",
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.39.0",
38
- "eslint-config-whiteroom": "^3.1.0",
39
- "prettier": "^2.8.8",
40
- "tsup": "^6.7.0",
41
- "typescript": "^5.0.4",
42
- "zod": "^3.21.4",
43
- "zod-validation-error": "^1.3.0"
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.0.4",
47
- "zod": "^3.21.4"
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
- test('should able to create action without input', async () => {
7
- const action = serverAct.action(async () => Promise.resolve('bar'));
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
- expectTypeOf(action).parameter(0).toBeUndefined();
10
- expectTypeOf(action).returns.resolves.toBeString();
11
- await expect(action()).resolves.toBe('bar');
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
- const action = serverAct.input(z.string()).action(async () => Promise.resolve('bar'));
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
- expectTypeOf(action).parameter(0).toBeString();
18
- expectTypeOf(action).returns.resolves.toBeString();
19
- await expect(action('foo')).resolves.toBe('bar');
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
- const action = serverAct.input(z.string()).action(async () => Promise.resolve('bar'));
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
- expectTypeOf(action).parameter(0).toBeString();
26
- expectTypeOf(action).returns.resolves.toBeString();
26
+ expectTypeOf(action).parameter(0).toBeString();
27
+ expectTypeOf(action).returns.resolves.toBeString();
27
28
 
28
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
29
- // @ts-ignore
30
- await expect(action(1)).rejects.toThrowError();
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
- describe('middleware should be called once', () => {
34
- const middlewareSpy = vi.fn(() => {
35
- return {prefix: 'best'};
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
- beforeEach(() => {
39
- vi.restoreAllMocks();
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('without input', async () => {
43
- const action = serverAct.middleware(middlewareSpy).action(async ({ctx}) => Promise.resolve(`${ctx.prefix}-bar`));
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
- await expect(action()).resolves.toBe('best-bar');
47
- expect(middlewareSpy).toBeCalledTimes(1);
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('without input', async () => {
51
- const actionWithInput = serverAct
52
- .middleware(middlewareSpy)
53
- .input(z.string())
54
- .action(async ({ctx, input}) => Promise.resolve(`${ctx.prefix}-${input}-bar`));
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
- expectTypeOf(actionWithInput).parameter(0).toBeString();
57
- expectTypeOf(actionWithInput).returns.resolves.toBeString();
58
- await expect(actionWithInput('foo')).resolves.toBe('best-foo-bar');
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
- type ActionParams<TInput = unknown, TContext = unknown> = {
19
+ interface ActionParams<TInput = unknown, TContext = unknown> {
19
20
  _input: TInput;
20
21
  _context: TContext;
21
- };
22
+ }
22
23
 
23
- type ActionBuilder<TParams extends ActionParams> = {
24
+ interface ActionBuilder<TParams extends ActionParams> {
24
25
  /**
25
- * Middleware allows you to run code before the action, and return context to 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
- type ActionBuilderDef<TParams extends ActionParams<any>> = {
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
- "moduleResolution": "nodenext",
11
+ "module": "NodeNext",
12
+ "moduleResolution": "NodeNext",
10
13
  "outDir": "./dist",
11
14
  "strict": true,
12
15
  "allowUnusedLabels": false,