import assert from "node:assert/strict"; import { test } from "vitest"; import { createCsrfTokenProvider, type CsrfTokenProvider, } from "../../../src/features/tech-log/adapters/http/studio-session-csrf.ts"; /** * Task 7 fix round 1 (C1, item 2). `createCsrfTokenProvider`'s `resolve()` * previously used `inFlight ??= deps.execute(options).then(...)`, which * evaluates `deps.execute(options)` — and therefore any re-entrant call back * into this same provider — before the `??=` assignment to `inFlight` * completes. If the operation an `execute` implementation calls happens to * require this same provider's token, `resolve()` re-enters itself while * `inFlight` is still `null`, recursing without bound * (`RangeError: Maximum call stack size exceeded`) instead of deduplicating. * The real fix for the TechLog Studio case is giving `getStudioSession` a * credential-free auth profile (`studio-csrf-composition.test.ts` proves * that end to end); this file pins the provider's own defense-in-depth * guard in isolation, so any future `execute` implementation with the same * mistake fails loudly and immediately instead of overflowing the stack. */ test("shares one in-flight request across concurrent callers", async () => { let executions = 0; let resolveExecute: ((snapshot: { csrfToken: string; csrfHeaderName: string }) => void) | undefined; const provider = createCsrfTokenProvider({ execute() { executions += 1; return new Promise((resolve) => { resolveExecute = resolve; }); }, }); const first = provider.token(); const second = provider.token(); resolveExecute?.({ csrfToken: "csrf-1", csrfHeaderName: "X-CSRF-TOKEN" }); assert.equal(await first, "csrf-1"); assert.equal(await second, "csrf-1"); assert.equal(executions, 1); }); test("caches the token after the first successful resolution", async () => { let executions = 0; const provider = createCsrfTokenProvider({ async execute() { executions += 1; return { csrfToken: `csrf-${executions}`, csrfHeaderName: "X-CSRF-TOKEN" }; }, }); assert.equal(await provider.token(), "csrf-1"); assert.equal(await provider.token(), "csrf-1"); assert.equal(executions, 1); }); test("re-fetches after invalidate()", async () => { let executions = 0; const provider = createCsrfTokenProvider({ async execute() { executions += 1; return { csrfToken: `csrf-${executions}`, csrfHeaderName: "X-CSRF-TOKEN" }; }, }); assert.equal(await provider.token(), "csrf-1"); provider.invalidate(); assert.equal(await provider.token(), "csrf-2"); assert.equal(executions, 2); }); test("fails loudly instead of recursing when execute re-enters the provider before its first request settles", async () => { let provider!: CsrfTokenProvider; provider = createCsrfTokenProvider({ async execute() { // Reproduces the shape of the C1 cycle directly: the operation that // issues the token itself asks this same provider for the token, // synchronously re-entering `resolve()` before `inFlight` is assigned. await provider.token(); return { csrfToken: "unreachable", csrfHeaderName: "X-CSRF-TOKEN" }; }, }); await assert.rejects(provider.token(), /re-entered/); });