Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: TheEdoRan/next-safe-action
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: v7.6.3
Choose a base ref
...
head repository: TheEdoRan/next-safe-action
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: v7.6.4
Choose a head ref
  • 4 commits
  • 11 files changed
  • 1 contributor

Commits on Aug 16, 2024

  1. chore: update Turborepo

    TheEdoRan committed Aug 16, 2024
    Copy the full SHA
    828fa5d View commit details
  2. Copy the full SHA
    a55cb1d View commit details
  3. chore: update pnpm

    TheEdoRan committed Aug 16, 2024
    Copy the full SHA
    9cb9b12 View commit details

Commits on Aug 17, 2024

  1. refactor(types): export infer utility types (#235)

    Code in this PR adds and exports infer utility types for safe action client, middleware functions, safe actions and hooks.
    
    re #233
    TheEdoRan authored Aug 17, 2024
    Copy the full SHA
    4876d2d View commit details
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -36,7 +36,7 @@
"cz-conventional-changelog": "^3.3.0",
"husky": "^9.0.11",
"is-ci": "^3.0.1",
"turbo": "^2.0.12"
"turbo": "^2.0.14"
},
"packageManager": "pnpm@9.7.0+sha512.dc09430156b427f5ecfc79888899e1c39d2d690f004be70e05230b72cb173d96839587545d09429b55ac3c429c801b4dc3c0e002f653830a420fa2dd4e3cf9cf"
"packageManager": "pnpm@9.7.1+sha512.faf344af2d6ca65c4c5c8c2224ea77a81a5e8859cbc4e06b1511ddce2f0151512431dd19e6aff31f2c6a8f5f2aced9bd2273e1fed7dd4de1868984059d2c4247"
}
4 changes: 2 additions & 2 deletions packages/next-safe-action/src/hooks-utils.ts
Original file line number Diff line number Diff line change
@@ -2,7 +2,7 @@ import * as React from "react";
import {} from "react/experimental";
import type {} from "zod";
import type { InferIn, Schema } from "./adapters/types";
import type { HookActionStatus, HookBaseUtils, HookCallbacks, HookResult } from "./hooks.types";
import type { HookActionStatus, HookBaseUtils, HookCallbacks, HookResult, HookShorthandStatus } from "./hooks.types";

