Files
diachron/backend/diachron/types.ts
Michael Wolf db1f2151de Rename express/ to backend/ and update references
Update paths in sync.sh, master/main.go, and CLAUDE.md to reflect
the directory rename.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-02 17:54:44 -05:00

118 lines
2.7 KiB
TypeScript

// types.ts
// FIXME: split this up into types used by app developers and types internal
// to the framework.
import type { Request as ExpressRequest } from "express";
import type { MatchFunction } from "path-to-regexp";
import { z } from "zod";
import type { Session } from "./auth/types";
import type { ContentType } from "./content-types";
import type { HttpCode } from "./http-codes";
import type { Permission, User } from "./user";
const methodParser = z.union([
z.literal("GET"),
z.literal("POST"),
z.literal("PUT"),
z.literal("PATCH"),
z.literal("DELETE"),
]);
export type Method = z.infer<typeof methodParser>;
const massageMethod = (input: string): Method => {
const r = methodParser.parse(input.toUpperCase());
return r;
};
export type Call = {
pattern: string;
path: string;
method: Method;
parameters: object;
request: ExpressRequest;
user: User;
session: Session;
};
export type InternalHandler = (req: ExpressRequest) => Promise<Result>;
export type Handler = (call: Call) => Promise<Result>;
export type ProcessedRoute = {
matcher: MatchFunction<Record<string, string>>;
method: Method;
handler: InternalHandler;
};
export type CookieOptions = {
httpOnly?: boolean;
secure?: boolean;
sameSite?: "strict" | "lax" | "none";
maxAge?: number;
path?: string;
};
export type Cookie = {
name: string;
value: string;
options?: CookieOptions;
};
export type Result = {
code: HttpCode;
contentType: ContentType;
result: string;
cookies?: Cookie[];
};
export type RedirectResult = Result & {
redirect: string;
};
export function isRedirect(result: Result): result is RedirectResult {
return "redirect" in result;
}
export type Route = {
path: string;
methods: Method[];
handler: Handler;
interruptable?: boolean;
};
// Authentication error classes
export class AuthenticationRequired extends Error {
constructor() {
super("Authentication required");
this.name = "AuthenticationRequired";
}
}
export class AuthorizationDenied extends Error {
constructor() {
super("Authorization denied");
this.name = "AuthorizationDenied";
}
}
// Helper for handlers to require authentication
export function requireAuth(call: Call): User {
if (call.user.isAnonymous()) {
throw new AuthenticationRequired();
}
return call.user;
}
// Helper for handlers to require specific permission
export function requirePermission(call: Call, permission: Permission): User {
const user = requireAuth(call);
if (!user.hasPermission(permission)) {
throw new AuthorizationDenied();
}
return user;
}
export type Domain = "app" | "fw";
export { methodParser, massageMethod };