server-act 1.1.6 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md 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
@@ -1,6 +1,6 @@
1
1
  Object.defineProperty(exports, '__esModule', { value: true });
2
2
 
3
- /* eslint-disable @typescript-eslint/no-unsafe-assignment */ /* eslint-disable @typescript-eslint/no-explicit-any */ function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
3
+ function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
4
4
  try {
5
5
  var info = gen[key](arg);
6
6
  var value = info.value;
@@ -43,10 +43,10 @@ function _extends() {
43
43
  };
44
44
  return _extends.apply(this, arguments);
45
45
  }
46
- const createNewServerActionBuilder = (def)=>{
46
+ function createNewServerActionBuilder(def) {
47
47
  return createServerActionBuilder(def);
48
- };
49
- const createServerActionBuilder = (initDef = {})=>{
48
+ }
49
+ function createServerActionBuilder(initDef = {}) {
50
50
  const _def = _extends({
51
51
  input: undefined,
52
52
  middleware: undefined
@@ -59,13 +59,14 @@ const createServerActionBuilder = (initDef = {})=>{
59
59
  input
60
60
  })),
61
61
  action: (action)=>{
62
+ // biome-ignore lint/suspicious/noExplicitAny: Intended
62
63
  return /*#__PURE__*/ _async_to_generator(function*(input) {
63
64
  const ctx = yield _def.middleware == null ? void 0 : _def.middleware.call(_def);
64
65
  if (_def.input) {
65
66
  const result = _def.input.safeParse(input);
66
67
  if (!result.success) {
67
- console.error('❌ Input validation error:', result.error.errors);
68
- throw new Error('Input validation error');
68
+ console.error("❌ Input validation error:", result.error.errors);
69
+ throw new Error("Input validation error");
69
70
  }
70
71
  }
71
72
  return yield action({
@@ -78,29 +79,32 @@ const createServerActionBuilder = (initDef = {})=>{
78
79
  return /*#__PURE__*/ _async_to_generator(function*(prevState, formData) {
79
80
  const ctx = yield _def.middleware == null ? void 0 : _def.middleware.call(_def);
80
81
  if (_def.input) {
81
- const result = _def.input.safeParse(formData);
82
+ const result = yield _def.input.safeParseAsync(formData);
82
83
  if (!result.success) {
83
84
  return yield action({
84
85
  ctx,
85
86
  prevState,
87
+ formData,
86
88
  formErrors: result.error
87
89
  });
88
90
  }
89
91
  return yield action({
90
92
  ctx,
91
93
  prevState,
94
+ formData,
92
95
  input: result.data
93
96
  });
94
97
  }
95
98
  return yield action({
96
99
  ctx,
97
100
  prevState,
101
+ formData,
98
102
  input: undefined
99
103
  });
100
104
  });
101
105
  }
102
106
  };
103
- };
107
+ }
104
108
  /**
105
109
  * Server action builder
106
110
  */ const serverAct = createServerActionBuilder();
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- /* eslint-disable @typescript-eslint/no-unsafe-assignment */ /* eslint-disable @typescript-eslint/no-explicit-any */ function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
1
+ function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
2
2
  try {
3
3
  var info = gen[key](arg);
4
4
  var value = info.value;
@@ -41,10 +41,10 @@ function _extends() {
41
41
  };
42
42
  return _extends.apply(this, arguments);
43
43
  }
44
- const createNewServerActionBuilder = (def)=>{
44
+ function createNewServerActionBuilder(def) {
45
45
  return createServerActionBuilder(def);
46
- };
47
- const createServerActionBuilder = (initDef = {})=>{
46
+ }
47
+ function createServerActionBuilder(initDef = {}) {
48
48
  const _def = _extends({
49
49
  input: undefined,
50
50
  middleware: undefined
@@ -57,13 +57,14 @@ const createServerActionBuilder = (initDef = {})=>{
57
57
  input
58
58
  })),
59
59
  action: (action)=>{
60
+ // biome-ignore lint/suspicious/noExplicitAny: Intended
60
61
  return /*#__PURE__*/ _async_to_generator(function*(input) {
61
62
  const ctx = yield _def.middleware == null ? void 0 : _def.middleware.call(_def);
62
63
  if (_def.input) {
63
64
  const result = _def.input.safeParse(input);
64
65
  if (!result.success) {
65
- console.error('❌ Input validation error:', result.error.errors);
66
- throw new Error('Input validation error');
66
+ console.error("❌ Input validation error:", result.error.errors);
67
+ throw new Error("Input validation error");
67
68
  }
68
69
  }
69
70
  return yield action({
@@ -76,29 +77,32 @@ const createServerActionBuilder = (initDef = {})=>{
76
77
  return /*#__PURE__*/ _async_to_generator(function*(prevState, formData) {
77
78
  const ctx = yield _def.middleware == null ? void 0 : _def.middleware.call(_def);
78
79
  if (_def.input) {
79
- const result = _def.input.safeParse(formData);
80
+ const result = yield _def.input.safeParseAsync(formData);
80
81
  if (!result.success) {
81
82
  return yield action({
82
83
  ctx,
83
84
  prevState,
85
+ formData,
84
86
  formErrors: result.error
85
87
  });
86
88
  }
87
89
  return yield action({
88
90
  ctx,
89
91
  prevState,
92
+ formData,
90
93
  input: result.data
91
94
  });
92
95
  }
93
96
  return yield action({
94
97
  ctx,
95
98
  prevState,
99
+ formData,
96
100
  input: undefined
97
101
  });
98
102
  });
99
103
  }
100
104
  };
101
- };
105
+ }
102
106
  /**
103
107
  * Server action builder
104
108
  */ const serverAct = createServerActionBuilder();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "server-act",
3
- "version": "1.1.6",
3
+ "version": "1.2.0",
4
4
  "homepage": "https://github.com/chungweileong94/server-act#readme",
5
5
  "author": "chungweileong94",
6
6
  "license": "MIT",
@@ -44,16 +44,13 @@
44
44
  "action"
45
45
  ],
46
46
  "devDependencies": {
47
- "bunchee": "^4.3.3",
48
- "eslint": "^8.49.0",
49
- "eslint-config-whiteroom": "^3.3.0",
50
- "prettier": "^3.0.3",
51
- "typescript": "^5.2.2",
47
+ "bunchee": "^5.1.2",
48
+ "typescript": "^5.4.5",
52
49
  "zod": "^3.22.2",
53
50
  "zod-form-data": "^2.0.2"
54
51
  },
55
52
  "peerDependencies": {
56
- "typescript": "^5.2.2",
53
+ "typescript": ">=5.0.0",
57
54
  "zod": "^3.22.2"
58
55
  },
59
56
  "peerDependenciesMeta": {
@@ -64,7 +61,7 @@
64
61
  "scripts": {
65
62
  "build": "bunchee",
66
63
  "dev": "bunchee -w",
67
- "test": "vitest run",
68
- "lint": "eslint src --ext .ts"
64
+ "typecheck": "tsc --noEmit",
65
+ "test": "vitest run"
69
66
  }
70
67
  }