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
+74 -2
View File
@@ -23,6 +23,8 @@ import {
withContextHeaders,
withSecurityHeaders,
resolveRequestUrl,
tenantMiddleware,
tracingMiddleware,
type Context,
type Middleware,
type Mode,
@@ -43,6 +45,8 @@ import {
type ResolvedTheme,
type MobileConfig,
type PwaConfig,
type ObservabilityConfig,
type TenancyConfig,
} from "@wrnexus/styles";
import {
LANG_COOKIE,
@@ -129,6 +133,10 @@ export interface RuntimeDeps {
pwa?: PwaConfig | false;
/** Framework security headers and CORS policy. */
security?: SecurityConfig;
/** Built-in request tracing and Server-Timing policy. */
observability?: ObservabilityConfig;
/** Built-in tenant identity resolution. */
tenancy?: TenancyConfig;
/** Max request body size in bytes (413 above this). Default 10 MB. */
maxBodyBytes?: number;
/** HMR hub for browser live-update sockets (dev only). */
@@ -158,6 +166,65 @@ function shouldEnableDevToolbar(mode: string, deps: RuntimeDeps): boolean {
);
}
function tenantIdentityFromConfig(
config: TenancyConfig,
): (ctx: Context) => Promise<{ id: string; slug?: string } | null> {
return async (ctx) => {
const host = ctx.url.hostname.toLowerCase();
if (config.mode === "domain") return host ? { id: host, slug: host } : null;
if (config.mode === "path") {
const segments = ctx.url.pathname.split("/").filter(Boolean);
const prefix = config.pathPrefix?.replace(/^\/+|\/+$/g, "");
const slug = prefix ? (segments[0] === prefix ? segments[1] : undefined) : segments[0];
return slug ? { id: slug, slug } : null;
}
if (config.mode === "subdomain" || config.mode === undefined) {
const roots = config.rootDomains?.map((domain) => domain.toLowerCase()) ?? [];
const root = roots.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" || slug === "localhost") return null;
return { id: slug, slug };
}
return null;
};
}
function frameworkMiddleware(deps: RuntimeDeps): Middleware[] {
const middleware: Middleware[] = [];
if (deps.observability && deps.observability.enabled !== false) {
middleware.push(
tracingMiddleware(undefined, {
sampleRate: deps.observability.sampleRate,
serverTiming: deps.observability.serverTiming,
onComplete:
deps.observability.exporter === "console"
? (ctx, records) => {
const total = records.find((record) => record.name === "http.request")?.durationMs;
console.log(
`[wrnexus:trace] ${ctx.req.method} ${ctx.url.pathname} ${total?.toFixed(2) ?? "0.00"}ms`,
);
}
: undefined,
}),
);
}
if (deps.tenancy && deps.tenancy.mode !== "custom") {
middleware.push(
tenantMiddleware(tenantIdentityFromConfig(deps.tenancy), {
required: deps.tenancy.required,
}),
);
}
return middleware;
}
function shouldReportNotFound(pathname: string): boolean {
return !(
pathname.startsWith("/__wrnexus/") ||
@@ -597,6 +664,11 @@ export interface Handlers {
/** Build the fetch + websocket handlers from a set of dependencies. */
export function createHandlers(deps: RuntimeDeps): Handlers {
const { mode, hmr, router, loadModule, getMiddleware, assets } = deps;
const builtInMiddleware = frameworkMiddleware(deps);
const resolveMiddleware = async (): Promise<Middleware[]> => [
...builtInMiddleware,
...(await getMiddleware()),
];
const maxBodyBytes = deps.maxBodyBytes ?? 10 * 1024 * 1024; // 10 MB default
// Server-side realtime room manager (shared by every `defineRoom` connection).
@@ -832,7 +904,7 @@ export function createHandlers(deps: RuntimeDeps): Handlers {
);
ctx.t = makeT(deps.i18n, ctx.lang);
}
const mws = await getMiddleware();
const mws = await resolveMiddleware();
const res = secure(
withContextHeaders(ctx, await runMiddleware(mws, ctx, () => dispatch(ctx))),
);
@@ -1271,7 +1343,7 @@ export function createHandlers(deps: RuntimeDeps): Handlers {
}
const res = withContextHeaders(
ctx,
await runMiddleware(await getMiddleware(), ctx, () => dispatch(ctx)),
await runMiddleware(await resolveMiddleware(), ctx, () => dispatch(ctx)),
);
const html = await res.text();
ws.send(JSON.stringify({ type: "html", html }));