forked from c-fu/arah2
feat(03-03): status strip, state cards, recenter control, boot choreography — map-first, D-09 staged states
- strip.ts: six-state lamp+word left cluster, ±M / FIX Ns AGO telemetry (U+00B1 glyph), elapsed-seconds for acquiring - cards.ts: boot/denied/lost builders from theme classes, machine-blink gantry (500ms JS duty cycle), GEO/SYS registers from strings.ts, D-06 CTA inversion (chat-fallback=btn-primary, retry=btn-secondary) - recenter.ts: 40x40 plate w/ >=44 hit slop, orthogonal inline-SVG crosshair, three data-attribute notch states, no inline handlers - main.ts: boot order map->session->chain (bootMap before acquireFix), null-map guards on every map consumer, ARAHARAH-LIVE emitted outside the guard, data-map=absent fallback, localeFromInitData, ASK VIA CHAT w/ D-03 revalidation, 1s tick re-running the chain at 45s staleness - map.ts: attribution control moved bottom-left (UI-SPEC flush chip, compact) - shell.css: attrib chip #map-scoped override (wins cascade over maplibre css), strip left cluster, recenter z-index - vite.config.ts: define __ARAHARAH_HARNESS__ keyed on --mode harness (bare ambient global would ReferenceError in plain dev; Rule 3) - session.test.mjs: SESS1-4 memory-token gates
This commit is contained in:
@@ -0,0 +1,54 @@
|
||||
#!/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)");
|
||||
});
|
||||
Reference in New Issue
Block a user