export const getActionStatus = <
ServerError,
@@ -42,7 +42,7 @@ export const getActionShorthandStatusObject = ({
}: {
status: HookActionStatus;
isTransitioning: boolean;
}) => {
}): HookShorthandStatus => {
return {
isIdle: status === "idle",
isExecuting: status === "executing",
17 changes: 12 additions & 5 deletions packages/next-safe-action/src/hooks.ts
Original file line number Diff line number Diff line change
@@ -7,7 +7,14 @@ import {} from "react/experimental";
import type {} from "zod";
import type { InferIn, Schema } from "./adapters/types";
import { getActionShorthandStatusObject, getActionStatus, useActionCallbacks, useExecuteOnMount } from "./hooks-utils";
import type { HookBaseUtils, HookCallbacks, HookResult, HookSafeActionFn } from "./hooks.types";
import type {
HookBaseUtils,
HookCallbacks,
HookResult,
HookSafeActionFn,
UseActionHookReturn,
UseOptimisticActionHookReturn,
} from "./hooks.types";
import { isError } from "./utils";

// HOOKS
@@ -29,7 +36,7 @@ export const useAction = <
>(
safeActionFn: HookSafeActionFn<ServerError, S, BAS, CVE, CBAVE, Data>,
utils?: HookBaseUtils<S> & HookCallbacks<ServerError, S, BAS, CVE, CBAVE, Data>
) => {
): UseActionHookReturn<ServerError, S, BAS, CVE, CBAVE, Data> => {
const [isTransitioning, startTransition] = React.useTransition();
const [result, setResult] = React.useState<HookResult<ServerError, S, BAS, CVE, CBAVE, Data>>({});
const [clientInput, setClientInput] = React.useState<S extends Schema ? InferIn<S> : void>();
@@ -124,7 +131,7 @@ export const useAction = <
return {
execute,
executeAsync,
input: clientInput,
input: clientInput as S extends Schema ? InferIn<S> : undefined,
result,
reset,
status,
@@ -154,7 +161,7 @@ export const useOptimisticAction = <
updateFn: (state: State, input: S extends Schema ? InferIn<S> : undefined) => State;
} & HookBaseUtils<S> &
HookCallbacks<ServerError, S, BAS, CVE, CBAVE, Data>
) => {
): UseOptimisticActionHookReturn<ServerError, S, BAS, CVE, CBAVE, Data, State> => {
const [isTransitioning, startTransition] = React.useTransition();
const [result, setResult] = React.useState<HookResult<ServerError, S, BAS, CVE, CBAVE, Data>>({});
const [clientInput, setClientInput] = React.useState<S extends Schema ? InferIn<S> : void>();
@@ -255,7 +262,7 @@ export const useOptimisticAction = <
return {
execute,
executeAsync,
input: clientInput,
input: clientInput as S extends Schema ? InferIn<S> : undefined,
result,
optimisticState,
reset,
110 changes: 108 additions & 2 deletions packages/next-safe-action/src/hooks.types.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { InferIn, Schema } from "./adapters/types";
import type { SafeActionResult } from "./index.types";
import type { SafeActionFn, SafeActionResult, SafeStateActionFn } from "./index.types";
import type { MaybePromise, Prettify } from "./utils.types";

/**
@@ -83,6 +83,112 @@ export type HookSafeStateActionFn<
) => Promise<SafeActionResult<ServerError, S, BAS, CVE, CBAVE, Data>>;

/**
* Type of the action status returned by `useAction` and `useOptimisticAction` hooks.
* Type of the action status returned by `useAction`, `useOptimisticAction` and `useStateAction` hooks.
*/
export type HookActionStatus = "idle" | "executing" | "hasSucceeded" | "hasErrored";

/**
* Type of the shorthand status object returned by `useAction`, `useOptimisticAction` and `useStateAction` hooks.
*/
export type HookShorthandStatus = {
isIdle: boolean;
isExecuting: boolean;
isTransitioning: boolean;
isPending: boolean;
hasSucceeded: boolean;
hasErrored: boolean;
};

/**
* Type of the return object of the `useAction` hook.
*/
export type UseActionHookReturn<
ServerError,
S extends Schema | undefined,
BAS extends readonly Schema[],
CVE,
CBAVE,
Data,
> = {
execute: (input: S extends Schema ? InferIn<S> : void) => void;
executeAsync: (
input: S extends Schema ? InferIn<S> : void
) => Promise<SafeActionResult<ServerError, S, BAS, CVE, CBAVE, Data> | undefined>;
input: S extends Schema ? InferIn<S> : undefined;
result: Prettify<HookResult<ServerError, S, BAS, CVE, CBAVE, Data>>;
reset: () => void;
status: HookActionStatus;
} & HookShorthandStatus;

/**
* Type of the return object of the `useOptimisticAction` hook.
*/
export type UseOptimisticActionHookReturn<
ServerError,
S extends Schema | undefined,
BAS extends readonly Schema[],
CVE,
CBAVE,
Data,
State,
> = UseActionHookReturn<ServerError, S, BAS, CVE, CBAVE, Data> &
HookShorthandStatus & {
optimisticState: State;
};

/**
* Type of the return object of the `useStateAction` hook.
*/
export type UseStateActionHookReturn<
ServerError,
S extends Schema | undefined,
BAS extends readonly Schema[],
CVE,
CBAVE,
Data,
> = Omit<UseActionHookReturn<ServerError, S, BAS, CVE, CBAVE, Data>, "executeAsync" | "reset"> & HookShorthandStatus;

/**
* Type of the return object of the `useAction` hook.
*/
export type InferUseActionHookReturn<T extends Function> =
T extends SafeActionFn<
infer ServerError,
infer S extends Schema | undefined,
infer BAS extends readonly Schema[],
infer CVE,
infer CBAVE,
infer Data
>
? UseActionHookReturn<ServerError, S, BAS, CVE, CBAVE, Data>
: never;

/**
* Type of the return object of the `useOptimisticAction` hook.
*/
export type InferUseOptimisticActionHookReturn<T extends Function, State = any> =
T extends SafeActionFn<
infer ServerError,
infer S extends Schema | undefined,
infer BAS extends readonly Schema[],
infer CVE,
infer CBAVE,
infer Data
>
? UseOptimisticActionHookReturn<ServerError, S, BAS, CVE, CBAVE, Data, State>
: never;

/**
* Type of the return object of the `useStateAction` hook.
*/
export type InferUseStateActionHookReturn<T extends Function> =
T extends SafeStateActionFn<
infer ServerError,
infer S extends Schema | undefined,
infer BAS extends readonly Schema[],
infer CVE,
infer CBAVE,
infer Data
>
? UseStateActionHookReturn<ServerError, S, BAS, CVE, CBAVE, Data>
: never;
80 changes: 80 additions & 0 deletions packages/next-safe-action/src/index.types.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { Infer, InferArray, InferIn, InferInArray, Schema, ValidationAdapter } from "./adapters/types";
import type { SafeActionClient } from "./safe-action-client";
import type { MaybePromise, Prettify } from "./utils.types";
import type { BindArgsValidationErrors, ValidationErrors } from "./validation-errors.types";

@@ -201,3 +202,82 @@ export type SafeActionUtils<
hasNotFound: boolean;
}) => MaybePromise<void>;
};

/**
* Infer input types of a safe action.
*/
export type InferSafeActionFnInput<T extends Function> = T extends
| SafeActionFn<any, infer S extends Schema | undefined, infer BAS extends readonly Schema[], any, any, any>
| SafeStateActionFn<any, infer S extends Schema | undefined, infer BAS extends readonly Schema[], any, any, any>
? S extends Schema
? {
clientInput: InferIn<S>;
bindArgsClientInputs: InferInArray<BAS>;
parsedInput: Infer<S>;
bindArgsParsedInputs: InferArray<BAS>;
}
: {
clientInput: undefined;
bindArgsClientInputs: InferInArray<BAS>;
parsedInput: undefined;
bindArgsParsedInputs: InferArray<BAS>;
}
: never;

/**
* Infer the result type of a safe action.
*/
export type InferSafeActionFnResult<T extends Function> = T extends
| SafeActionFn<
infer ServerError,
infer S extends Schema | undefined,
infer BAS extends readonly Schema[],
infer CVE,
infer CBAVE,
infer Data
>
| SafeStateActionFn<
infer ServerError,
infer S extends Schema | undefined,
infer BAS extends readonly Schema[],
infer CVE,
infer CBAVE,
infer Data
>
? SafeActionResult<ServerError, S, BAS, CVE, CBAVE, Data>
: never;

/**
* Infer the next context type returned by a middleware function using the `next` function.
*/
export type InferMiddlewareFnNextCtx<T> =
T extends MiddlewareFn<any, any, any, infer NextCtx extends object> ? NextCtx : never;

/**
* Infer the context type of a safe action client or middleware function.
*/
export type InferCtx<T> = T extends
| SafeActionClient<any, any, any, any, infer Ctx extends object, any, any, any, any, any>
| MiddlewareFn<any, any, infer Ctx extends object, any>
? Ctx
: never;

/**
* Infer the metadata type of a safe action client or middleware function.
*/
export type InferMetadata<T> = T extends
| SafeActionClient<any, any, any, infer MD, any, any, any, any, any, any>
| MiddlewareFn<any, infer MD, any, any>
? MD
: never;

/**
* Infer the server error type from a safe action client or a middleware function or a safe action function.
*/
export type InferServerError<T> = T extends
| SafeActionClient<infer ServerError, any, any, any, any, any, any, any, any, any>
| MiddlewareFn<infer ServerError, any, any, any>
| SafeActionFn<infer ServerError, any, any, any, any, any>
| SafeStateActionFn<infer ServerError, any, any, any, any, any>
? ServerError
: never;
6 changes: 3 additions & 3 deletions packages/next-safe-action/src/stateful-hooks.ts
Original file line number Diff line number Diff line change
@@ -5,7 +5,7 @@ import {} from "react/experimental";
import type {} from "zod";
import type { InferIn, Schema } from "./adapters/types";
import { getActionShorthandStatusObject, getActionStatus, useActionCallbacks, useExecuteOnMount } from "./hooks-utils";
import type { HookBaseUtils, HookCallbacks, HookSafeStateActionFn } from "./hooks.types";
import type { HookBaseUtils, HookCallbacks, HookSafeStateActionFn, UseStateActionHookReturn } from "./hooks.types";
/**
* Use the stateful action from a Client Component via hook. Used for actions defined with [`stateAction`](https://next-safe-action.dev/docs/safe-action-client/instance-methods#action--stateaction).
* @param safeActionFn The action function
@@ -27,7 +27,7 @@ export const useStateAction = <
permalink?: string;
} & HookBaseUtils<S> &
HookCallbacks<ServerError, S, BAS, CVE, CBAVE, Data>
) => {
): UseStateActionHookReturn<ServerError, S, BAS, CVE, CBAVE, Data> => {
const [result, dispatcher, isExecuting] = React.useActionState(
safeActionFn,
utils?.initResult ?? {},
@@ -75,7 +75,7 @@ export const useStateAction = <

return {
execute,
input: clientInput,
input: clientInput as S extends Schema ? InferIn<S> : undefined,
result,
status,
...getActionShorthandStatusObject({ status, isTransitioning }),
Loading