marmar-context / web / context / server / index.ts
index.ts
Raw
import { coverageReviewSchema } from "./schemas";
import { createServer } from "node:http";
import { readFile } from "node:fs/promises";
import { extname, resolve, sep } from "node:path";
import { fileURLToPath } from "node:url";
import { z } from "zod";
import { baseSchema } from "./schemas";
import {
  ENGINE_VERSION,
  RULES_VERSION,
} from "../../../src/domain/checks/engine";
import { CHECK_SIGNED_OFF } from "../../../src/domain/checks/signoff";
import { CASES } from "./cases";
import { assess } from "./context";
import {
  extract,
  modelConfig,
  modelReady,
  modelLabel,
  modelProvider,
  configureAzureSession,
  modelVerification,
} from "./model";
import { keepDraft, getDraft, keepReport, getReport } from "./sessions";
import { ModelError, modelLoad } from "./model-runtime";
import { runEvaluation } from "./evaluation";
import { hostingConfig, requestOwner, createPreviewLimiter } from "./hosting";

const root = fileURLToPath(new URL("../dist", import.meta.url));
const mime: Record<string, string> = {
  ".html": "text/html",
  ".js": "text/javascript",
  ".css": "text/css",
  ".svg": "image/svg+xml",
  ".ttf": "font/ttf",
  ".json": "application/json",
};
const hosting = hostingConfig();
const { port } = hosting;
const limitExtraction = createPreviewLimiter();
const server = createServer(async (req, res) => {
  const disconnected = new AbortController();
  res.on("close", () => {
    if (!res.writableEnded) disconnected.abort();
  });
  res.setHeader("X-Content-Type-Options", "nosniff");
  res.setHeader("Cache-Control", "no-store");
  res.setHeader("Referrer-Policy", "no-referrer");
  const json = (status: number, body: unknown) => {
    if (res.destroyed) return;
    res.writeHead(status, { "Content-Type": "application/json" });
    res.end(JSON.stringify(body));
  };
  try {
    const path = new URL(req.url ?? "/", "http://localhost").pathname;
    if (req.method === "GET" && path === "/healthz") {
      json(200, { ready: true });
      return;
    }
    const owner = requestOwner(hosting, req.headers);
    res.setHeader("X-Frame-Options", "DENY");
    if (hosting.hosted)
      res.setHeader("Strict-Transport-Security", "max-age=31536000");
    if (path.startsWith("/api/")) {
      if (req.method === "GET" && path === "/api/status") {
        json(200, {
          engineVersion: ENGINE_VERSION,
          rulesVersion: RULES_VERSION,
          rulesReviewed: CHECK_SIGNED_OFF,
          modelConfigured: modelReady(),
          hosted: hosting.hosted,
          modelConnectionManaged: hosting.hosted,
          model: modelLabel(),
          modelProvider: modelReady() ? modelProvider() : null,
          modelVerifiedAt: modelVerification(),
          modelLoad: modelLoad(),
        });
        return;
      }
      if (req.method === "GET" && path === "/api/cases") {
        json(200, CASES);
        return;
      }
      if (req.method === "GET" && path.startsWith("/api/reports/")) {
        const report = getReport(path.slice("/api/reports/".length), owner);
        res.setHeader(
          "Content-Disposition",
          'attachment; filename="marmar-context-evidence.json"'
        );
        json(200, report);
        return;
      }
      if (req.method !== "POST") {
        json(405, { error: "Method not allowed." });
        return;
      }
      if (!(req.headers["content-type"] ?? "").startsWith("application/json")) {
        json(415, { error: "Use application/json." });
        return;
      }
      let body = "";
      for await (const chunk of req) {
        body += chunk.toString();
        if (Buffer.byteLength(body) > 120000) {
          json(413, { error: "Request is too large." });
          return;
        }
      }
      let parsed: unknown;
      try {
        parsed = JSON.parse(body);
      } catch {
        json(400, { error: "Invalid JSON." });
        return;
      }
      if (path === "/api/evaluate") {
        json(200, runEvaluation());
        return;
      }
      if (path === "/api/model") {
        if (hosting.hosted) {
          json(403, {
            error:
              "Model connection is managed by the deployment administrator.",
          });
          return;
        }
        const data = z
          .object({
            endpoint: z.string().max(500),
            key: z.string().min(1).max(1000),
            model: z.string().min(1).max(150),
            auth: z.enum(["api-key", "bearer"]),
          })
          .strict()
          .parse(parsed);
        configureAzureSession(data);
        json(200, { configured: true });
        return;
      }
      if (path === "/api/extract") {
        if (hosting.hosted) limitExtraction(owner);
        const data = baseSchema
          .extend({
            useModel: z.boolean().default(false),
            freshModel: z.boolean().default(false),
          })
          .strict()
          .parse(parsed);
        json(
          200,
          keepDraft(
            await extract(
              data.sources,
              data.useModel,
              data.freshModel,
              disconnected.signal
            ),
            data.sources,
            owner
          )
        );
        return;
      }
      if (path === "/api/assess") {
        const data = baseSchema
          .extend({
            draftId: z.string().uuid(),
            review: z.record(z.string(), z.enum(["include", "exclude"])),
            coverageReview: coverageReviewSchema,
            fingerprint: z.string().length(64),
            acknowledgeUnparsed: z.boolean(),
          })
          .strict()
          .parse(parsed);
        json(
          200,
          keepReport(
            data.draftId,
            assess(
              data.sources,
              data.review,
              data.fingerprint,
              data.acknowledgeUnparsed,
              getDraft(data.draftId, data.sources, owner),
              data.coverageReview
            ),
            data.review,
            owner
          )
        );
        return;
      }
      json(404, { error: "Unknown endpoint." });
      return;
    }
    if (req.method !== "GET") {
      json(405, { error: "Method not allowed." });
      return;
    }
    // Paths without a file extension are app routes (/app/..., /invite/<token>): serve the page.
    const file =
      path === "/" || !extname(path)
        ? resolve(root, "index.html")
        : resolve(root, `.${decodeURIComponent(path)}`);
    if (!file.startsWith(root + sep)) {
      json(403, { error: "Invalid path." });
      return;
    }
    try {
      const data = await readFile(file);
      res.writeHead(200, {
        "Content-Type": mime[extname(file)] ?? "application/octet-stream",
      });
      res.end(data);
    } catch {
      json(404, {
        error: "File unavailable. Run npm run build before starting the demo.",
      });
    }
  } catch (error) {
    if (error instanceof ModelError && error.retryAfter)
      res.setHeader("Retry-After", String(error.retryAfter));
    json(error instanceof ModelError ? error.status : 400, {
      error:
        error instanceof z.ZodError
          ? "Invalid request. Check field types, lengths and the synthetic-data acknowledgement."
          : error instanceof Error
          ? error.message
          : "Unable to process request.",
    });
  }
});
server.requestTimeout = 30_000;
server.headersTimeout = 15_000;
server.listen(port, hosting.bind, () =>
  console.log(
    `MARMAR Context listening on port ${port} (${
      hosting.hosted ? "restricted hosted preview" : "local preview"
    }, synthetic data only)`
  )
);