mcpField
S
safe-action-advanced

safe-action-advanced

github.com/next-safe-actionDevelopment11.2k installsUpdated 8w ago
Repository

About safe-action-advanced

Advanced next-safe-action features for configuring server actions, handling framework errors, and working with typed metadata and inferred types. It is intended for developers who need action-level controls beyond the basic action flow.

Key features

  1. 01Bind extra arguments to actions
  2. 02Attach typed metadata
  3. 03Handle framework errors
  4. 04Infer action and middleware types
  5. 05Configure server-level callbacks

Use cases

  1. 01Passing resource IDs to an action
  2. 02Making metadata available in middleware
  3. 03Handling redirect or authorization errors
  4. 04Rethrowing handled server errors

Install

Copy the command and run it in a terminal.

$npx skills add https://github.com/next-safe-action/skills --skill safe-action-advanced

After installing, type/safe-action-advancedin Claude Code to confirm it loaded.

Bundled files

References and scripts installed along with SKILL.md.

bind-arguments.md
framework-errors.md
metadata.md
type-utilities.md

Details

From the project README

next-safe-action Advanced Features

Overview

FeatureUse Case
Bind argumentsPass extra args to actions via .bind() (e.g., resource IDs)
MetadataAttach typed metadata to actions for use in middleware
Framework errorsHandle redirect, notFound, forbidden, unauthorized in actions
Type utilitiesInfer types from action functions and middleware

Server-Level Action Callbacks

The second argument to .action() accepts callbacks that run on the server (not client-side hooks):

export const createPost = authActionClient
  .inputSchema(schema)
  .action(
    async ({ parsedInput, ctx }) => {
      const post = await db.post.create(parsedInput);
      return post;
    },
    {
      onSuccess: async ({ data, parsedInput, ctx, metadata, clientInput }) => {
        // Runs on the server after successful execution
        await invalidateCache("posts");
      },
      onError: async ({ error, metadata, ctx, clientInput, bindArgsClientInputs }) => {
        // error: { serverError?, validationErrors? }
        await logError(error);
      },
      onSettled: async ({ result }) => {
        // Always runs
        await recordMetrics(result);
      },
      onNavigation: async ({ navigationKind }) => {
        // Runs when a framework error (redirect, notFound, etc.) occurs
        console.log("Navigation:", navigationKind);
      },
    }
  );

These are distinct from hook callbacks (useAction({ onSuccess })) — server callbacks run in the Node.js runtime, hook callbacks run in the browser.

throwServerError

Re-throw server errors instead of returning them as result.serverError:

export const myAction = actionClient
  .inputSchema(schema)
  .action(serverCodeFn, {
    throwServerError: true,
    // The handled server error (return of handleServerError) is thrown
  });

Don't confuse this with returnServerError(): throwServerError throws the handled error (post-handleServerError) instead of returning it, while returnServerError(payload) returns a typed expected error in result.serverError, bypassing handleServerError entirely (see the safe-action-client skill's error-handling doc).

Comments

Markdown supported