feat: centralize application framework primitives
Quality / quality (ubuntu-latest) (push) Failing after 14m38s
Quality / quality (windows-latest) (push) Canceled after 0s

This commit is contained in:
2026-08-22 23:07:46 +05:30
parent 96e082b943
commit a3ddd39b7b
73 changed files with 1429 additions and 84 deletions
+76 -1
View File
@@ -1580,6 +1580,55 @@ export function createHandlers(deps: RuntimeDeps): Handlers {
});
}
const authorization = (
mod.authorization as
| Record<
string,
| string
| {
permission: string;
resource?: (ctx: Context) => unknown | Promise<unknown>;
exposeReason?: boolean;
mayDiscover?: boolean | ((ctx: Context) => boolean | Promise<boolean>);
}
>
| undefined
)?.[method];
if (authorization) {
if (!ctx.user) {
return Response.json({ ok: false, error: "Unauthorized" }, { status: 401 });
}
const rule =
typeof authorization === "string" ? { permission: authorization } : authorization;
const resource = rule.resource ? await rule.resource(ctx) : undefined;
if (rule.resource && resource == null) {
const mayDiscover =
typeof rule.mayDiscover === "function"
? await rule.mayDiscover(ctx)
: Boolean(rule.mayDiscover);
return Response.json(
{ ok: false, error: mayDiscover ? "Not Found" : "Forbidden" },
{ status: mayDiscover ? 404 : 403 },
);
}
const decision = ctx.authz ? await ctx.authz.decide(rule.permission, resource) : undefined;
const permissions = ctx.locals.permissions;
const allowed = decision
? decision.allowed
: typeof permissions === "function"
? await permissions(rule.permission, ctx)
: Array.isArray(permissions) && permissions.includes(rule.permission);
if (!allowed) {
return Response.json(
rule.exposeReason
? { ok: false, error: "Forbidden", reason: decision?.reason }
: { ok: false, error: "Forbidden" },
{ status: 403 },
);
}
ctx.resource = resource;
}
return (await handler(ctx)) as Response;
}
@@ -1740,6 +1789,33 @@ export function createHandlers(deps: RuntimeDeps): Handlers {
const storeContainer = requestStoreContainer(ctx.req, matched.route.raw);
const mod = await loadModule(matched.route.file);
ctx.params = matched.params;
const pageSecurity = (mod.__wrnexusSecurity ?? {}) as Record<string, string>;
if (/^(?:required|true)$/i.test(pageSecurity.auth ?? "") && !ctx.user) {
if (ctx.req.method.toUpperCase() === "POST") {
return Response.json({ error: "Authentication required" }, { status: 401 });
}
const login = new URL("/login", ctx.url);
login.searchParams.set("returnTo", ctx.url.pathname + ctx.url.search);
return Response.redirect(login, 302);
}
if (pageSecurity.permission) {
const decision = ctx.authz ? await ctx.authz.decide(pageSecurity.permission) : undefined;
const permissions = ctx.locals.permissions;
const allowed = decision
? decision.allowed
: typeof permissions === "function"
? await permissions(pageSecurity.permission, ctx)
: Array.isArray(permissions) && permissions.includes(pageSecurity.permission);
if (!allowed) {
if (ctx.req.method.toUpperCase() === "POST") {
return Response.json({ error: "Permission denied" }, { status: 403 });
}
const forbidden = new URL(pageSecurity.forbidden ?? "/forbidden", ctx.url);
if (decision?.reason) forbidden.searchParams.set("reason", decision.reason);
return Response.redirect(forbidden, 303);
}
}
if (ctx.req.method.toUpperCase() === "POST") {
const actionResponse = await handlePageAction(ctx, mod);
if (actionResponse) return actionResponse;
@@ -1749,7 +1825,6 @@ export function createHandlers(deps: RuntimeDeps): Handlers {
throw new Error(`Page ${matched.route.file} has no default export`);
}
ctx.params = matched.params;
const meta = (mod.meta ?? {}) as PageMeta;
const pageNavigation = (mod.__wrnexusNavigation ?? {}) as { preserve?: string };
const pageCache = (mod.__wrnexusCache ?? {}) as Record<string, string>;