Wire up Better Auth for session-based authentication. Add actor middleware that resolves local_trusted mode to an implicit board actor and authenticated mode to Better Auth sessions. Add access service with membership, permission, invite, and join-request management. Register access routes for member/invite/ join-request CRUD. Update health endpoint to report deployment mode and bootstrap status. Enforce tasks:assign and agents:create permissions in issue and agent routes. Add deployment mode validation at startup with guardrails (loopback-only for local_trusted, auth config required for authenticated). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
48 lines
1.3 KiB
TypeScript
48 lines
1.3 KiB
TypeScript
import { Router } from "express";
|
|
import type { Db } from "@paperclip/db";
|
|
import { count, sql } from "drizzle-orm";
|
|
import { instanceUserRoles } from "@paperclip/db";
|
|
import type { DeploymentExposure, DeploymentMode } from "@paperclip/shared";
|
|
|
|
export function healthRoutes(
|
|
db?: Db,
|
|
opts: {
|
|
deploymentMode: DeploymentMode;
|
|
deploymentExposure: DeploymentExposure;
|
|
authReady: boolean;
|
|
} = {
|
|
deploymentMode: "local_trusted",
|
|
deploymentExposure: "private",
|
|
authReady: true,
|
|
},
|
|
) {
|
|
const router = Router();
|
|
|
|
router.get("/", async (_req, res) => {
|
|
if (!db) {
|
|
res.json({ status: "ok" });
|
|
return;
|
|
}
|
|
|
|
let bootstrapStatus: "ready" | "bootstrap_pending" = "ready";
|
|
if (opts.deploymentMode === "authenticated") {
|
|
const roleCount = await db
|
|
.select({ count: count() })
|
|
.from(instanceUserRoles)
|
|
.where(sql`${instanceUserRoles.role} = 'instance_admin'`)
|
|
.then((rows) => Number(rows[0]?.count ?? 0));
|
|
bootstrapStatus = roleCount > 0 ? "ready" : "bootstrap_pending";
|
|
}
|
|
|
|
res.json({
|
|
status: "ok",
|
|
deploymentMode: opts.deploymentMode,
|
|
deploymentExposure: opts.deploymentExposure,
|
|
authReady: opts.authReady,
|
|
bootstrapStatus,
|
|
});
|
|
});
|
|
|
|
return router;
|
|
}
|