server-act
Advanced tools
Comparing version
@@ -10,4 +10,4 @@ import { z } from 'zod'; | ||
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; | ||
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; | ||
type InferInputType<T, TType extends 'in' | 'out'> = T extends UnsetMarker ? undefined : InferParserType<T, TType>; | ||
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; | ||
type InferInputType<T, TType extends "in" | "out"> = T extends UnsetMarker ? undefined : InferParserType<T, TType>; | ||
type InferContextType<T> = T extends UnsetMarker ? undefined : T; | ||
@@ -23,3 +23,3 @@ interface ActionParams<TInput = unknown, TContext = unknown> { | ||
middleware: <TContext>(middleware: () => Promise<TContext> | TContext) => ActionBuilder<{ | ||
_input: TParams['_input']; | ||
_input: TParams["_input"]; | ||
_context: TContext; | ||
@@ -32,3 +32,3 @@ }>; | ||
_input: TParser; | ||
_context: TParams['_context']; | ||
_context: TParams["_context"]; | ||
}>; | ||
@@ -39,18 +39,19 @@ /** | ||
action: <TOutput>(action: (params: { | ||
ctx: InferContextType<TParams['_context']>; | ||
input: InferInputType<TParams['_input'], 'out'>; | ||
}) => Promise<TOutput>) => SanitizeFunctionParam<(input: InferInputType<TParams['_input'], 'in'>) => Promise<TOutput>>; | ||
ctx: InferContextType<TParams["_context"]>; | ||
input: InferInputType<TParams["_input"], "out">; | ||
}) => Promise<TOutput>) => SanitizeFunctionParam<(input: InferInputType<TParams["_input"], "in">) => Promise<TOutput>>; | ||
/** | ||
* Create an action for React `useFormState` | ||
*/ | ||
formAction: <TState>(action: (params: Prettify<{ | ||
ctx: InferContextType<TParams['_context']>; | ||
formAction: <TState, TPrevState = undefined>(action: (params: Prettify<{ | ||
ctx: InferContextType<TParams["_context"]>; | ||
prevState: any; | ||
formData: FormData; | ||
} & ({ | ||
input: InferInputType<TParams['_input'], 'out'>; | ||
input: InferInputType<TParams["_input"], "out">; | ||
formErrors?: undefined; | ||
} | { | ||
input?: undefined; | ||
formErrors: z.ZodError<InferInputType<TParams['_input'], 'in'>>; | ||
})>) => Promise<TState>) => (prevState: TState, formData: FormData) => Promise<TState>; | ||
formErrors: z.ZodError<InferInputType<TParams["_input"], "in">>; | ||
})>) => Promise<TState>) => (prevState: TState | TPrevState, formData: FormData) => Promise<TState | TPrevState>; | ||
} | ||
@@ -57,0 +58,0 @@ /** |
@@ -68,4 +68,4 @@ Object.defineProperty(exports, '__esModule', { value: true }); | ||
if (!result.success) { | ||
console.error('❌ Input validation error:', result.error.errors); | ||
throw new Error('Input validation error'); | ||
console.error("❌ Input validation error:", result.error.errors); | ||
throw new Error("Input validation error"); | ||
} | ||
@@ -88,2 +88,3 @@ } | ||
prevState, | ||
formData, | ||
formErrors: result.error | ||
@@ -95,2 +96,3 @@ }); | ||
prevState, | ||
formData, | ||
input: result.data | ||
@@ -102,2 +104,3 @@ }); | ||
prevState, | ||
formData, | ||
input: undefined | ||
@@ -104,0 +107,0 @@ }); |
{ | ||
"name": "server-act", | ||
"version": "1.1.7", | ||
"version": "1.2.0", | ||
"homepage": "https://github.com/chungweileong94/server-act#readme", | ||
@@ -47,4 +47,4 @@ "author": "chungweileong94", | ||
"devDependencies": { | ||
"bunchee": "^4.3.3", | ||
"typescript": "^5.2.2", | ||
"bunchee": "^5.1.2", | ||
"typescript": "^5.4.5", | ||
"zod": "^3.22.2", | ||
@@ -54,3 +54,3 @@ "zod-form-data": "^2.0.2" | ||
"peerDependencies": { | ||
"typescript": "^5.2.2", | ||
"typescript": ">=5.0.0", | ||
"zod": "^3.22.2" | ||
@@ -57,0 +57,0 @@ }, |
@@ -24,6 +24,6 @@ # Server-Act | ||
// action.ts | ||
'use server'; | ||
"use server"; | ||
import {serverAct} from 'server-act'; | ||
import {z} from 'zod'; | ||
import { serverAct } from "server-act"; | ||
import { z } from "zod"; | ||
@@ -36,3 +36,3 @@ export const sayHelloAction = serverAct | ||
) | ||
.action(async ({input}) => { | ||
.action(async ({ input }) => { | ||
return `Hello, ${input.name}`; | ||
@@ -44,9 +44,9 @@ }); | ||
// client-component.tsx | ||
'use client'; | ||
"use client"; | ||
import {sayHelloAction} from './action'; | ||
import { sayHelloAction } from "./action"; | ||
export const ClientComponent = () => { | ||
const onClick = () => { | ||
const message = await sayHelloAction({name: 'John'}); | ||
const message = await sayHelloAction({ name: "John" }); | ||
console.log(message); // Hello, John | ||
@@ -67,11 +67,11 @@ }; | ||
// action.ts | ||
'use server'; | ||
"use server"; | ||
import {serverAct} from 'server-act'; | ||
import {z} from 'zod'; | ||
import { serverAct } from "server-act"; | ||
import { z } from "zod"; | ||
export const sayHelloAction = serverAct | ||
.middleware(() => { | ||
const userId = '...'; | ||
return {userId}; | ||
const userId = "..."; | ||
return { userId }; | ||
}) | ||
@@ -83,4 +83,4 @@ .input( | ||
) | ||
.action(async ({ctx, input}) => { | ||
console.log('User ID', ctx.userId); | ||
.action(async ({ ctx, input }) => { | ||
console.log("User ID", ctx.userId); | ||
return `Hello, ${input.name}`; | ||
@@ -90,8 +90,7 @@ }); | ||
### `useFormState` Support | ||
### `useActionState` Support | ||
> `useFormState` Documentation: | ||
> `useActionState` Documentation: | ||
> | ||
> - https://nextjs.org/docs/app/building-your-application/data-fetching/forms-and-mutations#error-handling | ||
> - https://react.dev/reference/react-dom/hooks/useFormState | ||
> - https://react.dev/reference/react/useActionState | ||
@@ -102,7 +101,7 @@ We recommend using [zod-form-data](https://www.npmjs.com/package/zod-form-data) for input validation. | ||
// action.ts; | ||
'use server'; | ||
"use server"; | ||
import {serverAct} from 'server-act'; | ||
import {z} from 'zod'; | ||
import {zfd} from 'zod-form-data'; | ||
import { serverAct } from "server-act"; | ||
import { z } from "zod"; | ||
import { zfd } from "zod-form-data"; | ||
@@ -114,12 +113,12 @@ export const sayHelloAction = serverAct | ||
z | ||
.string({required_error: `You haven't told me your name`}) | ||
.nonempty({message: 'You need to tell me your name!'}), | ||
.string({ required_error: `You haven't told me your name` }) | ||
.max(20, { message: "Any shorter name? You name is too long 😬" }), | ||
), | ||
}), | ||
) | ||
.formAction(async ({input, formErrors, ctx}) => { | ||
.formAction(async ({ formData, input, formErrors, ctx }) => { | ||
if (formErrors) { | ||
return {formErrors: formErrors.formErrors.fieldErrors}; | ||
return { formData, formErrors: formErrors.formErrors.fieldErrors }; | ||
} | ||
return {message: `Hello, ${input.name}!`}; | ||
return { message: `Hello, ${input.name}!` }; | ||
}); | ||
@@ -130,17 +129,22 @@ ``` | ||
// client-component.tsx | ||
'use client'; | ||
"use client"; | ||
import {sayHelloAction} from './action'; | ||
import { useActionState } from "react"; | ||
import { sayHelloAction } from "./action"; | ||
export const ClientComponent = () => { | ||
const [state, dispatch] = useFormState(sayHelloAction, {formErrors: {}}); | ||
const [state, dispatch] = useFormState(sayHelloAction, undefined); | ||
return ( | ||
<form action={dispatch}> | ||
<input name="name" required /> | ||
{state.formErrors?.name?.map((error) => <p key={error}>{error}</p>)} | ||
<input | ||
name="name" | ||
required | ||
defaultValue={state?.formData?.get("name")?.toString()} | ||
/> | ||
{state?.formErrors?.name?.map((error) => <p key={error}>{error}</p>)} | ||
<button type="submit">Submit</button> | ||
{!!state.message && <p>{state.message}</p>} | ||
{!!state?.message && <p>{state.message}</p>} | ||
</form> | ||
@@ -147,0 +151,0 @@ ); |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
18004
2.5%279
2.57%145
2.84%