重要前提
安装AI Skills的关键前提是:必须科学上网,且开启TUN模式,这一点至关重要,直接决定安装能否顺利完成,在此郑重提醒三遍:科学上网,科学上网,科学上网。查看完整安装教程 →
safe-action-middleware by next-safe-action/skills
npx skills add https://github.com/next-safe-action/skills --skill safe-action-middlewareimport { createSafeActionClient } from "next-safe-action";
const actionClient = createSafeActionClient();
// 使用 .use() 添加中间件
const authClient = actionClient.use(async ({ next }) => {
const session = await getSession();
if (!session?.user) {
throw new Error("Unauthorized");
}
// 通过 next({ ctx }) 将上下文传递给下一个中间件/操作
return next({
ctx: { userId: session.user.id },
});
});
.use() 向链中添加中间件 —— 你可以多次调用它.use() 都会返回一个新的客户端实例(不可变链)next({ ctx }) 累积 —— 每一级的 ctx 会与上一级的 ctx 深度合并const client = createSafeActionClient()
.use(async ({ next }) => {
console.log("1: before"); // 第 1 个运行
const result = await next({ ctx: { a: 1 } });
console.log("1: after"); // 第 4 个运行
return result;
})
.use(async ({ next, ctx }) => {
console.log("2: before", ctx.a); // 第 2 个运行,ctx.a = 1
const result = await next({ ctx: { b: 2 } });
console.log("2: after"); // 第 3 个运行
return result;
});
// 在 .action() 中:ctx = { a: 1, b: 2 }
广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
async ({
clientInput, // 来自客户端的原始输入 (unknown)
bindArgsClientInputs, // 原始绑定参数数组
ctx, // 来自先前中间件的累积上下文
metadata, // 通过 .metadata() 设置的元数据
next, // 调用以继续执行下一个中间件/操作
}) => {
// 可选地扩展上下文
return next({ ctx: { /* 新的上下文属性 */ } });
}
// 错误:忘记返回 next() —— 操作将挂起
.use(async ({ next }) => {
await doSomething();
next({ ctx: {} }); // 缺少 return!
})
// 正确:始终返回 next() 的结果
.use(async ({ next }) => {
await doSomething();
return next({ ctx: {} });
})
// 错误:捕获所有错误(会吞掉框架错误,如 redirect/notFound)
.use(async ({ next }) => {
try {
return await next({ ctx: {} });
} catch (error) {
return { serverError: "Something went wrong" }; // 吞掉了 redirect!
}
})
// 正确:重新抛出框架错误
.use(async ({ next }) => {
try {
return await next({ ctx: {} });
} catch (error) {
if (error instanceof Error && "digest" in error) {
throw error; // 让 Next.js 处理 redirects, notFound 等
}
// 处理其他错误
console.error(error);
return { serverError: "Something went wrong" };
}
})
每周安装量
63
代码仓库
首次出现
2026年3月6日
安全审计
安装于
cursor62
gemini-cli62
amp62
github-copilot62
codex62
kimi-cli62
import { createSafeActionClient } from "next-safe-action";
const actionClient = createSafeActionClient();
// Add middleware with .use()
const authClient = actionClient.use(async ({ next }) => {
const session = await getSession();
if (!session?.user) {
throw new Error("Unauthorized");
}
// Pass context to the next middleware/action via next({ ctx })
return next({
ctx: { userId: session.user.id },
});
});
.use() adds middleware to the chain — you can call it multiple times
Each .use() returns a new client instance (immutable chain)
Middleware executes top-to-bottom (in the order added)
Results flow bottom-to-top (the deepest middleware/action resolves first)
Context is accumulated via next({ ctx }) — each level's ctx is deep-merged with the previous
const client = createSafeActionClient() .use(async ({ next }) => { console.log("1: before"); // Runs 1st const result = await next({ ctx: { a: 1 } }); console.log("1: after"); // Runs 4th return result; }) .use(async ({ next, ctx }) => { console.log("2: before", ctx.a); // Runs 2nd, ctx.a = 1 const result = await next({ ctx: { b: 2 } }); console.log("2: after"); // Runs 3rd return result; });
// In .action(): ctx = { a: 1, b: 2 }
async ({
clientInput, // Raw input from the client (unknown)
bindArgsClientInputs, // Raw bind args array
ctx, // Accumulated context from previous middleware
metadata, // Metadata set via .metadata()
next, // Call to proceed to next middleware/action
}) => {
// Optionally extend context
return next({ ctx: { /* new context properties */ } });
}
// BAD: Forgetting to return next() — action will hang
.use(async ({ next }) => {
await doSomething();
next({ ctx: {} }); // Missing return!
})
// GOOD: Always return the result of next()
.use(async ({ next }) => {
await doSomething();
return next({ ctx: {} });
})
// BAD: Catching all errors (swallows framework errors like redirect/notFound)
.use(async ({ next }) => {
try {
return await next({ ctx: {} });
} catch (error) {
return { serverError: "Something went wrong" }; // Swallows redirect!
}
})
// GOOD: Re-throw framework errors
.use(async ({ next }) => {
try {
return await next({ ctx: {} });
} catch (error) {
if (error instanceof Error && "digest" in error) {
throw error; // Let Next.js handle redirects, notFound, etc.
}
// Handle other errors
console.error(error);
return { serverError: "Something went wrong" };
}
})
Weekly Installs
63
Repository
First Seen
Mar 6, 2026
Security Audits
Gen Agent Trust HubPassSocketPassSnykPass
Installed on
cursor62
gemini-cli62
amp62
github-copilot62
codex62
kimi-cli62
Azure RBAC 权限管理工具:查找最小角色、创建自定义角色与自动化分配
154,300 周安装