import type { Middleware } from "./types.ts";
import * as manifest from "../manifest.ts";
export type App = { use: (middleware: Middleware) => void };
export function sortComparator(a: string, b: string) {
function weight(s: string) {
if (s === "index") {
return -1;
}
if (s === "profile") {
return 1;
}
return 0;
}
const wa = weight(a);
const wb = weight(b);
if (wa !== wb) {
return wa - wb;
}
return a.localeCompare(b);
}
export function sortNames(names: string[]) {
return names.sort(sortComparator);
}
export function autoRegisterModules(app: App) {
try {
autoRegisterModulesFrom(
manifest as unknown as Record<string, unknown>,
app,
);
} catch (err) {
console.error(
"❌ [Loader] Failed reading manifest:",
(err as Error).message,
);
}
}
export function autoRegisterModulesFrom(
manifestObj: Record<string, unknown>,
app: App,
) {
const names = sortNames(Object.keys(manifestObj));
for (const name of names) {
const ns = manifestObj[name];
if (isNamespaceObject(ns)) {
registerFromNamespace(name, ns as Record<string, unknown>, app);
}
}
}
export function registerFromNamespace(
name: string,
ns: Record<string, unknown>,
app: App,
) {
const candidate = getRegistrationCandidate(name, ns);
if (!candidate) return false;
const wrapped: Middleware = (req, ctx, next) => {
if (!ctx.state) ctx.state = {};
const prevModule = ctx.state.module;
ctx.state.module = name;
let restored = false;
const restore = () => {
if (restored) return;
restored = true;
if (prevModule === undefined) {
delete ctx.state.module;
} else {
ctx.state.module = prevModule;
}
};
const wrappedNext = () => {
restore();
return next();
};
try {
const res = (candidate as unknown as Middleware)(req, ctx, wrappedNext) as
| Response
| Promise<Response>;
if (res && typeof (res as Promise<Response>).then === "function") {
return (res as Promise<Response>).then((v) => {
restore();
return v;
}, (err) => {
restore();
throw err;
});
}
restore();
return res;
} catch (err) {
restore();
throw err;
}
};
app.use(wrapped as unknown as Middleware);
if (candidate === ns.default) {
console.info(`✅ Registered default export from ${name}/mod.ts`);
} else {
console.info(`✅ Registered ${name} export from ${name}/mod.ts`);
}
return true;
}
export function isNamespaceObject(v: unknown): v is Record<string, unknown> {
return !!v && typeof v === "object";
}
export function getRegistrationCandidate(
name: string,
ns: Record<string, unknown>,
) {
const def = ns.default as unknown;
if (typeof def === "function") return def;
const named = ns[name];
if (typeof named === "function") return named;
return null;
}