server-act 1.1.7 → 1.2.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
@@ -21,10 +21,10 @@ pnpm add server-act zod
21
21
 
22
22
  ```ts
23
23
  // action.ts
24
- 'use server';
24
+ "use server";
25
25
 
26
- import {serverAct} from 'server-act';
27
- import {z} from 'zod';
26
+ import { serverAct } from "server-act";
27
+ import { z } from "zod";
28
28
 
29
29
  export const sayHelloAction = serverAct
30
30
  .input(
@@ -32,20 +32,20 @@ export const sayHelloAction = serverAct
32
32
  name: z.string(),
33
33
  }),
34
34
  )
35
- .action(async ({input}) => {
35
+ .action(async ({ input }) => {
36
36
  return `Hello, ${input.name}`;
37
37
  });
38
38
  ```
39
39
 
40
40
  ```tsx
41
41
  // client-component.tsx
42
- 'use client';
42
+ "use client";
43
43
 
44
- import {sayHelloAction} from './action';
44
+ import { sayHelloAction } from "./action";
45
45
 
46
46
  export const ClientComponent = () => {
47
47
  const onClick = () => {
48
- const message = await sayHelloAction({name: 'John'});
48
+ const message = await sayHelloAction({ name: "John" });
49
49
  console.log(message); // Hello, John
50
50
  };
51
51
 
@@ -61,79 +61,83 @@ export const ClientComponent = () => {
61
61
 
62
62
  ```ts
63
63
  // action.ts
64
- 'use server';
64
+ "use server";
65
65
 
66
- import {serverAct} from 'server-act';
67
- import {z} from 'zod';
66
+ import { serverAct } from "server-act";
67
+ import { z } from "zod";
68
68
 
69
69
  export const sayHelloAction = serverAct
70
70
  .middleware(() => {
71
- const userId = '...';
72
- return {userId};
71
+ const userId = "...";
72
+ return { userId };
73
73
  })
74
74
  .input(
75
75
  z.object({
76
76
  name: z.string(),
77
77
  }),
78
78
  )
