#!/usr/bin/env node /* * session.test.mjs — SESS1..SESS4, pure-function gates over session/store.ts. * ---------------------------------------------------------------------------- * The store is a module singleton: every case calls clearSession() first so * case order never leaks token state. SESS4 is the D-03/D-07 source gate — * store.ts must reference no persistence surface in CODE (comments stripped, * GEO3 gate pattern from no-storage.test.mjs). */ import { strict as assert } from "node:assert"; import { readFileSync } from "node:fs"; import path from "node:path"; import { fileURLToPath } from "node:url"; import { test } from "./harness.mjs"; const { setSession, getSession, isSessionStale, clearSession, SESSION_TTL_SECONDS } = await import("../src/session/store.ts"); test("SESS1 setSession/getSession round-trips and isSessionStale is false inside the 900s window", () => { clearSession(); setSession("token-abc", 1_000); assert.equal(getSession(), "token-abc"); assert.equal(isSessionStale(1_000 + SESSION_TTL_SECONDS - 1), false, "one second inside the window is fresh"); assert.equal(isSessionStale(1_000 + 1), false, "a fresh issuance is fresh"); }); test("SESS2 isSessionStale is true at or beyond 900s, and true before any token is set", () => { clearSession(); assert.equal(isSessionStale(1_234), true, "no token — stale by definition"); setSession("token-abc", 1_000); assert.equal(isSessionStale(1_000 + SESSION_TTL_SECONDS), true, "exactly 900s is already stale"); assert.equal(isSessionStale(1_000 + SESSION_TTL_SECONDS + 42), true, "beyond the window is stale"); }); test("SESS3 clearSession nulls the token", () => { setSession("to-be-cleared", 42); assert.equal(getSession(), "to-be-cleared"); clearSession(); assert.equal(getSession(), null); assert.equal(isSessionStale(43), true, "a cleared store is a stale store"); }); test("SESS4 store.ts references no storage API (source-introspection, comments stripped)", () => { const file = path.join(path.dirname(fileURLToPath(new URL(import.meta.url))), "..", "src", "session", "store.ts"); const code = readFileSync(file, "utf8") .replace(/\/\*[\s\S]*?\*\//g, " ") .replace(/(^|[^:\\])\/\/[^\n]*/g, "$1"); for (const banned of [ "localStorage", "sessionStorage", "indexedDB", "caches", "document.cookie", "setItem", "getItem", "removeItem", ]) { assert.ok(!code.includes(banned), `store.ts code references ${banned} — the memory-only invariant is broken`); } assert.ok(code.includes("SESSION_TTL_SECONDS = 900"), "the 900s TTL mirror by name stays present (D-03)"); });