seahaven-ap/packages/api/src/routes/helpers.ts

50 lines
1.5 KiB
TypeScript
Raw Normal View History

import { randomUUID } from "node:crypto";
import type { Context } from "hono";
import type { UserRole } from "../env.js";
import { can, type RbacAction } from "../auth/rbac.js";
import { errorJson } from "../http.js";
import type { AppBindings } from "../auth/middleware.js";
const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
export function isUuid(value: string): boolean {
return UUID_RE.test(value);
}
export function requireCan(c: Context<AppBindings>, action: RbacAction) {
const user = c.get("user");
if (!can(user.role, action)) {
return errorJson(c, 403, "FORBIDDEN", `Role ${user.role} is not allowed to ${action}.`);
}
return null;
}
export function caller(c: Context<AppBindings>) {
return c.get("user");
}
export function iso(value: Date | string): string {
return value instanceof Date ? value.toISOString() : new Date(value).toISOString();
}
export function asString(value: unknown, fallback = ""): string {
return typeof value === "string" ? value : fallback;
}
export function optionalString(value: unknown): string | null | undefined {
if (value === undefined) return undefined;
if (value === null) return null;
if (typeof value === "string") return value;
return undefined;
}
export function newId(): string {
return randomUUID();
}
export function parseJsonBody(c: Context): Promise<Record<string, unknown>> {
return c.req.json<Record<string, unknown>>();
}
export type { UserRole };