79
- .action(async ({ctx, input}) => {
80
- console.log('User ID', ctx.userId);
79
+ .action(async ({ ctx, input }) => {
80
+ console.log("User ID", ctx.userId);
81
81
  return `Hello, ${input.name}`;
82
82
  });
83
83
  ```
84
84
 
85
- ### `useFormState` Support
85
+ ### `useActionState` Support
86
86
 
87
- > `useFormState` Documentation:
87
+ > `useActionState` Documentation:
88
88
  >
89
- > - https://nextjs.org/docs/app/building-your-application/data-fetching/forms-and-mutations#error-handling
90
- > - https://react.dev/reference/react-dom/hooks/useFormState
89
+ > - https://react.dev/reference/react/useActionState
91
90
 
92
91
  We recommend using [zod-form-data](https://www.npmjs.com/package/zod-form-data) for input validation.
93
92
 
94
93
  ```ts
95
94
  // action.ts;
96
- 'use server';
95
+ "use server";
97
96
 
98
- import {serverAct} from 'server-act';
99
- import {z} from 'zod';
100
- import {zfd} from 'zod-form-data';
97
+ import { serverAct } from "server-act";
98
+ import { z } from "zod";
99
+ import { zfd } from "zod-form-data";
101
100
 
102
101
  export const sayHelloAction = serverAct
103
102
  .input(
104
103
  zfd.formData({
105
104
  name: zfd.text(
106
105
  z
107
- .string({required_error: `You haven't told me your name`})
108
- .nonempty({message: 'You need to tell me your name!'}),
106
+ .string({ required_error: `You haven't told me your name` })
107
+ .max(20, { message: "Any shorter name? You name is too long 😬" }),
109
108
  ),
110
109
  }),
111
110
  )
112
- .formAction(async ({input, formErrors, ctx}) => {
111
+ .formAction(async ({ formData, input, formErrors, ctx }) => {
113
112
  if (formErrors) {
114
- return {formErrors: formErrors.formErrors.fieldErrors};
113
+ return { formData, formErrors: formErrors.formErrors.fieldErrors };
115
114
  }
116
- return {message: `Hello, ${input.name}!`};
115
+ return { message: `Hello, ${input.name}!` };
117
116
  });
118
117
  ```
119
118
 
120
119
  ```tsx
121
120
  // client-component.tsx
122
- 'use client';
121
+ "use client";
123
122
 
124
- import {sayHelloAction} from './action';
123
+ import { useActionState } from "react";
124
+ import { sayHelloAction } from "./action";
125
125
 
126
126
  export const ClientComponent = () => {
127
- const [state, dispatch] = useFormState(sayHelloAction, {formErrors: {}});
127
+ const [state, dispatch] = useFormState(sayHelloAction, undefined);
128
128
 
129
129
  return (
130
130
  <form action={dispatch}>
131
- <input name="name" required />
132
- {state.formErrors?.name?.map((error) => <p key={error}>{error}</p>)}
131
+ <input
132
+ name="name"
133
+ required
134
+ defaultValue={state?.formData?.get("name")?.toString()}
135
+ />
136
+ {state?.formErrors?.name?.map((error) => <p key={error}>{error}</p>)}
133
137
 
134
138
  <button type="submit">Submit</button>
135
139
 
136
- {!!state.message && <p>{state.message}</p>}
140
+ {!!state?.message && <p>{state.message}</p>}
137
141
  </form>
138
142
  );
139
143
  };
package/dist/index.d.mts CHANGED
@@ -7,8 +7,8 @@ type Prettify<T> = {
7
7
  [P in keyof T]: T[P];
8
8
  } & {};
9
9
  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'> = T extends z.ZodEffects<infer I, any, any> ? I[TType extends 'in' ? '_input' : '_output'] : T extends z.ZodType ? T[TType extends 'in' ? '_input' : '_output'] : never;
11
- type InferInputType<T, TType extends 'in' | 'out'> = T extends UnsetMarker ? undefined : InferParserType<T, TType>;
10
+ type InferParserType<T, TType extends "in" | "out"> = T extends z.ZodEffects<infer I, any, any> ? I[TType extends "in" ? "_input" : "_output"] : T extends z.ZodType ? T[TType extends "in" ? "_input" : "_output"] : never;
11
+ type InferInputType<T, TType extends "in" | "out"> = T extends UnsetMarker ? undefined : InferParserType<T, TType>;
12
12
  type InferContextType<T> = T extends UnsetMarker ? undefined : T;
13
13
  interface ActionParams<TInput = unknown, TContext = unknown> {
14
14
  _input: TInput;
@@ -19,7 +19,7 @@ interface ActionBuilder<TParams extends ActionParams> {
19
19
  * Middleware allows you to run code before the action, its return value will pass as context to the action.
20
20
  */
21
21
  middleware: <TContext>(middleware: () => Promise<TContext> | TContext) => ActionBuilder<{
22
- _input: TParams['_input'];
22
+ _input: TParams["_input"];
23
23
  _context: TContext;
24
24
  }>;
25
25
  /**
@@ -27,28 +27,29 @@ interface ActionBuilder<TParams extends ActionParams> {
27
27
  */
28
28
  input: <TParser extends z.ZodType>(input: TParser) => ActionBuilder<{
29
29
  _input: TParser;
30
- _context: TParams['_context'];
30
+ _context: TParams["_context"];
31
31
  }>;
32
32
  /**
33
33
  * Create an action.
34
34
  */
35
35
  action: <TOutput>(action: (params: {
36
- ctx: InferContextType<TParams['_context']>;
37
- input: InferInputType<TParams['_input'], 'out'>;
38
- }) => Promise<TOutput>) => SanitizeFunctionParam<(input: InferInputType<TParams['_input'], 'in'>) => Promise<TOutput>>;
36
+ ctx: InferContextType<TParams["_context"]>;
37
+ input: InferInputType<TParams["_input"], "out">;
38
+ }) => Promise<TOutput>) => SanitizeFunctionParam<(input: InferInputType<TParams["_input"], "in">) => Promise<TOutput>>;
39
39
  /**
40
40
  * Create an action for React `useFormState`
41
41
  */
42
- formAction: <TState>(action: (params: Prettify<{
43
- ctx: InferContextType<TParams['_context']>;
42
+ formAction: <TState, TPrevState = undefined>(action: (params: Prettify<{
43
+ ctx: InferContextType<TParams["_context"]>;
44
44
  prevState: any;
45
+ formData: FormData;
45
46
  } & ({
46
- input: InferInputType<TParams['_input'], 'out'>;
47
+ input: InferInputType<TParams["_input"], "out">;
47
48
  formErrors?: undefined;
48
49
  } | {
49
50
  input?: undefined;
50
- formErrors: z.ZodError<InferInputType<TParams['_input'], 'in'>>;
51
- })>) => Promise<TState>) => (prevState: TState, formData: FormData) => Promise<TState>;
51
+ formErrors: z.ZodError<InferInputType<TParams["_input"], "in">>;
52
+ })>) => Promise<TState>) => (prevState: TState | TPrevState, formData: FormData) => Promise<TState | TPrevState>;
52
53
  }
53
54
  /**
54
55
  * Server action builder
package/dist/index.d.ts CHANGED
@@ -7,8 +7,8 @@ type Prettify<T> = {
7
7
  [P in keyof T]: T[P];
8
8
  } & {};
9
9
  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'> = T extends z.ZodEffects<infer I, any, any> ? I[TType extends 'in' ? '_input' : '_output'] : T extends z.ZodType ? T[TType extends 'in' ? '_input' : '_output'] : never;
11
- type InferInputType<T, TType extends 'in' | 'out'> = T extends UnsetMarker ? undefined : InferParserType<T, TType>;
10
+ type InferParserType<T, TType extends "in" | "out"> = T extends z.ZodEffects<infer I, any, any> ? I[TType extends "in" ? "_input" : "_output"] : T extends z.ZodType ? T[TType extends "in" ? "_input" : "_output"] : never;
11
+ type InferInputType<T, TType extends "in" | "out"> = T extends UnsetMarker ? undefined : InferParserType<T, TType>;
12
12
  type InferContextType<T> = T extends UnsetMarker ? undefined : T;
13
13
  interface ActionParams<TInput = unknown, TContext = unknown> {
14
14
  _input: TInput;
@@ -19,7 +19,7 @@ interface ActionBuilder<TParams extends ActionParams> {
19
19
  * Middleware allows you to run code before the action, its return value will pass as context to the action.
20
20
  */
21
21
  middleware: <TContext>(middleware: () => Promise<TContext> | TContext) => ActionBuilder<{
22
- _input: TParams['_input'];
22
+ _input: TParams["_input"];
23
23
  _context: TContext;
24
24
  }>;
25
25
  /**
@@ -27,28 +27,29 @@ interface ActionBuilder<TParams extends ActionParams> {
27
27
  */
28
28
  input: <TParser extends z.ZodType>(input: TParser) => ActionBuilder<{
29
29
  _input: TParser;
30
- _context: TParams['_context'];
30
+ _context: TParams["_context"];
31
31
  }>;
32
32
  /**
33
33
  * Create an action.
34
34
  */
35
35
  action: <TOutput>(action: (params: {
36
- ctx: InferContextType<TParams['_context']>;
37
- input: InferInputType<TParams['_input'], 'out'>;
38
- }) => Promise<TOutput>) => SanitizeFunctionParam<(input: InferInputType<TParams['_input'], 'in'>) => Promise<TOutput>>;
36
+ ctx: InferContextType<TParams["_context"]>;
37
+ input: InferInputType<TParams["_input"], "out">;
38
+ }) => Promise<TOutput>) => SanitizeFunctionParam<(input: InferInputType<TParams["_input"], "in">) => Promise<TOutput>>;
39
39
  /**
40
40
  * Create an action for React `useFormState`
41
41
  */
