Adapterهای Backend
پوشهی server/ بدون هیچ وابستگی (فقط node:crypto)، سمت سرورِ درخواستهایی را که ماژولهای مرورگر میفرستند پوشش میدهد: نشانهی CSRF وابسته به نشست، بررسی Origin، Idempotency-Key با پاسخ تکراری، محدودیت نرخ، همان Schema برای اعتبارسنجی، تشخیص نوع واقعی فایل و هدرهای امنیتی سازگار با Bana.
| ورودی | برای |
|---|---|
| @bana-ui/core/server | هسته: createGuard، verifyFile، securityHeaders، fieldErrors |
| @bana-ui/core/server/express | Express و Connect |
| @bana-ui/core/server/fetch | هر چیز با Request → Response: Next.js، Hono، Deno، Bun، Cloudflare |
| @bana-ui/core/server/fastify | Fastify |
import express from "express";
import { createGuard, securityHeaders } from "@bana-ui/core/server";
import { banaExpress, banaValidate } from "@bana-ui/core/server/express";
import schema from "./signup.schema.json" with { type: "json" }; // the same file the browser renders
const guard = createGuard({ secret: process.env.BANA_SECRET }); // 32+ random characters
const app = express();
app.use((req, res, next) => { res.set(securityHeaders()); next(); });
app.use(express.json());
app.use(banaExpress(guard)); // CSRF + Idempotency-Key + Origin
app.get("/", (req, res) => res.send(`<meta name="csrf-token" content="${req.bana.csrfToken}">…`));
app.post("/api/signup", banaValidate(guard, schema), (req, res) => {
const user = save(req.bana.values); // cleaned: Latin digits, ی/ک, hidden fields omitted
res.status(201).json({ ok: true, id: user.id });
}); // invalid → 422 { errors: { field: message } } shown under each field// Next.js / Hono / Deno / Bun
export const POST = withBana(guard, { session: (req) => sidFromCookie(req), schema },
async (req, { values }) => Response.json({ ok: true }, { status: 201 }));
// Fastify
await app.register(banaFastify, { guard });
app.post("/api/signup", { preValidation: banaFastify.validate(guard, schema) }, async (req) => ({ ok: true }));| پاسخ | وقتی |
|---|---|
| 403 | نشانهی CSRF نادرست/منقضی/متعلق به نشست دیگر، Origin ناشناس، یا Sec-Fetch-Site: cross-site |
| 409 / 422 | درخواست همکلید هنوز در حال پردازش است / همان کلید با بدنهی دیگر |
| 429 | محدودیت نرخ؛ هدر Retry-After را مرورگر (Safe Action) رعایت میکند |
همان پاسخ + Idempotent-Replayed | تلاش مجدد با همان Idempotency-Key و همان بدنه؛ کد شما دوباره اجرا نمیشود |
این لایه جایگزین Authentication و Authorization نیست.شناسهی نشست (
session) باید از سیستم ورود خودتان بیاید؛ اگر ندهید یک کوکی ناشناس __Host-bana-sid ساخته میشود (در توسعهی HTTP ساده cookie: { secure: false } بدهید). حافظهی پیشفرض Idempotency و محدودیت نرخ داخل پردازش است؛ با چند سرور یا ریاستارت از دست میرود، پس store / rateStore را به Redis یا پایگاهداده وصل کنید. آدرس IP پشت پروکسی را خودتان درست تنظیم کنید. verifyFile فقط چند نوع رایج (PNG، JPEG، GIF، WebP، PDF، ZIP) را از روی بایتها میشناسد و تجزیهی multipart (مثلاً busboy) با شماست.برای کار با CSP سختگیرانه، اسکریپت راهاندازی را فایل بیرونی بگذارید (import { Bana } from "/bana.js"; Bana.start();)؛ خود Bana هیچ اسکریپت یا استایل درونخطی لازم ندارد.