release: WRNexusJS 0.3.0

This commit is contained in:
2026-07-22 17:29:08 +05:30
parent 13dfa31d19
commit 07d8fb59d6
145 changed files with 9664 additions and 3881 deletions
+56
View File
@@ -0,0 +1,56 @@
import type { Context, Middleware } from "./context.ts";
export interface Tenant {
id: string;
slug?: string;
name?: string;
metadata?: Record<string, unknown>;
}
export type TenantResolver = (ctx: Context) => Tenant | null | Promise<Tenant | null>;
export interface TenantMiddlewareOptions {
required?: boolean;
status?: number;
}
export function tenantMiddleware(
resolveTenant: TenantResolver,
options: TenantMiddlewareOptions = {},
): Middleware {
return async (ctx, next) => {
const tenant = await resolveTenant(ctx);
ctx.tenant = tenant ?? undefined;
if (!tenant && options.required !== false) {
return new Response("Tenant not found", { status: options.status ?? 404 });
}
return next();
};
}
export function tenantFromSubdomain(
lookup: (slug: string, ctx: Context) => Tenant | null | Promise<Tenant | null>,
rootDomains: string[] = [],
): TenantResolver {
return async (ctx) => {
const host = ctx.url.hostname.toLowerCase();
const root = rootDomains.find((domain) => host === domain || host.endsWith(`.${domain}`));
const slug = root ? host.slice(0, -(root.length + 1)) : host.split(".")[0];
if (!slug || slug === host || slug === "www") return null;
return lookup(slug, ctx);
};
}
export function requireTenant(ctx: Context): Tenant {
if (!ctx.tenant)
throw new Error("WRN-TENANT-REQUIRED: tenant middleware has not resolved a tenant.");
return ctx.tenant;
}
/** Wrap a repository so every operation receives the current tenant id. */
export function tenantScope<T extends object>(
tenant: Tenant,
repository: T,
): T & { tenantId: string } {
return Object.assign(Object.create(repository), { tenantId: tenant.id });
}