server-act 1.4.0 → 1.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -2,7 +2,9 @@
2
2
 
3
3
  [![npm version](https://badge.fury.io/js/server-act.svg)](https://badge.fury.io/js/server-act)
4
4
 
5
- A simple React server action builder that provides input validation with zod.
5
+ A simple React server action builder that provides input validation.
6
+
7
+ You can use any validation library that supports [Standard Schema](https://standardschema.dev/).
6
8
 
7
9
  ## Installation
8
10
 
@@ -68,14 +70,15 @@ import { z } from "zod";
68
70
 
69
71
  export const sayHelloAction = serverAct
70
72
  .middleware(() => {
71
- const userId = "...";
72
- return { userId };
73
+ const t = i18n();
74
+ const userId = "..."
75
+ return { t, userId };
76
+ })
77
+ .input((ctx) => {
78
+ return z.object({
79
+ name: z.string().min(1, { message: ctx.t("form.name.required") }),
80
+ });
73
81
  })
74
- .input(
75
- z.object({
76
- name: z.string(),
77
- }),
78
- )
79
82
  .action(async ({ ctx, input }) => {
80
83
  console.log("User ID", ctx.userId);
81
84
  return `Hello, ${input.name}`;
@@ -110,7 +113,7 @@ export const sayHelloAction = serverAct
110
113
  )
111
114
  .formAction(async ({ formData, input, formErrors, ctx }) => {
112
115
  if (formErrors) {
113
- return { formData, formErrors: formErrors.formErrors.fieldErrors };
116
+ return { formData, formErrors: formErrors.fieldErrors };
114
117
  }
115
118
  return { message: `Hello, ${input.name}!` };
116
119
  });
package/dist/index.d.mts CHANGED
@@ -1,15 +1,21 @@
1
- import { z } from 'zod';
1
+ import { StandardSchemaV1 } from '@standard-schema/spec';
2
+
3
+ declare function getFormErrors(issues: ReadonlyArray<StandardSchemaV1.Issue>): {
4
+ messages: string[];
5
+ fieldErrors: Record<string, string[]>;
6
+ };
2
7
 
3
8
  declare const unsetMarker: unique symbol;
4
9
  type UnsetMarker = typeof unsetMarker;
10
+ type RemoveUnsetMarker<T> = T extends UnsetMarker ? undefined : T;
5
11
  type Equals<X, Y> = (<T>() => T extends X ? 1 : 2) extends <T>() => T extends Y ? 1 : 2 ? true : false;
6
12
  type Prettify<T> = {
7
13
  [P in keyof T]: T[P];
8
14
  } & {};
9
15
  type SanitizeFunctionParam<T extends (param: any) => any> = T extends (param: infer P) => infer R ? Equals<P, undefined> extends true ? () => R : Equals<P, P | undefined> extends true ? (param?: P) => R : (param: P) => R : never;
10
- type InferParserType<T, TType extends "in" | "out", TUnwrapEffects extends true | false> = T extends z.ZodEffects<infer InnerType, infer Output, infer Input> ? TUnwrapEffects extends true ? InnerType[TType extends "in" ? "_input" : "_output"] : TType extends "in" ? Input : Output : T extends z.ZodType ? T[TType extends "in" ? "_input" : "_output"] : never;
11
- type InferInputType<T, TType extends "in" | "out", TUnwrapEffects extends true | false = true> = T extends UnsetMarker ? undefined : InferParserType<T, TType, TUnwrapEffects>;
12
- type InferContextType<T> = T extends UnsetMarker ? undefined : T;
16
+ type InferParserType<T, TType extends "in" | "out"> = T extends StandardSchemaV1 ? TType extends "in" ? StandardSchemaV1.InferInput<T> : StandardSchemaV1.InferOutput<T> : never;
17
+ type InferInputType<T, TType extends "in" | "out"> = T extends UnsetMarker ? undefined : InferParserType<T, TType>;
18
+ type InferContextType<T> = RemoveUnsetMarker<T>;
13
19
  interface ActionParams<TInput = unknown, TContext = unknown> {
14
20
  _input: TInput;
15
21
  _context: TContext;
@@ -25,7 +31,7 @@ interface ActionBuilder<TParams extends ActionParams> {
25
31
  /**
26
32
  * Input validation for the action.
27
33
  */
28
- input: <TParser extends z.ZodType>(input: ((params: {
34
+ input: <TParser extends StandardSchemaV1>(input: ((params: {
29
35
  ctx: InferContextType<TParams["_context"]>;
30
36
  }) => Promise<TParser> | TParser) | TParser) => Omit<ActionBuilder<{
31
37
  _input: TParser;
@@ -37,21 +43,21 @@ interface ActionBuilder<TParams extends ActionParams> {
37
43
  action: <TOutput>(action: (params: {
38
44
  ctx: InferContextType<TParams["_context"]>;
39
45
  input: InferInputType<TParams["_input"], "out">;
40
- }) => Promise<TOutput>) => SanitizeFunctionParam<(input: InferInputType<TParams["_input"], "in"> | InferInputType<TParams["_input"], "in", false>) => Promise<TOutput>>;
46
+ }) => Promise<TOutput>) => SanitizeFunctionParam<(input: InferInputType<TParams["_input"], "in">) => Promise<TOutput>>;
41
47
  /**
42
48
  * Create an action for React `useActionState`
43
49
  */
44
- formAction: <TState, TPrevState = undefined>(action: (params: Prettify<{
50
+ formAction: <TState, TPrevState = UnsetMarker>(action: (params: Prettify<{
45
51
  ctx: InferContextType<TParams["_context"]>;
46
- prevState: any;
52
+ prevState: RemoveUnsetMarker<TPrevState>;
47
53
  formData: FormData;
48
54
  } & ({
49
55
  input: InferInputType<TParams["_input"], "out">;
50
56
  formErrors?: undefined;
51
57
  } | {
52
58
  input?: undefined;
53
- formErrors: z.ZodError<InferInputType<TParams["_input"], "in">>;
54
- })>) => Promise<TState>) => (prevState: TState | TPrevState, formData: InferInputType<TParams["_input"], "in"> | InferInputType<TParams["_input"], "in", false>) => Promise<TState | TPrevState>;
59
+ formErrors: ReturnType<typeof getFormErrors>;
60
+ })>) => Promise<TState>) => (prevState: TState | RemoveUnsetMarker<TPrevState>, formData: InferInputType<TParams["_input"], "in">) => Promise<TState | RemoveUnsetMarker<TPrevState>>;
55
61
  }
56
62
  /**
57
63
  * Server action builder
package/dist/index.d.ts CHANGED
@@ -1,15 +1,21 @@
1
- import { z } from 'zod';
1
+ import { StandardSchemaV1 } from '@standard-schema/spec';
2
+
3
+ declare function getFormErrors(issues: ReadonlyArray<StandardSchemaV1.Issue>): {
4
+ messages: string[];
5
+ fieldErrors: Record<string, string[]>;
6
+ };
2
7
 
3
8
  declare const unsetMarker: unique symbol;
4
9
  type UnsetMarker = typeof unsetMarker;
10
+ type RemoveUnsetMarker<T> = T extends UnsetMarker ? undefined : T;
5
11
  type Equals<X, Y> = (<T>() => T extends X ? 1 : 2) extends <T>() => T extends Y ? 1 : 2 ? true : false;
6
12
  type Prettify<T> = {
7
13
  [P in keyof T]: T[P];
8
14
  } & {};
9
15
  type SanitizeFunctionParam<T extends (param: any) => any> = T extends (param: infer P) => infer R ? Equals<P, undefined> extends true ? () => R : Equals<P, P | undefined> extends true ? (param?: P) => R : (param: P) => R : never;
10
- type InferParserType<T, TType extends "in" | "out", TUnwrapEffects extends true | false> = T extends z.ZodEffects<infer InnerType, infer Output, infer Input> ? TUnwrapEffects extends true ? InnerType[TType extends "in" ? "_input" : "_output"] : TType extends "in" ? Input : Output : T extends z.ZodType ? T[TType extends "in" ? "_input" : "_output"] : never;
11
- type InferInputType<T, TType extends "in" | "out", TUnwrapEffects extends true | false = true> = T extends UnsetMarker ? undefined : InferParserType<T, TType, TUnwrapEffects>;
12
- type InferContextType<T> = T extends UnsetMarker ? undefined : T;
16
+ type InferParserType<T, TType extends "in" | "out"> = T extends StandardSchemaV1 ? TType extends "in" ? StandardSchemaV1.InferInput<T> : StandardSchemaV1.InferOutput<T> : never;
17
+ type InferInputType<T, TType extends "in" | "out"> = T extends UnsetMarker ? undefined : InferParserType<T, TType>;
18
+ type InferContextType<T> = RemoveUnsetMarker<T>;
13
19
  interface ActionParams<TInput = unknown, TContext = unknown> {
14
20
  _input: TInput;
15
21
  _context: TContext;
@@ -25,7 +31,7 @@ interface ActionBuilder<TParams extends ActionParams> {
25
31
  /**
26
32
  * Input validation for the action.
27
33
  */
28
- input: <TParser extends z.ZodType>(input: ((params: {
34
+ input: <TParser extends StandardSchemaV1>(input: ((params: {
29
35
  ctx: InferContextType<TParams["_context"]>;
30
36
  }) => Promise<TParser> | TParser) | TParser) => Omit<ActionBuilder<{
31
37
  _input: TParser;
@@ -37,21 +43,21 @@ interface ActionBuilder<TParams extends ActionParams> {
37
43
  action: <TOutput>(action: (params: {
38
44
  ctx: InferContextType<TParams["_context"]>;
39
45
  input: InferInputType<TParams["_input"], "out">;
40
- }) => Promise<TOutput>) => SanitizeFunctionParam<(input: InferInputType<TParams["_input"], "in"> | InferInputType<TParams["_input"], "in", false>) => Promise<TOutput>>;
46
+ }) => Promise<TOutput>) => SanitizeFunctionParam<(input: InferInputType<TParams["_input"], "in">) => Promise<TOutput>>;
41
47
  /**
42
48
  * Create an action for React `useActionState`
43
49
  */
44
- formAction: <TState, TPrevState = undefined>(action: (params: Prettify<{
50
+ formAction: <TState, TPrevState = UnsetMarker>(action: (params: Prettify<{
45
51
  ctx: InferContextType<TParams["_context"]>;
46
- prevState: any;
52
+ prevState: RemoveUnsetMarker<TPrevState>;
47
53
  formData: FormData;
48
54
  } & ({
49
55
  input: InferInputType<TParams["_input"], "out">;
50
56
  formErrors?: undefined;
51
57
  } | {
52
58
  input?: undefined;
53
- formErrors: z.ZodError<InferInputType<TParams["_input"], "in">>;
54
- })>) => Promise<TState>) => (prevState: TState | TPrevState, formData: InferInputType<TParams["_input"], "in"> | InferInputType<TParams["_input"], "in", false>) => Promise<TState | TPrevState>;
59
+ formErrors: ReturnType<typeof getFormErrors>;
60
+ })>) => Promise<TState>) => (prevState: TState | RemoveUnsetMarker<TPrevState>, formData: InferInputType<TParams["_input"], "in">) => Promise<TState | RemoveUnsetMarker<TPrevState>>;
55
61
  }
56
62
  /**
57
63
  * Server action builder
package/dist/index.js CHANGED
@@ -1,5 +1,70 @@
1
1
  Object.defineProperty(exports, '__esModule', { value: true });
2
2
 
3
+ var utils = require('@standard-schema/utils');
4
+
5
+ function asyncGeneratorStep$1(gen, resolve, reject, _next, _throw, key, arg) {
6
+ try {
7
+ var info = gen[key](arg);
8
+ var value = info.value;
9
+ } catch (error) {
10
+ reject(error);
11
+ return;
12
+ }
13
+ if (info.done) {
14
+ resolve(value);
15
+ } else {
16
+ Promise.resolve(value).then(_next, _throw);
17
+ }
18
+ }
19
+ function _async_to_generator$1(fn) {
20
+ return function() {
21
+ var self = this, args = arguments;
22
+ return new Promise(function(resolve, reject) {
23
+ var gen = fn.apply(self, args);
24
+ function _next(value) {
25
+ asyncGeneratorStep$1(gen, resolve, reject, _next, _throw, "next", value);
26
+ }
27
+ function _throw(err) {
28
+ asyncGeneratorStep$1(gen, resolve, reject, _next, _throw, "throw", err);
29
+ }
30
+ _next(undefined);
31
+ });
32
+ };
33
+ }
34
+ function standardValidate(schema, input) {
35
+ return _standardValidate.apply(this, arguments);
36
+ }
37
+ function _standardValidate() {
38
+ _standardValidate = _async_to_generator$1(function*(schema, input) {
39
+ let result = schema["~standard"].validate(input);
40
+ if (result instanceof Promise) result = yield result;
41
+ return result;
42
+ });
43
+ return _standardValidate.apply(this, arguments);
44
+ }
45
+ function getFormErrors(issues) {
46
+ const messages = [];
47
+ const fieldErrors = {};
48
+ for (const issue of issues){
49
+ const dotPath = utils.getDotPath(issue);
50
+ if (dotPath) {
51
+ if (fieldErrors[dotPath]) {
52
+ fieldErrors[dotPath].push(issue.message);
53
+ } else {
54
+ fieldErrors[dotPath] = [
55
+ issue.message
56
+ ];
57
+ }
58
+ } else {
59
+ messages.push(issue.message);
60
+ }
61
+ }
62
+ return {
63
+ messages,
64
+ fieldErrors
65
+ };
66
+ }
67
+
3
68
  function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
4
69
  try {
5
70
  var info = gen[key](arg);
@@ -66,14 +131,14 @@ function createServerActionBuilder(initDef = {}) {
66
131
  const inputSchema = typeof _def.input === "function" ? yield _def.input({
67
132
  ctx
68
133
  }) : _def.input;
69
- const result = yield inputSchema.safeParseAsync(input);
70
- if (!result.success) {
71
- console.error("❌ Input validation error:", result.error.errors);
72
- throw new Error("Input validation error");
134
+ const result = yield standardValidate(inputSchema, input);
135
+ if (result.issues) {
136
+ throw new utils.SchemaError(result.issues);
73
137
  }
138
+ // biome-ignore lint/suspicious/noExplicitAny: It's fine
74
139
  return yield action({
75
140
  ctx,
76
- input: result.data
141
+ input: result.value
77
142
  });
78
143
  }
79
144
  return yield action({
@@ -90,25 +155,29 @@ function createServerActionBuilder(initDef = {}) {
90
155
  const inputSchema = typeof _def.input === "function" ? yield _def.input({
91
156
  ctx
92
157
  }) : _def.input;
93
- const result = yield inputSchema.safeParseAsync(formData);
94
- if (!result.success) {
158
+ const result = yield standardValidate(inputSchema, formData);
159
+ if (result.issues) {
95
160
  return yield action({
96
161
  ctx,
97
- prevState,
162
+ // biome-ignore lint/suspicious/noExplicitAny: It's fine
163
+ prevState: prevState,
98
164
  formData,
99
- formErrors: result.error
165
+ formErrors: getFormErrors(result.issues)
100
166
  });
101
167
  }
102
168
  return yield action({
103
169
  ctx,
104
- prevState,
170
+ // biome-ignore lint/suspicious/noExplicitAny: It's fine
171
+ prevState: prevState,
105
172
  formData,
106
- input: result.data
173
+ // biome-ignore lint/suspicious/noExplicitAny: It's fine
174
+ input: result.value
107
175
  });
108
176
  }
109
177
  return yield action({
110
178
  ctx,
111
- prevState,
179
+ // biome-ignore lint/suspicious/noExplicitAny: It's fine
180
+ prevState: prevState,
112
181
  formData,
113
182
  input: undefined
114
183
  });
package/dist/index.mjs CHANGED
@@ -1,3 +1,68 @@
1
+ import { getDotPath, SchemaError } from '@standard-schema/utils';
2
+
3
+ function asyncGeneratorStep$1(gen, resolve, reject, _next, _throw, key, arg) {
4
+ try {
5
+ var info = gen[key](arg);
6
+ var value = info.value;
7
+ } catch (error) {
8
+ reject(error);
9
+ return;
10
+ }
11
+ if (info.done) {
12
+ resolve(value);
13
+ } else {
14
+ Promise.resolve(value).then(_next, _throw);
15
+ }
16
+ }
17
+ function _async_to_generator$1(fn) {
18
+ return function() {
19
+ var self = this, args = arguments;
20
+ return new Promise(function(resolve, reject) {
21
+ var gen = fn.apply(self, args);
22
+ function _next(value) {
23
+ asyncGeneratorStep$1(gen, resolve, reject, _next, _throw, "next", value);
24
+ }
25
+ function _throw(err) {
26
+ asyncGeneratorStep$1(gen, resolve, reject, _next, _throw, "throw", err);
27
+ }
28
+ _next(undefined);
29
+ });
30
+ };
31
+ }
32
+ function standardValidate(schema, input) {
33
+ return _standardValidate.apply(this, arguments);
34
+ }
35
+ function _standardValidate() {
36
+ _standardValidate = _async_to_generator$1(function*(schema, input) {
37
+ let result = schema["~standard"].validate(input);
38
+ if (result instanceof Promise) result = yield result;
39
+ return result;
40
+ });
41
+ return _standardValidate.apply(this, arguments);
42
+ }
43
+ function getFormErrors(issues) {
44
+ const messages = [];
45
+ const fieldErrors = {};
46
+ for (const issue of issues){
47
+ const dotPath = getDotPath(issue);
48
+ if (dotPath) {
49
+ if (fieldErrors[dotPath]) {
50
+ fieldErrors[dotPath].push(issue.message);
51
+ } else {
52
+ fieldErrors[dotPath] = [
53
+ issue.message
54
+ ];
55
+ }
56
+ } else {
57
+ messages.push(issue.message);
58
+ }
59
+ }
60
+ return {
61
+ messages,
62
+ fieldErrors
63
+ };
64
+ }
65
+
1
66
  function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
2
67
  try {
3
68
  var info = gen[key](arg);
@@ -64,14 +129,14 @@ function createServerActionBuilder(initDef = {}) {
64
129
  const inputSchema = typeof _def.input === "function" ? yield _def.input({
65
130
  ctx
66
131
  }) : _def.input;
67
- const result = yield inputSchema.safeParseAsync(input);
68
- if (!result.success) {
69
- console.error("❌ Input validation error:", result.error.errors);
70
- throw new Error("Input validation error");
132
+ const result = yield standardValidate(inputSchema, input);
133
+ if (result.issues) {
134
+ throw new SchemaError(result.issues);
71
135
  }
136
+ // biome-ignore lint/suspicious/noExplicitAny: It's fine
72
137
  return yield action({
73
138
  ctx,
74
- input: result.data
139
+ input: result.value
75
140
  });
76
141
  }
77
142
  return yield action({
@@ -88,25 +153,29 @@ function createServerActionBuilder(initDef = {}) {
88
153
  const inputSchema = typeof _def.input === "function" ? yield _def.input({
89
154
  ctx
90
155
  }) : _def.input;
91
- const result = yield inputSchema.safeParseAsync(formData);
92
- if (!result.success) {
156
+ const result = yield standardValidate(inputSchema, formData);
157
+ if (result.issues) {
93
158
  return yield action({
94
159
  ctx,
95
- prevState,
160
+ // biome-ignore lint/suspicious/noExplicitAny: It's fine
161
+ prevState: prevState,
96
162
  formData,
97
- formErrors: result.error
163
+ formErrors: getFormErrors(result.issues)
98
164
  });
99
165
  }
100
166
  return yield action({
101
167
  ctx,
102
- prevState,
168
+ // biome-ignore lint/suspicious/noExplicitAny: It's fine
169
+ prevState: prevState,
103
170
  formData,
104
- input: result.data
171
+ // biome-ignore lint/suspicious/noExplicitAny: It's fine
172
+ input: result.value
105
173
  });
106
174
  }
107
175
  return yield action({
108
176
  ctx,
109
- prevState,
177
+ // biome-ignore lint/suspicious/noExplicitAny: It's fine
178
+ prevState: prevState,
110
179
  formData,
111
180
  input: undefined
112
181
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "server-act",
3
- "version": "1.4.0",
3
+ "version": "1.5.1",
4
4
  "homepage": "https://github.com/chungweileong94/server-act#readme",
5
5
  "author": "chungweileong94",
6
6
  "license": "MIT",
@@ -43,21 +43,33 @@
43
43
  "server action",
44
44
  "action"
45
45
  ],
46
- "devDependencies": {
47
- "bunchee": "^5.6.0",
48
- "typescript": "^5.6.3",
49
- "zod": "^3.22.2",
50
- "zod-form-data": "^2.0.2"
46
+ "dependencies": {
47
+ "@standard-schema/spec": "^1.0.0",
48
+ "@standard-schema/utils": "^0.3.0"
51
49
  },
52
50
  "peerDependencies": {
53
51
  "typescript": ">=5.0.0",
54
- "zod": "^3.22.2"
52
+ "valibot": "^1.0.0",
53
+ "zod": "^3.24.0"
55
54
  },
56
55
  "peerDependenciesMeta": {
57
56
  "typescript": {
58
57
  "optional": true
58
+ },
59
+ "zod": {
60
+ "optional": true
61
+ },
62
+ "valibot": {
63
+ "optional": true
59
64
  }
60
65
  },
66
+ "devDependencies": {
67
+ "bunchee": "^6.2.0",
68
+ "typescript": "^5.6.3",
69
+ "valibot": "1.0.0-rc.0",
70
+ "zod": "^3.24.2",
71
+ "zod-form-data": "^2.0.2"
72
+ },
61
73
  "scripts": {
62
74
  "build": "bunchee",
63
75
  "dev": "bunchee -w",