server-act 1.1.4 → 1.1.6
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 +140 -0
- package/dist/index.d.mts +3 -2
- package/dist/index.d.ts +3 -2
- package/package.json +3 -3
package/README.md
ADDED
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
# Server-Act
|
|
2
|
+
|
|
3
|
+
[](https://badge.fury.io/js/server-act)
|
|
4
|
+
|
|
5
|
+
A simple React server action builder that provides input validation with zod.
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
# npm
|
|
11
|
+
npm install server-act zod
|
|
12
|
+
|
|
13
|
+
# yarn
|
|
14
|
+
yarn add server-act zod
|
|
15
|
+
|
|
16
|
+
# pnpm
|
|
17
|
+
pnpm add server-act zod
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Usage
|
|
21
|
+
|
|
22
|
+
```ts
|
|
23
|
+
// action.ts
|
|
24
|
+
'use server';
|
|
25
|
+
|
|
26
|
+
import {serverAct} from 'server-act';
|
|
27
|
+
import {z} from 'zod';
|
|
28
|
+
|
|
29
|
+
export const sayHelloAction = serverAct
|
|
30
|
+
.input(
|
|
31
|
+
z.object({
|
|
32
|
+
name: z.string(),
|
|
33
|
+
}),
|
|
34
|
+
)
|
|
35
|
+
.action(async ({input}) => {
|
|
36
|
+
return `Hello, ${input.name}`;
|
|
37
|
+
});
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
```tsx
|
|
41
|
+
// client-component.tsx
|
|
42
|
+
'use client';
|
|
43
|
+
|
|
44
|
+
import {sayHelloAction} from './action';
|
|
45
|
+
|
|
46
|
+
export const ClientComponent = () => {
|
|
47
|
+
const onClick = () => {
|
|
48
|
+
const message = await sayHelloAction({name: 'John'});
|
|
49
|
+
console.log(message); // Hello, John
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
return (
|
|
53
|
+
<div>
|
|
54
|
+
<button onClick={onClick}>Trigger action</button>
|
|
55
|
+
</div>
|
|
56
|
+
);
|
|
57
|
+
};
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### With Middleware
|
|
61
|
+
|
|
62
|
+
```ts
|
|
63
|
+
// action.ts
|
|
64
|
+
'use server';
|
|
65
|
+
|
|
66
|
+
import {serverAct} from 'server-act';
|
|
67
|
+
import {z} from 'zod';
|
|
68
|
+
|
|
69
|
+
export const sayHelloAction = serverAct
|
|
70
|
+
.middleware(() => {
|
|
71
|
+
const userId = '...';
|
|
72
|
+
return {userId};
|
|
73
|
+
})
|
|
74
|
+
.input(
|
|
75
|
+
z.object({
|
|
76
|
+
name: z.string(),
|
|
77
|
+
}),
|
|
78
|
+
)
|
|
79
|
+
.action(async ({ctx, input}) => {
|
|
80
|
+
console.log('User ID', ctx.userId);
|
|
81
|
+
return `Hello, ${input.name}`;
|
|
82
|
+
});
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### `useFormState` Support
|
|
86
|
+
|
|
87
|
+
> `useFormState` Documentation:
|
|
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
|
|
91
|
+
|
|
92
|
+
We recommend using [zod-form-data](https://www.npmjs.com/package/zod-form-data) for input validation.
|
|
93
|
+
|
|
94
|
+
```ts
|
|
95
|
+
// action.ts;
|
|
96
|
+
'use server';
|
|
97
|
+
|
|
98
|
+
import {serverAct} from 'server-act';
|
|
99
|
+
import {z} from 'zod';
|
|
100
|
+
import {zfd} from 'zod-form-data';
|
|
101
|
+
|
|
102
|
+
export const sayHelloAction = serverAct
|
|
103
|
+
.input(
|
|
104
|
+
zfd.formData({
|
|
105
|
+
name: zfd.text(
|
|
106
|
+
z
|
|
107
|
+
.string({required_error: `You haven't told me your name`})
|
|
108
|
+
.nonempty({message: 'You need to tell me your name!'}),
|
|
109
|
+
),
|
|
110
|
+
}),
|
|
111
|
+
)
|
|
112
|
+
.formAction(async ({input, formErrors, ctx}) => {
|
|
113
|
+
if (formErrors) {
|
|
114
|
+
return {formErrors: formErrors.formErrors.fieldErrors};
|
|
115
|
+
}
|
|
116
|
+
return {message: `Hello, ${input.name}!`};
|
|
117
|
+
});
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
```tsx
|
|
121
|
+
// client-component.tsx
|
|
122
|
+
'use client';
|
|
123
|
+
|
|
124
|
+
import {sayHelloAction} from './action';
|
|
125
|
+
|
|
126
|
+
export const ClientComponent = () => {
|
|
127
|
+
const [state, dispatch] = useFormState(sayHelloAction, {formErrors: {}});
|
|
128
|
+
|
|
129
|
+
return (
|
|
130
|
+
<form action={dispatch}>
|
|
131
|
+
<input name="name" required />
|
|
132
|
+
{state.formErrors?.name?.map((error) => <p key={error}>{error}</p>)}
|
|
133
|
+
|
|
134
|
+
<button type="submit">Submit</button>
|
|
135
|
+
|
|
136
|
+
{!!state.message && <p>{state.message}</p>}
|
|
137
|
+
</form>
|
|
138
|
+
);
|
|
139
|
+
};
|
|
140
|
+
```
|
package/dist/index.d.mts
CHANGED
|
@@ -2,10 +2,11 @@ import { z } from 'zod';
|
|
|
2
2
|
|
|
3
3
|
declare const unsetMarker: unique symbol;
|
|
4
4
|
type UnsetMarker = typeof unsetMarker;
|
|
5
|
+
type Equals<X, Y> = (<T>() => T extends X ? 1 : 2) extends <T>() => T extends Y ? 1 : 2 ? true : false;
|
|
5
6
|
type Prettify<T> = {
|
|
6
7
|
[P in keyof T]: T[P];
|
|
7
8
|
} & {};
|
|
8
|
-
type
|
|
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;
|
|
9
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;
|
|
10
11
|
type InferInputType<T, TType extends 'in' | 'out'> = T extends UnsetMarker ? undefined : InferParserType<T, TType>;
|
|
11
12
|
type InferContextType<T> = T extends UnsetMarker ? undefined : T;
|
|
@@ -34,7 +35,7 @@ interface ActionBuilder<TParams extends ActionParams> {
|
|
|
34
35
|
action: <TOutput>(action: (params: {
|
|
35
36
|
ctx: InferContextType<TParams['_context']>;
|
|
36
37
|
input: InferInputType<TParams['_input'], 'out'>;
|
|
37
|
-
}) => Promise<TOutput>) => (
|
|
38
|
+
}) => Promise<TOutput>) => SanitizeFunctionParam<(input: InferInputType<TParams['_input'], 'in'>) => Promise<TOutput>>;
|
|
38
39
|
/**
|
|
39
40
|
* Create an action for React `useFormState`
|
|
40
41
|
*/
|
package/dist/index.d.ts
CHANGED
|
@@ -2,10 +2,11 @@ import { z } from 'zod';
|
|
|
2
2
|
|
|
3
3
|
declare const unsetMarker: unique symbol;
|
|
4
4
|
type UnsetMarker = typeof unsetMarker;
|
|
5
|
+
type Equals<X, Y> = (<T>() => T extends X ? 1 : 2) extends <T>() => T extends Y ? 1 : 2 ? true : false;
|
|
5
6
|
type Prettify<T> = {
|
|
6
7
|
[P in keyof T]: T[P];
|
|
7
8
|
} & {};
|
|
8
|
-
type
|
|
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;
|
|
9
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;
|
|
10
11
|
type InferInputType<T, TType extends 'in' | 'out'> = T extends UnsetMarker ? undefined : InferParserType<T, TType>;
|
|
11
12
|
type InferContextType<T> = T extends UnsetMarker ? undefined : T;
|
|
@@ -34,7 +35,7 @@ interface ActionBuilder<TParams extends ActionParams> {
|
|
|
34
35
|
action: <TOutput>(action: (params: {
|
|
35
36
|
ctx: InferContextType<TParams['_context']>;
|
|
36
37
|
input: InferInputType<TParams['_input'], 'out'>;
|
|
37
|
-
}) => Promise<TOutput>) => (
|
|
38
|
+
}) => Promise<TOutput>) => SanitizeFunctionParam<(input: InferInputType<TParams['_input'], 'in'>) => Promise<TOutput>>;
|
|
38
39
|
/**
|
|
39
40
|
* Create an action for React `useFormState`
|
|
40
41
|
*/
|
package/package.json
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "server-act",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.6",
|
|
4
4
|
"homepage": "https://github.com/chungweileong94/server-act#readme",
|
|
5
|
+
"author": "chungweileong94",
|
|
6
|
+
"license": "MIT",
|
|
5
7
|
"repository": {
|
|
6
8
|
"type": "git",
|
|
7
9
|
"url": "git+https://github.com/chungweileong94/server-act.git"
|
|
@@ -41,8 +43,6 @@
|
|
|
41
43
|
"server action",
|
|
42
44
|
"action"
|
|
43
45
|
],
|
|
44
|
-
"author": "chungweileong94",
|
|
45
|
-
"license": "MIT",
|
|
46
46
|
"devDependencies": {
|
|
47
47
|
"bunchee": "^4.3.3",
|
|
48
48
|
"eslint": "^8.49.0",
|