42
- formAction: <TState>(action: (params: Prettify<{
43
- ctx: InferContextType<TParams['_context']>;
42
+ formAction: <TState, TPrevState = undefined>(action: (params: Prettify<{
43
+ ctx: InferContextType<TParams["_context"]>;
44
44
  prevState: any;
45
+ formData: FormData;
45
46
  } & ({
46
- input: InferInputType<TParams['_input'], 'out'>;
47
+ input: InferInputType<TParams["_input"], "out">;
47
48
  formErrors?: undefined;
48
49
  } | {
49
50
  input?: undefined;
50
- formErrors: z.ZodError<InferInputType<TParams['_input'], 'in'>>;
51
- })>) => Promise<TState>) => (prevState: TState, formData: FormData) => Promise<TState>;
51
+ formErrors: z.ZodError<InferInputType<TParams["_input"], "in">>;
52
+ })>) => Promise<TState>) => (prevState: TState | TPrevState, formData: FormData) => Promise<TState | TPrevState>;
52
53
  }
53
54
  /**
54
55
  * Server action builder
package/dist/index.js CHANGED
@@ -63,10 +63,10 @@ function createServerActionBuilder(initDef = {}) {
63
63
  return /*#__PURE__*/ _async_to_generator(function*(input) {
64
64
  const ctx = yield _def.middleware == null ? void 0 : _def.middleware.call(_def);
65
65
  if (_def.input) {
66
- const result = _def.input.safeParse(input);
66
+ const result = yield _def.input.safeParseAsync(input);
67
67
  if (!result.success) {
68
- console.error('❌ Input validation error:', result.error.errors);
69
- throw new Error('Input validation error');
68
+ console.error("❌ Input validation error:", result.error.errors);
69
+ throw new Error("Input validation error");
70
70
  }
71
71
  }
72
72
  return yield action({
@@ -84,18 +84,21 @@ function createServerActionBuilder(initDef = {}) {
84
84
  return yield action({
85
85
  ctx,
86
86
  prevState,
87
+ formData,
87
88
  formErrors: result.error
88
89
  });
89
90
  }
90
91
  return yield action({
91
92
  ctx,
92
93
  prevState,
94
+ formData,
93
95
  input: result.data
94
96
  });
95
97
  }
96
98
  return yield action({
97
99
  ctx,
98
100
  prevState,
101
+ formData,
99
102
  input: undefined
100
103
  });
101
104
  });
package/dist/index.mjs CHANGED
@@ -61,10 +61,10 @@ function createServerActionBuilder(initDef = {}) {
61
61
  return /*#__PURE__*/ _async_to_generator(function*(input) {
62
62
  const ctx = yield _def.middleware == null ? void 0 : _def.middleware.call(_def);
63
63
  if (_def.input) {
64
- const result = _def.input.safeParse(input);
64
+ const result = yield _def.input.safeParseAsync(input);
65
65
  if (!result.success) {
66
- console.error('❌ Input validation error:', result.error.errors);
67
- throw new Error('Input validation error');
66
+ console.error("❌ Input validation error:", result.error.errors);
67
+ throw new Error("Input validation error");
68
68
  }
69
69
  }
70
70
  return yield action({
@@ -82,18 +82,21 @@ function createServerActionBuilder(initDef = {}) {
82
82
  return yield action({
83
83
  ctx,
84
84
  prevState,
85
+ formData,
85
86
  formErrors: result.error
86
87
  });
87
88
  }
88
89
  return yield action({
89
90
  ctx,
90
91
  prevState,
92
+ formData,
91
93
  input: result.data
92
94
  });
93
95
  }
94
96
  return yield action({
95
97
  ctx,
96
98
  prevState,
99
+ formData,
97
100
  input: undefined
98
101
  });
99
102
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "server-act",
3
- "version": "1.1.7",
3
+ "version": "1.2.1",
4
4
  "homepage": "https://github.com/chungweileong94/server-act#readme",
5
5
  "author": "chungweileong94",
6
6
  "license": "MIT",
@@ -44,13 +44,13 @@
44
44
  "action"
45
45
  ],
46
46
  "devDependencies": {
47
- "bunchee": "^4.3.3",
48
- "typescript": "^5.2.2",
47
+ "bunchee": "^5.1.2",
48
+ "typescript": "^5.4.5",
49
49
  "zod": "^3.22.2",
50
50
  "zod-form-data": "^2.0.2"
51
51
  },
52
52
  "peerDependencies": {
53
- "typescript": "^5.2.2",
53
+ "typescript": ">=5.0.0",
54
54
  "zod": "^3.22.2"
55
55
  },
56
56
  "peerDependenciesMeta": {