Skip to content

Commit

Permalink
docs(website): update documentation for v6
Browse files Browse the repository at this point in the history
  • Loading branch information
TheEdoRan committed Jan 2, 2024
1 parent d1fe2d2 commit d55c539
Show file tree
Hide file tree
Showing 12 changed files with 124 additions and 81 deletions.
2 changes: 1 addition & 1 deletion website/docs/contributing.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
sidebar_position: 10
sidebar_position: 11
description: Learn how to contribute to next-safe-action via GitHub.
---

Expand Down
22 changes: 16 additions & 6 deletions website/docs/getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,22 +7,32 @@ description: Getting started with next-safe-action version 5.

:::note
This is the documentation for the current version of the library (5.x.x). If you are looking for version 3.x.x or 2.x.x docs, please check out [README_v3](https://github.com/TheEdoRan/next-safe-action/blob/main/packages/next-safe-action/README_v3.md) or [README_v2](https://github.com/TheEdoRan/next-safe-action/blob/main/packages/next-safe-action/README_v2.md) from the GitHub repository.

If you're still using Next.js 13, please install version 4 of the library with `npm i next-safe-action@v4`.
:::

:::info Requirements
- v4: Next.js >= 13.4.2, v5: Next.js >= 14.0.0
- TypeScript >= 5.0.0
- Zod >= 3.0.0
- pre-v6: Zod >= 3.0.0, from v6: a validation library supported by [TypeSchema](https://typeschema.com/#coverage)
:::

**next-safe-action** provides a typesafe Server Actions implementation for Next.js 13 App Router, using Zod.
**next-safe-action** provides a typesafe Server Actions implementation for Next.js App Router.

## Validation libraries support

We will use Zod as our validation library in this documentation, but since version 6 of next-safe-action, you can use your validation library of choice, or even multiple and custom ones at the same time, thanks to the **TypeSchema** library. You can find supported libraries [here](https://typeschema.com/#coverage).

## Installation

For Next.js >= 14, use the following command:

```bash npm2yarn
npm i next-safe-action
```

For Next.js 13, use the following command:

```bash npm2yarn
npm i next-safe-action zod
npm i next-safe-action@v4 zod
```

## Usage
Expand All @@ -45,7 +55,7 @@ This is a basic client, without any options. If you want to explore the full set

### 2. Define a new action

This is how a safe action is created. Providing a Zod input schema to the function, we're sure that data that comes in is type safe and validated.
This is how a safe action is created. Providing a validation input schema to the function, we're sure that data that comes in is type safe and validated.
The second argument of this function is an async function that receives the parsed input, and defines what happens on the server when the action is called from client. In short, this is your server code. It never runs on the client:

```typescript title="src/app/login-action.ts"
Expand Down
6 changes: 3 additions & 3 deletions website/docs/introduction.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
---
sidebar_position: 1
description: next-safe-action is a library that takes full advantage of the latest and greatest Next.js, React and TypeScript features, using Zod, to let you define typesafe Server Actions and execute them inside Client Components.
description: next-safe-action is a library that takes full advantage of the latest and greatest Next.js, React and TypeScript features, using validation libraries of your choice, to let you define typesafe Server Actions and execute them inside Client Components.
---

# Introduction

**next-safe-action** is a library that takes full advantage of the latest and greatest Next.js, React and TypeScript features, using Zod, to let you define **typesafe** Server Actions and execute them inside Client Components.
**next-safe-action** is a library that takes full advantage of the latest and greatest Next.js, React and TypeScript features, using validation libraries of your choice, to let you define **typesafe** Server Actions and execute them inside Client Components.

## How does it work?

Expand All @@ -20,6 +20,6 @@ Your browser does not support the video tag.
- ✅ Pretty simple
- ✅ End-to-end type safety
- ✅ Context based clients (with middlewares)
- ✅ Input validation using Zod
- ✅ Input validation using multiple validation libraries
- ✅ Advanced server error handling
- ✅ Optimistic updates
8 changes: 8 additions & 0 deletions website/docs/migration-from-v5-to-v6.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
sidebar_position: 10
description: Learn how to migrate from next-safe-action version 5 to version 6.
---

# Migration from v5 to v6

WIP
17 changes: 7 additions & 10 deletions website/docs/safe-action-client/custom-server-error-handling.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,7 @@ Here's a simple example, changing the message for every error thrown on the serv
export const action = createSafeActionClient({
// Can also be an async function.
handleReturnedServerError(e) {
return {
serverError: "Oh no, something went wrong!",
};
return "Oh no, something went wrong!";
},
});
```
Expand All @@ -27,22 +25,21 @@ export const action = createSafeActionClient({
A more useful one would be to customize the message based on the error type. We can, for instance, create a custom error class and check the error type inside this function:

```typescript title=src/lib/safe-action.ts
import { DEFAULT_SERVER_ERROR } from "next-safe-action";

class MyCustomError extends Error {}

export const action = createSafeActionClient({
// Can also be an async function.
handleReturnedServerError(e) {
// In this case, we can use the 'MyCustomError` class to unmask errors
// and return them with their actual messages to the client.
if (e instanceof MyCustomError) {
return {
serverError: e.message,
};
return e.message;
}

// Every other error will be masked with this message.
return {
serverError: "Oh no, something went wrong!",
};
// Every other error that occurs will be masked with the default message.
return DEFAULT_SERVER_ERROR;
},
});
```
Expand Down
52 changes: 36 additions & 16 deletions website/docs/types.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,39 +5,53 @@ description: List of exported types.

# Types

## /

### `SafeClientOpts`

Type of options when creating a new safe action client.

```typescript
export type SafeClientOpts<Context> = {
handleServerErrorLog?: (e: Error) => MaybePromise<void>;
handleReturnedServerError?: (e: Error) => MaybePromise<string>;
middleware?: (parsedInput: unknown) => MaybePromise<Context>;
};
```

### `SafeAction`

Type of the function called from Client Components with typesafe input data.

```typescript
type SafeAction<Schema extends z.ZodTypeAny, Data> = (input: z.input<Schema>) => Promise<{
type SafeAction<S extends Schema, Data> = (input: InferIn<S>) => Promise<{
data?: Data;
serverError?: string;
validationError?: Partial<Record<keyof z.input<Schema> | "_root", string[]>>;
validationErrors?: Partial<Record<keyof Infer<S> | "_root", string[]>>;
}>;
```

### `ServerCode`
### `ServerCodeFn`

Type of the function that executes server code when defining a new safe action.

```typescript
type ServerCode<Schema extends z.ZodTypeAny, Data, Context> = (
parsedInput: z.infer<Schema>,
type ServerCodeFn<S extends Schema, Data, Context> = (
parsedInput: Infer<S>,
ctx: Context
) => Promise<Data>;
```

## /hooks

### `HookResult`

Type of `result` object returned by `useAction` and `useOptimisticAction` hooks.

If a server-client communication error occurs, `fetchError` will be set to the error message.

```typescript
type HookResult<Schema extends z.ZodTypeAny, Data> = Awaited<
ReturnType<SafeAction<Schema, Data>>
> & {
type HookResult<S extends Schema, Data> = Awaited<ReturnType<SafeAction<S, Data>>> & {
fetchError?: string;
};
```
Expand All @@ -47,17 +61,17 @@ type HookResult<Schema extends z.ZodTypeAny, Data> = Awaited<
Type of hooks callbacks. These are executed when action is in a specific state.

```typescript
type HookCallbacks<Schema extends z.ZodTypeAny, Data> = {
onExecute?: (input: z.input<Schema>) => MaybePromise<void>;
onSuccess?: (data: Data, input: z.input<Schema>, reset: () => void) => MaybePromise<void>;
type HookCallbacks<S extends Schema, Data> = {
onExecute?: (input: InferIn<S>) => MaybePromise<void>;
onSuccess?: (data: Data, input: InferIn<S>, reset: () => void) => MaybePromise<void>;
onError?: (
error: Omit<HookResult<Schema, Data>, "data">,
input: z.input<Schema>,
error: Omit<HookResult<S, Data>, "data">,
input: InferIn<S>,
reset: () => void
) => MaybePromise<void>;
onSettled?: (
result: HookResult<Schema, Data>,
input: z.input<Schema>,
result: HookResult<S, Data>,
input: InferIn<S>,
reset: () => void
) => MaybePromise<void>;
};
Expand All @@ -69,4 +83,10 @@ Type of the action status returned by `useAction` and `useOptimisticAction` hook

```typescript
type HookActionStatus = "idle" | "executing" | "hasSucceeded" | "hasErrored";
```
```

---

## TypeSchema library

`Infer`, `InferIn`, `Schema` types come from [TypeSchema](https://typeschema.com/#types) library.
2 changes: 1 addition & 1 deletion website/docs/usage-from-client/action-result-object.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,5 @@ Here's how action result object is structured (all keys are optional):
| Name | When | Value |
|--------------------|--------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `data?` | Execution is successful. | What you returned in action's server code. |
| `validationError?` | Data doesn't pass Zod schema validation. | A partial `Record` of input schema keys as key or `_root`, and `string[]` as value. `_root` is a reserved key, used for Zod global validation. Example: `{ _root: ["A global error"], email: ["Email is required."] }`. |
| `validationErrors?` | Input data doesn't pass schema validation. | A partial `Record` of input schema keys as key or `_root`, and `string[]` as value. `_root` is a reserved key, used for global validation issues. Example: `{ _root: ["A global error"], email: ["Email is required."] }`. |
| `serverError?` | An error occurs during action's server code execution. | A `string` that by default is "Something went wrong while executing the operation" for every server error that occurs, but this is [configurable](/docs/safe-action-client/custom-server-error-handling#handlereturnedservererror) when instantiating a new client. |
8 changes: 4 additions & 4 deletions website/docs/usage-from-client/hooks/callbacks.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ Here is the full list of callbacks, with their behavior explained. All of them a

| Name | [`HookActionStatus`](/docs/types#hookactionstatus) state | Arguments |
|--------------|------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------|
| `onExecute?` | `"executing"` | `input: z.input<Schema>` |
| `onSuccess?` | `"hasSucceeded"` | `data: Data`,<br/> `input: z.input<Schema>`,<br/> `reset: () => void` |
| `onError?` | `"hasErrored"` | `error: Omit<HookResult<Schema, Data>, "data">`,<br/> `input: z.input<Schema>`,<br/> `reset: () => void` |
| `onSettled?` | `"hasSucceeded"` or `"hasErrored"` (after `onSuccess` and/or `onError`) | `result: HookResult<Schema, Data>`,<br/> `input: z.input<Schema>`,<br/> `reset: () => void` |
| `onExecute?` | `"executing"` | `input: InferIn<S>` |
| `onSuccess?` | `"hasSucceeded"` | `data: Data`,<br/> `input: InferIn<S>`,<br/> `reset: () => void` |
| `onError?` | `"hasErrored"` | `error: Omit<HookResult<S, Data>, "data">`,<br/> `input: InferIn<S>`,<br/> `reset: () => void` |
| `onSettled?` | `"hasSucceeded"` or `"hasErrored"` (after `onSuccess` and/or `onError`) | `result: HookResult<S, Data>`,<br/> `input: InferIn<S>`,<br/> `reset: () => void` |
3 changes: 2 additions & 1 deletion website/docs/usage-from-client/hooks/useaction.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ export const greetUser = action(schema, async ({ name }) => {
2. In your Client Component, you can use it like this:

```tsx title=src/app/greet.tsx
import { useAction } from "next-safe-action/hooks";
import { greetUser } from "@/app/greet-action";

export default function Greet() {
Expand Down Expand Up @@ -67,7 +68,7 @@ As you can see, here we display a greet message after the action is performed, i

| Name | Type | Purpose |
|-----------|----------------------------------------------|---------------------------------------------------------------------------------------------------|
| `execute` | `(input: z.input<Schema>) => void` | An action caller with no return. The input is the same as the safe action you passed to the hook. |
| `execute` | `(input: InferIn<S>) => void` | An action caller with no return. The input is the same as the safe action you passed to the hook. |
| `result` | [`HookResult`](/docs/types#hookresult) | When the action gets called via `execute`, this is the result object. |
| `status` | [`HookActionStatus`](/docs/types#hookresult) | The action current status. |
| `reset` | `() => void` | You can programmatically reset the `result` object with this function. |
Expand Down
5 changes: 3 additions & 2 deletions website/docs/usage-from-client/hooks/useoptimisticaction.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ export default function Home() {
3. Finally, in your Client Component, you can use it like this:

```tsx title=src/app/add-likes.tsx
import { useOptimisticAction } from "next-safe-action/hooks";
import { addLikes } from "@/app/add-likes-action";

type Props = {
Expand Down Expand Up @@ -103,7 +104,7 @@ export default function AddLikes({ numOfLikes }: Props) {
|------------------|-----------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `safeAction` | [`SafeAction`](/docs/types#safeaction) | This is the action that will be called when you use `execute` from hook's return object. |
| `initialOptimisticData` | `Data` (return type of the `safeAction` you passed as first argument) | An initializer for the optimistic state. Usually this value comes from the parent Server Component. |
| `reducer` | `(state: Data, input: z.input<Schema>) => Data` | When you call the action via `execute`, this function determines how the optimistic update is performed. Basically, here you define what happens **immediately** after `execute` is called, and before the actual result comes back from the server. |
| `reducer` | `(state: Data, input: InferIn<S>) => Data` | When you call the action via `execute`, this function determines how the optimistic update is performed. Basically, here you define what happens **immediately** after `execute` is called, and before the actual result comes back from the server. |
| `callbacks?` | [`HookCallbacks`](/docs/types#hookcallbacks) | Optional callbacks. More information about them [here](/docs/usage-from-client/hooks/callbacks). |


Expand All @@ -113,7 +114,7 @@ export default function AddLikes({ numOfLikes }: Props) {

| Name | Type | Purpose |
|------------------|-----------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `execute` | `(input: z.input<Schema>) => void` | An action caller with no return. The input is the same as the safe action you passed to the hook. |
| `execute` | `(input: InferIn<S>) => void` | An action caller with no return. The input is the same as the safe action you passed to the hook. |
| `result` | [`HookResult`](/docs/types#hookresult) | When the action gets called via `execute`, this is the result object. |
| `status` | [`HookActionStatus`](/docs/types#hookresult) | The action current status. |
| `reset` | `() => void` | You can programmatically reset the `result` object with this function. |
Expand Down
Loading

0 comments on commit d55c539

Please sign in to comment.