@fitzzero/quickdraw-core 5.1.0 → 5.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +533 -180
- package/dist/{admin-DKwkIh5i.d.ts → admin-DWWrT1h6.d.ts} +2 -2
- package/dist/{adminSchemas-2DUA_hZ8.d.ts → adminSchemas-D4bFKsrb.d.ts} +6 -4
- package/dist/{auth-BhWqdyb-.d.ts → auth-DXiSJZaf.d.ts} +42 -16
- package/dist/{caller-CXTFswBO.d.ts → caller-BT-Mv4bD.d.ts} +117 -22
- package/dist/{chunk-RT6OILOI.js → chunk-4D2DOGAW.js} +2 -14
- package/dist/chunk-4D2DOGAW.js.map +1 -0
- package/dist/chunk-5CGO426C.js +15 -0
- package/dist/chunk-5CGO426C.js.map +1 -0
- package/dist/{chunk-A6DJBGOG.js → chunk-6K5BY47X.js} +4594 -3481
- package/dist/chunk-6K5BY47X.js.map +1 -0
- package/dist/{chunk-VJTFXHOK.js → chunk-753VJIUP.js} +13 -15
- package/dist/chunk-753VJIUP.js.map +1 -0
- package/dist/{chunk-JZBCLNDU.js → chunk-7QCUX4TK.js} +4 -4
- package/dist/chunk-7QCUX4TK.js.map +1 -0
- package/dist/chunk-AK23XSWD.js +16 -0
- package/dist/chunk-AK23XSWD.js.map +1 -0
- package/dist/{chunk-3674EIRT.js → chunk-AONAFOYU.js} +14 -5
- package/dist/{chunk-3674EIRT.js.map → chunk-AONAFOYU.js.map} +1 -1
- package/dist/chunk-DKE6QO26.js +136 -0
- package/dist/chunk-DKE6QO26.js.map +1 -0
- package/dist/{chunk-H23KEFBA.js → chunk-DUBU3BB3.js} +30 -1
- package/dist/chunk-DUBU3BB3.js.map +1 -0
- package/dist/{chunk-CDKG4TFA.js → chunk-GKH3LJ7N.js} +1 -1
- package/dist/chunk-GKH3LJ7N.js.map +1 -0
- package/dist/{chunk-KNDDCVQJ.js → chunk-GSIPUNJL.js} +49 -9
- package/dist/chunk-GSIPUNJL.js.map +1 -0
- package/dist/{chunk-DD4SKCNO.js → chunk-LCC7HNFP.js} +12 -1
- package/dist/chunk-LCC7HNFP.js.map +1 -0
- package/dist/{chunk-2PWMUVC7.js → chunk-MBH6IDSM.js} +480 -12
- package/dist/chunk-MBH6IDSM.js.map +1 -0
- package/dist/{chunk-2UELNHDD.js → chunk-NMXYENH4.js} +10 -10
- package/dist/{chunk-2UELNHDD.js.map → chunk-NMXYENH4.js.map} +1 -1
- package/dist/chunk-NO4M6PO5.js +101 -0
- package/dist/chunk-NO4M6PO5.js.map +1 -0
- package/dist/{chunk-TBMKJ26R.js → chunk-NW6U45HX.js} +3 -1
- package/dist/chunk-NW6U45HX.js.map +1 -0
- package/dist/{chunk-REX5YPHX.js → chunk-RJ5I2VO3.js} +74 -19
- package/dist/chunk-RJ5I2VO3.js.map +1 -0
- package/dist/{chunk-QEKVYG5F.js → chunk-RL4VKLBX.js} +1 -1
- package/dist/{chunk-QEKVYG5F.js.map → chunk-RL4VKLBX.js.map} +1 -1
- package/dist/chunk-XH2IZVLT.js +62 -0
- package/dist/chunk-XH2IZVLT.js.map +1 -0
- package/dist/{chunk-4DIQHASK.js → chunk-Z5ILULF2.js} +26 -7
- package/dist/chunk-Z5ILULF2.js.map +1 -0
- package/dist/cli/quickdraw-docs.js +5 -3
- package/dist/cli/quickdraw-docs.js.map +1 -1
- package/dist/client/index.d.ts +30 -18
- package/dist/client/index.js +8 -6
- package/dist/client/index.js.map +1 -1
- package/dist/{clientTypes-Bc-G8n-U.d.ts → clientTypes-hWcPUVS9.d.ts} +3 -3
- package/dist/{connection-Cr1BU07W.d.ts → connection-CgijdGpT.d.ts} +8 -4
- package/dist/{createServer-CP9eDHZZ.d.ts → createServer-Cp-Wk500.d.ts} +36 -14
- package/dist/{createTestApp-UKVGEmOf.d.ts → createTestApp-BB_PkqQ7.d.ts} +16 -10
- package/dist/{envelope-Cp3YcVxC.d.ts → envelope-DzWyIXjj.d.ts} +18 -4
- package/dist/{http-Djj2Inuu.d.ts → http-DotQ5bj8.d.ts} +68 -17
- package/dist/index.d.ts +7 -7
- package/dist/index.js +37 -13
- package/dist/index.js.map +1 -1
- package/dist/{infer-Teo1xpsd.d.ts → infer-BmoZsL9a.d.ts} +43 -10
- package/dist/logger-Yz93KzdV.d.ts +30 -0
- package/dist/{metrics-BdBu5o8G.d.ts → metrics-DW80Exve.d.ts} +2 -2
- package/dist/origins-kvpxnVcW.d.ts +8 -0
- package/dist/prisma/index.d.ts +5 -5
- package/dist/prisma/index.js +130 -67
- package/dist/prisma/index.js.map +1 -1
- package/dist/{rateLimit-ZMIZJUZF.js → rateLimit-5RKBFLUR.js} +2 -2
- package/dist/server/auth/index.d.ts +82 -33
- package/dist/server/auth/index.js +273 -268
- package/dist/server/auth/index.js.map +1 -1
- package/dist/server/express/index.d.ts +9 -2
- package/dist/server/express/index.js +1 -1
- package/dist/server/index.d.ts +147 -67
- package/dist/server/index.js +520 -381
- package/dist/server/index.js.map +1 -1
- package/dist/server/mcp/index.d.ts +63 -17
- package/dist/server/mcp/index.js +256 -54
- package/dist/server/mcp/index.js.map +1 -1
- package/dist/server/otel.d.ts +3 -3
- package/dist/{sharing-DVa8W-yR.d.ts → sharing-UDLn1049.d.ts} +3 -3
- package/dist/testing/client.d.ts +14 -14
- package/dist/testing/client.js +9 -7
- package/dist/testing/client.js.map +1 -1
- package/dist/testing/index.d.ts +12 -12
- package/dist/testing/index.js +21 -12
- package/dist/testing/index.js.map +1 -1
- package/dist/testing/mock.d.ts +5 -5
- package/dist/testing/mock.js +8 -6
- package/dist/{types-Cu0vmx7c.d.ts → types-CYliTP65.d.ts} +1 -1
- package/dist/utils/index.d.ts +1 -1
- package/package.json +1 -1
- package/dist/chunk-2PWMUVC7.js.map +0 -1
- package/dist/chunk-4DIQHASK.js.map +0 -1
- package/dist/chunk-A6DJBGOG.js.map +0 -1
- package/dist/chunk-CDKG4TFA.js.map +0 -1
- package/dist/chunk-DD4SKCNO.js.map +0 -1
- package/dist/chunk-H23KEFBA.js.map +0 -1
- package/dist/chunk-JZBCLNDU.js.map +0 -1
- package/dist/chunk-KNDDCVQJ.js.map +0 -1
- package/dist/chunk-REX5YPHX.js.map +0 -1
- package/dist/chunk-RT6OILOI.js.map +0 -1
- package/dist/chunk-TBMKJ26R.js.map +0 -1
- package/dist/chunk-VJTFXHOK.js.map +0 -1
- package/dist/chunk-YSWH776Y.js +0 -13
- package/dist/chunk-YSWH776Y.js.map +0 -1
- package/dist/logger-BY28acW-.d.ts +0 -16
- /package/dist/{rateLimit-ZMIZJUZF.js.map → rateLimit-5RKBFLUR.js.map} +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/testing/frames.ts","../../src/testing/budget.ts","../../src/testing/budgetCompare.ts","../../src/testing/instrument.ts","../../src/testing/socket.ts","../../src/testing/createTestApp.ts","../../src/testing/recordingSink.ts","../../src/testing/accessInputs.ts","../../src/testing/accessSnapshotFile.ts","../../src/testing/accessSnapshotCompare.ts","../../src/testing/accessMatrix.ts","../../src/testing/accessSnapshotPlan.ts","../../src/testing/accessSnapshot.ts"],"sourcesContent":["// The frame recorder of `createTestApp` (RFC 0003 section 13): every frame\n// the server sends any socket of the test app, as the server sent it to that\n// socket, with the user the socket acts for and when it was sent. Tests\n// assert on frames this way instead of putting raw listeners on client\n// sockets, and it covers every client: sockets from `app.connect`, client\n// connections from `./testing/client`, and any other.\n//\n// It records what goes out through Socket.IO's outgoing-packet hook on each\n// server socket, which sees direct emits and room broadcasts alike, so an\n// entity frame stripped for one access tier is recorded as that tier's\n// sockets received it. Events are recorded by name, whatever they are: the\n// v5 frames (`qd:hello`, `qd:e`, `qd:c`, `qd:changed`, `qd:revoked`,\n// `qd:access`, `qd:rotate`, and `qd:event` and `qd:stream` once services\n// send them) and an app's own. Acknowledgements are replies, not frames, and\n// are not recorded.\n\nimport type { AnyContract } from \"../contract/defineContract\";\nimport type { EventName, EventPayloadOf, StreamItemOf, StreamName } from \"../contract/infer\";\nimport { SERVER_EVENTS, type ServerEventName } from \"../contract/names\";\nimport type { EventFrame, ServerToClientEvents, StreamFrame } from \"../protocol/envelope\";\nimport type { QuickdrawIo } from \"../server/transports/types\";\n\n/** The payload of a v5 server event, by its name. */\nexport type ServerFrameOf<E extends ServerEventName> = Parameters<ServerToClientEvents[E]>[0];\n\n/** One frame the server sent one socket. */\nexport interface RecordedFrame<Data = unknown> {\n /** The event: `\"qd:e\"`, `\"qd:c\"`, `\"qd:changed\"`, ... */\n readonly event: string;\n /** The frame: the event's first argument. */\n readonly data: Data;\n /** Every argument of the event, for an app's own events that send more than one. */\n readonly args: readonly unknown[];\n /** The id of the socket it was sent to; the client socket's `id` is the same. */\n readonly socketId: string;\n /** The user the socket acts for, or `null` for an anonymous socket. */\n readonly userId: string | null;\n /** When the server sent it: `Date.now()`. */\n readonly at: number;\n}\n\n/** Which frames to take: all that match every field given. */\nexport interface FrameQuery<E extends string = string> {\n readonly event?: E;\n readonly socketId?: string;\n /** The user the socket acts for; `null` for anonymous sockets. */\n readonly userId?: string | null;\n}\n\n/**\n * The frames of one v5 event that match every field given, and `where`\n * when it is given: a predicate over the frame with its `data` typed as\n * the event's (`PresenceFrame` for `\"qd:presence\"`; `D` narrows an item or\n * a payload, as `streamFrames` and `eventFrames` do for a contract's).\n */\nexport interface EventQuery<E extends ServerEventName, D = ServerFrameOf<E>> extends FrameQuery<E> {\n readonly event: E;\n readonly where?: (frame: RecordedFrame<D>) => boolean;\n}\n\n/** A query, or a predicate over recorded frames. */\nexport type FrameMatch =\n | FrameQuery\n | EventQuery<ServerEventName, never>\n | ((frame: RecordedFrame) => boolean);\n\n/**\n * `app.frames`: every frame the test app's server sent since it started (or\n * since `clear()`), oldest first.\n *\n * @example\n * app.frames({ event: \"qd:e\", userId: cy.id }).map((frame) => frame.data);\n * app.frames.clear();\n * await app.server.dispatcher.caller(alice).taskService.rename({ id, title });\n * await app.frames.waitFor({ event: \"qd:changed\", userId: bob.id });\n */\nexport interface FrameRecorder {\n /** The frames of one v5 event that match `query` (and its `where`), typed by the event. */\n <E extends ServerEventName, D = ServerFrameOf<E>>(query: EventQuery<E, D>): RecordedFrame<D>[];\n /** The frames that match `match`, or every frame. */\n (match?: FrameMatch): RecordedFrame[];\n /** Forgets every frame recorded so far. */\n clear(): void;\n /**\n * Resolves with the first frame that matches: one recorded already (since\n * the last `clear()`), or the next one sent. Rejects when none arrives\n * within `timeoutMs` (default 5,000). An event query's `where`, and the\n * frame it resolves with, are typed by the event; `streamFrames` and\n * `eventFrames` type a contract's items and payloads too.\n *\n * @example\n * const { data } = await app.frames.waitFor({\n * ...streamFrames(gameContract, \"world\", (snapshot) => snapshot.tick === tick),\n * socketId: player.socket.id,\n * });\n * data[3].players; // a WorldSnapshot's\n */\n waitFor<E extends ServerEventName, D = ServerFrameOf<E>>(\n query: EventQuery<E, D>,\n timeoutMs?: number,\n ): Promise<RecordedFrame<D>>;\n waitFor(match: FrameMatch, timeoutMs?: number): Promise<RecordedFrame>;\n}\n\n/**\n * The `qd:stream` frames of one stream of `contract` (of one scope, with\n * `scope`), items typed, that `where` accepts: spread it into a query of\n * `app.frames` or `waitFor` beside `socketId` or `userId`.\n */\nexport function streamFrames<C extends AnyContract, K extends StreamName<C>>(\n contract: C,\n stream: K,\n where?: (\n item: StreamItemOf<C, K>,\n frame: RecordedFrame<StreamFrame<StreamItemOf<C, K>>>,\n ) => boolean,\n scope?: string,\n): EventQuery<typeof SERVER_EVENTS.stream, StreamFrame<StreamItemOf<C, K>>> {\n return Object.freeze({\n event: SERVER_EVENTS.stream,\n where: (frame: RecordedFrame<StreamFrame<StreamItemOf<C, K>>>) => {\n const [s, name, frameScope, item] = frame.data;\n return (\n s === contract.name &&\n name === stream &&\n (scope === undefined || frameScope === scope) &&\n (where === undefined || where(item, frame))\n );\n },\n });\n}\n\n/**\n * The `qd:event` frames of one event of `contract`, payloads typed, that\n * `where` accepts: spread it into a query of `app.frames` or `waitFor`.\n */\nexport function eventFrames<C extends AnyContract, K extends EventName<C>>(\n contract: C,\n event: K,\n where?: (\n payload: EventPayloadOf<C, K>,\n frame: RecordedFrame<EventFrame<EventPayloadOf<C, K>>>,\n ) => boolean,\n): EventQuery<typeof SERVER_EVENTS.event, EventFrame<EventPayloadOf<C, K>>> {\n return Object.freeze({\n event: SERVER_EVENTS.event,\n where: (frame: RecordedFrame<EventFrame<EventPayloadOf<C, K>>>) => {\n const [s, name, payload] = frame.data;\n return (\n s === contract.name && name === event && (where === undefined || where(payload, frame))\n );\n },\n });\n}\n\nconst DEFAULT_WAIT_MS = 5000;\n\n/** A `waitFor` still waiting. */\ninterface Waiter {\n readonly matches: (frame: RecordedFrame) => boolean;\n readonly resolve: (frame: RecordedFrame) => void;\n}\n\n/** The predicate `match` stands for. */\nfunction predicateOf(match: FrameMatch | undefined): (frame: RecordedFrame) => boolean {\n if (match === undefined) {\n return () => true;\n }\n if (typeof match === \"function\") {\n return match;\n }\n const where =\n \"where\" in match ? (match.where as ((frame: RecordedFrame) => boolean) | undefined) : undefined;\n return (frame) =>\n (match.event === undefined || frame.event === match.event) &&\n (match.socketId === undefined || frame.socketId === match.socketId) &&\n (match.userId === undefined || frame.userId === match.userId) &&\n (where === undefined || where(frame));\n}\n\n/** The text a timed-out `waitFor` names its match with. */\nfunction describeMatch(match: FrameMatch): string {\n if (typeof match === \"function\") {\n return \"the predicate\";\n }\n const { where, ...fields } = match as FrameQuery & { readonly where?: unknown };\n return where === undefined ? JSON.stringify(fields) : `${JSON.stringify(fields)} and its where`;\n}\n\n/**\n * Records every frame `io`'s server sends from now on. Its middleware runs\n * after the server's own, once a socket is authenticated, so a socket the\n * server refuses records nothing and `qd:hello` is the first frame of each.\n */\nexport function recordFrames(io: QuickdrawIo): FrameRecorder {\n const frames: RecordedFrame[] = [];\n const waiters = new Set<Waiter>();\n\n io.use((serverSocket, next) => {\n serverSocket.onAnyOutgoing((event: string, ...args: unknown[]) => {\n const frame: RecordedFrame = Object.freeze({\n event,\n data: args[0],\n args: Object.freeze([...args]),\n socketId: serverSocket.id,\n userId: serverSocket.data.principal?.userId ?? null,\n at: Date.now(),\n });\n frames.push(frame);\n for (const waiter of [...waiters]) {\n if (waiter.matches(frame)) {\n waiters.delete(waiter);\n waiter.resolve(frame);\n }\n }\n });\n next();\n });\n\n const waitFor = (match: FrameMatch, timeoutMs = DEFAULT_WAIT_MS): Promise<RecordedFrame> => {\n const matches = predicateOf(match);\n const found = frames.find(matches);\n if (found !== undefined) {\n return Promise.resolve(found);\n }\n return new Promise<RecordedFrame>((resolve, reject) => {\n const timer = setTimeout(() => {\n waiters.delete(waiter);\n reject(new Error(`No frame matched ${describeMatch(match)} within ${timeoutMs} ms`));\n }, timeoutMs);\n const waiter: Waiter = {\n matches,\n resolve: (frame) => {\n clearTimeout(timer);\n resolve(frame);\n },\n };\n waiters.add(waiter);\n });\n };\n\n const recorder = (match?: FrameMatch): RecordedFrame[] => frames.filter(predicateOf(match));\n return Object.assign(recorder, {\n clear: (): void => {\n frames.length = 0;\n },\n waitFor,\n }) as FrameRecorder;\n}\n","// `expectBudget` (RFC 0003 section 13): performance as something a test can\n// fail on. It runs one step of a test against the apps `createTestApp`\n// started and records what the step cost, then compares that with the\n// budget file next to the test, `__budgets__/<test file>.json`:\n//\n// - per call (a method call through `app.as(...)`, a socket or HTTP), its\n// service and method, the database statements its handler ran and the\n// bytes of its reply, from the call's completion record;\n// - for the whole step, every statement the apps' tracked database clients\n// ran (access checks, flushes and subscriptions included) and every byte\n// their servers wrote to sockets, plus the in-process replies.\n//\n// Counts and bytes, never time, so a budget is the same on every machine. A\n// missing entry is written. A rise fails with the old and new numbers, unless\n// QD_ALLOW_BUDGET_GROWTH allows it (`1` for every budget, or a comma-separated\n// list of budget names), which writes the new budget instead. A fall is\n// written locally, so the budget tightens as the code improves; under CI\n// (`CI=1` or `CI=true`) it fails too, so removed work is noticed and accepted\n// by running the tests locally. Bytes move by up to 5% either way without\n// counting as a change (ids and timestamps vary in length); statements must\n// match exactly. Two tests of one file may not name a step alike.\n\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { basename, dirname, join, relative } from \"node:path\";\nimport type { CallRecord } from \"../server/pipeline/metrics\";\nimport {\n compareBudgets,\n describeChanges,\n mergeBudget,\n type Budget,\n type BudgetCall,\n} from \"./budgetCompare\";\n\nexport type { Budget, BudgetCall };\n\n/**\n * The environment variable that lets a budget grow: `QD_ALLOW_BUDGET_GROWTH=1`\n * for every budget, or a comma-separated list of budget names.\n */\nexport const BUDGET_GROWTH_ENV = \"QD_ALLOW_BUDGET_GROWTH\";\n\n/** Whether {@link BUDGET_GROWTH_ENV} lets the budget `name` grow: `1`, or a list naming it. */\nexport function growthAllowed(name: string, value = process.env[BUDGET_GROWTH_ENV]): boolean {\n if (value === undefined) {\n return false;\n }\n const allowed = value.split(\",\").map((item) => item.trim());\n return (allowed.length === 1 && allowed[0] === \"1\") || allowed.includes(name);\n}\n\n/** Whether the tests run under CI (`CI=1` or `CI=true`), where a budget that fell fails. */\nexport function underCi(value = process.env.CI): boolean {\n return value === \"1\" || value === \"true\";\n}\n\n/** Options of {@link expectBudget}. */\nexport interface BudgetOptions {\n /** The entry's name in the budget file: unique within the test file. */\n readonly name: string;\n /**\n * The test file the budget file sits next to. Default: the running test's\n * file, from the test runner (vitest, or jest's `expect.getState()`).\n */\n readonly file?: string;\n}\n\n/** What {@link expectBudget} measured, and what it did with the budget file. */\nexport interface BudgetResult {\n readonly name: string;\n /** The budget file. */\n readonly path: string;\n /** What the step cost. */\n readonly measured: Budget;\n /**\n * `\"written\"`: there was no entry; `\"unchanged\"`: within the budget;\n * `\"lowered\"`: below it, and the entry now says so; `\"grown\"`: above it,\n * accepted with QD_ALLOW_BUDGET_GROWTH=1.\n */\n readonly change: \"written\" | \"unchanged\" | \"lowered\" | \"grown\";\n}\n\n/** A test app's counters, which `createTestApp` registers while the app runs. */\nexport interface BudgetSource {\n /** Identifies the tracked client the statements are counted on: apps sharing one count once. */\n readonly counter: object | undefined;\n /** Statements the app's tracked client has run so far; `undefined` without one. */\n statements(): number | undefined;\n /** Bytes the app's server has written to its sockets so far. */\n bytes(): number;\n}\n\nconst sources = new Set<BudgetSource>();\n\nlet recording: CallRecord[] | undefined;\n\n/** Registers a test app's counters; returns the function that removes them. */\nexport function addBudgetSource(source: BudgetSource): () => void {\n sources.add(source);\n return () => {\n sources.delete(source);\n };\n}\n\n/** Hands a completion record to the step being measured, if any: a test app's `onCall`. */\nexport function recordBudgetCall(record: CallRecord): void {\n recording?.push(record);\n}\n\ninterface Totals {\n readonly statements: number;\n readonly bytes: number;\n}\n\nfunction totalsOf(live: readonly BudgetSource[]): Totals {\n const counted = new Set<object>();\n let statements = 0;\n let bytes = 0;\n for (const source of live) {\n bytes += source.bytes();\n if (source.counter === undefined || counted.has(source.counter)) {\n continue;\n }\n counted.add(source.counter);\n statements += source.statements() ?? 0;\n }\n return { statements, bytes };\n}\n\n/** Socket replies are among the bytes the servers wrote; every other reply is added on its own. */\nfunction viaSocket(record: CallRecord): boolean {\n return record.transport === \"socket\" || record.transport === \"legacy\";\n}\n\nfunction callOf(record: CallRecord): BudgetCall {\n return {\n call: `${record.service}.${record.method}`,\n statements: record.sqlStatements ?? 0,\n bytes: record.bytes,\n ...(record.outcome === \"ok\" ? {} : { outcome: record.outcome }),\n };\n}\n\n/** Strings by UTF-16 code unit: the same order on every machine, whatever its locale. */\nfunction byCodeUnit(a: string, b: string): number {\n if (a === b) {\n return 0;\n }\n return a < b ? -1 : 1;\n}\n\n/** Calls in a stable order, so concurrent calls compare the same on every run. */\nexport function byCall(a: BudgetCall, b: BudgetCall): number {\n return (\n byCodeUnit(a.call, b.call) ||\n byCodeUnit(a.outcome ?? \"\", b.outcome ?? \"\") ||\n a.statements - b.statements ||\n a.bytes - b.bytes\n );\n}\n\nfunction budgetOf(before: Totals, after: Totals, records: readonly CallRecord[]): Budget {\n const replies = records\n .filter((record) => !viaSocket(record))\n .reduce((sum, record) => sum + record.bytes, 0);\n return {\n statements: after.statements - before.statements,\n bytes: after.bytes - before.bytes + replies,\n calls: records.map(callOf).sort(byCall),\n };\n}\n\n/** Waits for work the step's last reply left behind, such as an ambient flush. */\nfunction settle(): Promise<void> {\n return new Promise((resolve) => {\n setImmediate(resolve);\n });\n}\n\n/** Runs `run` and measures it. */\nasync function measure(run: () => unknown): Promise<Budget> {\n if (recording !== undefined) {\n throw new Error(\"expectBudget: another budget is being measured; measure one step at a time\");\n }\n const live = [...sources];\n if (live.length === 0) {\n throw new Error(\"expectBudget: no test app is running; start one with createTestApp first\");\n }\n const before = totalsOf(live);\n const records: CallRecord[] = [];\n recording = records;\n try {\n await run();\n await settle();\n } finally {\n recording = undefined;\n }\n return budgetOf(before, totalsOf(live), records);\n}\n\nconst EXPECT_GLOBAL = Symbol.for(\"expect-global\");\n\n/** The test runner's global `expect` (vitest's, or jest's), and the running test's file and name. */\nexport interface RunnerState {\n readonly runner: object | undefined;\n readonly testPath: string | undefined;\n readonly testName: string | undefined;\n}\n\nfunction nonEmpty(value: unknown): string | undefined {\n return typeof value === \"string\" && value.length > 0 ? value : undefined;\n}\n\n/** What the test runner's global `expect` says about the running test (`snapshotAccessMatrix` reads it too). */\nexport function runnerState(): RunnerState {\n const holder = globalThis as Record<PropertyKey, unknown>;\n for (const candidate of [holder[EXPECT_GLOBAL], holder.expect]) {\n const getState = (candidate as { readonly getState?: unknown } | undefined)?.getState;\n if (typeof getState === \"function\") {\n const state = (getState as () => unknown).call(candidate) as {\n readonly testPath?: unknown;\n readonly currentTestName?: unknown;\n };\n return {\n runner: candidate as object,\n testPath: nonEmpty(state.testPath),\n testName: nonEmpty(state.currentTestName),\n };\n }\n }\n return { runner: undefined, testPath: undefined, testName: undefined };\n}\n\n/** Per test runner, the steps measured so far: `budget file\\0name` to the test that measured it. */\nconst claimed = new WeakMap<object, Map<string, string>>();\nconst NO_RUNNER = {};\n\n/**\n * Refuses a step name another test of the same file used: two tests sharing\n * an entry would rewrite each other's budget. The same test measuring it\n * again (a retry) is allowed.\n */\nfunction claimName(path: string, name: string, state: RunnerState): void {\n const runner = state.runner ?? NO_RUNNER;\n const names = claimed.get(runner) ?? new Map<string, string>();\n claimed.set(runner, names);\n const key = `${path}\\u0000${name}`;\n const test = state.testName ?? \"\";\n const owner = names.get(key);\n if (owner !== undefined && owner !== test) {\n throw new TypeError(\n `expectBudget: two tests of ${shownPath(path)} name a step \"${name}\" (\"${owner}\" and \"${test}\"); give each step its own name`,\n );\n }\n names.set(key, test);\n}\n\n/** `path` relative to the working directory when it is inside it. */\nexport function shownPath(path: string): string {\n const near = relative(process.cwd(), path);\n return near.startsWith(\"..\") ? path : near;\n}\n\n/** The budget file of `testFile`: `__budgets__/<its name>.json` in its directory. */\nexport function budgetFileOf(testFile: string): string {\n return join(dirname(testFile), \"__budgets__\", `${basename(testFile)}.json`);\n}\n\n/** A budget file: `{ \"version\": 1, \"budgets\": { [name]: Budget } }`, names sorted. */\ninterface BudgetFile {\n readonly version: 1;\n readonly budgets: Readonly<Record<string, unknown>>;\n}\n\nfunction readBudgets(path: string): Readonly<Record<string, unknown>> {\n if (!existsSync(path)) {\n return {};\n }\n const parsed = JSON.parse(readFileSync(path, \"utf8\")) as Partial<BudgetFile> | null;\n if (parsed?.version !== 1 || typeof parsed.budgets !== \"object\" || parsed.budgets === null) {\n throw new Error(\n `expectBudget: ${path} is not a budget file ({ \"version\": 1, \"budgets\": {...} })`,\n );\n }\n return parsed.budgets;\n}\n\nfunction isCount(value: unknown): value is number {\n return typeof value === \"number\" && Number.isSafeInteger(value) && value >= 0;\n}\n\nfunction isCall(value: unknown): value is BudgetCall {\n const call = value as Partial<Record<keyof BudgetCall, unknown>> | null;\n return (\n typeof value === \"object\" &&\n call !== null &&\n typeof call.call === \"string\" &&\n isCount(call.statements) &&\n isCount(call.bytes)\n );\n}\n\nfunction isBudget(value: unknown): value is Budget {\n const budget = value as Partial<Record<keyof Budget, unknown>> | null;\n return (\n typeof value === \"object\" &&\n budget !== null &&\n isCount(budget.statements) &&\n isCount(budget.bytes) &&\n Array.isArray(budget.calls) &&\n (budget.calls as readonly unknown[]).every(isCall)\n );\n}\n\n/** The entry `name` of the budget file at `path`, or `undefined` when it has none. */\nfunction storedBudget(path: string, name: string): Budget | undefined {\n const budgets = readBudgets(path);\n if (!Object.hasOwn(budgets, name)) {\n return undefined;\n }\n const stored: unknown = budgets[name];\n if (!isBudget(stored)) {\n throw new Error(\n `expectBudget(\"${name}\"): its entry in ${path} is not a budget; delete it to measure it again`,\n );\n }\n return stored;\n}\n\nfunction writeBudget(path: string, name: string, budget: Budget): void {\n const budgets: Record<string, unknown> = { ...readBudgets(path), [name]: budget };\n const sorted = Object.fromEntries(\n Object.keys(budgets)\n .sort()\n .map((key) => [key, budgets[key]]),\n );\n mkdirSync(dirname(path), { recursive: true });\n writeFileSync(path, `${JSON.stringify({ version: 1, budgets: sorted }, null, 2)}\\n`);\n}\n\nfunction checkOptions(options: BudgetOptions): { readonly name: string; readonly path: string } {\n if (typeof options !== \"object\" || options === null) {\n throw new TypeError(\"expectBudget(run, { name }): pass the budget's name\");\n }\n const { name } = options;\n if (typeof name !== \"string\" || name.trim().length === 0) {\n throw new TypeError(\"expectBudget: name must be a non-empty string\");\n }\n const state = runnerState();\n const file = options.file ?? state.testPath;\n if (file === undefined) {\n throw new TypeError(\n \"expectBudget: no test file is running to put the budget beside; pass { file }\",\n );\n }\n const path = budgetFileOf(file);\n claimName(path, name, state);\n return { name, path };\n}\n\n/**\n * Runs `run`, one step of a test, and compares what it cost with its entry in\n * the budget file next to the test (`__budgets__/<test file>.json`): the\n * database statements and reply bytes of each call it made, and every\n * statement and socket byte of the step. Rejects when the step costs more\n * than its budget, naming each number that grew with its old and new values,\n * unless `QD_ALLOW_BUDGET_GROWTH` allows it (`1`, or a comma-separated list\n * of names); writes the entry when it is new, lower, or allowed to grow.\n * Under CI (`CI=1` or `CI=true`) a lower step fails as well (\"budget\n * changed; rerun locally to accept\"). Two tests of one file may not name a\n * step alike (`TypeError`). Measure one step at a time.\n *\n * A call's statements are its handler's, as its completion record counts\n * them: the access check before the handler is not among them, a kit's reads\n * to filter by access are, and a call that joined another's shared run\n * counts none. The step's statements count everything the apps' tracked\n * clients ran while `run` did, access checks and flushes included. Await,\n * in `run`, everything the step should cost: the replies and the frames it\n * is about.\n *\n * @example\n * await expectBudget(() => app.as(ada).taskService.list({ limit: 20 }), { name: \"list as owner\" });\n */\nexport async function expectBudget(\n run: () => unknown,\n options: BudgetOptions,\n): Promise<BudgetResult> {\n if (typeof run !== \"function\") {\n throw new TypeError(\"expectBudget: run must be a function that makes the step's calls\");\n }\n const { name, path } = checkOptions(options);\n const measured = await measure(run);\n const stored = storedBudget(path, name);\n if (stored === undefined) {\n writeBudget(path, name, measured);\n return { name, path, measured, change: \"written\" };\n }\n const comparison = compareBudgets(stored, measured);\n if (comparison.grew && !growthAllowed(name)) {\n throw new Error(\n `expectBudget(\"${name}\"): the step costs more than its budget (${shownPath(path)}):\\n` +\n `${describeChanges(comparison)}\\n` +\n `Make it cheaper, or set ${BUDGET_GROWTH_ENV}=1 (or ${BUDGET_GROWTH_ENV}=\"${name}\") to accept the new budget.`,\n );\n }\n if (!comparison.grew && !comparison.fell) {\n return { name, path, measured, change: \"unchanged\" };\n }\n if (!comparison.grew && underCi()) {\n throw new Error(\n `expectBudget(\"${name}\"): budget changed; rerun locally to accept (${shownPath(path)}):\\n` +\n `${describeChanges(comparison, \"fell\")}\\n` +\n \"The step costs less than its budget: run the tests without CI to write the lower budget, and commit it.\",\n );\n }\n writeBudget(path, name, mergeBudget(stored, measured, comparison));\n return { name, path, measured, change: comparison.grew ? \"grown\" : \"lowered\" };\n}\n","// How `expectBudget` compares a measured step with its stored budget\n// (`budget.ts`): statements must match exactly, bytes may move by up to\n// `BUDGET_BYTES_TOLERANCE` either way, and a step whose calls changed (other\n// methods, outcomes, or how many) is a change of its own that counts as\n// growth. A budget only moves down by itself: a number within the tolerance\n// keeps its stored value, so small byte drifts never rewrite the file.\n\n/** One call of a budgeted step. */\nexport interface BudgetCall {\n /** `\"taskService.list\"`. */\n readonly call: string;\n /** The statements its handler ran, from its completion record; 0 for a call that joined a shared run. */\n readonly statements: number;\n /** Its reply's size as its transport measured it (`app.as(...)`: the reply as JSON). */\n readonly bytes: number;\n /** How it failed; absent when it succeeded. */\n readonly outcome?: string;\n}\n\n/** What one step cost: an entry of a budget file. */\nexport interface Budget {\n /** Every statement the apps' tracked clients ran during the step. */\n readonly statements: number;\n /** Every byte the apps' servers wrote to sockets during the step, plus the in-process replies. */\n readonly bytes: number;\n /** The step's calls, sorted by method. */\n readonly calls: readonly BudgetCall[];\n}\n\n/** How far bytes may move, up or down, before it counts as a change: 5%. */\nexport const BUDGET_BYTES_TOLERANCE = 0.05;\n\ntype Direction = \"grew\" | \"fell\" | \"same\";\n\n/** One number of a budget, before and now. */\ninterface NumberChange {\n readonly label: string;\n readonly was: number;\n readonly now: number;\n readonly direction: Direction;\n readonly bytes: boolean;\n}\n\n/** A measured step against its budget. */\nexport interface Comparison {\n /** A number grew past the budget, or the step's calls changed. */\n readonly grew: boolean;\n /** A number fell below the budget. */\n readonly fell: boolean;\n /** The step's calls are other than the budget's: other methods, outcomes, or how many. */\n readonly callsChanged: boolean;\n readonly changes: readonly NumberChange[];\n readonly was: Budget;\n readonly now: Budget;\n}\n\nfunction directionOf(was: number, now: number, bytes: boolean): Direction {\n const tolerance = bytes ? BUDGET_BYTES_TOLERANCE : 0;\n if (now > was * (1 + tolerance)) {\n return \"grew\";\n }\n return now < was * (1 - tolerance) ? \"fell\" : \"same\";\n}\n\nfunction change(label: string, was: number, now: number, bytes: boolean): NumberChange {\n return { label, was, now, direction: directionOf(was, now, bytes), bytes };\n}\n\nfunction signature(call: BudgetCall): string {\n return call.outcome === undefined ? call.call : `${call.call} (${call.outcome})`;\n}\n\nfunction sameCalls(was: readonly BudgetCall[], now: readonly BudgetCall[]): boolean {\n return (\n was.length === now.length &&\n was.every((call, index) => {\n const other = now[index];\n return other !== undefined && signature(call) === signature(other);\n })\n );\n}\n\n/** Compares a measured step with its budget. */\nexport function compareBudgets(was: Budget, now: Budget): Comparison {\n const changes: NumberChange[] = [\n change(\"statements\", was.statements, now.statements, false),\n change(\"bytes\", was.bytes, now.bytes, true),\n ];\n const callsChanged = !sameCalls(was.calls, now.calls);\n if (!callsChanged) {\n now.calls.forEach((call, index) => {\n const stored = was.calls[index] ?? call;\n const label = `${call.call} (call ${index + 1})`;\n changes.push(\n change(`${label} statements`, stored.statements, call.statements, false),\n change(`${label} bytes`, stored.bytes, call.bytes, true),\n );\n });\n }\n return {\n grew: callsChanged || changes.some((each) => each.direction === \"grew\"),\n fell: changes.some((each) => each.direction === \"fell\"),\n callsChanged,\n changes,\n was,\n now,\n };\n}\n\nfunction describe(each: NumberChange): string {\n const line = ` ${each.label}: was ${each.was}, now ${each.now}`;\n if (!each.bytes || each.was === 0) {\n return line;\n }\n const percent = ((each.now - each.was) / each.was) * 100;\n return `${line} (${percent > 0 ? \"+\" : \"\"}${percent.toFixed(1)}%; bytes may move by ${BUDGET_BYTES_TOLERANCE * 100}%)`;\n}\n\n/**\n * The lines of a failure message: each number that moved `direction` (grew,\n * by default) with its old and new values, and for growth the changed calls.\n */\nexport function describeChanges(\n comparison: Comparison,\n direction: \"grew\" | \"fell\" = \"grew\",\n): string {\n const lines = comparison.changes.filter((each) => each.direction === direction).map(describe);\n if (direction === \"grew\" && comparison.callsChanged) {\n const list = (calls: readonly BudgetCall[]): string =>\n calls.length === 0 ? \"none\" : calls.map(signature).join(\", \");\n lines.push(` calls: was ${list(comparison.was.calls)}; now ${list(comparison.now.calls)}`);\n }\n return lines.join(\"\\n\");\n}\n\n/**\n * The budget to store after a comparison that changed something: the\n * measured step where its calls changed, else each number that moved past\n * the tolerance at its new value and every other number as it was.\n */\nexport function mergeBudget(was: Budget, now: Budget, comparison: Comparison): Budget {\n if (comparison.callsChanged) {\n return now;\n }\n const pick = (stored: number, measured: number, bytes: boolean): number =>\n directionOf(stored, measured, bytes) === \"same\" ? stored : measured;\n return {\n statements: pick(was.statements, now.statements, false),\n bytes: pick(was.bytes, now.bytes, true),\n calls: now.calls.map((call, index) => {\n const stored = was.calls[index] ?? call;\n return {\n ...call,\n statements: pick(stored.statements, call.statements, false),\n bytes: pick(stored.bytes, call.bytes, true),\n };\n }),\n };\n}\n","// What `createTestApp` adds to the server it boots, besides the frame\n// recorder (`frames.ts`): strict development warnings when asked, the\n// counters `expectBudget` measures a step with (`budget.ts`: the calls'\n// completion records, the tracked client's statements, the bytes written to\n// sockets), and an in-process caller that reports its replies' size.\n\nimport { consoleLogger, type Logger } from \"../contract/logger\";\nimport { utf8ByteLength } from \"../protocol/utf8\";\nimport { createCaller } from \"../server/caller\";\nimport { STRICT_WARNINGS } from \"../server/devWarnings\";\nimport type { CallRecord } from \"../server/pipeline/metrics\";\nimport { toCallReply, type DispatchRequest, type DispatchResult } from \"../server/pipeline/request\";\nimport { storageOf, type StorageAdapter } from \"../server/storage\";\nimport type { QuickdrawIo } from \"../server/transports/types\";\nimport { statementsIssued } from \"../server/uow/unitOfWork\";\nimport { addBudgetSource, recordBudgetCall } from \"./budget\";\n\n/** The test app's default logger: warnings and errors only. */\nexport const quietLogger: Logger = {\n debug: () => undefined,\n info: () => undefined,\n warn: (message, meta) => consoleLogger.warn(message, meta),\n error: (message, meta) => consoleLogger.error(message, meta),\n child: () => quietLogger,\n};\n\n/** The options of `createTestApp` this module reads. */\nexport interface InstrumentedOptions {\n readonly onCall?: (record: CallRecord) => void;\n /**\n * Under vitest or jest (`VITEST` or `JEST_WORKER_ID` set), throw every\n * development warning raised in this app's method calls (N+1 statements,\n * unbounded reads, oversized replies, nested writes) as a `DevWarningError`\n * where it is raised, so the test that caused it fails. Warnings outside\n * its calls, such as an ambient write while seeding, are logged; `close()`\n * ends it. Default `false`: warnings are logged once.\n */\n readonly strictWarnings?: boolean;\n}\n\n/** True under vitest or jest, where `strictWarnings` applies. */\nfunction underTestRunner(): boolean {\n return process.env.VITEST !== undefined || process.env.JEST_WORKER_ID !== undefined;\n}\n\n/**\n * `options` for `createServer`: `strictWarnings` turned into the dispatcher's\n * hidden strict flag, and an `onCall` that also hands every record to the\n * step `expectBudget` is measuring.\n */\nexport function instrumentOptions<O extends InstrumentedOptions>(\n options: O,\n): Omit<O, \"strictWarnings\"> {\n const { strictWarnings, onCall, ...rest } = options;\n return {\n ...rest,\n onCall: (record: CallRecord) => {\n recordBudgetCall(record);\n onCall?.(record);\n },\n [STRICT_WARNINGS]: strictWarnings === true && underTestRunner(),\n } as Omit<O, \"strictWarnings\">;\n}\n\nfunction sizeOf(data: unknown): number {\n if (typeof data === \"string\") {\n return utf8ByteLength(data);\n }\n return ArrayBuffer.isView(data) || data instanceof ArrayBuffer ? data.byteLength : 0;\n}\n\n/** What `meterServer` reads its counters from. */\nexport interface MeteredApp {\n readonly io: QuickdrawIo;\n readonly db?: unknown;\n readonly storage?: StorageAdapter;\n}\n\n/**\n * Counts the bytes of every message `app.io` writes to a socket (events and\n * acknowledgements, once per receiving socket) and registers them, with the\n * statements of the app's tracked client, for `expectBudget`. Returns the\n * function that unregisters them, for `close()`.\n */\nexport function meterServer(app: MeteredApp): () => void {\n let bytes = 0;\n app.io.use((socket, next) => {\n socket.conn.on(\n \"packetCreate\",\n (packet: { readonly type?: unknown; readonly data?: unknown }) => {\n if (packet.type === \"message\") {\n bytes += sizeOf(packet.data);\n }\n },\n );\n next();\n });\n const unitOfWork = (app.storage ?? storageOf(app.db))?.unitOfWork;\n return addBudgetSource({\n counter: unitOfWork,\n statements: () => (unitOfWork === undefined ? undefined : statementsIssued(unitOfWork)),\n bytes: () => bytes,\n });\n}\n\n/** A reply's size as the HTTP transport would send it: its JSON. */\nfunction replySize(result: DispatchResult): number | undefined {\n try {\n return utf8ByteLength(JSON.stringify(toCallReply(result)));\n } catch {\n return undefined;\n }\n}\n\n/**\n * An in-process caller acting as `principal`, through `call`, whose calls\n * report their reply's size (as JSON) in their completion records, as a\n * transport's do.\n */\nexport function measuredCaller(\n call: (request: DispatchRequest) => Promise<DispatchResult>,\n principal: Parameters<typeof createCaller>[1],\n): object {\n return createCaller(() => (request) => call({ ...request, respond: replySize }), principal);\n}\n","// Socket helpers for tests, ported from 4.1 (4.1 `src/server/testing.ts:135-180`).\n// 4.1's `emitWithAck` unwrapped the 4.x `{ success, data }` reply; this one\n// resolves with the acknowledgement as the server sent it, since a v5 reply\n// (`{ ok, d }`) and a 4.x one now both exist. For typed v5 calls use\n// `connect(principal).call` from `createTestApp`.\n\nimport { io, type Socket } from \"socket.io-client\";\nimport type { CallReply } from \"../protocol/envelope\";\nimport { fromWire } from \"../protocol/errors\";\nimport { PROTOCOL_VERSION, type HelloFrame } from \"../protocol/version\";\nimport { lazyMembers, type CallOptions } from \"../server/caller\";\nimport { QUICKDRAW_VERSION } from \"../version\";\n\n/** A Socket.IO client socket. */\nexport type ClientSocket = Socket;\n\n/**\n * Emits `event` with `payload` and resolves with the server's acknowledgement.\n * Without a payload none is sent (Socket.IO would send `undefined` as `null`).\n * Rejects when no acknowledgement arrives within `timeoutMs`.\n */\nexport function emitWithAck<Reply = unknown>(\n socket: Socket,\n event: string,\n payload?: unknown,\n timeoutMs = 5000,\n): Promise<Reply> {\n return new Promise((resolve, reject) => {\n const timeout = setTimeout(() => {\n reject(new Error(`Timeout waiting for ${event}`));\n }, timeoutMs);\n const ack = (reply: Reply): void => {\n clearTimeout(timeout);\n resolve(reply);\n };\n if (payload === undefined) {\n socket.emit(event, ack);\n } else {\n socket.emit(event, payload, ack);\n }\n });\n}\n\n/** Resolves with the payload of the next `event` the socket receives; rejects after `timeoutMs`. */\nexport function waitForEvent<T = unknown>(\n socket: Socket,\n event: string,\n timeoutMs = 5000,\n): Promise<T> {\n return new Promise((resolve, reject) => {\n let timeout: ReturnType<typeof setTimeout> | undefined;\n const handler = (data: T): void => {\n clearTimeout(timeout);\n resolve(data);\n };\n timeout = setTimeout(() => {\n socket.off(event, handler);\n reject(new Error(`Timeout waiting for event ${event}`));\n }, timeoutMs);\n socket.once(event, handler);\n });\n}\n\ninterface Envelope {\n readonly id: number;\n readonly s: string;\n readonly m: string;\n readonly i?: unknown;\n}\n\nasync function callOverSocket(\n socket: Socket,\n envelope: Envelope,\n signal: AbortSignal | undefined,\n timeoutMs: number,\n): Promise<unknown> {\n const cancel = (): void => {\n socket.emit(\"qd:cancel\", { id: envelope.id });\n };\n const pending = emitWithAck<CallReply>(socket, \"qd:call\", envelope, timeoutMs);\n if (signal?.aborted === true) {\n cancel();\n } else {\n signal?.addEventListener(\"abort\", cancel, { once: true });\n }\n try {\n const reply = await pending;\n if (!reply.ok) {\n throw fromWire(reply.e);\n }\n return reply.nm === true ? undefined : reply.d;\n } finally {\n signal?.removeEventListener(\"abort\", cancel);\n }\n}\n\n/**\n * A caller like `dispatcher.caller(principal)` whose calls travel over\n * `socket` as `qd:call` frames: `call.taskService.get(input)` resolves with\n * the data or rejects with the call's `QuickdrawError`. An aborted `signal`\n * sends `qd:cancel`.\n */\nexport function socketCaller(socket: Socket, timeoutMs: number): object {\n let nextId = 0;\n return lazyMembers((service) =>\n lazyMembers((method) => (input?: unknown, options?: CallOptions) => {\n const id = nextId;\n nextId += 1;\n const envelope =\n input === undefined\n ? { id, s: service, m: method }\n : { id, s: service, m: method, i: input };\n return callOverSocket(socket, envelope, options?.signal, timeoutMs);\n }),\n );\n}\n\n/** Connects and resolves with the server's hello, or rejects with the `connect_error`. */\nfunction handshake(socket: Socket, timeoutMs: number): Promise<HelloFrame> {\n return new Promise((resolve, reject) => {\n const finish = (error: Error | undefined, frame?: HelloFrame): void => {\n clearTimeout(timer);\n socket.off(\"qd:hello\", onHello);\n socket.off(\"connect_error\", onError);\n if (frame === undefined) {\n reject(error);\n } else {\n resolve(frame);\n }\n };\n const onHello = (frame: HelloFrame): void => finish(undefined, frame);\n const onError = (error: Error): void => finish(error);\n const timer = setTimeout(() => {\n finish(new Error(`No qd:hello within ${timeoutMs} ms`));\n }, timeoutMs);\n socket.once(\"qd:hello\", onHello);\n socket.once(\"connect_error\", onError);\n socket.connect();\n });\n}\n\n/**\n * Opens a v5 socket to `url` that never reconnects, with `auth` plus the v5\n * handshake (`auth.qd`), and resolves once the server said hello. A refused\n * connection rejects with the `connect_error` and leaves the socket closed.\n */\nexport async function connectV5(\n url: string,\n auth: Readonly<Record<string, unknown>>,\n timeoutMs: number,\n): Promise<{ readonly socket: Socket; readonly hello: HelloFrame }> {\n const socket = io(url, {\n forceNew: true,\n reconnection: false,\n autoConnect: false,\n transports: [\"websocket\"],\n auth: { ...auth, qd: { protocol: PROTOCOL_VERSION, client: QUICKDRAW_VERSION } },\n });\n try {\n return { socket, hello: await handshake(socket, timeoutMs) };\n } catch (error) {\n socket.disconnect();\n throw error;\n }\n}\n","// `createTestApp` (RFC 0003 section 13): the app's real server on a free\n// port, with an `authenticate` that trusts the principal a test connects as\n// (its grants loaded by `auth.loadServiceAccess` when it carries none, for\n// sockets and `as(principal)` alike),\n// and a recorder of every frame the server sends (`frames.ts`). Its\n// dispatcher becomes the current one of the `initQuickdraw` instance that\n// defined the services, so `qd.stream`, `qd.presence` and `qd.run` reach\n// it. While it runs, `expectBudget` measures it (`instrument.ts`), and\n// `strictWarnings` makes the development warnings of its method calls\n// throw; `close()` ends both. It replaces 4.1's\n// `createTestServer` and `connectAsUser` (4.1 `src/server/testing.ts:62-130`),\n// which took a fixed port counter and authenticated by a bare user id.\n\nimport type { AddressInfo } from \"node:net\";\nimport type { HelloFrame } from \"../protocol/version\";\nimport type { Caller } from \"../server/caller\";\nimport { createServer, type QuickdrawServer, type ServerOptions } from \"../server/createServer\";\nimport type { ContractOfServices, PrincipalOfServices } from \"../server/dispatcher\";\nimport { runtimeOf, type AnyService } from \"../server/service\";\nimport { isPrincipal, type ServerAuth } from \"../server/transports/auth\";\nimport { recordFrames, type FrameRecorder } from \"./frames\";\nimport {\n instrumentOptions,\n measuredCaller,\n meterServer,\n quietLogger,\n type InstrumentedOptions,\n} from \"./instrument\";\nimport { connectV5, socketCaller, type ClientSocket } from \"./socket\";\n\n/**\n * Makes `dispatcher` the current one of every `initQuickdraw` instance that\n * defined one of `services`, as that instance's own `createServer` would:\n * `qd.stream(...).push`, `qd.presence`, `qd.run` and `qd.caller` then go\n * through the test app. The last app created wins.\n */\nfunction adoptDispatcher(services: readonly AnyService[], dispatcher: object): void {\n const runtimes = new Set(services.map((service) => runtimeOf(service)));\n for (const runtime of runtimes) {\n runtime?.adopt?.(dispatcher);\n }\n}\n\ntype Call = QuickdrawServer[\"dispatcher\"][\"call\"];\n\n/**\n * `call`, with the grants `load` gives a principal that carries none, at\n * each call: what `createServer`'s principal resolver does for a socket's\n * handshake and an HTTP call.\n */\nfunction withGrants(call: Call, load: ServerAuth[\"loadServiceAccess\"]): Call {\n if (load === undefined) {\n return call;\n }\n return async (request) => {\n const { principal } = request;\n if (\n principal === null ||\n (principal.serviceAccess !== undefined && principal.serviceAccess !== null)\n ) {\n return await call(request);\n }\n const serviceAccess = (await load(principal.userId)) ?? {};\n return await call({ ...request, principal: { ...principal, serviceAccess } });\n };\n}\n\n/**\n * Options of {@link createTestApp}: the server's, and `strictWarnings`.\n * Without `auth.authenticate` a socket acts as the `principal` it connects\n * with; the rate limiter is off unless `rateLimit` is given; the logger\n * prints warnings and errors only.\n */\nexport type TestAppOptions<S extends readonly AnyService[]> = ServerOptions<S> &\n Pick<InstrumentedOptions, \"strictWarnings\">;\n\n/** A socket connected to the test app. */\nexport interface TestConnection<S extends readonly AnyService[] = readonly AnyService[]> {\n /** The raw Socket.IO client socket, for frames `call` does not cover. */\n readonly socket: ClientSocket;\n /** The server's `qd:hello`. */\n readonly hello: HelloFrame;\n /**\n * Calls methods over this socket, typed like `as(principal)`:\n * `call.taskService.get(input)` resolves with the data or rejects with the\n * call's `QuickdrawError`. Aborting `options.signal` sends `qd:cancel`.\n */\n readonly call: Caller<ContractOfServices<S>>;\n /** Disconnects the socket. */\n close(): void;\n}\n\n/** The running test app. */\nexport interface TestApp<S extends readonly AnyService[] = readonly AnyService[]> {\n /** The server's URL, `http://127.0.0.1:{port}`. */\n readonly url: string;\n readonly server: QuickdrawServer<S>;\n /**\n * Every frame the server sent any socket since the app started (or since\n * `frames.clear()`), with the socket, its user and the time:\n * `app.frames({ event: \"qd:e\", userId })`, `app.frames.waitFor(match)`.\n */\n readonly frames: FrameRecorder;\n /**\n * A typed in-process caller acting as `principal` (`null` for anonymous).\n * Its calls' completion records carry their reply's size as JSON, as an\n * HTTP call's do, so `expectBudget` sees their bytes. A principal that\n * carries no `serviceAccess` gets its grants from the server's\n * `auth.loadServiceAccess` at every call, as an HTTP call's and a\n * socket's principal do, so in-process and socket calls authorize alike;\n * one that carries grants (even `{}`) keeps them.\n */\n as(principal: PrincipalOfServices<S> | null): Caller<ContractOfServices<S>>;\n /**\n * Connects a real v5 socket acting as `principal` (`null` for anonymous);\n * resolves once the server said hello, rejects when it refused the socket.\n */\n connect(principal: PrincipalOfServices<S> | null): Promise<TestConnection<S>>;\n /**\n * Disconnects every socket `connect` opened, then closes the server; the\n * tracked client goes back to the dispatcher attached before the app's.\n */\n close(): Promise<void>;\n}\n\nconst TIMEOUT_MS = 5000;\n\n/**\n * Boots the app's services on `createServer`, listening on a free port of\n * 127.0.0.1, for tests that call them in process or over real sockets.\n * `strictWarnings: true` (under vitest or jest) makes every development\n * warning raised in the app's method calls throw where it is raised, so a\n * test that causes one fails; warnings outside its calls (seeding through\n * the tracked client, say) are logged, and nothing is strict after `close()`.\n *\n * @example\n * const app = await createTestApp({ services: [taskService], db: testPrisma });\n * await app.as(alice).taskService.rename({ id, title });\n * const { call } = await app.connect(alice);\n * await call.taskService.get({ id });\n * await app.frames.waitFor({ event: \"qd:e\", userId: alice.userId });\n * await app.close();\n */\nexport async function createTestApp<const S extends readonly AnyService[]>(\n options: TestAppOptions<S>,\n): Promise<TestApp<S>> {\n type P = PrincipalOfServices<S>;\n // The spread keeps `services` and `db` as given; TypeScript cannot see that\n // through the conditional `db` member of the options.\n const server = createServer<S>({\n ...instrumentOptions(options),\n logger: options.logger ?? quietLogger,\n rateLimit: options.rateLimit ?? false,\n auth: {\n authenticate: ({ auth }) => (isPrincipal(auth.principal) ? (auth.principal as P) : null),\n ...options.auth,\n },\n } as ServerOptions<S>);\n adoptDispatcher(options.services, server.dispatcher);\n const frames = recordFrames(server.io);\n const unmeter = meterServer({ io: server.io, db: options.db, storage: options.storage });\n await new Promise<void>((resolve) => {\n server.httpServer.listen(0, \"127.0.0.1\", resolve);\n });\n const { port } = server.httpServer.address() as AddressInfo;\n const url = `http://127.0.0.1:${port}`;\n const sockets = new Set<ClientSocket>();\n\n return {\n url,\n server,\n frames,\n as: (principal) =>\n measuredCaller(\n withGrants(server.dispatcher.call, options.auth?.loadServiceAccess),\n principal,\n ) as Caller<ContractOfServices<S>>,\n async connect(principal) {\n const { socket, hello } = await connectV5(\n url,\n principal === null ? {} : { principal },\n TIMEOUT_MS,\n );\n sockets.add(socket);\n return {\n socket,\n hello,\n call: socketCaller(socket, TIMEOUT_MS) as Caller<ContractOfServices<S>>,\n close: () => {\n sockets.delete(socket);\n socket.disconnect();\n },\n };\n },\n async close() {\n unmeter();\n for (const socket of sockets) {\n socket.disconnect();\n }\n sockets.clear();\n await server.close();\n },\n };\n}\n","// A flush sink that keeps what it receives (RFC 0003 section 5.3), for tests\n// that assert which writes a method, a `qd.run` block or a job made:\n//\n// const sink = createRecordingSink();\n// const dispatcher = createDispatcher({ services, db: trackPrisma(prisma), flushSink: sink });\n// await dispatcher.caller(alice).taskService.rename({ id, title });\n// expect(sink.writes()).toEqual([expect.objectContaining({ model: \"task\", id, op: \"update\" })]);\n\nimport type { FlushInfo, FlushSink } from \"../server/uow/flushSink\";\nimport type { WriteRecord } from \"../server/uow/types\";\n\n/** One flush a recording sink received. */\nexport interface RecordedFlush {\n readonly writes: readonly WriteRecord[];\n readonly info: FlushInfo;\n}\n\n/** A flush sink that records every flush, from {@link createRecordingSink}. */\nexport interface RecordingSink extends FlushSink {\n /** Every flush received so far, oldest first. */\n readonly flushes: readonly RecordedFlush[];\n /** Every write received so far, in flush order. */\n writes(): WriteRecord[];\n /** Resolves with the next flush, or with the oldest one not yet taken by `next`. */\n next(): Promise<RecordedFlush>;\n /** Forgets every flush received so far. */\n clear(): void;\n}\n\n/** Creates a {@link RecordingSink}. */\nexport function createRecordingSink(): RecordingSink {\n const flushes: RecordedFlush[] = [];\n const waiting: ((flush: RecordedFlush) => void)[] = [];\n let taken = 0;\n return {\n flushes,\n flush(writes: readonly WriteRecord[], info: FlushInfo): Promise<void> {\n const flush = { writes: [...writes], info };\n flushes.push(flush);\n const resolve = waiting.shift();\n if (resolve === undefined) {\n return Promise.resolve();\n }\n taken = flushes.length;\n resolve(flush);\n return Promise.resolve();\n },\n writes: () => flushes.flatMap((flush) => flush.writes),\n next(): Promise<RecordedFlush> {\n const flush = flushes[taken];\n if (flush !== undefined) {\n taken += 1;\n return Promise.resolve(flush);\n }\n return new Promise((resolve) => {\n waiting.push(resolve);\n });\n },\n clear(): void {\n flushes.length = 0;\n taken = 0;\n },\n };\n}\n","// The inputs `snapshotAccessMatrix` makes for a method the app gives no input\n// for (`accessSnapshot.ts`): the row the cell is about, put where the\n// method's access form reads it, and the input's other required values made\n// from its Standard JSON Schema (Zod 4.2 or later), each as small as the\n// schema allows. An input is usable only when it passes the method's input\n// schema and, for an `entry` or `scope` form, names the cell's row where the\n// form looks for it: the form's own id selector decides, so a function `id`\n// is followed too. A keyless `todoSchema()` accepts `{}`, and an `entry` form\n// then refuses the missing id with `FORBIDDEN` for everyone: a cell that\n// looks plausible and means nothing. A cell without a usable input is never\n// called.\n\nimport { hasJsonSchema, validate } from \"../contract/standardSchema\";\nimport { accessIds, isCustomAccess } from \"../server/access/forms\";\nimport type { AccessForm, EntryAccess, ScopeAccess } from \"../server/access/types\";\nimport { inputKeys } from \"../server/emit/projection\";\nimport type { AnyService, ServiceMethod } from \"../server/service\";\n\ntype Json = Readonly<Record<string, unknown>>;\n\nfunction isRecord(value: unknown): value is Json {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\n/** How deep a schema is followed: past it, a value is left out (a recursive schema). */\nconst MAX_DEPTH = 12;\n\n/** Values JSON Schema has no form for become `{}` (any value), as the rowless check reads them (Zod 4). */\nconst UNREPRESENTABLE_AS_ANY = Object.freeze({ unrepresentable: \"any\" });\n\n/** A string of each string format the schema libraries write, valid for it. */\nconst FORMATS: Readonly<Record<string, string>> = Object.freeze({\n email: \"snapshot@example.com\",\n \"idn-email\": \"snapshot@example.com\",\n uri: \"https://example.com/\",\n url: \"https://example.com/\",\n \"uri-reference\": \"https://example.com/\",\n hostname: \"example.com\",\n uuid: \"00000000-0000-4000-8000-000000000000\",\n guid: \"00000000-0000-4000-8000-000000000000\",\n \"date-time\": \"2026-01-01T00:00:00.000Z\",\n date: \"2026-01-01\",\n time: \"00:00:00\",\n duration: \"P1D\",\n ipv4: \"127.0.0.1\",\n ipv6: \"::1\",\n cuid: \"cjld2cjxh0000qzrmn831i7rn\",\n cuid2: \"tz4a98xxat96iws9zmbrgj3a\",\n ulid: \"01ARZ3NDEKTSV4RRFFQ69G5FAV\",\n nanoid: \"V1StGXR8_Z5jdHi6B-myT\",\n e164: \"+15555550100\",\n});\n\n/** What a string with a `pattern` is tried with when its format's string does not match it. */\nconst PATTERN_CANDIDATES: readonly string[] = [\"x\", ...new Set(Object.values(FORMATS))];\n\n/** The node a JSON Schema node stands for: the one its `$ref` names in `root`, or itself. */\nfunction referenced(node: Json, root: Json): Json | undefined {\n const ref = node.$ref;\n if (typeof ref !== \"string\") {\n return node;\n }\n if (ref === \"#\") {\n return root;\n }\n const match = /^#\\/(definitions|\\$defs)\\/(.+)$/.exec(ref);\n const defs = match === null ? undefined : root[match[1] ?? \"\"];\n const target = isRecord(defs) ? defs[match?.[2] ?? \"\"] : undefined;\n return isRecord(target) ? target : undefined;\n}\n\n/** The node's type: `\"null\"` when a list of types allows it, `\"object\"` for bare properties. */\nfunction typeOf(node: Json): string | undefined {\n const { type } = node;\n if (typeof type === \"string\") {\n return type;\n }\n if (Array.isArray(type)) {\n const types = type.filter((each): each is string => typeof each === \"string\");\n return types.includes(\"null\") ? \"null\" : types[0];\n }\n return isRecord(node.properties) ? \"object\" : undefined;\n}\n\nfunction isNullBranch(node: unknown): boolean {\n return isRecord(node) && typeOf(node) === \"null\";\n}\n\n/** A test of a string against the node's `pattern`; `undefined` without one (or one this engine cannot read). */\nfunction patternOf(node: Json): ((value: string) => boolean) | undefined {\n if (typeof node.pattern !== \"string\") {\n return undefined;\n }\n try {\n const regex = new RegExp(node.pattern, \"u\");\n return (value) => regex.test(value);\n } catch {\n return undefined;\n }\n}\n\nfunction sampleString(node: Json): string {\n const format = typeof node.format === \"string\" ? FORMATS[node.format] : undefined;\n const matches = patternOf(node);\n let value = format ?? \"x\";\n if (matches !== undefined && !matches(value)) {\n value = PATTERN_CANDIDATES.find(matches) ?? value;\n }\n const min = typeof node.minLength === \"number\" ? node.minLength : 0;\n if (value.length < min) {\n value += \"x\".repeat(min - value.length);\n }\n return typeof node.maxLength === \"number\" ? value.slice(0, node.maxLength) : value;\n}\n\n/** The number nearest 0 within the node's bounds, on its `multipleOf`. */\nfunction sampleNumber(node: Json, integer: boolean): number {\n const { minimum, maximum, exclusiveMinimum, exclusiveMaximum, multipleOf } = node;\n let value = 0;\n if (typeof minimum === \"number\" && value < minimum) {\n value = integer ? Math.ceil(minimum) : minimum;\n }\n if (typeof exclusiveMinimum === \"number\" && value <= exclusiveMinimum) {\n value = Math.floor(exclusiveMinimum) + 1;\n }\n if (typeof maximum === \"number\" && value > maximum) {\n value = integer ? Math.floor(maximum) : maximum;\n }\n if (typeof exclusiveMaximum === \"number\" && value >= exclusiveMaximum) {\n value = Math.ceil(exclusiveMaximum) - 1;\n }\n if (typeof multipleOf === \"number\" && multipleOf > 0 && value % multipleOf !== 0) {\n value = Math.ceil(value / multipleOf) * multipleOf;\n }\n return value;\n}\n\n/** Every required property, each as small as it may be; one that allows anything is `null`. */\nfunction sampleObject(node: Json, root: Json, depth: number): Record<string, unknown> {\n const properties = isRecord(node.properties) ? node.properties : {};\n const required = Array.isArray(node.required) ? node.required : [];\n const value: Record<string, unknown> = {};\n for (const key of required) {\n if (typeof key === \"string\") {\n value[key] = sample(properties[key], root, depth + 1) ?? null;\n }\n }\n return value;\n}\n\n/** A tuple's items, or the fewest items a list allows. */\nfunction sampleArray(node: Json, root: Json, depth: number): unknown[] {\n let tuple: readonly unknown[] | undefined;\n if (Array.isArray(node.prefixItems)) {\n tuple = node.prefixItems;\n } else if (Array.isArray(node.items)) {\n tuple = node.items;\n }\n if (tuple !== undefined) {\n return tuple.map((item) => sample(item, root, depth + 1) ?? null);\n }\n const length = typeof node.minItems === \"number\" ? node.minItems : 0;\n return Array.from({ length }, () => sample(node.items, root, depth + 1) ?? null);\n}\n\n/** A value of each part of an `allOf`, merged when they are objects. */\nfunction sampleAll(parts: readonly unknown[], root: Json, depth: number): unknown {\n const values = parts.map((part) => sample(part, root, depth + 1));\n if (values.every((value) => isRecord(value) || value === undefined)) {\n return Object.assign({}, ...values) as unknown;\n }\n return values.find((value) => value !== undefined);\n}\n\n/** A value of the node's type; `undefined` for a node of no type, which allows anything. */\nfunction sampleType(node: Json, root: Json, depth: number): unknown {\n switch (typeOf(node)) {\n case \"object\":\n return sampleObject(node, root, depth);\n case \"array\":\n return sampleArray(node, root, depth);\n case \"string\":\n return sampleString(node);\n case \"integer\":\n return sampleNumber(node, true);\n case \"number\":\n return sampleNumber(node, false);\n case \"boolean\":\n return false;\n case \"null\":\n return null;\n default:\n return undefined;\n }\n}\n\n/**\n * The smallest value JSON Schema `node` allows: its `const`, the first of its\n * `enum`, `null` where a union allows it (else its first branch), the parts\n * of an `allOf` merged, or a value of its type (`sampleType`). `undefined`\n * for a schema that allows anything: at the top level, the input of a method\n * that takes none.\n */\nfunction sample(node: unknown, root: Json, depth: number): unknown {\n const target = isRecord(node) && depth <= MAX_DEPTH ? referenced(node, root) : undefined;\n if (target === undefined) {\n return undefined;\n }\n if (Object.hasOwn(target, \"const\")) {\n return target.const;\n }\n if (Array.isArray(target.enum) && target.enum.length > 0) {\n return target.enum[0] as unknown;\n }\n const branches = Array.isArray(target.anyOf) ? target.anyOf : target.oneOf;\n if (Array.isArray(branches) && branches.length > 0) {\n return branches.some(isNullBranch) ? null : sample(branches[0], root, depth + 1);\n }\n if (Array.isArray(target.allOf) && target.allOf.length > 0) {\n return sampleAll(target.allOf, root, depth);\n }\n return sampleType(target, root, depth);\n}\n\n/** A method's input as its JSON Schema describes it, read once per method. */\ninterface InputShape {\n /** The smallest input the schema allows; `undefined` without JSON Schema (a Zod 3 schema). */\n readonly skeleton: unknown;\n /** The JSON Schema document, for its `$ref`s. */\n readonly root: Json;\n /** The top-level properties, when the input is one object. */\n readonly properties: Json | undefined;\n /** True when the input itself is a string: a bare id. */\n readonly isString: boolean;\n}\n\nconst shapes = new WeakMap<ServiceMethod, InputShape>();\n\n/** The input's JSON Schema, or `undefined` when its schema cannot write one. */\nfunction jsonSchemaOf(method: ServiceMethod): Json | undefined {\n if (!hasJsonSchema(method.input)) {\n return undefined;\n }\n try {\n const json = method.input[\"~standard\"].jsonSchema.input({\n target: \"draft-07\",\n libraryOptions: UNREPRESENTABLE_AS_ANY,\n });\n return isRecord(json) ? json : undefined;\n } catch {\n return undefined;\n }\n}\n\nfunction shapeOf(method: ServiceMethod): InputShape {\n const known = shapes.get(method);\n if (known !== undefined) {\n return known;\n }\n const root = jsonSchemaOf(method);\n const described = root === undefined ? undefined : referenced(root, root);\n const shape: InputShape = {\n skeleton: root === undefined ? undefined : sample(root, root, 0),\n root: root ?? {},\n properties: isRecord(described?.properties) ? described.properties : undefined,\n isString: described !== undefined && typeOf(described) === \"string\",\n };\n shapes.set(method, shape);\n return shape;\n}\n\n/** The `entry` or `scope` part of a form, which reads a row id from the input; `undefined` for any other form. */\nexport function rowForm(form: AccessForm): EntryAccess | ScopeAccess | undefined {\n if (typeof form !== \"object\" || isCustomAccess(form)) {\n return undefined;\n }\n return form.entry === undefined && form.scope === undefined ? undefined : form;\n}\n\n/**\n * The service whose row a method's cells are about: the method's own for an\n * `entry` form, the `of` contract's for a `scope` form, and for any other\n * form its own when the input has a top-level `id` (a `rowless` method, a\n * `custom` check); `undefined` for a method about no row.\n */\nexport function rowServiceOf(service: AnyService, method: ServiceMethod): string | undefined {\n const form = rowForm(method.access);\n if (form?.scope !== undefined) {\n return form.of.name;\n }\n if (form !== undefined) {\n return service.name;\n }\n return inputKeys(method.input)?.includes(\"id\") === true ? service.name : undefined;\n}\n\n/** True when `node` may hold a row id: a string, a list, or a value it does not describe. */\nfunction mayHoldId(node: unknown): boolean {\n if (!isRecord(node)) {\n return true;\n }\n const type = typeOf(node);\n return type === undefined || type === \"string\" || type === \"array\" || type === \"null\";\n}\n\n/** The rank of a key a function selector may read the row from: `id` first, then `...Id` and `...Ids`. */\nfunction keyRank(key: string): number {\n if (key === \"id\" || key === \"ids\") {\n return 0;\n }\n return /Ids?$/.test(key) ? 1 : 2;\n}\n\n/** The input keys a function selector may read the row from, most likely first. */\nfunction selectorKeys(shape: InputShape): readonly string[] {\n const { properties } = shape;\n if (properties === undefined) {\n return shape.isString ? [] : [\"id\"];\n }\n return Object.keys(properties)\n .filter((key) => mayHoldId(properties[key]))\n .sort((a, b) => keyRank(a) - keyRank(b));\n}\n\n/** The row's id and a list of it, the list first when the key's schema is an array. */\nfunction idValues(shape: InputShape, key: string, row: string): readonly unknown[] {\n const node = shape.properties?.[key];\n const target = isRecord(node) ? referenced(node, shape.root) : undefined;\n return target !== undefined && typeOf(target) === \"array\" ? [[row], row] : [row, [row]];\n}\n\n/** The keys a cell's row may go at: where the form reads it, or `id` for a form that reads none. */\nfunction rowKeys(\n form: EntryAccess | ScopeAccess | undefined,\n shape: InputShape,\n): readonly string[] {\n if (form === undefined) {\n return [\"id\"];\n }\n if (typeof form.id === \"function\") {\n return selectorKeys(shape);\n }\n return [form.id ?? \"id\"];\n}\n\n/**\n * The inputs a cell tries, in order: the row put at each key it may go at\n * (for a form that reads no row, at the input's `id`), or the skeleton alone\n * for a cell about no row.\n */\nfunction candidates(method: ServiceMethod, row: string | undefined): readonly unknown[] {\n const shape = shapeOf(method);\n const form = rowForm(method.access);\n const hasId = form !== undefined || inputKeys(method.input)?.includes(\"id\") === true;\n if (row === undefined || !hasId) {\n return [shape.skeleton];\n }\n const base = isRecord(shape.skeleton) ? shape.skeleton : {};\n const placed = rowKeys(form, shape).flatMap((key) =>\n idValues(shape, key, row).map((value) => ({ ...base, [key]: value })),\n );\n const bare = typeof form?.id === \"function\" && (shape.isString || shape.properties === undefined);\n return bare ? [...placed, row] : placed;\n}\n\n/** True when `input` passes the method's input schema. */\nexport async function isValidInput(method: ServiceMethod, input: unknown): Promise<boolean> {\n const result = await validate(method.input, input);\n return result.issues === undefined;\n}\n\n/** True when the form reads `row` from the parsed input, as the access check will. */\nfunction namesRow(form: EntryAccess | ScopeAccess, parsed: unknown, row: string): boolean {\n try {\n return accessIds(form, parsed).includes(row);\n } catch {\n return false;\n }\n}\n\n/**\n * The input a cell about `row` calls `method` with, made from the method's\n * input schema: the first candidate that passes the schema and, for an\n * `entry` or `scope` form, names `row` where the form reads it. `undefined`\n * when none does: the cell is inconclusive and never called.\n */\nexport async function generatedInput(\n method: ServiceMethod,\n row: string | undefined,\n): Promise<{ readonly input: unknown } | undefined> {\n const form = rowForm(method.access);\n for (const input of candidates(method, row)) {\n const result = await validate(method.input, input);\n if (result.issues !== undefined) {\n continue;\n }\n if (form === undefined || (row !== undefined && namesRow(form, result.value, row))) {\n return { input };\n }\n }\n return undefined;\n}\n","// The access snapshot file (`accessSnapshot.ts`): `__access__/<test file>.json`\n// beside the test, `{ version: 1, principals, methods, subscriptions,\n// collections, excluded }` with every key sorted, so a change to who may\n// call what shows in a pull request as the lines that changed. What a run\n// does with it:\n//\n// - no file: it is written; under CI (`CI=1` or `CI=true`) that fails\n// instead, because a snapshot that writes itself pins nothing;\n// - a cell whose outcome changed, or a principal whose kind did: fails,\n// naming each, until QD_UPDATE_ACCESS_SNAPSHOT=1 (or `true`) rewrites the\n// file;\n// - cells added or removed only (a new method, principal or exclusion):\n// written locally, a failure under CI.\n//\n// QD_UPDATE_ACCESS_SNAPSHOT under CI fails: CI only compares. A budget may\n// write itself under CI (`budget.ts`); an access snapshot never does.\n\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { basename, dirname, join } from \"node:path\";\nimport {\n ACCESS_SECTIONS,\n compareAccessSnapshots,\n describeDifferences,\n describeReshape,\n hasDifferences,\n isReshaped,\n type AccessComparison,\n type AccessSnapshot,\n} from \"./accessSnapshotCompare\";\nimport { runnerState, shownPath, underCi, type RunnerState } from \"./budget\";\n\n/** The environment variable that rewrites access snapshots: `QD_UPDATE_ACCESS_SNAPSHOT=1` (or `true`). */\nexport const ACCESS_SNAPSHOT_ENV = \"QD_UPDATE_ACCESS_SNAPSHOT\";\n\n/** Whether {@link ACCESS_SNAPSHOT_ENV} asks to rewrite the snapshots: `1` or `true`. */\nexport function updateRequested(value = process.env[ACCESS_SNAPSHOT_ENV]): boolean {\n return value === \"1\" || value === \"true\";\n}\n\n/** What a run did with the snapshot file. */\nexport type AccessSnapshotChange = \"written\" | \"unchanged\" | \"updated\";\n\n/** The access snapshot file of `testFile`: `__access__/<its name>.json` in its directory. */\nexport function accessSnapshotFileOf(testFile: string): string {\n return join(dirname(testFile), \"__access__\", `${basename(testFile)}.json`);\n}\n\n/** Per runner, the snapshot files taken so far: path to the test that took it. */\nconst claimed = new WeakMap<object, Map<string, string>>();\nconst NO_RUNNER = {};\n\n/** Refuses a second test of one file taking a snapshot: they would rewrite each other's. A retry is allowed. */\nfunction claimFile(path: string, state: RunnerState): void {\n const runner = state.runner ?? NO_RUNNER;\n const files = claimed.get(runner) ?? new Map<string, string>();\n claimed.set(runner, files);\n const test = state.testName ?? \"\";\n const owner = files.get(path);\n if (owner !== undefined && owner !== test) {\n throw new TypeError(\n `snapshotAccessMatrix: two tests take an access snapshot into ${shownPath(path)} (\"${owner}\" and \"${test}\"); take one snapshot per test file (one test file per service, or pass { file })`,\n );\n }\n files.set(path, test);\n}\n\n/**\n * The snapshot file of a run: beside `file`, or beside the running test's\n * file (from the test runner). Throws a `TypeError` when there is neither,\n * and when another test of the file took a snapshot into it already.\n */\nexport function snapshotPathOf(file: string | undefined): string {\n const state = runnerState();\n const testFile = file ?? state.testPath;\n if (testFile === undefined) {\n throw new TypeError(\n \"snapshotAccessMatrix: no test file is running to put the snapshot beside; pass { file }\",\n );\n }\n const path = accessSnapshotFileOf(testFile);\n claimFile(path, state);\n return path;\n}\n\ntype Json = Readonly<Record<string, unknown>>;\n\nfunction isRecord(value: unknown): value is Json {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction isRow(value: unknown): boolean {\n return isRecord(value) && Object.values(value).every((cell) => typeof cell === \"string\");\n}\n\nfunction isPrincipal(value: unknown): boolean {\n return (\n value === null || (isRecord(value) && (value.kind === null || typeof value.kind === \"string\"))\n );\n}\n\nfunction isSnapshot(value: unknown): value is AccessSnapshot {\n if (!isRecord(value) || value.version !== 1 || !isRecord(value.principals)) {\n return false;\n }\n const { principals, excluded } = value;\n return (\n ACCESS_SECTIONS.every((section) => {\n const rows = value[section];\n return isRecord(rows) && Object.values(rows).every(isRow);\n }) &&\n Object.values(principals).every(isPrincipal) &&\n Array.isArray(excluded) &&\n excluded.every((name) => typeof name === \"string\")\n );\n}\n\n/** The snapshot stored at `path`, or `undefined` when there is no file; throws for a file that is not one. */\nexport function readAccessSnapshot(path: string): AccessSnapshot | undefined {\n if (!existsSync(path)) {\n return undefined;\n }\n let parsed: unknown;\n try {\n parsed = JSON.parse(readFileSync(path, \"utf8\"));\n } catch {\n parsed = undefined;\n }\n if (!isSnapshot(parsed)) {\n throw new Error(\n `snapshotAccessMatrix: ${shownPath(path)} is not an access snapshot ({ \"version\": 1, \"principals\", \"methods\", \"subscriptions\", \"collections\", \"excluded\" }); delete it to record the matrix again`,\n );\n }\n return parsed;\n}\n\n/** `value` with the keys of every object in it sorted: the same file on every machine. */\nfunction sortKeys(value: unknown): unknown {\n if (Array.isArray(value)) {\n return value.map(sortKeys);\n }\n if (!isRecord(value)) {\n return value;\n }\n return Object.fromEntries(\n Object.keys(value)\n .sort()\n .map((key) => [key, sortKeys(value[key])]),\n );\n}\n\n/** Writes `snapshot` to `path`, every key and the exclusions sorted, making its directory. */\nexport function writeAccessSnapshot(path: string, snapshot: AccessSnapshot): void {\n const sorted = { ...snapshot, excluded: [...snapshot.excluded].sort() };\n mkdirSync(dirname(path), { recursive: true });\n writeFileSync(path, `${JSON.stringify(sortKeys(sorted), null, 2)}\\n`);\n}\n\nfunction plural(count: number, one: string, many: string): string {\n return `${count} ${count === 1 ? one : many}`;\n}\n\n/** The line saying how many cells were never called, for the end of a message; none when all were. */\nfunction inconclusiveNote(inconclusive: readonly string[]): string[] {\n if (inconclusive.length === 0) {\n return [];\n }\n return [\n `${plural(inconclusive.length, \"cell was\", \"cells were\")} never called (VALIDATION): no input passed the method's input schema; give their inputs with inputs.`,\n ];\n}\n\n/** The error of a run whose cells or principals differ from the snapshot. */\nfunction differencesError(\n shown: string,\n comparison: AccessComparison,\n inconclusive: readonly string[],\n): Error {\n const counts = [\n ...(comparison.changed.length > 0\n ? [plural(comparison.changed.length, \"cell differs\", \"cells differ\")]\n : []),\n ...(comparison.principals.length > 0\n ? [plural(comparison.principals.length, \"principal differs\", \"principals differ\")]\n : []),\n ];\n return new Error(\n [\n `snapshotAccessMatrix: ${counts.join(\" and \")} from the access snapshot (${shown}):`,\n ...describeDifferences(comparison),\n ...(isReshaped(comparison) ? describeReshape(comparison) : []),\n `If every change is meant, run the tests again with ${ACCESS_SNAPSHOT_ENV}=1, review the file and commit it.`,\n ...inconclusiveNote(inconclusive),\n ].join(\"\\n\"),\n );\n}\n\n/**\n * Compares a run's `snapshot` with the file at `path` and writes the file\n * when the rules allow (see the module comment); throws when they do not.\n * `inconclusive` lists the cells never called, for the messages.\n */\nexport function settleSnapshot(\n path: string,\n snapshot: AccessSnapshot,\n inconclusive: readonly string[],\n): AccessSnapshotChange {\n const shown = shownPath(path);\n const ci = underCi();\n const update = updateRequested();\n if (update && ci) {\n throw new Error(\n `snapshotAccessMatrix: ${ACCESS_SNAPSHOT_ENV} is set under CI, where an access snapshot is only compared: rewrite ${shown} locally, review it and commit it`,\n );\n }\n const stored = readAccessSnapshot(path);\n if (stored === undefined) {\n if (ci) {\n throw new Error(\n [\n `snapshotAccessMatrix: there is no access snapshot at ${shown}, and under CI none is written: a snapshot that writes itself pins nothing.`,\n \"Run the tests locally to record it, review it and commit it.\",\n ...inconclusiveNote(inconclusive),\n ].join(\"\\n\"),\n );\n }\n writeAccessSnapshot(path, snapshot);\n return \"written\";\n }\n const comparison = compareAccessSnapshots(stored, snapshot);\n const differs = hasDifferences(comparison);\n if (!differs && !isReshaped(comparison)) {\n return \"unchanged\";\n }\n if (differs && !update) {\n throw differencesError(shown, comparison, inconclusive);\n }\n if (ci) {\n throw new Error(\n [\n `snapshotAccessMatrix: the access matrix has other cells than its snapshot (${shown}); rerun locally to accept:`,\n ...describeReshape(comparison),\n \"Run the tests without CI to write the snapshot, review it and commit it.\",\n ...inconclusiveNote(inconclusive),\n ].join(\"\\n\"),\n );\n }\n writeAccessSnapshot(path, snapshot);\n return \"updated\";\n}\n","// What an access snapshot holds (`accessSnapshot.ts`), and how a run's\n// matrix is compared with the stored one: the cells whose outcome changed\n// (each marked when it opens or closes access), the principals whose kind\n// changed, and the rows, principals and cells only one side has. A row of a\n// section is one method, entity subscribe or collection scope (with its row\n// variant), and holds one outcome per principal.\n\nimport type { ErrorCode } from \"../protocol/errors\";\n\n/** What one cell recorded: `\"ok\"`, or the error code the call or subscribe failed with. */\nexport type AccessOutcome = \"ok\" | ErrorCode;\n\n/**\n * A principal as the snapshot records it: its `kind` (`null` for a principal\n * without one), or `null` for the anonymous caller.\n */\nexport type AccessSnapshotPrincipal = { readonly kind: string | null } | null;\n\n/** One row of the matrix (a method, subscribe or scope, with its row variant): an outcome per principal. */\nexport type AccessSnapshotRow = Readonly<Record<string, AccessOutcome>>;\n\n/** The contents of an access snapshot file. */\nexport interface AccessSnapshot {\n readonly version: 1;\n /** Every principal of the matrix, the anonymous caller included, by name. */\n readonly principals: Readonly<Record<string, AccessSnapshotPrincipal>>;\n /** Method calls: `<service>.<method>`, plus ` (<variant>)` for a row variant. */\n readonly methods: Readonly<Record<string, AccessSnapshotRow>>;\n /** Entity subscribes (`qd:sub`): `<service>`, plus ` (<variant>)`. */\n readonly subscriptions: Readonly<Record<string, AccessSnapshotRow>>;\n /** Collection scopes (`qd:col:sub`): `<service>.<collection>`, plus ` (<variant>)` (`(self)` for a `\"self\"` scope). */\n readonly collections: Readonly<Record<string, AccessSnapshotRow>>;\n /** The methods left out with `exclude`, as `<service>.<method>`. */\n readonly excluded: readonly string[];\n}\n\n/** The sections of a snapshot that hold cells. */\nexport const ACCESS_SECTIONS = [\"methods\", \"subscriptions\", \"collections\"] as const;\n\n/** A section of a snapshot that holds cells. */\nexport type AccessSection = (typeof ACCESS_SECTIONS)[number];\n\n/** How a section's rows are named in a message: a subscribe or scope by its frame. */\nconst SECTION_PREFIX: Readonly<Record<AccessSection, string>> = Object.freeze({\n methods: \"\",\n subscriptions: \"qd:sub \",\n collections: \"qd:col:sub \",\n});\n\n/** One cell that differs between the stored snapshot and the run. */\nexport interface AccessCellChange {\n readonly section: AccessSection;\n /** The row's key in its section: `taskService.get (own)`. */\n readonly row: string;\n readonly principal: string;\n /** What the snapshot holds; `undefined` for a cell it does not have. */\n readonly before: AccessOutcome | undefined;\n /** What the run recorded; `undefined` for a cell it no longer has. */\n readonly after: AccessOutcome | undefined;\n}\n\n/** A principal of both whose record differs: another kind, or anonymous on one side only. */\nexport interface AccessPrincipalChange {\n readonly name: string;\n readonly before: AccessSnapshotPrincipal;\n readonly after: AccessSnapshotPrincipal;\n}\n\n/** How a run's matrix differs from the stored snapshot. */\nexport interface AccessComparison {\n /** Cells both have whose outcome differs. */\n readonly changed: readonly AccessCellChange[];\n /** Principals both have whose record differs. */\n readonly principals: readonly AccessPrincipalChange[];\n /** Rows only the run has, as a message names them (`qd:sub taskService (own)`). */\n readonly rowsAdded: readonly string[];\n /** Rows only the snapshot has. */\n readonly rowsRemoved: readonly string[];\n readonly principalsAdded: readonly string[];\n readonly principalsRemoved: readonly string[];\n /** Cells of rows and principals both have that only one side holds (an edited file). */\n readonly cells: readonly AccessCellChange[];\n /** Methods newly excluded. */\n readonly excludedAdded: readonly string[];\n /** Methods no longer excluded. */\n readonly excludedRemoved: readonly string[];\n}\n\n/** The items of `items` that `other` lacks, sorted. */\nfunction only(items: Iterable<string>, other: ReadonlySet<string>): string[] {\n return [...items].filter((item) => !other.has(item)).sort();\n}\n\nfunction samePrincipal(a: AccessSnapshotPrincipal, b: AccessSnapshotPrincipal): boolean {\n return a === null || b === null ? a === b : a.kind === b.kind;\n}\n\nfunction cellOf(row: AccessSnapshotRow, principal: string): AccessOutcome | undefined {\n return Object.hasOwn(row, principal) ? row[principal] : undefined;\n}\n\n/** The differing cells of one row both sides have, among the principals both have. */\nfunction compareRow(\n section: AccessSection,\n row: string,\n sides: { readonly before: AccessSnapshotRow; readonly after: AccessSnapshotRow },\n principals: readonly string[],\n): AccessCellChange[] {\n return principals.flatMap((principal) => {\n const before = cellOf(sides.before, principal);\n const after = cellOf(sides.after, principal);\n return before === after ? [] : [{ section, row, principal, before, after }];\n });\n}\n\n/** The principals both sides have whose record differs. */\nfunction comparePrincipals(\n before: AccessSnapshot,\n after: AccessSnapshot,\n shared: readonly string[],\n): AccessPrincipalChange[] {\n return shared.flatMap((name) => {\n const was = before.principals[name] ?? null;\n const is = after.principals[name] ?? null;\n return samePrincipal(was, is) ? [] : [{ name, before: was, after: is }];\n });\n}\n\n/** Compares a run's matrix (`after`) with the stored snapshot (`before`). */\nexport function compareAccessSnapshots(\n before: AccessSnapshot,\n after: AccessSnapshot,\n): AccessComparison {\n const namesBefore = new Set(Object.keys(before.principals));\n const namesAfter = new Set(Object.keys(after.principals));\n const shared = [...namesAfter].filter((name) => namesBefore.has(name)).sort();\n const differing: AccessCellChange[] = [];\n const rowsAdded: string[] = [];\n const rowsRemoved: string[] = [];\n for (const section of ACCESS_SECTIONS) {\n const rowsBefore = new Set(Object.keys(before[section]));\n const rowsAfter = new Set(Object.keys(after[section]));\n const prefix = SECTION_PREFIX[section];\n rowsAdded.push(...only(rowsAfter, rowsBefore).map((row) => prefix + row));\n rowsRemoved.push(...only(rowsBefore, rowsAfter).map((row) => prefix + row));\n for (const row of [...rowsAfter].filter((key) => rowsBefore.has(key)).sort()) {\n const sides = { before: before[section][row] ?? {}, after: after[section][row] ?? {} };\n differing.push(...compareRow(section, row, sides, shared));\n }\n }\n const excludedBefore = new Set(before.excluded);\n const excludedAfter = new Set(after.excluded);\n const oneSided = (change: AccessCellChange): boolean =>\n change.before === undefined || change.after === undefined;\n return {\n changed: differing.filter((change) => !oneSided(change)),\n principals: comparePrincipals(before, after, shared),\n rowsAdded,\n rowsRemoved,\n principalsAdded: only(namesAfter, namesBefore),\n principalsRemoved: only(namesBefore, namesAfter),\n cells: differing.filter(oneSided),\n excludedAdded: only(excludedAfter, excludedBefore),\n excludedRemoved: only(excludedBefore, excludedAfter),\n };\n}\n\n/** True when a cell's outcome or a principal changed: what fails until the change is accepted. */\nexport function hasDifferences(comparison: AccessComparison): boolean {\n return comparison.changed.length > 0 || comparison.principals.length > 0;\n}\n\n/** True when the matrix has other rows, principals, cells or exclusions than the snapshot. */\nexport function isReshaped(comparison: AccessComparison): boolean {\n return [\n comparison.rowsAdded,\n comparison.rowsRemoved,\n comparison.principalsAdded,\n comparison.principalsRemoved,\n comparison.cells,\n comparison.excludedAdded,\n comparison.excludedRemoved,\n ].some((list) => list.length > 0);\n}\n\n/** An outcome that refuses the caller. */\nfunction denies(outcome: AccessOutcome | undefined): boolean {\n return outcome === \"UNAUTHENTICATED\" || outcome === \"FORBIDDEN\";\n}\n\n/** An outcome that says access let the call through: anything but a refusal or an unusable input. */\nfunction passes(outcome: AccessOutcome | undefined): boolean {\n return outcome !== undefined && outcome !== \"VALIDATION\" && !denies(outcome);\n}\n\n/** Whether a changed cell opens access (a refusal became a pass), closes it, or neither. */\nexport function accessFlip(change: AccessCellChange): \"opens access\" | \"closes access\" | undefined {\n if (denies(change.before) && passes(change.after)) {\n return \"opens access\";\n }\n if (passes(change.before) && denies(change.after)) {\n return \"closes access\";\n }\n return undefined;\n}\n\n/** A cell as a message names it: `taskService.get (own) as bo`, `qd:sub taskService as bo`. */\nexport function cellName(cell: Pick<AccessCellChange, \"section\" | \"row\" | \"principal\">): string {\n return `${SECTION_PREFIX[cell.section]}${cell.row} as ${cell.principal}`;\n}\n\n/** At most this many lines of one kind in a message. */\nconst MAX_LINES = 50;\n\nfunction capped(lines: readonly string[]): string[] {\n if (lines.length <= MAX_LINES) {\n return [...lines];\n }\n return [...lines.slice(0, MAX_LINES), ` ... and ${lines.length - MAX_LINES} more`];\n}\n\nfunction shownPrincipal(principal: AccessSnapshotPrincipal): string {\n if (principal === null) {\n return \"anonymous\";\n }\n return principal.kind === null ? \"no kind\" : `kind ${principal.kind}`;\n}\n\n/** Where a changed cell goes in a message: those that open access first, then those that close it. */\nfunction flipRank(change: AccessCellChange): number {\n const flip = accessFlip(change);\n if (flip === \"opens access\") {\n return 0;\n }\n return flip === \"closes access\" ? 1 : 2;\n}\n\n/** One line per changed principal and cell, the cells that open access first, then those that close it. */\nexport function describeDifferences(comparison: AccessComparison): string[] {\n const principals = comparison.principals.map(\n (change) =>\n ` principal ${change.name}: ${shownPrincipal(change.before)} → ${shownPrincipal(change.after)}`,\n );\n const cells = [...comparison.changed]\n .sort((a, b) => flipRank(a) - flipRank(b))\n .map((change) => {\n const flip = accessFlip(change);\n const line = ` ${cellName(change)}: ${String(change.before)} → ${String(change.after)}`;\n return flip === undefined ? line : `${line} (${flip})`;\n });\n return [...capped(principals), ...capped(cells)];\n}\n\n/** One line per row, principal, cell and exclusion only one side has. */\nexport function describeReshape(comparison: AccessComparison): string[] {\n const lines = (label: string, items: readonly string[]): string[] =>\n capped(items.map((item) => ` ${label}: ${item}`));\n const cells = comparison.cells.map(\n (cell) => `${cellName(cell)}: ${cell.before ?? \"none\"} → ${cell.after ?? \"none\"}`,\n );\n return [\n ...lines(\"added\", comparison.rowsAdded),\n ...lines(\"removed\", comparison.rowsRemoved),\n ...lines(\"added principal\", comparison.principalsAdded),\n ...lines(\"removed principal\", comparison.principalsRemoved),\n ...lines(\"now excluded\", comparison.excludedAdded),\n ...lines(\"no longer excluded\", comparison.excludedRemoved),\n ...lines(\"cell\", cells),\n ];\n}\n","// `describeAccessMatrix` (RFC 0003 section 13): runs each case (a method and\n// its input) as each principal, and anonymously, through a running test app,\n// and compares every outcome with the expected allow/deny table. The calls go\n// through the app's real dispatcher (in process, or over real sockets), so\n// the matrix exercises the pipeline's authorization stage, not an engine in\n// isolation.\n//\n// await describeAccessMatrix(app, {\n// service: taskService,\n// principals: { owner, member, stranger },\n// cases: [\n// { method: \"get\", input: { id }, allow: [\"owner\", \"member\"] },\n// { method: \"rename\", input: { id, title: \"x\" }, allow: [\"owner\"] },\n// ],\n// });\n//\n// Each cell records the principal's `kind`, so a matrix over principals of\n// several kinds (a user, an agent's token) shows which kind each outcome is\n// for: a method's `kinds` refuses the others with `FORBIDDEN`, before its\n// access form, and the report names the kind of each cell that differs.\n//\n// Every cell calls the method for real, so a mutation runs once per principal\n// it allows: give inputs that can run again, or `input` as a function, called\n// for each cell with the principal it runs as, which makes a fresh row (a\n// task to delete, a name not yet taken) so no cell depends on the cells\n// before it, whatever the order of the principals:\n//\n// { method: \"remove\", input: async () => ({ id: await newTask() }), allow: [\"owner\"] }\n\nimport type { AnyContract } from \"../contract/defineContract\";\nimport type { InputOf, MethodName } from \"../contract/infer\";\nimport { QuickdrawError, type ErrorCode } from \"../protocol/errors\";\nimport type { PrincipalOfServices } from \"../server/dispatcher\";\nimport type { AnyService, Service } from \"../server/service\";\nimport type { Principal, QuickdrawTypes } from \"../server/types\";\nimport type { TestApp, TestConnection } from \"./createTestApp\";\n\n/**\n * What one cell expects: `\"allow\"` (the call succeeds), `\"deny\"` (it fails\n * with `UNAUTHENTICATED` without a principal and `FORBIDDEN` with one), or\n * the exact error code.\n */\nexport type MatrixOutcome = \"allow\" | \"deny\" | ErrorCode;\n\n/** The name the anonymous caller has in a matrix, unless `principals` names one as `null`. */\nexport const ANONYMOUS = \"anonymous\";\n\n/** The cell an input factory makes the input of: who the call runs as. */\nexport interface MatrixCell<Name extends string = string, P = Principal> {\n /** The principal's name in the matrix (`\"anonymous\"` for the added anonymous caller). */\n readonly name: Name;\n /** The principal itself, or `null` for an anonymous caller. */\n readonly principal: P | null;\n}\n\n/** A case's input made per cell: a fresh row for a mutation that cannot run twice on one. */\nexport type MatrixInputFactory<Input, Name extends string = string, P = Principal> = (\n cell: MatrixCell<Name, P>,\n) => Input | PromiseLike<Input>;\n\n/** One row of the matrix: a method, its input, and who may call it. */\nexport type AccessMatrixCase<C extends AnyContract, Name extends string, P = Principal> = {\n readonly [M in MethodName<C>]: {\n readonly method: M;\n /**\n * The input, or a function making it for each cell (called just before\n * that cell's call), so a mutation that can run once per row (a delete,\n * a unique name) gets a row of its own in every cell.\n */\n readonly input: InputOf<C, M> | MatrixInputFactory<InputOf<C, M>, Name, P>;\n /** Names the case in the report; default the method name. */\n readonly label?: string;\n /** The principals the call succeeds for; it is denied for everyone else. */\n readonly allow?: readonly Name[];\n /** Outcomes per principal, over `allow`. */\n readonly expect?: Partial<Readonly<Record<Name, MatrixOutcome>>>;\n };\n}[MethodName<C>];\n\n/** Options of {@link describeAccessMatrix}. */\nexport interface AccessMatrixOptions<C extends AnyContract, P, Name extends string> {\n /** The service whose methods the cases call; the app must serve it. */\n readonly service: Service<QuickdrawTypes, C>;\n /** The callers, by name. An anonymous caller named `\"anonymous\"` is added unless one is `null`. */\n readonly principals: Readonly<Record<Name, P | null>>;\n readonly cases: readonly AccessMatrixCase<C, NoInfer<Name> | typeof ANONYMOUS, NoInfer<P>>[];\n /** Call in process (`\"caller\"`, the default) or over a real socket per principal. */\n readonly via?: \"caller\" | \"socket\";\n}\n\n/** One cell: a case run as one principal. */\nexport interface AccessMatrixCell {\n readonly case: string;\n readonly principal: string;\n /** The principal's `kind`; `undefined` for the anonymous caller and a principal without one. */\n readonly kind: string | undefined;\n readonly expected: MatrixOutcome;\n /** `\"allow\"` when the call succeeded, or its error code. */\n readonly actual: \"allow\" | ErrorCode;\n readonly pass: boolean;\n}\n\n/** What {@link describeAccessMatrix} found: every cell, in order. */\nexport interface AccessMatrixReport {\n readonly cells: readonly AccessMatrixCell[];\n}\n\ntype MethodFunction = (input: unknown) => Promise<unknown>;\ntype ServiceFunctions = Readonly<Record<string, MethodFunction>>;\n\nfunction matches(expected: MatrixOutcome, actual: string, anonymous: boolean): boolean {\n if (expected === \"deny\") {\n return actual === (anonymous ? \"UNAUTHENTICATED\" : \"FORBIDDEN\");\n }\n return expected === actual;\n}\n\nasync function outcomeOf(call: () => Promise<unknown>): Promise<\"allow\" | ErrorCode> {\n try {\n await call();\n return \"allow\";\n } catch (error) {\n if (error instanceof QuickdrawError) {\n return error.code;\n }\n throw error;\n }\n}\n\nfunction report(serviceName: string, cells: readonly AccessMatrixCell[]): string {\n const failed = cells.filter((cell) => !cell.pass);\n const lines = failed.map((cell) => {\n const kind = cell.kind === undefined ? \"\" : ` (kind ${cell.kind})`;\n return ` ${cell.case} as ${cell.principal}${kind}: expected ${cell.expected}, got ${cell.actual}`;\n });\n return `describeAccessMatrix(${serviceName}): ${failed.length} of ${cells.length} cells differ\\n${lines.join(\"\\n\")}`;\n}\n\n/** The callers of each principal: in process, or over one socket each (closed by `close`). */\nfunction callers<S extends readonly AnyService[]>(\n app: TestApp<S>,\n serviceName: string,\n via: \"caller\" | \"socket\",\n): { of(principal: PrincipalOfServices<S> | null): Promise<ServiceFunctions>; close(): void } {\n const connections = new Map<unknown, Promise<TestConnection<S>>>();\n const pick = (caller: unknown): ServiceFunctions =>\n (caller as Readonly<Record<string, ServiceFunctions>>)[serviceName] ?? {};\n return {\n async of(principal) {\n if (via === \"caller\") {\n return pick(app.as(principal));\n }\n let connection = connections.get(principal);\n if (connection === undefined) {\n connection = app.connect(principal);\n connections.set(principal, connection);\n }\n return pick((await connection).call);\n },\n close() {\n for (const connection of connections.values()) {\n connection.then(\n (open) => open.close(),\n () => undefined,\n );\n }\n },\n };\n}\n\n/**\n * Runs every case as every principal, and anonymously, through `app` (from\n * `createTestApp`), and compares each outcome with the case's `allow` or\n * `expect`. Resolves with every cell; rejects with an `Error` listing each\n * cell that differs.\n */\nexport async function describeAccessMatrix<\n S extends readonly AnyService[],\n C extends AnyContract,\n const Name extends string,\n>(\n app: TestApp<S>,\n options: AccessMatrixOptions<C, PrincipalOfServices<S>, Name>,\n): Promise<AccessMatrixReport> {\n const { service, cases } = options;\n if (app.server.dispatcher.registry.services.get(service.name) !== service) {\n throw new TypeError(`describeAccessMatrix: the app does not serve ${service.name}`);\n }\n const principals: [string, PrincipalOfServices<S> | null][] = Object.entries(options.principals);\n if (!principals.some(([, principal]) => principal === null)) {\n principals.push([ANONYMOUS, null]);\n }\n const via = callers(app, service.name, options.via ?? \"caller\");\n const cells: AccessMatrixCell[] = [];\n try {\n for (const entry of cases) {\n const expectations: Partial<Record<string, MatrixOutcome>> = entry.expect ?? {};\n for (const [name, principal] of principals) {\n const allowed = (entry.allow as readonly string[] | undefined)?.includes(name) === true;\n const expected = expectations[name] ?? (allowed ? \"allow\" : \"deny\");\n const method = (await via.of(principal))[entry.method];\n if (method === undefined) {\n throw new TypeError(`describeAccessMatrix: ${service.name} has no ${entry.method}`);\n }\n const { input } = entry as { readonly input: unknown };\n const made =\n typeof input === \"function\"\n ? await (input as MatrixInputFactory<unknown>)({ name, principal })\n : input;\n const actual = await outcomeOf(() => method(made));\n const pass = matches(expected, actual, principal === null);\n cells.push({\n case: entry.label ?? entry.method,\n principal: name,\n kind: principal?.kind,\n expected,\n actual,\n pass,\n });\n }\n }\n } finally {\n via.close();\n }\n if (cells.some((cell) => !cell.pass)) {\n throw new Error(report(service.name, cells));\n }\n return { cells };\n}\n","// What `snapshotAccessMatrix` will run (`accessSnapshot.ts`), read from its\n// options and the app before any cell: the principals and rows a fixture\n// gives, checked, and the rows of the matrix. A method has one row per\n// variant of the row it is about (`accessInputs.ts`, `rowServiceOf`), an\n// entity subscribe one per variant of its service's rows, and a collection\n// one per variant of its anchor's rows (a `\"self\"` scope one, `(self)`).\n// `rows` must name every service those are about: a matrix of cells that\n// could reach no row pins nothing, so a missing service fails before any\n// cell runs.\n\nimport type { AnyService, ServiceMethod } from \"../server/service\";\nimport { rowServiceOf } from \"./accessInputs\";\nimport { ANONYMOUS } from \"./accessMatrix\";\nimport type { TestApp } from \"./createTestApp\";\n\n/** The row ids a matrix's cells are about, by service name: one id, or named variants (`{ own, other }`). */\nexport type AccessRows = Readonly<Record<string, string | Readonly<Record<string, string>>>>;\n\n/** The callers of a matrix by name, or a function of the fixture making them. */\nexport type AccessPrincipals<P, Fixture, Name extends string = string> =\n | Readonly<Record<Name, P | null>>\n | ((fixture: Fixture) => Readonly<Record<Name, P | null>>);\n\n/** The rows of one fixture: per service, its row id by variant (`undefined` for a single id). */\nexport type Rows = ReadonlyMap<string, ReadonlyMap<string | undefined, string>>;\n\n/** A method of the matrix, for one row variant. */\nexport interface MethodRow {\n /** The row's key in the snapshot: `<service>.<method>`, plus ` (<variant>)`. */\n readonly key: string;\n readonly service: AnyService;\n readonly method: ServiceMethod;\n /** The service whose row the method is about; `undefined` for a method about no row. */\n readonly rowService: string | undefined;\n readonly variant: string | undefined;\n}\n\n/** An entity subscribe of the matrix: every row variant of one service, in one `qd:sub`. */\nexport interface SubscribeRow {\n readonly service: string;\n /** The rows' keys in the snapshot, by variant. */\n readonly keys: ReadonlyMap<string | undefined, string>;\n}\n\n/** A collection scope of the matrix, for one row variant of its anchor (or the caller's own id). */\nexport interface ScopeRow {\n readonly key: string;\n readonly service: string;\n readonly collection: string;\n /** The anchor service; `undefined` for a `\"self\"` scope, whose value is the caller's user id. */\n readonly anchor: string | undefined;\n readonly variant: string | undefined;\n}\n\n/** Every row of the matrix, in the order a principal runs them, and the methods left out. */\nexport interface Plan {\n readonly subscribes: readonly SubscribeRow[];\n readonly scopes: readonly ScopeRow[];\n readonly queries: readonly MethodRow[];\n readonly mutations: readonly MethodRow[];\n readonly excluded: readonly string[];\n}\n\ntype Json = Readonly<Record<string, unknown>>;\n\nexport function isRecord(value: unknown): value is Json {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\n/** Throws the `TypeError` of a matrix that cannot run as given. */\nexport function fail(message: string): never {\n throw new TypeError(`snapshotAccessMatrix: ${message}`);\n}\n\n/** By name, in UTF-16 code unit order: the same order on every machine. */\nfunction byName(a: string, b: string): number {\n if (a === b) {\n return 0;\n }\n return a < b ? -1 : 1;\n}\n\n/** A row's key: its base, plus ` (<variant>)` for a named variant. */\nexport function keyOf(base: string, variant: string | undefined): string {\n return variant === undefined ? base : `${base} (${variant})`;\n}\n\n/** The principals `given` makes for `fixture`, plus the anonymous caller unless one is `null`. */\nexport function readPrincipals<P, Fixture>(\n given: AccessPrincipals<P, Fixture>,\n fixture: Fixture,\n): Map<string, P | null> {\n const record: unknown = typeof given === \"function\" ? given(fixture) : given;\n if (!isRecord(record)) {\n fail(\"principals must map names to principals (null for an anonymous caller)\");\n }\n const principals = new Map<string, P | null>();\n for (const [name, principal] of Object.entries(record)) {\n if (principal !== null && !isRecord(principal)) {\n fail(`principals.${name} must be a principal, or null for an anonymous caller`);\n }\n principals.set(name, principal as P | null);\n }\n if (![...principals.values()].includes(null)) {\n if (principals.has(ANONYMOUS)) {\n fail(\n `a principal is named \"${ANONYMOUS}\", the name of the anonymous caller added for you: name your anonymous caller with null, or rename that principal`,\n );\n }\n principals.set(ANONYMOUS, null);\n }\n return principals;\n}\n\n/** The variants of one service's entry in `rows`, checked. */\nfunction variantsIn(service: string, value: unknown): Map<string | undefined, string> {\n if (typeof value === \"string\" && value.length > 0) {\n return new Map([[undefined, value]]);\n }\n const entries = isRecord(value) ? Object.entries(value) : [];\n const ids: [string, string][] = [];\n for (const [variant, id] of entries) {\n if (typeof id === \"string\" && id.length > 0) {\n ids.push([variant, id]);\n }\n }\n if (ids.length === 0 || ids.length !== entries.length) {\n fail(`rows.${service} must be a row id, or named row ids ({ own: id, other: id })`);\n }\n return new Map(ids.sort(([a], [b]) => byName(a, b)));\n}\n\n/** The rows `rows(fixture)` gave: every service it names must be served, and every id a non-empty string. */\nexport function readRows(given: unknown, served: ReadonlyMap<string, AnyService>): Rows {\n if (!isRecord(given)) {\n fail(\"rows(fixture) must map service names to a row id, or to named row ids\");\n }\n const rows = new Map<string, ReadonlyMap<string | undefined, string>>();\n for (const [service, value] of Object.entries(given)) {\n if (!served.has(service)) {\n fail(`rows names ${service}, which the app does not serve`);\n }\n rows.set(service, variantsIn(service, value));\n }\n return rows;\n}\n\n/** True when two fixtures' principals and rows have the same names: the matrix's rows and columns. */\nexport function sameShape(\n a: { readonly principals: ReadonlyMap<string, unknown>; readonly rows: Rows },\n b: { readonly principals: ReadonlyMap<string, unknown>; readonly rows: Rows },\n): boolean {\n const names = (map: ReadonlyMap<unknown, unknown>): string => [...map.keys()].join(\"\\n\");\n const rows = (of: Rows): string =>\n [...of].map(([service, ids]) => `${service}:${names(ids)}`).join(\"\\n\\n\");\n return names(a.principals) === names(b.principals) && rows(a.rows) === rows(b.rows);\n}\n\n/** The variants of a service's rows: `[undefined]` for a single id, or for a method about no row. */\nexport function variantsOf(rows: Rows, service: string | undefined): (string | undefined)[] {\n const ids = service === undefined ? undefined : rows.get(service);\n return ids === undefined ? [undefined] : [...ids.keys()];\n}\n\n/** The services the matrix covers (default every service the app serves), each served, by name. */\nexport function servicesOf(app: TestApp, given: readonly AnyService[] | undefined): AnyService[] {\n const { services } = app.server.dispatcher.registry;\n if (given === undefined) {\n return [...services.values()].sort((a, b) => byName(a.name, b.name));\n }\n if (!Array.isArray(given)) {\n fail(\"services must be a list of services the app serves\");\n }\n for (const service of given) {\n if (services.get(service.name) !== service) {\n fail(`the app does not serve ${service.name}`);\n }\n }\n return [...new Set(given)].sort((a, b) => byName(a.name, b.name));\n}\n\n/** The methods `exclude` names, each a method of the matrix's services. */\nexport function excludedOf(\n services: readonly AnyService[],\n given: readonly string[] | undefined,\n): Set<string> {\n const known = new Set(\n services.flatMap((service) =>\n Object.keys(service.methods).map((name) => `${service.name}.${name}`),\n ),\n );\n if (given !== undefined && !Array.isArray(given)) {\n fail(\"exclude must be a list of methods, as <service>.<method>\");\n }\n const excluded = new Set<string>();\n for (const name of given ?? []) {\n if (typeof name !== \"string\" || !known.has(name)) {\n fail(\n `exclude names ${String(name)}, which is no method (<service>.<method>) of the matrix's services`,\n );\n }\n excluded.add(name);\n }\n return excluded;\n}\n\n/** The methods of the matrix, one row per variant of the row each is about. */\nfunction methodRows(\n services: readonly AnyService[],\n excluded: ReadonlySet<string>,\n rows: Rows,\n): MethodRow[] {\n const list: MethodRow[] = [];\n for (const service of services) {\n for (const name of Object.keys(service.methods).sort(byName)) {\n const method = service.methods[name];\n const base = `${service.name}.${name}`;\n if (method === undefined || excluded.has(base)) {\n continue;\n }\n const rowService = rowServiceOf(service, method);\n for (const variant of variantsOf(rows, rowService)) {\n list.push({ key: keyOf(base, variant), service, method, rowService, variant });\n }\n }\n }\n return list;\n}\n\n/** The entity subscribes of the matrix: one per service with rows to subscribe to. */\nfunction subscribeRows(services: readonly AnyService[], rows: Rows): SubscribeRow[] {\n return services\n .filter((service) => service.model !== undefined && service.contract.entity !== undefined)\n .map((service) => ({\n service: service.name,\n keys: new Map(\n variantsOf(rows, service.name).map((variant) => [variant, keyOf(service.name, variant)]),\n ),\n }));\n}\n\n/** The collection scopes of the matrix: one per variant of each collection's anchor, `(self)` for a self scope. */\nfunction scopeRows(services: readonly AnyService[], rows: Rows): ScopeRow[] {\n const list: ScopeRow[] = [];\n for (const service of services) {\n for (const collection of [...service.collections.keys()].sort(byName)) {\n const anchor = service.collections.get(collection)?.anchor?.name;\n const base = `${service.name}.${collection}`;\n if (anchor === undefined) {\n list.push({\n key: keyOf(base, \"self\"),\n service: service.name,\n collection,\n anchor,\n variant: undefined,\n });\n continue;\n }\n for (const variant of variantsOf(rows, anchor)) {\n list.push({\n key: keyOf(base, variant),\n service: service.name,\n collection,\n anchor,\n variant,\n });\n }\n }\n }\n return list;\n}\n\n/** Throws when `rows` names no row of a service a row of the matrix is about, listing every such service. */\nfunction checkRowsCover(plan: Plan, rows: Rows): void {\n const needs = new Map<string, Set<string>>();\n const need = (service: string | undefined, what: string): void => {\n if (service !== undefined && !rows.has(service)) {\n needs.set(service, (needs.get(service) ?? new Set()).add(what));\n }\n };\n for (const row of [...plan.queries, ...plan.mutations]) {\n need(row.rowService, `${row.service.name}.${row.method.name}`);\n }\n for (const row of plan.subscribes) {\n need(row.service, `qd:sub ${row.service}`);\n }\n for (const row of plan.scopes) {\n need(row.anchor, `qd:col:sub ${row.service}.${row.collection}`);\n }\n if (needs.size > 0) {\n const missing = [...needs].map(([service, what]) => `${service} (for ${[...what].join(\", \")})`);\n fail(\n `rows names no row of ${missing.join(\"; \")}. Give rows(fixture) a row id of each, or named row ids ({ own: id, other: id }); leave a method out with exclude`,\n );\n }\n}\n\n/** Every row of the matrix: the methods of `services` but those excluded, their subscribes and scopes. */\nexport function planOf(\n services: readonly AnyService[],\n excluded: ReadonlySet<string>,\n rows: Rows,\n): Plan {\n const methods = methodRows(services, excluded, rows);\n const plan: Plan = {\n subscribes: subscribeRows(services, rows),\n scopes: scopeRows(services, rows),\n queries: methods.filter((row) => row.method.kind === \"query\"),\n mutations: methods.filter((row) => row.method.kind === \"mutation\"),\n excluded: [...excluded].sort(byName),\n };\n checkRowsCover(plan, rows);\n return plan;\n}\n","// `snapshotAccessMatrix` (RFC 0003 section 13): who may call what, for every\n// method, entity subscribe and collection scope of an app's services and\n// every principal, recorded once in a file beside the test and compared on\n// every later run, so a changed cell fails until someone accepts it.\n// `describeAccessMatrix` pins hand-written cases of one service; a\n// migration, a policy refactor or a new principal kind wants the whole\n// table, diffed.\n//\n// await snapshotAccessMatrix(app, {\n// principals: (board) => ({ owner: { userId: board.ada }, member: { userId: board.bo } }),\n// reset: async () => {\n// await resetDatabase(prisma);\n// return await seed(prisma);\n// },\n// rows: (board) => ({ projectService: board.p1, taskService: { own: board.t1, other: board.t2 } }),\n// });\n//\n// Each principal, and an anonymous caller, runs in turn: every entity\n// subscribe and collection scope over a socket of its own, then every query,\n// then every mutation, in process, each with a real input: the app's\n// (`inputs`), or one made from the input's JSON Schema with the cell's row\n// where the method's access form reads it (`accessInputs.ts`). A mutation\n// the pipeline did not refuse may have written, so `reset` runs again after\n// it, and every cell sees the rows `reset` makes. What runs is planned\n// before any cell (`accessSnapshotPlan.ts`); the file is\n// `__access__/<test file>.json` (`accessSnapshotFile.ts`).\n\nimport { QuickdrawError } from \"../protocol/errors\";\nimport type { PrincipalOfServices } from \"../server/dispatcher\";\nimport type { AnyService, ServiceMethod } from \"../server/service\";\nimport type { Principal } from \"../server/types\";\nimport { generatedInput, isValidInput } from \"./accessInputs\";\nimport type {\n AccessOutcome,\n AccessSnapshot,\n AccessSnapshotPrincipal,\n AccessSnapshotRow,\n} from \"./accessSnapshotCompare\";\nimport { settleSnapshot, snapshotPathOf, type AccessSnapshotChange } from \"./accessSnapshotFile\";\nimport {\n excludedOf,\n fail,\n isRecord,\n planOf,\n readPrincipals,\n readRows,\n sameShape,\n servicesOf,\n type AccessPrincipals,\n type AccessRows,\n type MethodRow,\n type Plan,\n type Rows,\n} from \"./accessSnapshotPlan\";\nimport type { TestApp, TestConnection } from \"./createTestApp\";\nimport { emitWithAck } from \"./socket\";\n\nexport type { AccessPrincipals, AccessRows };\n\n/** The cell an `inputs` function makes the input of. */\nexport interface AccessSnapshotRef {\n /** The service's name. */\n readonly service: string;\n /** The method's name. */\n readonly method: string;\n readonly kind: ServiceMethod[\"kind\"];\n /** The row variant, when `rows` names variants for the service whose row the method is about. */\n readonly variant: string | undefined;\n /**\n * The row the cell is about, from `rows`: the method's own service's for\n * an `entry` form, the `of` contract's for a `scope` form, and its own\n * for any other form whose input has an `id`; `undefined` for a method\n * about no row.\n */\n readonly row: string | undefined;\n /** The name of the principal the cell runs as. */\n readonly principal: string;\n}\n\n/** Options of {@link snapshotAccessMatrix}. `Fixture` is what `reset` resolves with. */\nexport interface AccessSnapshotOptions<P, Fixture, Name extends string> {\n /**\n * The callers, by name, or a function of the fixture making them (read\n * again after every reset, for a seed that makes new ids); their names\n * must stay the same. An anonymous caller named `\"anonymous\"` is added\n * unless one is `null`.\n */\n readonly principals: AccessPrincipals<P, Fixture, Name>;\n /**\n * Empties the database and seeds it, resolving with what the seed made\n * (the fixture): the app's `resetDatabase` (from `./testing/prisma`) and\n * its seed, writing with the untracked client. Called first, and again\n * after every mutation the pipeline did not refuse.\n */\n readonly reset: () => Fixture | PromiseLike<Fixture>;\n /**\n * The row each service's cells are about, by service name: a row id, or\n * named variants (`{ own: p1, other: p2 }`), each a row of its own in the\n * snapshot. It must name every service whose rows a method's form, an\n * entity subscribe or a collection scope of the matrix reads.\n */\n readonly rows: (fixture: Fixture) => AccessRows;\n /**\n * A method's input for one cell, when the generated one will not do;\n * `undefined` to generate it. An input that fails the method's input\n * schema is recorded as `VALIDATION` and never called.\n */\n readonly inputs?: (ref: AccessSnapshotRef, fixture: Fixture) => unknown;\n /** The services whose methods, subscribes and scopes the matrix holds. Default: every service the app serves. */\n readonly services?: readonly AnyService[];\n /** Methods left out, as `<service>.<method>`: those whose outcome is not the same on every run. */\n readonly exclude?: readonly string[];\n /** The test file the snapshot sits beside. Default: the running test's file, from the test runner. */\n readonly file?: string;\n}\n\n/** What {@link snapshotAccessMatrix} recorded, and what it did with the snapshot file. */\nexport interface AccessSnapshotReport {\n /** The snapshot file. */\n readonly path: string;\n /**\n * `\"written\"`: there was no file; `\"unchanged\"`: the matrix is the stored\n * one; `\"updated\"`: the file was rewritten (cells added or removed in a\n * local run, or changes accepted with `QD_UPDATE_ACCESS_SNAPSHOT=1`).\n */\n readonly change: AccessSnapshotChange;\n /** The matrix this run recorded. */\n readonly snapshot: AccessSnapshot;\n /**\n * The cells never called because no input passed the method's input\n * schema (or named the cell's row where its form reads it), as\n * `<row> as <principal>`: recorded as `VALIDATION`, they pin nothing\n * about access. Give their inputs with `inputs`.\n */\n readonly inconclusive: readonly string[];\n}\n\ntype MethodFunction = (input: unknown) => Promise<unknown>;\n\n/** The outcomes of a mutation the pipeline refused before its handler ran: no reset follows them. */\nconst REFUSALS: ReadonlySet<string> = new Set([\"UNAUTHENTICATED\", \"FORBIDDEN\", \"VALIDATION\"]);\n\n/** The scope an anonymous caller subscribes to in a `\"self\"` collection: it has no user id. */\nconst ANONYMOUS_SCOPE = \"anonymous\";\n\n/** The recorded outcomes of a section: per row key, then principal name. */\ntype Cells = Map<string, Map<string, AccessOutcome>>;\n\n/** One run of the matrix: the current fixture, its principals and rows, and the cells so far. */\ninterface Run<P extends Principal, Fixture> {\n readonly app: TestApp;\n readonly options: AccessSnapshotOptions<P, Fixture, string>;\n readonly served: ReadonlyMap<string, AnyService>;\n readonly plan: Plan;\n fixture: Fixture;\n principals: Map<string, P | null>;\n rows: Rows;\n readonly methods: Cells;\n readonly subscriptions: Cells;\n readonly collections: Cells;\n readonly inconclusive: string[];\n}\n\nfunction record(cells: Cells, key: string, principal: string, outcome: AccessOutcome): void {\n const row = cells.get(key) ?? new Map<string, AccessOutcome>();\n cells.set(key, row.set(principal, outcome));\n}\n\n/** Resets the database, and reads the new fixture's principals and rows; their names must not change. */\nasync function reset<P extends Principal, Fixture>(run: Run<P, Fixture>): Promise<void> {\n const fixture = await run.options.reset();\n const next = {\n principals: readPrincipals(run.options.principals, fixture),\n rows: readRows(run.options.rows(fixture), run.served),\n };\n if (!sameShape(run, next)) {\n fail(\n \"principals and rows must name the same principals, services and variants after every reset\",\n );\n }\n run.fixture = fixture;\n run.principals = next.principals;\n run.rows = next.rows;\n}\n\nfunction rowIdOf(rows: Rows, service: string, variant: string | undefined): string | undefined {\n return rows.get(service)?.get(variant);\n}\n\n/** How a call ended: `\"ok\"`, or the code of the `QuickdrawError` it failed with; anything else is thrown. */\nasync function outcomeOf(call: () => Promise<unknown>): Promise<AccessOutcome> {\n try {\n await call();\n return \"ok\";\n } catch (error) {\n if (error instanceof QuickdrawError) {\n return error.code;\n }\n throw error;\n }\n}\n\n/** The outcome an acknowledgement (or one id's result in it) says: `\"ok\"`, or its error's code. */\nfunction outcomeOfReply(reply: unknown, event: string): AccessOutcome {\n if (isRecord(reply) && reply.ok === true) {\n return \"ok\";\n }\n const code = isRecord(reply) && isRecord(reply.e) ? reply.e.code : undefined;\n if (typeof code !== \"string\") {\n throw new Error(`snapshotAccessMatrix: ${event} answered ${JSON.stringify(reply)}`);\n }\n return code as AccessOutcome;\n}\n\n/** The input of one method cell: the app's, or a generated one; `undefined` when none is usable. */\nasync function inputOf<P extends Principal, Fixture>(\n run: Run<P, Fixture>,\n row: MethodRow,\n name: string,\n): Promise<{ readonly value: unknown } | undefined> {\n const id =\n row.rowService === undefined ? undefined : rowIdOf(run.rows, row.rowService, row.variant);\n const ref: AccessSnapshotRef = {\n service: row.service.name,\n method: row.method.name,\n kind: row.method.kind,\n variant: row.variant,\n row: id,\n principal: name,\n };\n const given: unknown = await run.options.inputs?.(ref, run.fixture);\n if (given !== undefined) {\n return (await isValidInput(row.method, given)) ? { value: given } : undefined;\n }\n const made = await generatedInput(row.method, id);\n return made === undefined ? undefined : { value: made.input };\n}\n\n/** The method a cell calls, through the app's in-process caller acting as `principal`. */\nfunction methodOf(app: TestApp, row: MethodRow, principal: Principal | null): MethodFunction {\n const caller = app.as(principal) as unknown as Readonly<\n Record<string, Readonly<Record<string, MethodFunction>> | undefined>\n >;\n const method = caller[row.service.name]?.[row.method.name];\n if (method === undefined) {\n throw new TypeError(`snapshotAccessMatrix: ${row.service.name} has no ${row.method.name}`);\n }\n return method;\n}\n\n/** Calls one method as one principal and records the outcome; resets after a mutation the pipeline let through. */\nasync function callCell<P extends Principal, Fixture>(\n run: Run<P, Fixture>,\n row: MethodRow,\n name: string,\n): Promise<void> {\n const input = await inputOf(run, row, name);\n if (input === undefined) {\n record(run.methods, row.key, name, \"VALIDATION\");\n run.inconclusive.push(`${row.key} as ${name}`);\n return;\n }\n const method = methodOf(run.app, row, run.principals.get(name) ?? null);\n const outcome = await outcomeOf(() => method(input.value));\n record(run.methods, row.key, name, outcome);\n if (row.method.kind === \"mutation\" && !REFUSALS.has(outcome)) {\n await reset(run);\n }\n}\n\n/** Every entity subscribe of the matrix over `connection`: one `qd:sub` per service, all its variants at once. */\nasync function subscribeEntities<P extends Principal, Fixture>(\n run: Run<P, Fixture>,\n connection: TestConnection,\n name: string,\n): Promise<void> {\n for (const row of run.plan.subscribes) {\n const variants = [...row.keys.keys()];\n const ids = variants.map((variant) => rowIdOf(run.rows, row.service, variant) ?? \"\");\n const reply: unknown = await emitWithAck(connection.socket, \"qd:sub\", { s: row.service, ids });\n const results =\n isRecord(reply) && reply.ok === true && Array.isArray(reply.r) ? reply.r : undefined;\n variants.forEach((variant, index) => {\n const outcome = outcomeOfReply(results === undefined ? reply : results[index], \"qd:sub\");\n record(run.subscriptions, row.keys.get(variant) ?? row.service, name, outcome);\n });\n }\n}\n\n/** Every collection scope of the matrix over `connection`, one `qd:col:sub` each. */\nasync function subscribeScopes<P extends Principal, Fixture>(\n run: Run<P, Fixture>,\n connection: TestConnection,\n name: string,\n): Promise<void> {\n const principal = run.principals.get(name) ?? null;\n for (const row of run.plan.scopes) {\n const scope =\n row.anchor === undefined\n ? (principal?.userId ?? ANONYMOUS_SCOPE)\n : (rowIdOf(run.rows, row.anchor, row.variant) ?? \"\");\n const frame = { s: row.service, c: row.collection, scope, limit: 1 };\n const reply: unknown = await emitWithAck(connection.socket, \"qd:col:sub\", frame);\n record(run.collections, row.key, name, outcomeOfReply(reply, \"qd:col:sub\"));\n }\n}\n\n/** The code a refused connection carries (its `connect_error` data), if it carries one. */\nfunction refusalCode(error: unknown): AccessOutcome | undefined {\n const data: unknown =\n error instanceof Error ? (error as { readonly data?: unknown }).data : undefined;\n const code = isRecord(data) ? data.code : undefined;\n return typeof code === \"string\" ? (code as AccessOutcome) : undefined;\n}\n\n/** Records `code` for every subscribe and scope of one principal: its socket was refused. */\nfunction refuseAll<P extends Principal, Fixture>(\n run: Run<P, Fixture>,\n name: string,\n code: AccessOutcome,\n): void {\n for (const row of run.plan.subscribes) {\n for (const key of row.keys.values()) {\n record(run.subscriptions, key, name, code);\n }\n }\n for (const row of run.plan.scopes) {\n record(run.collections, row.key, name, code);\n }\n}\n\n/** The subscribes and scopes of one principal, over a socket of its own. */\nasync function subscribeAll<P extends Principal, Fixture>(\n run: Run<P, Fixture>,\n name: string,\n): Promise<void> {\n if (run.plan.subscribes.length === 0 && run.plan.scopes.length === 0) {\n return;\n }\n let connection: TestConnection;\n try {\n connection = await run.app.connect(run.principals.get(name) ?? null);\n } catch (error) {\n const code = refusalCode(error);\n if (code === undefined) {\n throw error;\n }\n refuseAll(run, name, code);\n return;\n }\n try {\n await subscribeEntities(run, connection, name);\n await subscribeScopes(run, connection, name);\n } finally {\n connection.close();\n }\n}\n\nfunction rowsOf(cells: Cells): Record<string, AccessSnapshotRow> {\n return Object.fromEntries([...cells].map(([key, row]) => [key, Object.fromEntries(row)]));\n}\n\n/** The snapshot of a finished run, with the principals as the first fixture made them. */\nfunction snapshotOf<P extends Principal, Fixture>(\n run: Run<P, Fixture>,\n principals: ReadonlyMap<string, P | null>,\n): AccessSnapshot {\n const recorded = [...principals].map(([name, principal]): [string, AccessSnapshotPrincipal] => [\n name,\n principal === null ? null : { kind: principal.kind ?? null },\n ]);\n return {\n version: 1,\n principals: Object.fromEntries(recorded),\n methods: rowsOf(run.methods),\n subscriptions: rowsOf(run.subscriptions),\n collections: rowsOf(run.collections),\n excluded: run.plan.excluded,\n };\n}\n\n/** The options, checked as far as they can be before the first reset. */\nfunction checkOptions(options: unknown): void {\n if (\n !isRecord(options) ||\n typeof options.reset !== \"function\" ||\n typeof options.rows !== \"function\"\n ) {\n fail(\"pass { principals, reset, rows }: reset() seeds the rows, rows(fixture) names them\");\n }\n if (options.inputs !== undefined && typeof options.inputs !== \"function\") {\n fail(\"inputs must be a function of the cell and the fixture\");\n }\n}\n\n/**\n * Records who may call what through `app` (from `createTestApp`): every\n * method of `services` (default: every service the app serves), each\n * entity subscribe (`qd:sub`) and each collection scope (`qd:col:sub`), as\n * every principal and anonymously, against the rows `reset` seeds, and\n * compares the matrix with the snapshot file beside the test\n * (`__access__/<test file>.json`, keys sorted: commit it).\n *\n * - A missing file is written. Under CI (`CI=1` or `CI=true`) it fails\n * instead: a snapshot that writes itself pins nothing.\n * - A cell whose outcome changed fails, naming the row (method and\n * variant), the principal and both outcomes, and whether the change opens\n * or closes access. Accept the changes with `QD_UPDATE_ACCESS_SNAPSHOT=1`,\n * which rewrites the file (never under CI).\n * - Cells added or removed (a new method, principal or exclusion) rewrite\n * the file locally, and fail under CI.\n *\n * Outcomes are exact: `\"ok\"`, or the error code. Each principal's `kind` is\n * recorded too, and a changed kind fails like a cell. A cell whose input\n * failed the method's input schema is `VALIDATION`, never called, and\n * listed in the report's `inconclusive`. Leave out methods whose outcome is\n * not the same on every run with `exclude`. One snapshot per test file.\n *\n * @example\n * const report = await snapshotAccessMatrix(app, { principals, reset, rows });\n * expect(report.inconclusive).toEqual([]);\n */\nexport async function snapshotAccessMatrix<\n S extends readonly AnyService[],\n Fixture,\n const Name extends string,\n>(\n app: TestApp<S>,\n options: AccessSnapshotOptions<PrincipalOfServices<S>, Fixture, Name>,\n): Promise<AccessSnapshotReport> {\n checkOptions(options);\n const path = snapshotPathOf(options.file);\n const generic = app as unknown as TestApp;\n const served = generic.server.dispatcher.registry.services;\n const services = servicesOf(generic, options.services);\n const excluded = excludedOf(services, options.exclude);\n const fixture = await options.reset();\n const principals = readPrincipals<PrincipalOfServices<S>, Fixture>(options.principals, fixture);\n const rows = readRows(options.rows(fixture), served);\n const run: Run<PrincipalOfServices<S>, Fixture> = {\n app: generic,\n options: options as AccessSnapshotOptions<PrincipalOfServices<S>, Fixture, string>,\n served,\n plan: planOf(services, excluded, rows),\n fixture,\n principals,\n rows,\n methods: new Map(),\n subscriptions: new Map(),\n collections: new Map(),\n inconclusive: [],\n };\n for (const name of principals.keys()) {\n await subscribeAll(run, name);\n for (const row of [...run.plan.queries, ...run.plan.mutations]) {\n await callCell(run, row, name);\n }\n }\n const snapshot = snapshotOf(run, principals);\n const change = settleSnapshot(path, snapshot, run.inconclusive);\n return { path, change, snapshot, inconclusive: run.inconclusive };\n}\n"],"mappings":"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","names":["io","matches","record","record","matches","existsSync","mkdirSync","readFileSync","writeFileSync","basename","dirname","join","change","join","dirname","basename","claimed","NO_RUNNER","isRecord","isPrincipal","existsSync","readFileSync","mkdirSync","writeFileSync","isRecord","record","outcomeOf","isRecord","checkOptions","change"]}
|
|
1
|
+
{"version":3,"sources":["../../src/testing/frames.ts","../../src/testing/budget.ts","../../src/testing/budgetCompare.ts","../../src/testing/instrument.ts","../../src/testing/socket.ts","../../src/testing/createTestApp.ts","../../src/testing/recordingSink.ts","../../src/testing/accessInputs.ts","../../src/testing/accessSnapshotFile.ts","../../src/testing/accessSnapshotCompare.ts","../../src/testing/accessMatrix.ts","../../src/testing/accessSnapshotPlan.ts","../../src/testing/accessSnapshot.ts"],"sourcesContent":["// The frame recorder of `createTestApp` (RFC 0003 section 13): every frame\n// the server sends any socket of the test app, as the server sent it to that\n// socket, with the user the socket acts for and when it was sent. Tests\n// assert on frames this way instead of putting raw listeners on client\n// sockets, and it covers every client: sockets from `app.connect`, client\n// connections from `./testing/client`, and any other.\n//\n// It records what goes out through Socket.IO's outgoing-packet hook on each\n// server socket, which sees direct emits and room broadcasts alike, so an\n// entity frame stripped for one access tier is recorded as that tier's\n// sockets received it. Events are recorded by name, whatever they are: the\n// v5 frames (`qd:hello`, `qd:e`, `qd:c`, `qd:changed`, `qd:revoked`,\n// `qd:access`, `qd:rotate`, and `qd:event` and `qd:stream` once services\n// send them) and an app's own. Acknowledgements are replies, not frames, and\n// are not recorded.\n\nimport type { AnyContract } from \"../contract/defineContract\";\nimport type { EventName, EventPayloadOf, StreamItemOf, StreamName } from \"../contract/infer\";\nimport { SERVER_EVENTS, type ServerEventName } from \"../contract/names\";\nimport type { EventFrame, ServerToClientEvents, StreamFrame } from \"../protocol/envelope\";\nimport type { QuickdrawIo } from \"../server/transports/types\";\n\n/** The payload of a v5 server event, by its name. */\nexport type ServerFrameOf<E extends ServerEventName> = Parameters<ServerToClientEvents[E]>[0];\n\n/** One frame the server sent one socket. */\nexport interface RecordedFrame<Data = unknown> {\n /** The event: `\"qd:e\"`, `\"qd:c\"`, `\"qd:changed\"`, ... */\n readonly event: string;\n /** The frame: the event's first argument. */\n readonly data: Data;\n /** Every argument of the event, for an app's own events that send more than one. */\n readonly args: readonly unknown[];\n /** The id of the socket it was sent to; the client socket's `id` is the same. */\n readonly socketId: string;\n /** The user the socket acts for, or `null` for an anonymous socket. */\n readonly userId: string | null;\n /** When the server sent it: `Date.now()`. */\n readonly at: number;\n}\n\n/** Which frames to take: all that match every field given. */\nexport interface FrameQuery<E extends string = string> {\n readonly event?: E;\n readonly socketId?: string;\n /** The user the socket acts for; `null` for anonymous sockets. */\n readonly userId?: string | null;\n}\n\n/**\n * The frames of one v5 event that match every field given, and `where`\n * when it is given: a predicate over the frame with its `data` typed as\n * the event's (`PresenceFrame` for `\"qd:presence\"`; `D` narrows an item or\n * a payload, as `streamFrames` and `eventFrames` do for a contract's).\n */\nexport interface EventQuery<E extends ServerEventName, D = ServerFrameOf<E>> extends FrameQuery<E> {\n readonly event: E;\n readonly where?: (frame: RecordedFrame<D>) => boolean;\n}\n\n/** A query, or a predicate over recorded frames. */\nexport type FrameMatch =\n | FrameQuery\n | EventQuery<ServerEventName, never>\n | ((frame: RecordedFrame) => boolean);\n\n/**\n * `app.frames`: every frame the test app's server sent since it started (or\n * since `clear()`), oldest first.\n *\n * @example\n * app.frames({ event: \"qd:e\", userId: cy.id }).map((frame) => frame.data);\n * app.frames.clear();\n * await app.server.dispatcher.caller(alice).taskService.rename({ id, title });\n * await app.frames.waitFor({ event: \"qd:changed\", userId: bob.id });\n */\nexport interface FrameRecorder {\n /** The frames of one v5 event that match `query` (and its `where`), typed by the event. */\n <E extends ServerEventName, D = ServerFrameOf<E>>(query: EventQuery<E, D>): RecordedFrame<D>[];\n /** The frames that match `match`, or every frame. */\n (match?: FrameMatch): RecordedFrame[];\n /** Forgets every frame recorded so far. */\n clear(): void;\n /**\n * Resolves with the first frame that matches: one recorded already (since\n * the last `clear()`), or the next one sent. Rejects when none arrives\n * within `timeoutMs` (default 5,000). An event query's `where`, and the\n * frame it resolves with, are typed by the event; `streamFrames` and\n * `eventFrames` type a contract's items and payloads too.\n *\n * @example\n * const { data } = await app.frames.waitFor({\n * ...streamFrames(gameContract, \"world\", (snapshot) => snapshot.tick === tick),\n * socketId: player.socket.id,\n * });\n * data[3].players; // a WorldSnapshot's\n */\n waitFor<E extends ServerEventName, D = ServerFrameOf<E>>(\n query: EventQuery<E, D>,\n timeoutMs?: number,\n ): Promise<RecordedFrame<D>>;\n waitFor(match: FrameMatch, timeoutMs?: number): Promise<RecordedFrame>;\n}\n\n/**\n * The `qd:stream` frames of one stream of `contract` (of one scope, with\n * `scope`), items typed, that `where` accepts: spread it into a query of\n * `app.frames` or `waitFor` beside `socketId` or `userId`.\n */\nexport function streamFrames<C extends AnyContract, K extends StreamName<C>>(\n contract: C,\n stream: K,\n where?: (\n item: StreamItemOf<C, K>,\n frame: RecordedFrame<StreamFrame<StreamItemOf<C, K>>>,\n ) => boolean,\n scope?: string,\n): EventQuery<typeof SERVER_EVENTS.stream, StreamFrame<StreamItemOf<C, K>>> {\n return Object.freeze({\n event: SERVER_EVENTS.stream,\n where: (frame: RecordedFrame<StreamFrame<StreamItemOf<C, K>>>) => {\n const [s, name, frameScope, item] = frame.data;\n return (\n s === contract.name &&\n name === stream &&\n (scope === undefined || frameScope === scope) &&\n (where === undefined || where(item, frame))\n );\n },\n });\n}\n\n/**\n * The `qd:event` frames of one event of `contract`, payloads typed, that\n * `where` accepts: spread it into a query of `app.frames` or `waitFor`.\n */\nexport function eventFrames<C extends AnyContract, K extends EventName<C>>(\n contract: C,\n event: K,\n where?: (\n payload: EventPayloadOf<C, K>,\n frame: RecordedFrame<EventFrame<EventPayloadOf<C, K>>>,\n ) => boolean,\n): EventQuery<typeof SERVER_EVENTS.event, EventFrame<EventPayloadOf<C, K>>> {\n return Object.freeze({\n event: SERVER_EVENTS.event,\n where: (frame: RecordedFrame<EventFrame<EventPayloadOf<C, K>>>) => {\n const [s, name, payload] = frame.data;\n return (\n s === contract.name && name === event && (where === undefined || where(payload, frame))\n );\n },\n });\n}\n\nconst DEFAULT_WAIT_MS = 5000;\n\n/** A `waitFor` still waiting. */\ninterface Waiter {\n readonly matches: (frame: RecordedFrame) => boolean;\n readonly resolve: (frame: RecordedFrame) => void;\n}\n\n/** The predicate `match` stands for. */\nfunction predicateOf(match: FrameMatch | undefined): (frame: RecordedFrame) => boolean {\n if (match === undefined) {\n return () => true;\n }\n if (typeof match === \"function\") {\n return match;\n }\n const where =\n \"where\" in match ? (match.where as ((frame: RecordedFrame) => boolean) | undefined) : undefined;\n return (frame) =>\n (match.event === undefined || frame.event === match.event) &&\n (match.socketId === undefined || frame.socketId === match.socketId) &&\n (match.userId === undefined || frame.userId === match.userId) &&\n (where === undefined || where(frame));\n}\n\n/** The text a timed-out `waitFor` names its match with. */\nfunction describeMatch(match: FrameMatch): string {\n if (typeof match === \"function\") {\n return \"the predicate\";\n }\n const { where, ...fields } = match as FrameQuery & { readonly where?: unknown };\n return where === undefined ? JSON.stringify(fields) : `${JSON.stringify(fields)} and its where`;\n}\n\n/**\n * Records every frame `io`'s server sends from now on. Its middleware runs\n * after the server's own, once a socket is authenticated, so a socket the\n * server refuses records nothing and `qd:hello` is the first frame of each.\n */\nexport function recordFrames(io: QuickdrawIo): FrameRecorder {\n const frames: RecordedFrame[] = [];\n const waiters = new Set<Waiter>();\n\n io.use((serverSocket, next) => {\n serverSocket.onAnyOutgoing((event: string, ...args: unknown[]) => {\n const frame: RecordedFrame = Object.freeze({\n event,\n data: args[0],\n args: Object.freeze([...args]),\n socketId: serverSocket.id,\n userId: serverSocket.data.principal?.userId ?? null,\n at: Date.now(),\n });\n frames.push(frame);\n for (const waiter of [...waiters]) {\n if (waiter.matches(frame)) {\n waiters.delete(waiter);\n waiter.resolve(frame);\n }\n }\n });\n next();\n });\n\n const waitFor = (match: FrameMatch, timeoutMs = DEFAULT_WAIT_MS): Promise<RecordedFrame> => {\n const matches = predicateOf(match);\n const found = frames.find(matches);\n if (found !== undefined) {\n return Promise.resolve(found);\n }\n return new Promise<RecordedFrame>((resolve, reject) => {\n const timer = setTimeout(() => {\n waiters.delete(waiter);\n reject(new Error(`No frame matched ${describeMatch(match)} within ${timeoutMs} ms`));\n }, timeoutMs);\n const waiter: Waiter = {\n matches,\n resolve: (frame) => {\n clearTimeout(timer);\n resolve(frame);\n },\n };\n waiters.add(waiter);\n });\n };\n\n const recorder = (match?: FrameMatch): RecordedFrame[] => frames.filter(predicateOf(match));\n return Object.assign(recorder, {\n clear: (): void => {\n frames.length = 0;\n },\n waitFor,\n }) as FrameRecorder;\n}\n","// `expectBudget` (RFC 0003 section 13): performance as something a test can\n// fail on. It runs one step of a test against the apps `createTestApp`\n// started and records what the step cost, then compares that with the\n// budget file next to the test, `__budgets__/<test file>.json`:\n//\n// - per call (a method call through `app.as(...)`, a socket or HTTP), its\n// service and method, the database statements its handler ran and the\n// bytes of its reply, from the call's completion record;\n// - for the whole step, every statement the apps' tracked database clients\n// ran (access checks, flushes and subscriptions included) and every byte\n// their servers wrote to sockets, plus the in-process replies.\n//\n// Counts and bytes, never time, so a budget is the same on every machine. A\n// missing entry is written. A rise fails with the old and new numbers, unless\n// QD_ALLOW_BUDGET_GROWTH allows it (`1` for every budget, or a comma-separated\n// list of budget names), which writes the new budget instead. A fall is\n// written locally, so the budget tightens as the code improves; under CI\n// (`CI=1` or `CI=true`) it fails too, so removed work is noticed and accepted\n// by running the tests locally. Bytes move by up to 5% either way without\n// counting as a change (ids and timestamps vary in length); statements must\n// match exactly. Two tests of one file may not name a step alike.\n\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { basename, dirname, join, relative } from \"node:path\";\nimport type { CallRecord } from \"../server/pipeline/metrics\";\nimport {\n compareBudgets,\n describeChanges,\n mergeBudget,\n type Budget,\n type BudgetCall,\n} from \"./budgetCompare\";\n\nexport type { Budget, BudgetCall };\n\n/**\n * The environment variable that lets a budget grow: `QD_ALLOW_BUDGET_GROWTH=1`\n * for every budget, or a comma-separated list of budget names.\n */\nexport const BUDGET_GROWTH_ENV = \"QD_ALLOW_BUDGET_GROWTH\";\n\n/** Whether {@link BUDGET_GROWTH_ENV} lets the budget `name` grow: `1`, or a list naming it. */\nexport function growthAllowed(name: string, value = process.env[BUDGET_GROWTH_ENV]): boolean {\n if (value === undefined) {\n return false;\n }\n const allowed = value.split(\",\").map((item) => item.trim());\n return (allowed.length === 1 && allowed[0] === \"1\") || allowed.includes(name);\n}\n\n/** Whether the tests run under CI (`CI=1` or `CI=true`), where a budget that fell fails. */\nexport function underCi(value = process.env.CI): boolean {\n return value === \"1\" || value === \"true\";\n}\n\n/** Options of {@link expectBudget}. */\nexport interface BudgetOptions {\n /** The entry's name in the budget file: unique within the test file. */\n readonly name: string;\n /**\n * The test file the budget file sits next to. Default: the running test's\n * file, from the test runner (vitest, or jest's `expect.getState()`).\n */\n readonly file?: string;\n}\n\n/** What {@link expectBudget} measured, and what it did with the budget file. */\nexport interface BudgetResult {\n readonly name: string;\n /** The budget file. */\n readonly path: string;\n /** What the step cost. */\n readonly measured: Budget;\n /**\n * `\"written\"`: there was no entry; `\"unchanged\"`: within the budget;\n * `\"lowered\"`: below it, and the entry now says so; `\"grown\"`: above it,\n * accepted with QD_ALLOW_BUDGET_GROWTH=1.\n */\n readonly change: \"written\" | \"unchanged\" | \"lowered\" | \"grown\";\n}\n\n/** A test app's counters, which `createTestApp` registers while the app runs. */\nexport interface BudgetSource {\n /** Identifies the tracked client the statements are counted on: apps sharing one count once. */\n readonly counter: object | undefined;\n /** Statements the app's tracked client has run so far; `undefined` without one. */\n statements(): number | undefined;\n /** Bytes the app's server has written to its sockets so far. */\n bytes(): number;\n}\n\nconst sources = new Set<BudgetSource>();\n\nlet recording: CallRecord[] | undefined;\n\n/** Registers a test app's counters; returns the function that removes them. */\nexport function addBudgetSource(source: BudgetSource): () => void {\n sources.add(source);\n return () => {\n sources.delete(source);\n };\n}\n\n/** Hands a completion record to the step being measured, if any: a test app's `onCall`. */\nexport function recordBudgetCall(record: CallRecord): void {\n recording?.push(record);\n}\n\ninterface Totals {\n readonly statements: number;\n readonly bytes: number;\n}\n\nfunction totalsOf(live: readonly BudgetSource[]): Totals {\n const counted = new Set<object>();\n let statements = 0;\n let bytes = 0;\n for (const source of live) {\n bytes += source.bytes();\n if (source.counter === undefined || counted.has(source.counter)) {\n continue;\n }\n counted.add(source.counter);\n statements += source.statements() ?? 0;\n }\n return { statements, bytes };\n}\n\n/** Socket replies are among the bytes the servers wrote; every other reply is added on its own. */\nfunction viaSocket(record: CallRecord): boolean {\n return record.transport === \"socket\" || record.transport === \"legacy\";\n}\n\nfunction callOf(record: CallRecord): BudgetCall {\n return {\n call: `${record.service}.${record.method}`,\n statements: record.sqlStatements ?? 0,\n bytes: record.bytes,\n ...(record.outcome === \"ok\" ? {} : { outcome: record.outcome }),\n };\n}\n\n/** Strings by UTF-16 code unit: the same order on every machine, whatever its locale. */\nfunction byCodeUnit(a: string, b: string): number {\n if (a === b) {\n return 0;\n }\n return a < b ? -1 : 1;\n}\n\n/** Calls in a stable order, so concurrent calls compare the same on every run. */\nexport function byCall(a: BudgetCall, b: BudgetCall): number {\n return (\n byCodeUnit(a.call, b.call) ||\n byCodeUnit(a.outcome ?? \"\", b.outcome ?? \"\") ||\n a.statements - b.statements ||\n a.bytes - b.bytes\n );\n}\n\nfunction budgetOf(before: Totals, after: Totals, records: readonly CallRecord[]): Budget {\n const replies = records\n .filter((record) => !viaSocket(record))\n .reduce((sum, record) => sum + record.bytes, 0);\n return {\n statements: after.statements - before.statements,\n bytes: after.bytes - before.bytes + replies,\n calls: records.map(callOf).sort(byCall),\n };\n}\n\n/** Waits for work the step's last reply left behind, such as an ambient flush. */\nfunction settle(): Promise<void> {\n return new Promise((resolve) => {\n setImmediate(resolve);\n });\n}\n\n/** Runs `run` and measures it. */\nasync function measure(run: () => unknown): Promise<Budget> {\n if (recording !== undefined) {\n throw new Error(\"expectBudget: another budget is being measured; measure one step at a time\");\n }\n const live = [...sources];\n if (live.length === 0) {\n throw new Error(\"expectBudget: no test app is running; start one with createTestApp first\");\n }\n const before = totalsOf(live);\n const records: CallRecord[] = [];\n recording = records;\n try {\n await run();\n await settle();\n } finally {\n recording = undefined;\n }\n return budgetOf(before, totalsOf(live), records);\n}\n\nconst EXPECT_GLOBAL = Symbol.for(\"expect-global\");\n\n/** The test runner's global `expect` (vitest's, or jest's), and the running test's file and name. */\nexport interface RunnerState {\n readonly runner: object | undefined;\n readonly testPath: string | undefined;\n readonly testName: string | undefined;\n}\n\nfunction nonEmpty(value: unknown): string | undefined {\n return typeof value === \"string\" && value.length > 0 ? value : undefined;\n}\n\n/** What the test runner's global `expect` says about the running test (`snapshotAccessMatrix` reads it too). */\nexport function runnerState(): RunnerState {\n const holder = globalThis as Record<PropertyKey, unknown>;\n for (const candidate of [holder[EXPECT_GLOBAL], holder.expect]) {\n const getState = (candidate as { readonly getState?: unknown } | undefined)?.getState;\n if (typeof getState === \"function\") {\n const state = (getState as () => unknown).call(candidate) as {\n readonly testPath?: unknown;\n readonly currentTestName?: unknown;\n };\n return {\n runner: candidate as object,\n testPath: nonEmpty(state.testPath),\n testName: nonEmpty(state.currentTestName),\n };\n }\n }\n return { runner: undefined, testPath: undefined, testName: undefined };\n}\n\n/** Per test runner, the steps measured so far: `budget file\\0name` to the test that measured it. */\nconst claimed = new WeakMap<object, Map<string, string>>();\nconst NO_RUNNER = {};\n\n/**\n * Refuses a step name another test of the same file used: two tests sharing\n * an entry would rewrite each other's budget. The same test measuring it\n * again (a retry) is allowed.\n */\nfunction claimName(path: string, name: string, state: RunnerState): void {\n const runner = state.runner ?? NO_RUNNER;\n const names = claimed.get(runner) ?? new Map<string, string>();\n claimed.set(runner, names);\n const key = `${path}\\u0000${name}`;\n const test = state.testName ?? \"\";\n const owner = names.get(key);\n if (owner !== undefined && owner !== test) {\n throw new TypeError(\n `expectBudget: two tests of ${shownPath(path)} name a step \"${name}\" (\"${owner}\" and \"${test}\"); give each step its own name`,\n );\n }\n names.set(key, test);\n}\n\n/** `path` relative to the working directory when it is inside it. */\nexport function shownPath(path: string): string {\n const near = relative(process.cwd(), path);\n return near.startsWith(\"..\") ? path : near;\n}\n\n/** The budget file of `testFile`: `__budgets__/<its name>.json` in its directory. */\nexport function budgetFileOf(testFile: string): string {\n return join(dirname(testFile), \"__budgets__\", `${basename(testFile)}.json`);\n}\n\n/** A budget file: `{ \"version\": 1, \"budgets\": { [name]: Budget } }`, names sorted. */\ninterface BudgetFile {\n readonly version: 1;\n readonly budgets: Readonly<Record<string, unknown>>;\n}\n\nfunction readBudgets(path: string): Readonly<Record<string, unknown>> {\n if (!existsSync(path)) {\n return {};\n }\n const parsed = JSON.parse(readFileSync(path, \"utf8\")) as Partial<BudgetFile> | null;\n if (parsed?.version !== 1 || typeof parsed.budgets !== \"object\" || parsed.budgets === null) {\n throw new Error(\n `expectBudget: ${path} is not a budget file ({ \"version\": 1, \"budgets\": {...} })`,\n );\n }\n return parsed.budgets;\n}\n\nfunction isCount(value: unknown): value is number {\n return typeof value === \"number\" && Number.isSafeInteger(value) && value >= 0;\n}\n\nfunction isCall(value: unknown): value is BudgetCall {\n const call = value as Partial<Record<keyof BudgetCall, unknown>> | null;\n return (\n typeof value === \"object\" &&\n call !== null &&\n typeof call.call === \"string\" &&\n isCount(call.statements) &&\n isCount(call.bytes)\n );\n}\n\nfunction isBudget(value: unknown): value is Budget {\n const budget = value as Partial<Record<keyof Budget, unknown>> | null;\n return (\n typeof value === \"object\" &&\n budget !== null &&\n isCount(budget.statements) &&\n isCount(budget.bytes) &&\n Array.isArray(budget.calls) &&\n (budget.calls as readonly unknown[]).every(isCall)\n );\n}\n\n/** The entry `name` of the budget file at `path`, or `undefined` when it has none. */\nfunction storedBudget(path: string, name: string): Budget | undefined {\n const budgets = readBudgets(path);\n if (!Object.hasOwn(budgets, name)) {\n return undefined;\n }\n const stored: unknown = budgets[name];\n if (!isBudget(stored)) {\n throw new Error(\n `expectBudget(\"${name}\"): its entry in ${path} is not a budget; delete it to measure it again`,\n );\n }\n return stored;\n}\n\nfunction writeBudget(path: string, name: string, budget: Budget): void {\n const budgets: Record<string, unknown> = { ...readBudgets(path), [name]: budget };\n const sorted = Object.fromEntries(\n Object.keys(budgets)\n .sort()\n .map((key) => [key, budgets[key]]),\n );\n mkdirSync(dirname(path), { recursive: true });\n writeFileSync(path, `${JSON.stringify({ version: 1, budgets: sorted }, null, 2)}\\n`);\n}\n\nfunction checkOptions(options: BudgetOptions): { readonly name: string; readonly path: string } {\n if (typeof options !== \"object\" || options === null) {\n throw new TypeError(\"expectBudget(run, { name }): pass the budget's name\");\n }\n const { name } = options;\n if (typeof name !== \"string\" || name.trim().length === 0) {\n throw new TypeError(\"expectBudget: name must be a non-empty string\");\n }\n const state = runnerState();\n const file = options.file ?? state.testPath;\n if (file === undefined) {\n throw new TypeError(\n \"expectBudget: no test file is running to put the budget beside; pass { file }\",\n );\n }\n const path = budgetFileOf(file);\n claimName(path, name, state);\n return { name, path };\n}\n\n/**\n * Runs `run`, one step of a test, and compares what it cost with its entry in\n * the budget file next to the test (`__budgets__/<test file>.json`): the\n * database statements and reply bytes of each call it made, and every\n * statement and socket byte of the step. Rejects when the step costs more\n * than its budget, naming each number that grew with its old and new values,\n * unless `QD_ALLOW_BUDGET_GROWTH` allows it (`1`, or a comma-separated list\n * of names); writes the entry when it is new, lower, or allowed to grow.\n * Under CI (`CI=1` or `CI=true`) a lower step fails as well (\"budget\n * changed; rerun locally to accept\"). Two tests of one file may not name a\n * step alike (`TypeError`). Measure one step at a time.\n *\n * A call's statements are its handler's, as its completion record counts\n * them: the access check before the handler is not among them, a kit's reads\n * to filter by access are, and a call that joined another's shared run\n * counts none. The step's statements count everything the apps' tracked\n * clients ran while `run` did, access checks and flushes included. Await,\n * in `run`, everything the step should cost: the replies and the frames it\n * is about.\n *\n * @example\n * await expectBudget(() => app.as(ada).taskService.list({ limit: 20 }), { name: \"list as owner\" });\n */\nexport async function expectBudget(\n run: () => unknown,\n options: BudgetOptions,\n): Promise<BudgetResult> {\n if (typeof run !== \"function\") {\n throw new TypeError(\"expectBudget: run must be a function that makes the step's calls\");\n }\n const { name, path } = checkOptions(options);\n const measured = await measure(run);\n const stored = storedBudget(path, name);\n if (stored === undefined) {\n writeBudget(path, name, measured);\n return { name, path, measured, change: \"written\" };\n }\n const comparison = compareBudgets(stored, measured);\n if (comparison.grew && !growthAllowed(name)) {\n throw new Error(\n `expectBudget(\"${name}\"): the step costs more than its budget (${shownPath(path)}):\\n` +\n `${describeChanges(comparison)}\\n` +\n `Make it cheaper, or set ${BUDGET_GROWTH_ENV}=1 (or ${BUDGET_GROWTH_ENV}=\"${name}\") to accept the new budget.`,\n );\n }\n if (!comparison.grew && !comparison.fell) {\n return { name, path, measured, change: \"unchanged\" };\n }\n if (!comparison.grew && underCi()) {\n throw new Error(\n `expectBudget(\"${name}\"): budget changed; rerun locally to accept (${shownPath(path)}):\\n` +\n `${describeChanges(comparison, \"fell\")}\\n` +\n \"The step costs less than its budget: run the tests without CI to write the lower budget, and commit it.\",\n );\n }\n writeBudget(path, name, mergeBudget(stored, measured, comparison));\n return { name, path, measured, change: comparison.grew ? \"grown\" : \"lowered\" };\n}\n","// How `expectBudget` compares a measured step with its stored budget\n// (`budget.ts`): statements must match exactly, bytes may move by up to\n// `BUDGET_BYTES_TOLERANCE` either way, and a step whose calls changed (other\n// methods, outcomes, or how many) is a change of its own that counts as\n// growth. A budget only moves down by itself: a number within the tolerance\n// keeps its stored value, so small byte drifts never rewrite the file.\n\n/** One call of a budgeted step. */\nexport interface BudgetCall {\n /** `\"taskService.list\"`. */\n readonly call: string;\n /** The statements its handler ran, from its completion record; 0 for a call that joined a shared run. */\n readonly statements: number;\n /** Its reply's size as its transport measured it (`app.as(...)`: the reply as JSON). */\n readonly bytes: number;\n /** How it failed; absent when it succeeded. */\n readonly outcome?: string;\n}\n\n/** What one step cost: an entry of a budget file. */\nexport interface Budget {\n /** Every statement the apps' tracked clients ran during the step. */\n readonly statements: number;\n /** Every byte the apps' servers wrote to sockets during the step, plus the in-process replies. */\n readonly bytes: number;\n /** The step's calls, sorted by method. */\n readonly calls: readonly BudgetCall[];\n}\n\n/** How far bytes may move, up or down, before it counts as a change: 5%. */\nexport const BUDGET_BYTES_TOLERANCE = 0.05;\n\ntype Direction = \"grew\" | \"fell\" | \"same\";\n\n/** One number of a budget, before and now. */\ninterface NumberChange {\n readonly label: string;\n readonly was: number;\n readonly now: number;\n readonly direction: Direction;\n readonly bytes: boolean;\n}\n\n/** A measured step against its budget. */\nexport interface Comparison {\n /** A number grew past the budget, or the step's calls changed. */\n readonly grew: boolean;\n /** A number fell below the budget. */\n readonly fell: boolean;\n /** The step's calls are other than the budget's: other methods, outcomes, or how many. */\n readonly callsChanged: boolean;\n readonly changes: readonly NumberChange[];\n readonly was: Budget;\n readonly now: Budget;\n}\n\nfunction directionOf(was: number, now: number, bytes: boolean): Direction {\n const tolerance = bytes ? BUDGET_BYTES_TOLERANCE : 0;\n if (now > was * (1 + tolerance)) {\n return \"grew\";\n }\n return now < was * (1 - tolerance) ? \"fell\" : \"same\";\n}\n\nfunction change(label: string, was: number, now: number, bytes: boolean): NumberChange {\n return { label, was, now, direction: directionOf(was, now, bytes), bytes };\n}\n\nfunction signature(call: BudgetCall): string {\n return call.outcome === undefined ? call.call : `${call.call} (${call.outcome})`;\n}\n\nfunction sameCalls(was: readonly BudgetCall[], now: readonly BudgetCall[]): boolean {\n return (\n was.length === now.length &&\n was.every((call, index) => {\n const other = now[index];\n return other !== undefined && signature(call) === signature(other);\n })\n );\n}\n\n/** Compares a measured step with its budget. */\nexport function compareBudgets(was: Budget, now: Budget): Comparison {\n const changes: NumberChange[] = [\n change(\"statements\", was.statements, now.statements, false),\n change(\"bytes\", was.bytes, now.bytes, true),\n ];\n const callsChanged = !sameCalls(was.calls, now.calls);\n if (!callsChanged) {\n now.calls.forEach((call, index) => {\n const stored = was.calls[index] ?? call;\n const label = `${call.call} (call ${index + 1})`;\n changes.push(\n change(`${label} statements`, stored.statements, call.statements, false),\n change(`${label} bytes`, stored.bytes, call.bytes, true),\n );\n });\n }\n return {\n grew: callsChanged || changes.some((each) => each.direction === \"grew\"),\n fell: changes.some((each) => each.direction === \"fell\"),\n callsChanged,\n changes,\n was,\n now,\n };\n}\n\nfunction describe(each: NumberChange): string {\n const line = ` ${each.label}: was ${each.was}, now ${each.now}`;\n if (!each.bytes || each.was === 0) {\n return line;\n }\n const percent = ((each.now - each.was) / each.was) * 100;\n return `${line} (${percent > 0 ? \"+\" : \"\"}${percent.toFixed(1)}%; bytes may move by ${BUDGET_BYTES_TOLERANCE * 100}%)`;\n}\n\n/**\n * The lines of a failure message: each number that moved `direction` (grew,\n * by default) with its old and new values, and for growth the changed calls.\n */\nexport function describeChanges(\n comparison: Comparison,\n direction: \"grew\" | \"fell\" = \"grew\",\n): string {\n const lines = comparison.changes.filter((each) => each.direction === direction).map(describe);\n if (direction === \"grew\" && comparison.callsChanged) {\n const list = (calls: readonly BudgetCall[]): string =>\n calls.length === 0 ? \"none\" : calls.map(signature).join(\", \");\n lines.push(` calls: was ${list(comparison.was.calls)}; now ${list(comparison.now.calls)}`);\n }\n return lines.join(\"\\n\");\n}\n\n/**\n * The budget to store after a comparison that changed something: the\n * measured step where its calls changed, else each number that moved past\n * the tolerance at its new value and every other number as it was.\n */\nexport function mergeBudget(was: Budget, now: Budget, comparison: Comparison): Budget {\n if (comparison.callsChanged) {\n return now;\n }\n const pick = (stored: number, measured: number, bytes: boolean): number =>\n directionOf(stored, measured, bytes) === \"same\" ? stored : measured;\n return {\n statements: pick(was.statements, now.statements, false),\n bytes: pick(was.bytes, now.bytes, true),\n calls: now.calls.map((call, index) => {\n const stored = was.calls[index] ?? call;\n return {\n ...call,\n statements: pick(stored.statements, call.statements, false),\n bytes: pick(stored.bytes, call.bytes, true),\n };\n }),\n };\n}\n","// What `createTestApp` adds to the server it boots, besides the frame\n// recorder (`frames.ts`): strict development warnings when asked, the\n// counters `expectBudget` measures a step with (`budget.ts`: the calls'\n// completion records, the tracked client's statements, the bytes written to\n// sockets), and an in-process caller that reports its replies' size.\n\nimport { consoleLogger, type Logger } from \"../contract/logger\";\nimport { utf8ByteLength } from \"../protocol/utf8\";\nimport { createCaller } from \"../server/caller\";\nimport { STRICT_WARNINGS } from \"../server/devWarnings\";\nimport type { CallRecord } from \"../server/pipeline/metrics\";\nimport { toCallReply, type DispatchRequest, type DispatchResult } from \"../server/pipeline/request\";\nimport { storageOf, type StorageAdapter } from \"../server/storage\";\nimport type { QuickdrawIo } from \"../server/transports/types\";\nimport { statementsIssued } from \"../server/uow/unitOfWork\";\nimport { addBudgetSource, recordBudgetCall } from \"./budget\";\n\n/** The test app's default logger: warnings and errors only. */\nexport const quietLogger: Logger = {\n debug: () => undefined,\n info: () => undefined,\n warn: (message, meta) => consoleLogger.warn(message, meta),\n error: (message, meta) => consoleLogger.error(message, meta),\n child: () => quietLogger,\n};\n\n/** The options of `createTestApp` this module reads. */\nexport interface InstrumentedOptions {\n readonly onCall?: (record: CallRecord) => void;\n /**\n * Under vitest or jest (`VITEST` or `JEST_WORKER_ID` set), throw every\n * development warning raised in this app's method calls (N+1 statements,\n * unbounded reads, oversized replies, nested writes) as a `DevWarningError`\n * where it is raised, so the test that caused it fails. A warning raised\n * at start (`tiered-field-in-output`, `resolver-without-reads`,\n * `untracked-access-model`, `channel-without-requires`) fails the app's\n * start. Warnings outside its\n * calls, such as an ambient write while seeding, are logged; `close()`\n * ends it. Default `false`: warnings are logged once.\n */\n readonly strictWarnings?: boolean;\n}\n\n/** True under vitest or jest, where `strictWarnings` applies. */\nfunction underTestRunner(): boolean {\n return process.env.VITEST !== undefined || process.env.JEST_WORKER_ID !== undefined;\n}\n\n/**\n * `options` for `createServer`: `strictWarnings` turned into the dispatcher's\n * hidden strict flag, and an `onCall` that also hands every record to the\n * step `expectBudget` is measuring.\n */\nexport function instrumentOptions<O extends InstrumentedOptions>(\n options: O,\n): Omit<O, \"strictWarnings\"> {\n const { strictWarnings, onCall, ...rest } = options;\n return {\n ...rest,\n onCall: (record: CallRecord) => {\n recordBudgetCall(record);\n onCall?.(record);\n },\n [STRICT_WARNINGS]: strictWarnings === true && underTestRunner(),\n } as Omit<O, \"strictWarnings\">;\n}\n\nfunction sizeOf(data: unknown): number {\n if (typeof data === \"string\") {\n return utf8ByteLength(data);\n }\n return ArrayBuffer.isView(data) || data instanceof ArrayBuffer ? data.byteLength : 0;\n}\n\n/** What `meterServer` reads its counters from. */\nexport interface MeteredApp {\n readonly io: QuickdrawIo;\n readonly db?: unknown;\n readonly storage?: StorageAdapter;\n}\n\n/**\n * Counts the bytes of every message `app.io` writes to a socket (events and\n * acknowledgements, once per receiving socket) and registers them, with the\n * statements of the app's tracked client, for `expectBudget`. Returns the\n * function that unregisters them, for `close()`.\n */\nexport function meterServer(app: MeteredApp): () => void {\n let bytes = 0;\n app.io.use((socket, next) => {\n socket.conn.on(\n \"packetCreate\",\n (packet: { readonly type?: unknown; readonly data?: unknown }) => {\n if (packet.type === \"message\") {\n bytes += sizeOf(packet.data);\n }\n },\n );\n next();\n });\n const unitOfWork = (app.storage ?? storageOf(app.db))?.unitOfWork;\n return addBudgetSource({\n counter: unitOfWork,\n statements: () => (unitOfWork === undefined ? undefined : statementsIssued(unitOfWork)),\n bytes: () => bytes,\n });\n}\n\n/** A reply's size as the HTTP transport would send it: its JSON. */\nfunction replySize(result: DispatchResult): number | undefined {\n try {\n return utf8ByteLength(JSON.stringify(toCallReply(result)));\n } catch {\n return undefined;\n }\n}\n\n/**\n * An in-process caller acting as `principal`, through `call`, whose calls\n * report their reply's size (as JSON) in their completion records, as a\n * transport's do.\n */\nexport function measuredCaller(\n call: (request: DispatchRequest) => Promise<DispatchResult>,\n principal: Parameters<typeof createCaller>[1],\n): object {\n return createCaller(() => (request) => call({ ...request, respond: replySize }), principal);\n}\n","// Socket helpers for tests, ported from 4.1 (4.1 `src/server/testing.ts:135-180`).\n// 4.1's `emitWithAck` unwrapped the 4.x `{ success, data }` reply; this one\n// resolves with the acknowledgement as the server sent it, since a v5 reply\n// (`{ ok, d }`) and a 4.x one now both exist. For typed v5 calls use\n// `connect(principal).call` from `createTestApp`.\n\nimport { io, type Socket } from \"socket.io-client\";\nimport type { CallReply } from \"../protocol/envelope\";\nimport { fromWire } from \"../protocol/errors\";\nimport { PROTOCOL_VERSION, type HelloFrame } from \"../protocol/version\";\nimport { lazyMembers, type CallOptions } from \"../server/caller\";\nimport { QUICKDRAW_VERSION } from \"../version\";\n\n/** A Socket.IO client socket. */\nexport type ClientSocket = Socket;\n\n/**\n * Emits `event` with `payload` and resolves with the server's acknowledgement.\n * Without a payload none is sent (Socket.IO would send `undefined` as `null`).\n * Rejects when no acknowledgement arrives within `timeoutMs`.\n */\nexport function emitWithAck<Reply = unknown>(\n socket: Socket,\n event: string,\n payload?: unknown,\n timeoutMs = 5000,\n): Promise<Reply> {\n return new Promise((resolve, reject) => {\n const timeout = setTimeout(() => {\n reject(new Error(`Timeout waiting for ${event}`));\n }, timeoutMs);\n const ack = (reply: Reply): void => {\n clearTimeout(timeout);\n resolve(reply);\n };\n if (payload === undefined) {\n socket.emit(event, ack);\n } else {\n socket.emit(event, payload, ack);\n }\n });\n}\n\n/** Resolves with the payload of the next `event` the socket receives; rejects after `timeoutMs`. */\nexport function waitForEvent<T = unknown>(\n socket: Socket,\n event: string,\n timeoutMs = 5000,\n): Promise<T> {\n return new Promise((resolve, reject) => {\n let timeout: ReturnType<typeof setTimeout> | undefined;\n const handler = (data: T): void => {\n clearTimeout(timeout);\n resolve(data);\n };\n timeout = setTimeout(() => {\n socket.off(event, handler);\n reject(new Error(`Timeout waiting for event ${event}`));\n }, timeoutMs);\n socket.once(event, handler);\n });\n}\n\ninterface Envelope {\n readonly id: number;\n readonly s: string;\n readonly m: string;\n readonly i?: unknown;\n}\n\nasync function callOverSocket(\n socket: Socket,\n envelope: Envelope,\n signal: AbortSignal | undefined,\n timeoutMs: number,\n): Promise<unknown> {\n const cancel = (): void => {\n socket.emit(\"qd:cancel\", { id: envelope.id });\n };\n const pending = emitWithAck<CallReply>(socket, \"qd:call\", envelope, timeoutMs);\n if (signal?.aborted === true) {\n cancel();\n } else {\n signal?.addEventListener(\"abort\", cancel, { once: true });\n }\n try {\n const reply = await pending;\n if (!reply.ok) {\n throw fromWire(reply.e);\n }\n return reply.nm === true ? undefined : reply.d;\n } finally {\n signal?.removeEventListener(\"abort\", cancel);\n }\n}\n\n/**\n * A caller like `dispatcher.caller(principal)` whose calls travel over\n * `socket` as `qd:call` frames: `call.taskService.get(input)` resolves with\n * the data or rejects with the call's `QuickdrawError`. An aborted `signal`\n * sends `qd:cancel`.\n */\nexport function socketCaller(socket: Socket, timeoutMs: number): object {\n let nextId = 0;\n return lazyMembers((service) =>\n lazyMembers((method) => (input?: unknown, options?: CallOptions) => {\n const id = nextId;\n nextId += 1;\n const envelope =\n input === undefined\n ? { id, s: service, m: method }\n : { id, s: service, m: method, i: input };\n return callOverSocket(socket, envelope, options?.signal, timeoutMs);\n }),\n );\n}\n\n/** Connects and resolves with the server's hello, or rejects with the `connect_error`. */\nfunction handshake(socket: Socket, timeoutMs: number): Promise<HelloFrame> {\n return new Promise((resolve, reject) => {\n const finish = (error: Error | undefined, frame?: HelloFrame): void => {\n clearTimeout(timer);\n socket.off(\"qd:hello\", onHello);\n socket.off(\"connect_error\", onError);\n if (frame === undefined) {\n reject(error);\n } else {\n resolve(frame);\n }\n };\n const onHello = (frame: HelloFrame): void => finish(undefined, frame);\n const onError = (error: Error): void => finish(error);\n const timer = setTimeout(() => {\n finish(new Error(`No qd:hello within ${timeoutMs} ms`));\n }, timeoutMs);\n socket.once(\"qd:hello\", onHello);\n socket.once(\"connect_error\", onError);\n socket.connect();\n });\n}\n\n/**\n * Opens a v5 socket to `url` that never reconnects, with `auth` plus the v5\n * handshake (`auth.qd`), and resolves once the server said hello. A refused\n * connection rejects with the `connect_error` and leaves the socket closed.\n */\nexport async function connectV5(\n url: string,\n auth: Readonly<Record<string, unknown>>,\n timeoutMs: number,\n): Promise<{ readonly socket: Socket; readonly hello: HelloFrame }> {\n const socket = io(url, {\n forceNew: true,\n reconnection: false,\n autoConnect: false,\n transports: [\"websocket\"],\n auth: { ...auth, qd: { protocol: PROTOCOL_VERSION, client: QUICKDRAW_VERSION } },\n });\n try {\n return { socket, hello: await handshake(socket, timeoutMs) };\n } catch (error) {\n socket.disconnect();\n throw error;\n }\n}\n","// `createTestApp` (RFC 0003 section 13): the app's real server on a free\n// port, with an `authenticate` that trusts the principal a test connects as\n// (its grants loaded by `auth.loadServiceAccess` when it carries none, for\n// sockets and `as(principal)` alike),\n// and a recorder of every frame the server sends (`frames.ts`). Its\n// dispatcher becomes the current one of the `initQuickdraw` instance that\n// defined the services, so `qd.stream`, `qd.presence` and `qd.run` reach\n// it. While it runs, `expectBudget` measures it (`instrument.ts`), and\n// `strictWarnings` makes the development warnings of its method calls\n// throw, and a warning raised at start (`tiered-field-in-output`,\n// `resolver-without-reads`, `channel-without-requires`, or\n// `untracked-access-model`, which `createServer` checks in the background\n// and this awaits) fails its start;\n// `close()` ends both. It replaces 4.1's\n// `createTestServer` and `connectAsUser` (4.1 `src/server/testing.ts:62-130`),\n// which took a fixed port counter and authenticated by a bare user id.\n\nimport type { AddressInfo } from \"node:net\";\nimport type { HelloFrame } from \"../protocol/version\";\nimport type { Caller } from \"../server/caller\";\nimport {\n createServer,\n startupChecksOf,\n type QuickdrawServer,\n type ServerOptions,\n} from \"../server/createServer\";\nimport type { ContractOfServices, PrincipalOfServices } from \"../server/dispatcher\";\nimport { runtimeOf, type AnyService } from \"../server/service\";\nimport { isPrincipal, type ServerAuth } from \"../server/transports/auth\";\nimport { recordFrames, type FrameRecorder } from \"./frames\";\nimport {\n instrumentOptions,\n measuredCaller,\n meterServer,\n quietLogger,\n type InstrumentedOptions,\n} from \"./instrument\";\nimport { connectV5, socketCaller, type ClientSocket } from \"./socket\";\n\n/**\n * Makes `dispatcher` the current one of every `initQuickdraw` instance that\n * defined one of `services`, as that instance's own `createServer` would:\n * `qd.stream(...).push`, `qd.presence`, `qd.run` and `qd.caller` then go\n * through the test app. The last app created wins.\n */\nfunction adoptDispatcher(services: readonly AnyService[], dispatcher: object): void {\n const runtimes = new Set(services.map((service) => runtimeOf(service)));\n for (const runtime of runtimes) {\n runtime?.adopt?.(dispatcher);\n }\n}\n\ntype Call = QuickdrawServer[\"dispatcher\"][\"call\"];\n\n/**\n * `call`, with the grants `load` gives a principal that carries none, at\n * each call: what `createServer`'s principal resolver does for a socket's\n * handshake and an HTTP call.\n */\nfunction withGrants(call: Call, load: ServerAuth[\"loadServiceAccess\"]): Call {\n if (load === undefined) {\n return call;\n }\n return async (request) => {\n const { principal } = request;\n if (\n principal === null ||\n (principal.serviceAccess !== undefined && principal.serviceAccess !== null)\n ) {\n return await call(request);\n }\n const serviceAccess = (await load(principal.userId)) ?? {};\n return await call({ ...request, principal: { ...principal, serviceAccess } });\n };\n}\n\n/**\n * Options of {@link createTestApp}: the server's, and `strictWarnings`.\n * Without `auth.authenticate` a socket acts as the `principal` it connects\n * with; the rate limiter is off unless `rateLimit` is given; the logger\n * prints warnings and errors only.\n */\nexport type TestAppOptions<S extends readonly AnyService[]> = ServerOptions<S> &\n Pick<InstrumentedOptions, \"strictWarnings\">;\n\n/** A socket connected to the test app. */\nexport interface TestConnection<S extends readonly AnyService[] = readonly AnyService[]> {\n /** The raw Socket.IO client socket, for frames `call` does not cover. */\n readonly socket: ClientSocket;\n /** The server's `qd:hello`. */\n readonly hello: HelloFrame;\n /**\n * Calls methods over this socket, typed like `as(principal)`:\n * `call.taskService.get(input)` resolves with the data or rejects with the\n * call's `QuickdrawError`. Aborting `options.signal` sends `qd:cancel`.\n */\n readonly call: Caller<ContractOfServices<S>>;\n /** Disconnects the socket. */\n close(): void;\n}\n\n/** The running test app. */\nexport interface TestApp<S extends readonly AnyService[] = readonly AnyService[]> {\n /** The server's URL, `http://127.0.0.1:{port}`. */\n readonly url: string;\n readonly server: QuickdrawServer<S>;\n /**\n * Every frame the server sent any socket since the app started (or since\n * `frames.clear()`), with the socket, its user and the time:\n * `app.frames({ event: \"qd:e\", userId })`, `app.frames.waitFor(match)`.\n */\n readonly frames: FrameRecorder;\n /**\n * A typed in-process caller acting as `principal` (`null` for anonymous).\n * Its calls' completion records carry their reply's size as JSON, as an\n * HTTP call's do, so `expectBudget` sees their bytes. A principal that\n * carries no `serviceAccess` gets its grants from the server's\n * `auth.loadServiceAccess` at every call, as an HTTP call's and a\n * socket's principal do, so in-process and socket calls authorize alike;\n * one that carries grants (even `{}`) keeps them.\n */\n as(principal: PrincipalOfServices<S> | null): Caller<ContractOfServices<S>>;\n /**\n * Connects a real v5 socket acting as `principal` (`null` for anonymous);\n * resolves once the server said hello, rejects when it refused the socket.\n */\n connect(principal: PrincipalOfServices<S> | null): Promise<TestConnection<S>>;\n /**\n * Disconnects every socket `connect` opened, then closes the server; the\n * tracked client goes back to the dispatcher attached before the app's.\n */\n close(): Promise<void>;\n}\n\nconst TIMEOUT_MS = 5000;\n\n/**\n * Boots the app's services on `createServer`, listening on a free port of\n * 127.0.0.1, for tests that call them in process or over real sockets.\n * `strictWarnings: true` (under vitest or jest) makes every development\n * warning raised in the app's method calls throw where it is raised, so a\n * test that causes one fails, and one raised at start\n * (`tiered-field-in-output`, `resolver-without-reads`,\n * `untracked-access-model`, `channel-without-requires`) rejects this;\n * warnings outside its calls (seeding through the tracked client, say) are\n * logged, and nothing is strict after `close()`.\n *\n * @example\n * const app = await createTestApp({ services: [taskService], db: testPrisma });\n * await app.as(alice).taskService.rename({ id, title });\n * const { call } = await app.connect(alice);\n * await call.taskService.get({ id });\n * await app.frames.waitFor({ event: \"qd:e\", userId: alice.userId });\n * await app.close();\n */\nexport async function createTestApp<const S extends readonly AnyService[]>(\n options: TestAppOptions<S>,\n): Promise<TestApp<S>> {\n type P = PrincipalOfServices<S>;\n // The spread keeps `services` and `db` as given; TypeScript cannot see that\n // through the conditional `db` member of the options.\n const server = createServer<S>({\n ...instrumentOptions(options),\n logger: options.logger ?? quietLogger,\n rateLimit: options.rateLimit ?? false,\n auth: {\n authenticate: ({ auth }) => (isPrincipal(auth.principal) ? (auth.principal as P) : null),\n ...options.auth,\n },\n } as ServerOptions<S>);\n try {\n // The checks createServer starts in the background: a strict app fails to start on one.\n await startupChecksOf(server);\n } catch (error) {\n // The warning is the answer, whatever closing the server that never listened says.\n await server.close().catch(() => undefined);\n throw error;\n }\n adoptDispatcher(options.services, server.dispatcher);\n const frames = recordFrames(server.io);\n const unmeter = meterServer({ io: server.io, db: options.db, storage: options.storage });\n await new Promise<void>((resolve) => {\n server.httpServer.listen(0, \"127.0.0.1\", resolve);\n });\n const { port } = server.httpServer.address() as AddressInfo;\n const url = `http://127.0.0.1:${port}`;\n const sockets = new Set<ClientSocket>();\n\n return {\n url,\n server,\n frames,\n as: (principal) =>\n measuredCaller(\n withGrants(server.dispatcher.call, options.auth?.loadServiceAccess),\n principal,\n ) as Caller<ContractOfServices<S>>,\n async connect(principal) {\n const { socket, hello } = await connectV5(\n url,\n principal === null ? {} : { principal },\n TIMEOUT_MS,\n );\n sockets.add(socket);\n return {\n socket,\n hello,\n call: socketCaller(socket, TIMEOUT_MS) as Caller<ContractOfServices<S>>,\n close: () => {\n sockets.delete(socket);\n socket.disconnect();\n },\n };\n },\n async close() {\n unmeter();\n for (const socket of sockets) {\n socket.disconnect();\n }\n sockets.clear();\n await server.close();\n },\n };\n}\n","// A flush sink that keeps what it receives (RFC 0003 section 5.3), for tests\n// that assert which writes a method, a `qd.run` block or a job made:\n//\n// const sink = createRecordingSink();\n// const dispatcher = createDispatcher({ services, db: trackPrisma(prisma), flushSink: sink });\n// await dispatcher.caller(alice).taskService.rename({ id, title });\n// expect(sink.writes()).toEqual([expect.objectContaining({ model: \"task\", id, op: \"update\" })]);\n\nimport type { FlushInfo, FlushSink } from \"../server/uow/flushSink\";\nimport type { WriteRecord } from \"../server/uow/types\";\n\n/** One flush a recording sink received. */\nexport interface RecordedFlush {\n readonly writes: readonly WriteRecord[];\n readonly info: FlushInfo;\n}\n\n/** A flush sink that records every flush, from {@link createRecordingSink}. */\nexport interface RecordingSink extends FlushSink {\n /** Every flush received so far, oldest first. */\n readonly flushes: readonly RecordedFlush[];\n /** Every write received so far, in flush order. */\n writes(): WriteRecord[];\n /** Resolves with the next flush, or with the oldest one not yet taken by `next`. */\n next(): Promise<RecordedFlush>;\n /** Forgets every flush received so far. */\n clear(): void;\n}\n\n/** Creates a {@link RecordingSink}. */\nexport function createRecordingSink(): RecordingSink {\n const flushes: RecordedFlush[] = [];\n const waiting: ((flush: RecordedFlush) => void)[] = [];\n let taken = 0;\n return {\n flushes,\n flush(writes: readonly WriteRecord[], info: FlushInfo): Promise<void> {\n const flush = { writes: [...writes], info };\n flushes.push(flush);\n const resolve = waiting.shift();\n if (resolve === undefined) {\n return Promise.resolve();\n }\n taken = flushes.length;\n resolve(flush);\n return Promise.resolve();\n },\n writes: () => flushes.flatMap((flush) => flush.writes),\n next(): Promise<RecordedFlush> {\n const flush = flushes[taken];\n if (flush !== undefined) {\n taken += 1;\n return Promise.resolve(flush);\n }\n return new Promise((resolve) => {\n waiting.push(resolve);\n });\n },\n clear(): void {\n flushes.length = 0;\n taken = 0;\n },\n };\n}\n","// The inputs `snapshotAccessMatrix` makes for a method the app gives no input\n// for (`accessSnapshot.ts`): the row the cell is about, put where the\n// method's access form reads it, and the input's other required values made\n// from its Standard JSON Schema (Zod 4.2 or later), each as small as the\n// schema allows. An input is usable only when it passes the method's input\n// schema and, for an `entry` or `scope` form, names the cell's row where the\n// form looks for it: the form's own id selector decides, so a function `id`\n// is followed too. A keyless `todoSchema()` accepts `{}`, and an `entry` form\n// then refuses the missing id with `FORBIDDEN` for everyone: a cell that\n// looks plausible and means nothing. A cell without a usable input is never\n// called.\n\nimport { hasJsonSchema, validate } from \"../contract/standardSchema\";\nimport { accessIds, isCustomAccess } from \"../server/access/forms\";\nimport type { AccessForm, EntryAccess, ScopeAccess } from \"../server/access/types\";\nimport { inputKeys } from \"../server/emit/projection\";\nimport type { AnyService, ServiceMethod } from \"../server/service\";\n\ntype Json = Readonly<Record<string, unknown>>;\n\nfunction isRecord(value: unknown): value is Json {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\n/** How deep a schema is followed: past it, a value is left out (a recursive schema). */\nconst MAX_DEPTH = 12;\n\n/** Values JSON Schema has no form for become `{}` (any value), as the rowless check reads them (Zod 4). */\nconst UNREPRESENTABLE_AS_ANY = Object.freeze({ unrepresentable: \"any\" });\n\n/** A string of each string format the schema libraries write, valid for it. */\nconst FORMATS: Readonly<Record<string, string>> = Object.freeze({\n email: \"snapshot@example.com\",\n \"idn-email\": \"snapshot@example.com\",\n uri: \"https://example.com/\",\n url: \"https://example.com/\",\n \"uri-reference\": \"https://example.com/\",\n hostname: \"example.com\",\n uuid: \"00000000-0000-4000-8000-000000000000\",\n guid: \"00000000-0000-4000-8000-000000000000\",\n \"date-time\": \"2026-01-01T00:00:00.000Z\",\n date: \"2026-01-01\",\n time: \"00:00:00\",\n duration: \"P1D\",\n ipv4: \"127.0.0.1\",\n ipv6: \"::1\",\n cuid: \"cjld2cjxh0000qzrmn831i7rn\",\n cuid2: \"tz4a98xxat96iws9zmbrgj3a\",\n ulid: \"01ARZ3NDEKTSV4RRFFQ69G5FAV\",\n nanoid: \"V1StGXR8_Z5jdHi6B-myT\",\n e164: \"+15555550100\",\n});\n\n/** What a string with a `pattern` is tried with when its format's string does not match it. */\nconst PATTERN_CANDIDATES: readonly string[] = [\"x\", ...new Set(Object.values(FORMATS))];\n\n/** The node a JSON Schema node stands for: the one its `$ref` names in `root`, or itself. */\nfunction referenced(node: Json, root: Json): Json | undefined {\n const ref = node.$ref;\n if (typeof ref !== \"string\") {\n return node;\n }\n if (ref === \"#\") {\n return root;\n }\n const match = /^#\\/(definitions|\\$defs)\\/(.+)$/.exec(ref);\n const defs = match === null ? undefined : root[match[1] ?? \"\"];\n const target = isRecord(defs) ? defs[match?.[2] ?? \"\"] : undefined;\n return isRecord(target) ? target : undefined;\n}\n\n/** The node's type: `\"null\"` when a list of types allows it, `\"object\"` for bare properties. */\nfunction typeOf(node: Json): string | undefined {\n const { type } = node;\n if (typeof type === \"string\") {\n return type;\n }\n if (Array.isArray(type)) {\n const types = type.filter((each): each is string => typeof each === \"string\");\n return types.includes(\"null\") ? \"null\" : types[0];\n }\n return isRecord(node.properties) ? \"object\" : undefined;\n}\n\nfunction isNullBranch(node: unknown): boolean {\n return isRecord(node) && typeOf(node) === \"null\";\n}\n\n/** A test of a string against the node's `pattern`; `undefined` without one (or one this engine cannot read). */\nfunction patternOf(node: Json): ((value: string) => boolean) | undefined {\n if (typeof node.pattern !== \"string\") {\n return undefined;\n }\n try {\n const regex = new RegExp(node.pattern, \"u\");\n return (value) => regex.test(value);\n } catch {\n return undefined;\n }\n}\n\nfunction sampleString(node: Json): string {\n const format = typeof node.format === \"string\" ? FORMATS[node.format] : undefined;\n const matches = patternOf(node);\n let value = format ?? \"x\";\n if (matches !== undefined && !matches(value)) {\n value = PATTERN_CANDIDATES.find(matches) ?? value;\n }\n const min = typeof node.minLength === \"number\" ? node.minLength : 0;\n if (value.length < min) {\n value += \"x\".repeat(min - value.length);\n }\n return typeof node.maxLength === \"number\" ? value.slice(0, node.maxLength) : value;\n}\n\n/** The number nearest 0 within the node's bounds, on its `multipleOf`. */\nfunction sampleNumber(node: Json, integer: boolean): number {\n const { minimum, maximum, exclusiveMinimum, exclusiveMaximum, multipleOf } = node;\n let value = 0;\n if (typeof minimum === \"number\" && value < minimum) {\n value = integer ? Math.ceil(minimum) : minimum;\n }\n if (typeof exclusiveMinimum === \"number\" && value <= exclusiveMinimum) {\n value = Math.floor(exclusiveMinimum) + 1;\n }\n if (typeof maximum === \"number\" && value > maximum) {\n value = integer ? Math.floor(maximum) : maximum;\n }\n if (typeof exclusiveMaximum === \"number\" && value >= exclusiveMaximum) {\n value = Math.ceil(exclusiveMaximum) - 1;\n }\n if (typeof multipleOf === \"number\" && multipleOf > 0 && value % multipleOf !== 0) {\n value = Math.ceil(value / multipleOf) * multipleOf;\n }\n return value;\n}\n\n/** Every required property, each as small as it may be; one that allows anything is `null`. */\nfunction sampleObject(node: Json, root: Json, depth: number): Record<string, unknown> {\n const properties = isRecord(node.properties) ? node.properties : {};\n const required = Array.isArray(node.required) ? node.required : [];\n const value: Record<string, unknown> = {};\n for (const key of required) {\n if (typeof key === \"string\") {\n value[key] = sample(properties[key], root, depth + 1) ?? null;\n }\n }\n return value;\n}\n\n/** A tuple's items, or the fewest items a list allows. */\nfunction sampleArray(node: Json, root: Json, depth: number): unknown[] {\n let tuple: readonly unknown[] | undefined;\n if (Array.isArray(node.prefixItems)) {\n tuple = node.prefixItems;\n } else if (Array.isArray(node.items)) {\n tuple = node.items;\n }\n if (tuple !== undefined) {\n return tuple.map((item) => sample(item, root, depth + 1) ?? null);\n }\n const length = typeof node.minItems === \"number\" ? node.minItems : 0;\n return Array.from({ length }, () => sample(node.items, root, depth + 1) ?? null);\n}\n\n/** A value of each part of an `allOf`, merged when they are objects. */\nfunction sampleAll(parts: readonly unknown[], root: Json, depth: number): unknown {\n const values = parts.map((part) => sample(part, root, depth + 1));\n if (values.every((value) => isRecord(value) || value === undefined)) {\n return Object.assign({}, ...values) as unknown;\n }\n return values.find((value) => value !== undefined);\n}\n\n/** A value of the node's type; `undefined` for a node of no type, which allows anything. */\nfunction sampleType(node: Json, root: Json, depth: number): unknown {\n switch (typeOf(node)) {\n case \"object\":\n return sampleObject(node, root, depth);\n case \"array\":\n return sampleArray(node, root, depth);\n case \"string\":\n return sampleString(node);\n case \"integer\":\n return sampleNumber(node, true);\n case \"number\":\n return sampleNumber(node, false);\n case \"boolean\":\n return false;\n case \"null\":\n return null;\n default:\n return undefined;\n }\n}\n\n/**\n * The smallest value JSON Schema `node` allows: its `const`, the first of its\n * `enum`, `null` where a union allows it (else its first branch), the parts\n * of an `allOf` merged, or a value of its type (`sampleType`). `undefined`\n * for a schema that allows anything: at the top level, the input of a method\n * that takes none.\n */\nfunction sample(node: unknown, root: Json, depth: number): unknown {\n const target = isRecord(node) && depth <= MAX_DEPTH ? referenced(node, root) : undefined;\n if (target === undefined) {\n return undefined;\n }\n if (Object.hasOwn(target, \"const\")) {\n return target.const;\n }\n if (Array.isArray(target.enum) && target.enum.length > 0) {\n return target.enum[0] as unknown;\n }\n const branches = Array.isArray(target.anyOf) ? target.anyOf : target.oneOf;\n if (Array.isArray(branches) && branches.length > 0) {\n return branches.some(isNullBranch) ? null : sample(branches[0], root, depth + 1);\n }\n if (Array.isArray(target.allOf) && target.allOf.length > 0) {\n return sampleAll(target.allOf, root, depth);\n }\n return sampleType(target, root, depth);\n}\n\n/** A method's input as its JSON Schema describes it, read once per method. */\ninterface InputShape {\n /** The smallest input the schema allows; `undefined` without JSON Schema (a Zod 3 schema). */\n readonly skeleton: unknown;\n /** The JSON Schema document, for its `$ref`s. */\n readonly root: Json;\n /** The top-level properties, when the input is one object. */\n readonly properties: Json | undefined;\n /** True when the input itself is a string: a bare id. */\n readonly isString: boolean;\n}\n\nconst shapes = new WeakMap<ServiceMethod, InputShape>();\n\n/** The input's JSON Schema, or `undefined` when its schema cannot write one. */\nfunction jsonSchemaOf(method: ServiceMethod): Json | undefined {\n if (!hasJsonSchema(method.input)) {\n return undefined;\n }\n try {\n const json = method.input[\"~standard\"].jsonSchema.input({\n target: \"draft-07\",\n libraryOptions: UNREPRESENTABLE_AS_ANY,\n });\n return isRecord(json) ? json : undefined;\n } catch {\n return undefined;\n }\n}\n\nfunction shapeOf(method: ServiceMethod): InputShape {\n const known = shapes.get(method);\n if (known !== undefined) {\n return known;\n }\n const root = jsonSchemaOf(method);\n const described = root === undefined ? undefined : referenced(root, root);\n const shape: InputShape = {\n skeleton: root === undefined ? undefined : sample(root, root, 0),\n root: root ?? {},\n properties: isRecord(described?.properties) ? described.properties : undefined,\n isString: described !== undefined && typeOf(described) === \"string\",\n };\n shapes.set(method, shape);\n return shape;\n}\n\n/** The `entry` or `scope` part of a form, which reads a row id from the input; `undefined` for any other form. */\nexport function rowForm(form: AccessForm): EntryAccess | ScopeAccess | undefined {\n if (typeof form !== \"object\" || isCustomAccess(form)) {\n return undefined;\n }\n return form.entry === undefined && form.scope === undefined ? undefined : form;\n}\n\n/**\n * The service whose row a method's cells are about: the method's own for an\n * `entry` form, the `of` contract's for a `scope` form, and for any other\n * form its own when the input has a top-level `id` (a `rowless` method, a\n * `custom` check); `undefined` for a method about no row.\n */\nexport function rowServiceOf(service: AnyService, method: ServiceMethod): string | undefined {\n const form = rowForm(method.access);\n if (form?.scope !== undefined) {\n return form.of.name;\n }\n if (form !== undefined) {\n return service.name;\n }\n return inputKeys(method.input)?.includes(\"id\") === true ? service.name : undefined;\n}\n\n/** True when `node` may hold a row id: a string, a list, or a value it does not describe. */\nfunction mayHoldId(node: unknown): boolean {\n if (!isRecord(node)) {\n return true;\n }\n const type = typeOf(node);\n return type === undefined || type === \"string\" || type === \"array\" || type === \"null\";\n}\n\n/** The rank of a key a function selector may read the row from: `id` first, then `...Id` and `...Ids`. */\nfunction keyRank(key: string): number {\n if (key === \"id\" || key === \"ids\") {\n return 0;\n }\n return /Ids?$/.test(key) ? 1 : 2;\n}\n\n/** The input keys a function selector may read the row from, most likely first. */\nfunction selectorKeys(shape: InputShape): readonly string[] {\n const { properties } = shape;\n if (properties === undefined) {\n return shape.isString ? [] : [\"id\"];\n }\n return Object.keys(properties)\n .filter((key) => mayHoldId(properties[key]))\n .sort((a, b) => keyRank(a) - keyRank(b));\n}\n\n/** The row's id and a list of it, the list first when the key's schema is an array. */\nfunction idValues(shape: InputShape, key: string, row: string): readonly unknown[] {\n const node = shape.properties?.[key];\n const target = isRecord(node) ? referenced(node, shape.root) : undefined;\n return target !== undefined && typeOf(target) === \"array\" ? [[row], row] : [row, [row]];\n}\n\n/** The keys a cell's row may go at: where the form reads it, or `id` for a form that reads none. */\nfunction rowKeys(\n form: EntryAccess | ScopeAccess | undefined,\n shape: InputShape,\n): readonly string[] {\n if (form === undefined) {\n return [\"id\"];\n }\n if (typeof form.id === \"function\") {\n return selectorKeys(shape);\n }\n return [form.id ?? \"id\"];\n}\n\n/**\n * The inputs a cell tries, in order: the row put at each key it may go at\n * (for a form that reads no row, at the input's `id`), or the skeleton alone\n * for a cell about no row.\n */\nfunction candidates(method: ServiceMethod, row: string | undefined): readonly unknown[] {\n const shape = shapeOf(method);\n const form = rowForm(method.access);\n const hasId = form !== undefined || inputKeys(method.input)?.includes(\"id\") === true;\n if (row === undefined || !hasId) {\n return [shape.skeleton];\n }\n const base = isRecord(shape.skeleton) ? shape.skeleton : {};\n const placed = rowKeys(form, shape).flatMap((key) =>\n idValues(shape, key, row).map((value) => ({ ...base, [key]: value })),\n );\n const bare = typeof form?.id === \"function\" && (shape.isString || shape.properties === undefined);\n return bare ? [...placed, row] : placed;\n}\n\n/** True when `input` passes the method's input schema. */\nexport async function isValidInput(method: ServiceMethod, input: unknown): Promise<boolean> {\n const result = await validate(method.input, input);\n return result.issues === undefined;\n}\n\n/** True when the form reads `row` from the parsed input, as the access check will. */\nfunction namesRow(form: EntryAccess | ScopeAccess, parsed: unknown, row: string): boolean {\n try {\n return accessIds(form, parsed).includes(row);\n } catch {\n return false;\n }\n}\n\n/**\n * The input a cell about `row` calls `method` with, made from the method's\n * input schema: the first candidate that passes the schema and, for an\n * `entry` or `scope` form, names `row` where the form reads it. `undefined`\n * when none does: the cell is inconclusive and never called.\n */\nexport async function generatedInput(\n method: ServiceMethod,\n row: string | undefined,\n): Promise<{ readonly input: unknown } | undefined> {\n const form = rowForm(method.access);\n for (const input of candidates(method, row)) {\n const result = await validate(method.input, input);\n if (result.issues !== undefined) {\n continue;\n }\n if (form === undefined || (row !== undefined && namesRow(form, result.value, row))) {\n return { input };\n }\n }\n return undefined;\n}\n","// The access snapshot file (`accessSnapshot.ts`): `__access__/<test file>.json`\n// beside the test, `{ version: 1, principals, methods, subscriptions,\n// collections, excluded }` with every key sorted, so a change to who may\n// call what shows in a pull request as the lines that changed. What a run\n// does with it:\n//\n// - no file: it is written; under CI (`CI=1` or `CI=true`) that fails\n// instead, because a snapshot that writes itself pins nothing;\n// - a cell whose outcome changed, or a principal whose kind did: fails,\n// naming each, until QD_UPDATE_ACCESS_SNAPSHOT=1 (or `true`) rewrites the\n// file;\n// - cells added or removed only (a new method, principal or exclusion):\n// written locally, a failure under CI.\n//\n// QD_UPDATE_ACCESS_SNAPSHOT under CI fails: CI only compares. A budget may\n// write itself under CI (`budget.ts`); an access snapshot never does.\n\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { basename, dirname, join } from \"node:path\";\nimport {\n ACCESS_SECTIONS,\n compareAccessSnapshots,\n describeDifferences,\n describeReshape,\n hasDifferences,\n isReshaped,\n type AccessComparison,\n type AccessSnapshot,\n} from \"./accessSnapshotCompare\";\nimport { runnerState, shownPath, underCi, type RunnerState } from \"./budget\";\n\n/** The environment variable that rewrites access snapshots: `QD_UPDATE_ACCESS_SNAPSHOT=1` (or `true`). */\nexport const ACCESS_SNAPSHOT_ENV = \"QD_UPDATE_ACCESS_SNAPSHOT\";\n\n/** Whether {@link ACCESS_SNAPSHOT_ENV} asks to rewrite the snapshots: `1` or `true`. */\nexport function updateRequested(value = process.env[ACCESS_SNAPSHOT_ENV]): boolean {\n return value === \"1\" || value === \"true\";\n}\n\n/** What a run did with the snapshot file. */\nexport type AccessSnapshotChange = \"written\" | \"unchanged\" | \"updated\";\n\n/** The access snapshot file of `testFile`: `__access__/<its name>.json` in its directory. */\nexport function accessSnapshotFileOf(testFile: string): string {\n return join(dirname(testFile), \"__access__\", `${basename(testFile)}.json`);\n}\n\n/** Per runner, the snapshot files taken so far: path to the test that took it. */\nconst claimed = new WeakMap<object, Map<string, string>>();\nconst NO_RUNNER = {};\n\n/** Refuses a second test of one file taking a snapshot: they would rewrite each other's. A retry is allowed. */\nfunction claimFile(path: string, state: RunnerState): void {\n const runner = state.runner ?? NO_RUNNER;\n const files = claimed.get(runner) ?? new Map<string, string>();\n claimed.set(runner, files);\n const test = state.testName ?? \"\";\n const owner = files.get(path);\n if (owner !== undefined && owner !== test) {\n throw new TypeError(\n `snapshotAccessMatrix: two tests take an access snapshot into ${shownPath(path)} (\"${owner}\" and \"${test}\"); take one snapshot per test file (one test file per service, or pass { file })`,\n );\n }\n files.set(path, test);\n}\n\n/**\n * The snapshot file of a run: beside `file`, or beside the running test's\n * file (from the test runner). Throws a `TypeError` when there is neither,\n * and when another test of the file took a snapshot into it already.\n */\nexport function snapshotPathOf(file: string | undefined): string {\n const state = runnerState();\n const testFile = file ?? state.testPath;\n if (testFile === undefined) {\n throw new TypeError(\n \"snapshotAccessMatrix: no test file is running to put the snapshot beside; pass { file }\",\n );\n }\n const path = accessSnapshotFileOf(testFile);\n claimFile(path, state);\n return path;\n}\n\ntype Json = Readonly<Record<string, unknown>>;\n\nfunction isRecord(value: unknown): value is Json {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction isRow(value: unknown): boolean {\n return isRecord(value) && Object.values(value).every((cell) => typeof cell === \"string\");\n}\n\nfunction isPrincipal(value: unknown): boolean {\n return (\n value === null || (isRecord(value) && (value.kind === null || typeof value.kind === \"string\"))\n );\n}\n\nfunction isSnapshot(value: unknown): value is AccessSnapshot {\n if (!isRecord(value) || value.version !== 1 || !isRecord(value.principals)) {\n return false;\n }\n const { principals, excluded } = value;\n return (\n ACCESS_SECTIONS.every((section) => {\n const rows = value[section];\n return isRecord(rows) && Object.values(rows).every(isRow);\n }) &&\n Object.values(principals).every(isPrincipal) &&\n Array.isArray(excluded) &&\n excluded.every((name) => typeof name === \"string\")\n );\n}\n\n/** The snapshot stored at `path`, or `undefined` when there is no file; throws for a file that is not one. */\nexport function readAccessSnapshot(path: string): AccessSnapshot | undefined {\n if (!existsSync(path)) {\n return undefined;\n }\n let parsed: unknown;\n try {\n parsed = JSON.parse(readFileSync(path, \"utf8\"));\n } catch {\n parsed = undefined;\n }\n if (!isSnapshot(parsed)) {\n throw new Error(\n `snapshotAccessMatrix: ${shownPath(path)} is not an access snapshot ({ \"version\": 1, \"principals\", \"methods\", \"subscriptions\", \"collections\", \"excluded\" }); delete it to record the matrix again`,\n );\n }\n return parsed;\n}\n\n/** `value` with the keys of every object in it sorted: the same file on every machine. */\nfunction sortKeys(value: unknown): unknown {\n if (Array.isArray(value)) {\n return value.map(sortKeys);\n }\n if (!isRecord(value)) {\n return value;\n }\n return Object.fromEntries(\n Object.keys(value)\n .sort()\n .map((key) => [key, sortKeys(value[key])]),\n );\n}\n\n/** Writes `snapshot` to `path`, every key and the exclusions sorted, making its directory. */\nexport function writeAccessSnapshot(path: string, snapshot: AccessSnapshot): void {\n const sorted = { ...snapshot, excluded: [...snapshot.excluded].sort() };\n mkdirSync(dirname(path), { recursive: true });\n writeFileSync(path, `${JSON.stringify(sortKeys(sorted), null, 2)}\\n`);\n}\n\nfunction plural(count: number, one: string, many: string): string {\n return `${count} ${count === 1 ? one : many}`;\n}\n\n/** The line saying how many cells were never called, for the end of a message; none when all were. */\nfunction inconclusiveNote(inconclusive: readonly string[]): string[] {\n if (inconclusive.length === 0) {\n return [];\n }\n return [\n `${plural(inconclusive.length, \"cell was\", \"cells were\")} never called (VALIDATION): no input passed the method's input schema; give their inputs with inputs.`,\n ];\n}\n\n/** The error of a run whose cells or principals differ from the snapshot. */\nfunction differencesError(\n shown: string,\n comparison: AccessComparison,\n inconclusive: readonly string[],\n): Error {\n const counts = [\n ...(comparison.changed.length > 0\n ? [plural(comparison.changed.length, \"cell differs\", \"cells differ\")]\n : []),\n ...(comparison.principals.length > 0\n ? [plural(comparison.principals.length, \"principal differs\", \"principals differ\")]\n : []),\n ];\n return new Error(\n [\n `snapshotAccessMatrix: ${counts.join(\" and \")} from the access snapshot (${shown}):`,\n ...describeDifferences(comparison),\n ...(isReshaped(comparison) ? describeReshape(comparison) : []),\n `If every change is meant, run the tests again with ${ACCESS_SNAPSHOT_ENV}=1, review the file and commit it.`,\n ...inconclusiveNote(inconclusive),\n ].join(\"\\n\"),\n );\n}\n\n/**\n * Compares a run's `snapshot` with the file at `path` and writes the file\n * when the rules allow (see the module comment); throws when they do not.\n * `inconclusive` lists the cells never called, for the messages.\n */\nexport function settleSnapshot(\n path: string,\n snapshot: AccessSnapshot,\n inconclusive: readonly string[],\n): AccessSnapshotChange {\n const shown = shownPath(path);\n const ci = underCi();\n const update = updateRequested();\n if (update && ci) {\n throw new Error(\n `snapshotAccessMatrix: ${ACCESS_SNAPSHOT_ENV} is set under CI, where an access snapshot is only compared: rewrite ${shown} locally, review it and commit it`,\n );\n }\n const stored = readAccessSnapshot(path);\n if (stored === undefined) {\n if (ci) {\n throw new Error(\n [\n `snapshotAccessMatrix: there is no access snapshot at ${shown}, and under CI none is written: a snapshot that writes itself pins nothing.`,\n \"Run the tests locally to record it, review it and commit it.\",\n ...inconclusiveNote(inconclusive),\n ].join(\"\\n\"),\n );\n }\n writeAccessSnapshot(path, snapshot);\n return \"written\";\n }\n const comparison = compareAccessSnapshots(stored, snapshot);\n const differs = hasDifferences(comparison);\n if (!differs && !isReshaped(comparison)) {\n return \"unchanged\";\n }\n if (differs && !update) {\n throw differencesError(shown, comparison, inconclusive);\n }\n if (ci) {\n throw new Error(\n [\n `snapshotAccessMatrix: the access matrix has other cells than its snapshot (${shown}); rerun locally to accept:`,\n ...describeReshape(comparison),\n \"Run the tests without CI to write the snapshot, review it and commit it.\",\n ...inconclusiveNote(inconclusive),\n ].join(\"\\n\"),\n );\n }\n writeAccessSnapshot(path, snapshot);\n return \"updated\";\n}\n","// What an access snapshot holds (`accessSnapshot.ts`), and how a run's\n// matrix is compared with the stored one: the cells whose outcome changed\n// (each marked when it opens or closes access), the principals whose kind\n// changed, and the rows, principals and cells only one side has. A row of a\n// section is one method, entity subscribe or collection scope (with its row\n// variant), and holds one outcome per principal.\n\nimport type { ErrorCode } from \"../protocol/errors\";\n\n/** What one cell recorded: `\"ok\"`, or the error code the call or subscribe failed with. */\nexport type AccessOutcome = \"ok\" | ErrorCode;\n\n/**\n * A principal as the snapshot records it: its `kind` (`null` for a principal\n * without one), or `null` for the anonymous caller.\n */\nexport type AccessSnapshotPrincipal = { readonly kind: string | null } | null;\n\n/** One row of the matrix (a method, subscribe or scope, with its row variant): an outcome per principal. */\nexport type AccessSnapshotRow = Readonly<Record<string, AccessOutcome>>;\n\n/** The contents of an access snapshot file. */\nexport interface AccessSnapshot {\n readonly version: 1;\n /** Every principal of the matrix, the anonymous caller included, by name. */\n readonly principals: Readonly<Record<string, AccessSnapshotPrincipal>>;\n /** Method calls: `<service>.<method>`, plus ` (<variant>)` for a row variant. */\n readonly methods: Readonly<Record<string, AccessSnapshotRow>>;\n /** Entity subscribes (`qd:sub`): `<service>`, plus ` (<variant>)`. */\n readonly subscriptions: Readonly<Record<string, AccessSnapshotRow>>;\n /** Collection scopes (`qd:col:sub`): `<service>.<collection>`, plus ` (<variant>)` (`(self)` for a `\"self\"` scope). */\n readonly collections: Readonly<Record<string, AccessSnapshotRow>>;\n /** The methods left out with `exclude`, as `<service>.<method>`. */\n readonly excluded: readonly string[];\n}\n\n/** The sections of a snapshot that hold cells. */\nexport const ACCESS_SECTIONS = [\"methods\", \"subscriptions\", \"collections\"] as const;\n\n/** A section of a snapshot that holds cells. */\nexport type AccessSection = (typeof ACCESS_SECTIONS)[number];\n\n/** How a section's rows are named in a message: a subscribe or scope by its frame. */\nconst SECTION_PREFIX: Readonly<Record<AccessSection, string>> = Object.freeze({\n methods: \"\",\n subscriptions: \"qd:sub \",\n collections: \"qd:col:sub \",\n});\n\n/** One cell that differs between the stored snapshot and the run. */\nexport interface AccessCellChange {\n readonly section: AccessSection;\n /** The row's key in its section: `taskService.get (own)`. */\n readonly row: string;\n readonly principal: string;\n /** What the snapshot holds; `undefined` for a cell it does not have. */\n readonly before: AccessOutcome | undefined;\n /** What the run recorded; `undefined` for a cell it no longer has. */\n readonly after: AccessOutcome | undefined;\n}\n\n/** A principal of both whose record differs: another kind, or anonymous on one side only. */\nexport interface AccessPrincipalChange {\n readonly name: string;\n readonly before: AccessSnapshotPrincipal;\n readonly after: AccessSnapshotPrincipal;\n}\n\n/** How a run's matrix differs from the stored snapshot. */\nexport interface AccessComparison {\n /** Cells both have whose outcome differs. */\n readonly changed: readonly AccessCellChange[];\n /** Principals both have whose record differs. */\n readonly principals: readonly AccessPrincipalChange[];\n /** Rows only the run has, as a message names them (`qd:sub taskService (own)`). */\n readonly rowsAdded: readonly string[];\n /** Rows only the snapshot has. */\n readonly rowsRemoved: readonly string[];\n readonly principalsAdded: readonly string[];\n readonly principalsRemoved: readonly string[];\n /** Cells of rows and principals both have that only one side holds (an edited file). */\n readonly cells: readonly AccessCellChange[];\n /** Methods newly excluded. */\n readonly excludedAdded: readonly string[];\n /** Methods no longer excluded. */\n readonly excludedRemoved: readonly string[];\n}\n\n/** The items of `items` that `other` lacks, sorted. */\nfunction only(items: Iterable<string>, other: ReadonlySet<string>): string[] {\n return [...items].filter((item) => !other.has(item)).sort();\n}\n\nfunction samePrincipal(a: AccessSnapshotPrincipal, b: AccessSnapshotPrincipal): boolean {\n return a === null || b === null ? a === b : a.kind === b.kind;\n}\n\nfunction cellOf(row: AccessSnapshotRow, principal: string): AccessOutcome | undefined {\n return Object.hasOwn(row, principal) ? row[principal] : undefined;\n}\n\n/** The differing cells of one row both sides have, among the principals both have. */\nfunction compareRow(\n section: AccessSection,\n row: string,\n sides: { readonly before: AccessSnapshotRow; readonly after: AccessSnapshotRow },\n principals: readonly string[],\n): AccessCellChange[] {\n return principals.flatMap((principal) => {\n const before = cellOf(sides.before, principal);\n const after = cellOf(sides.after, principal);\n return before === after ? [] : [{ section, row, principal, before, after }];\n });\n}\n\n/** The principals both sides have whose record differs. */\nfunction comparePrincipals(\n before: AccessSnapshot,\n after: AccessSnapshot,\n shared: readonly string[],\n): AccessPrincipalChange[] {\n return shared.flatMap((name) => {\n const was = before.principals[name] ?? null;\n const is = after.principals[name] ?? null;\n return samePrincipal(was, is) ? [] : [{ name, before: was, after: is }];\n });\n}\n\n/** Compares a run's matrix (`after`) with the stored snapshot (`before`). */\nexport function compareAccessSnapshots(\n before: AccessSnapshot,\n after: AccessSnapshot,\n): AccessComparison {\n const namesBefore = new Set(Object.keys(before.principals));\n const namesAfter = new Set(Object.keys(after.principals));\n const shared = [...namesAfter].filter((name) => namesBefore.has(name)).sort();\n const differing: AccessCellChange[] = [];\n const rowsAdded: string[] = [];\n const rowsRemoved: string[] = [];\n for (const section of ACCESS_SECTIONS) {\n const rowsBefore = new Set(Object.keys(before[section]));\n const rowsAfter = new Set(Object.keys(after[section]));\n const prefix = SECTION_PREFIX[section];\n rowsAdded.push(...only(rowsAfter, rowsBefore).map((row) => prefix + row));\n rowsRemoved.push(...only(rowsBefore, rowsAfter).map((row) => prefix + row));\n for (const row of [...rowsAfter].filter((key) => rowsBefore.has(key)).sort()) {\n const sides = { before: before[section][row] ?? {}, after: after[section][row] ?? {} };\n differing.push(...compareRow(section, row, sides, shared));\n }\n }\n const excludedBefore = new Set(before.excluded);\n const excludedAfter = new Set(after.excluded);\n const oneSided = (change: AccessCellChange): boolean =>\n change.before === undefined || change.after === undefined;\n return {\n changed: differing.filter((change) => !oneSided(change)),\n principals: comparePrincipals(before, after, shared),\n rowsAdded,\n rowsRemoved,\n principalsAdded: only(namesAfter, namesBefore),\n principalsRemoved: only(namesBefore, namesAfter),\n cells: differing.filter(oneSided),\n excludedAdded: only(excludedAfter, excludedBefore),\n excludedRemoved: only(excludedBefore, excludedAfter),\n };\n}\n\n/** True when a cell's outcome or a principal changed: what fails until the change is accepted. */\nexport function hasDifferences(comparison: AccessComparison): boolean {\n return comparison.changed.length > 0 || comparison.principals.length > 0;\n}\n\n/** True when the matrix has other rows, principals, cells or exclusions than the snapshot. */\nexport function isReshaped(comparison: AccessComparison): boolean {\n return [\n comparison.rowsAdded,\n comparison.rowsRemoved,\n comparison.principalsAdded,\n comparison.principalsRemoved,\n comparison.cells,\n comparison.excludedAdded,\n comparison.excludedRemoved,\n ].some((list) => list.length > 0);\n}\n\n/** An outcome that refuses the caller. */\nfunction denies(outcome: AccessOutcome | undefined): boolean {\n return outcome === \"UNAUTHENTICATED\" || outcome === \"FORBIDDEN\";\n}\n\n/** An outcome that says access let the call through: anything but a refusal or an unusable input. */\nfunction passes(outcome: AccessOutcome | undefined): boolean {\n return outcome !== undefined && outcome !== \"VALIDATION\" && !denies(outcome);\n}\n\n/** Whether a changed cell opens access (a refusal became a pass), closes it, or neither. */\nexport function accessFlip(change: AccessCellChange): \"opens access\" | \"closes access\" | undefined {\n if (denies(change.before) && passes(change.after)) {\n return \"opens access\";\n }\n if (passes(change.before) && denies(change.after)) {\n return \"closes access\";\n }\n return undefined;\n}\n\n/** A cell as a message names it: `taskService.get (own) as bo`, `qd:sub taskService as bo`. */\nexport function cellName(cell: Pick<AccessCellChange, \"section\" | \"row\" | \"principal\">): string {\n return `${SECTION_PREFIX[cell.section]}${cell.row} as ${cell.principal}`;\n}\n\n/** At most this many lines of one kind in a message. */\nconst MAX_LINES = 50;\n\nfunction capped(lines: readonly string[]): string[] {\n if (lines.length <= MAX_LINES) {\n return [...lines];\n }\n return [...lines.slice(0, MAX_LINES), ` ... and ${lines.length - MAX_LINES} more`];\n}\n\nfunction shownPrincipal(principal: AccessSnapshotPrincipal): string {\n if (principal === null) {\n return \"anonymous\";\n }\n return principal.kind === null ? \"no kind\" : `kind ${principal.kind}`;\n}\n\n/** Where a changed cell goes in a message: those that open access first, then those that close it. */\nfunction flipRank(change: AccessCellChange): number {\n const flip = accessFlip(change);\n if (flip === \"opens access\") {\n return 0;\n }\n return flip === \"closes access\" ? 1 : 2;\n}\n\n/** One line per changed principal and cell, the cells that open access first, then those that close it. */\nexport function describeDifferences(comparison: AccessComparison): string[] {\n const principals = comparison.principals.map(\n (change) =>\n ` principal ${change.name}: ${shownPrincipal(change.before)} → ${shownPrincipal(change.after)}`,\n );\n const cells = [...comparison.changed]\n .sort((a, b) => flipRank(a) - flipRank(b))\n .map((change) => {\n const flip = accessFlip(change);\n const line = ` ${cellName(change)}: ${String(change.before)} → ${String(change.after)}`;\n return flip === undefined ? line : `${line} (${flip})`;\n });\n return [...capped(principals), ...capped(cells)];\n}\n\n/** One line per row, principal, cell and exclusion only one side has. */\nexport function describeReshape(comparison: AccessComparison): string[] {\n const lines = (label: string, items: readonly string[]): string[] =>\n capped(items.map((item) => ` ${label}: ${item}`));\n const cells = comparison.cells.map(\n (cell) => `${cellName(cell)}: ${cell.before ?? \"none\"} → ${cell.after ?? \"none\"}`,\n );\n return [\n ...lines(\"added\", comparison.rowsAdded),\n ...lines(\"removed\", comparison.rowsRemoved),\n ...lines(\"added principal\", comparison.principalsAdded),\n ...lines(\"removed principal\", comparison.principalsRemoved),\n ...lines(\"now excluded\", comparison.excludedAdded),\n ...lines(\"no longer excluded\", comparison.excludedRemoved),\n ...lines(\"cell\", cells),\n ];\n}\n","// `describeAccessMatrix` (RFC 0003 section 13): runs each case (a method and\n// its input) as each principal, and anonymously, through a running test app,\n// and compares every outcome with the expected allow/deny table. The calls go\n// through the app's real dispatcher (in process, or over real sockets), so\n// the matrix exercises the pipeline's authorization stage, not an engine in\n// isolation.\n//\n// await describeAccessMatrix(app, {\n// service: taskService,\n// principals: { owner, member, stranger },\n// cases: [\n// { method: \"get\", input: { id }, allow: [\"owner\", \"member\"] },\n// { method: \"rename\", input: { id, title: \"x\" }, allow: [\"owner\"] },\n// ],\n// });\n//\n// Each cell records the principal's `kind`, so a matrix over principals of\n// several kinds (a user, an agent's token) shows which kind each outcome is\n// for: a method's `kinds` refuses the others with `FORBIDDEN`, before its\n// access form, and the report names the kind of each cell that differs.\n//\n// Every cell calls the method for real, so a mutation runs once per principal\n// it allows: give inputs that can run again, or `input` as a function, called\n// for each cell with the principal it runs as, which makes a fresh row (a\n// task to delete, a name not yet taken) so no cell depends on the cells\n// before it, whatever the order of the principals:\n//\n// { method: \"remove\", input: async () => ({ id: await newTask() }), allow: [\"owner\"] }\n\nimport type { AnyContract } from \"../contract/defineContract\";\nimport type { InputOf, MethodName } from \"../contract/infer\";\nimport { QuickdrawError, type ErrorCode } from \"../protocol/errors\";\nimport type { PrincipalOfServices } from \"../server/dispatcher\";\nimport type { AnyService, Service } from \"../server/service\";\nimport type { Principal, QuickdrawTypes } from \"../server/types\";\nimport type { TestApp, TestConnection } from \"./createTestApp\";\n\n/**\n * What one cell expects: `\"allow\"` (the call succeeds), `\"deny\"` (it fails\n * with `UNAUTHENTICATED` without a principal and `FORBIDDEN` with one), or\n * the exact error code.\n */\nexport type MatrixOutcome = \"allow\" | \"deny\" | ErrorCode;\n\n/** The name the anonymous caller has in a matrix, unless `principals` names one as `null`. */\nexport const ANONYMOUS = \"anonymous\";\n\n/** The cell an input factory makes the input of: who the call runs as. */\nexport interface MatrixCell<Name extends string = string, P = Principal> {\n /** The principal's name in the matrix (`\"anonymous\"` for the added anonymous caller). */\n readonly name: Name;\n /** The principal itself, or `null` for an anonymous caller. */\n readonly principal: P | null;\n}\n\n/** A case's input made per cell: a fresh row for a mutation that cannot run twice on one. */\nexport type MatrixInputFactory<Input, Name extends string = string, P = Principal> = (\n cell: MatrixCell<Name, P>,\n) => Input | PromiseLike<Input>;\n\n/** One row of the matrix: a method, its input, and who may call it. */\nexport type AccessMatrixCase<C extends AnyContract, Name extends string, P = Principal> = {\n readonly [M in MethodName<C>]: {\n readonly method: M;\n /**\n * The input, or a function making it for each cell (called just before\n * that cell's call), so a mutation that can run once per row (a delete,\n * a unique name) gets a row of its own in every cell.\n */\n readonly input: InputOf<C, M> | MatrixInputFactory<InputOf<C, M>, Name, P>;\n /** Names the case in the report; default the method name. */\n readonly label?: string;\n /** The principals the call succeeds for; it is denied for everyone else. */\n readonly allow?: readonly Name[];\n /** Outcomes per principal, over `allow`. */\n readonly expect?: Partial<Readonly<Record<Name, MatrixOutcome>>>;\n };\n}[MethodName<C>];\n\n/** Options of {@link describeAccessMatrix}. */\nexport interface AccessMatrixOptions<C extends AnyContract, P, Name extends string> {\n /** The service whose methods the cases call; the app must serve it. */\n readonly service: Service<QuickdrawTypes, C>;\n /** The callers, by name. An anonymous caller named `\"anonymous\"` is added unless one is `null`. */\n readonly principals: Readonly<Record<Name, P | null>>;\n readonly cases: readonly AccessMatrixCase<C, NoInfer<Name> | typeof ANONYMOUS, NoInfer<P>>[];\n /** Call in process (`\"caller\"`, the default) or over a real socket per principal. */\n readonly via?: \"caller\" | \"socket\";\n}\n\n/** One cell: a case run as one principal. */\nexport interface AccessMatrixCell {\n readonly case: string;\n readonly principal: string;\n /** The principal's `kind`; `undefined` for the anonymous caller and a principal without one. */\n readonly kind: string | undefined;\n readonly expected: MatrixOutcome;\n /** `\"allow\"` when the call succeeded, or its error code. */\n readonly actual: \"allow\" | ErrorCode;\n readonly pass: boolean;\n}\n\n/** What {@link describeAccessMatrix} found: every cell, in order. */\nexport interface AccessMatrixReport {\n readonly cells: readonly AccessMatrixCell[];\n}\n\ntype MethodFunction = (input: unknown) => Promise<unknown>;\ntype ServiceFunctions = Readonly<Record<string, MethodFunction>>;\n\nfunction matches(expected: MatrixOutcome, actual: string, anonymous: boolean): boolean {\n if (expected === \"deny\") {\n return actual === (anonymous ? \"UNAUTHENTICATED\" : \"FORBIDDEN\");\n }\n return expected === actual;\n}\n\nasync function outcomeOf(call: () => Promise<unknown>): Promise<\"allow\" | ErrorCode> {\n try {\n await call();\n return \"allow\";\n } catch (error) {\n if (error instanceof QuickdrawError) {\n return error.code;\n }\n throw error;\n }\n}\n\nfunction report(serviceName: string, cells: readonly AccessMatrixCell[]): string {\n const failed = cells.filter((cell) => !cell.pass);\n const lines = failed.map((cell) => {\n const kind = cell.kind === undefined ? \"\" : ` (kind ${cell.kind})`;\n return ` ${cell.case} as ${cell.principal}${kind}: expected ${cell.expected}, got ${cell.actual}`;\n });\n return `describeAccessMatrix(${serviceName}): ${failed.length} of ${cells.length} cells differ\\n${lines.join(\"\\n\")}`;\n}\n\n/** The callers of each principal: in process, or over one socket each (closed by `close`). */\nfunction callers<S extends readonly AnyService[]>(\n app: TestApp<S>,\n serviceName: string,\n via: \"caller\" | \"socket\",\n): { of(principal: PrincipalOfServices<S> | null): Promise<ServiceFunctions>; close(): void } {\n const connections = new Map<unknown, Promise<TestConnection<S>>>();\n const pick = (caller: unknown): ServiceFunctions =>\n (caller as Readonly<Record<string, ServiceFunctions>>)[serviceName] ?? {};\n return {\n async of(principal) {\n if (via === \"caller\") {\n return pick(app.as(principal));\n }\n let connection = connections.get(principal);\n if (connection === undefined) {\n connection = app.connect(principal);\n connections.set(principal, connection);\n }\n return pick((await connection).call);\n },\n close() {\n for (const connection of connections.values()) {\n connection.then(\n (open) => open.close(),\n () => undefined,\n );\n }\n },\n };\n}\n\n/**\n * Runs every case as every principal, and anonymously, through `app` (from\n * `createTestApp`), and compares each outcome with the case's `allow` or\n * `expect`. Resolves with every cell; rejects with an `Error` listing each\n * cell that differs.\n */\nexport async function describeAccessMatrix<\n S extends readonly AnyService[],\n C extends AnyContract,\n const Name extends string,\n>(\n app: TestApp<S>,\n options: AccessMatrixOptions<C, PrincipalOfServices<S>, Name>,\n): Promise<AccessMatrixReport> {\n const { service, cases } = options;\n if (app.server.dispatcher.registry.services.get(service.name) !== service) {\n throw new TypeError(`describeAccessMatrix: the app does not serve ${service.name}`);\n }\n const principals: [string, PrincipalOfServices<S> | null][] = Object.entries(options.principals);\n if (!principals.some(([, principal]) => principal === null)) {\n principals.push([ANONYMOUS, null]);\n }\n const via = callers(app, service.name, options.via ?? \"caller\");\n const cells: AccessMatrixCell[] = [];\n try {\n for (const entry of cases) {\n const expectations: Partial<Record<string, MatrixOutcome>> = entry.expect ?? {};\n for (const [name, principal] of principals) {\n const allowed = (entry.allow as readonly string[] | undefined)?.includes(name) === true;\n const expected = expectations[name] ?? (allowed ? \"allow\" : \"deny\");\n const method = (await via.of(principal))[entry.method];\n if (method === undefined) {\n throw new TypeError(`describeAccessMatrix: ${service.name} has no ${entry.method}`);\n }\n const { input } = entry as { readonly input: unknown };\n const made =\n typeof input === \"function\"\n ? await (input as MatrixInputFactory<unknown>)({ name, principal })\n : input;\n const actual = await outcomeOf(() => method(made));\n const pass = matches(expected, actual, principal === null);\n cells.push({\n case: entry.label ?? entry.method,\n principal: name,\n kind: principal?.kind,\n expected,\n actual,\n pass,\n });\n }\n }\n } finally {\n via.close();\n }\n if (cells.some((cell) => !cell.pass)) {\n throw new Error(report(service.name, cells));\n }\n return { cells };\n}\n","// What `snapshotAccessMatrix` will run (`accessSnapshot.ts`), read from its\n// options and the app before any cell: the principals and rows a fixture\n// gives, checked, and the rows of the matrix. A method has one row per\n// variant of the row it is about (`accessInputs.ts`, `rowServiceOf`), an\n// entity subscribe one per variant of its service's rows, and a collection\n// one per variant of its anchor's rows (a `\"self\"` scope one, `(self)`).\n// `rows` must name every service those are about: a matrix of cells that\n// could reach no row pins nothing, so a missing service fails before any\n// cell runs.\n\nimport type { AnyService, ServiceMethod } from \"../server/service\";\nimport { rowServiceOf } from \"./accessInputs\";\nimport { ANONYMOUS } from \"./accessMatrix\";\nimport type { TestApp } from \"./createTestApp\";\n\n/** The row ids a matrix's cells are about, by service name: one id, or named variants (`{ own, other }`). */\nexport type AccessRows = Readonly<Record<string, string | Readonly<Record<string, string>>>>;\n\n/** The callers of a matrix by name, or a function of the fixture making them. */\nexport type AccessPrincipals<P, Fixture, Name extends string = string> =\n | Readonly<Record<Name, P | null>>\n | ((fixture: Fixture) => Readonly<Record<Name, P | null>>);\n\n/** The rows of one fixture: per service, its row id by variant (`undefined` for a single id). */\nexport type Rows = ReadonlyMap<string, ReadonlyMap<string | undefined, string>>;\n\n/** A method of the matrix, for one row variant. */\nexport interface MethodRow {\n /** The row's key in the snapshot: `<service>.<method>`, plus ` (<variant>)`. */\n readonly key: string;\n readonly service: AnyService;\n readonly method: ServiceMethod;\n /** The service whose row the method is about; `undefined` for a method about no row. */\n readonly rowService: string | undefined;\n readonly variant: string | undefined;\n}\n\n/** An entity subscribe of the matrix: every row variant of one service, in one `qd:sub`. */\nexport interface SubscribeRow {\n readonly service: string;\n /** The rows' keys in the snapshot, by variant. */\n readonly keys: ReadonlyMap<string | undefined, string>;\n}\n\n/** A collection scope of the matrix, for one row variant of its anchor (or the caller's own id). */\nexport interface ScopeRow {\n readonly key: string;\n readonly service: string;\n readonly collection: string;\n /** The anchor service; `undefined` for a `\"self\"` scope, whose value is the caller's user id. */\n readonly anchor: string | undefined;\n readonly variant: string | undefined;\n}\n\n/** Every row of the matrix, in the order a principal runs them, and the methods left out. */\nexport interface Plan {\n readonly subscribes: readonly SubscribeRow[];\n readonly scopes: readonly ScopeRow[];\n readonly queries: readonly MethodRow[];\n readonly mutations: readonly MethodRow[];\n readonly excluded: readonly string[];\n}\n\ntype Json = Readonly<Record<string, unknown>>;\n\nexport function isRecord(value: unknown): value is Json {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\n/** Throws the `TypeError` of a matrix that cannot run as given. */\nexport function fail(message: string): never {\n throw new TypeError(`snapshotAccessMatrix: ${message}`);\n}\n\n/** By name, in UTF-16 code unit order: the same order on every machine. */\nfunction byName(a: string, b: string): number {\n if (a === b) {\n return 0;\n }\n return a < b ? -1 : 1;\n}\n\n/** A row's key: its base, plus ` (<variant>)` for a named variant. */\nexport function keyOf(base: string, variant: string | undefined): string {\n return variant === undefined ? base : `${base} (${variant})`;\n}\n\n/** The principals `given` makes for `fixture`, plus the anonymous caller unless one is `null`. */\nexport function readPrincipals<P, Fixture>(\n given: AccessPrincipals<P, Fixture>,\n fixture: Fixture,\n): Map<string, P | null> {\n const record: unknown = typeof given === \"function\" ? given(fixture) : given;\n if (!isRecord(record)) {\n fail(\"principals must map names to principals (null for an anonymous caller)\");\n }\n const principals = new Map<string, P | null>();\n for (const [name, principal] of Object.entries(record)) {\n if (principal !== null && !isRecord(principal)) {\n fail(`principals.${name} must be a principal, or null for an anonymous caller`);\n }\n principals.set(name, principal as P | null);\n }\n if (![...principals.values()].includes(null)) {\n if (principals.has(ANONYMOUS)) {\n fail(\n `a principal is named \"${ANONYMOUS}\", the name of the anonymous caller added for you: name your anonymous caller with null, or rename that principal`,\n );\n }\n principals.set(ANONYMOUS, null);\n }\n return principals;\n}\n\n/** The variants of one service's entry in `rows`, checked. */\nfunction variantsIn(service: string, value: unknown): Map<string | undefined, string> {\n if (typeof value === \"string\" && value.length > 0) {\n return new Map([[undefined, value]]);\n }\n const entries = isRecord(value) ? Object.entries(value) : [];\n const ids: [string, string][] = [];\n for (const [variant, id] of entries) {\n if (typeof id === \"string\" && id.length > 0) {\n ids.push([variant, id]);\n }\n }\n if (ids.length === 0 || ids.length !== entries.length) {\n fail(`rows.${service} must be a row id, or named row ids ({ own: id, other: id })`);\n }\n return new Map(ids.sort(([a], [b]) => byName(a, b)));\n}\n\n/** The rows `rows(fixture)` gave: every service it names must be served, and every id a non-empty string. */\nexport function readRows(given: unknown, served: ReadonlyMap<string, AnyService>): Rows {\n if (!isRecord(given)) {\n fail(\"rows(fixture) must map service names to a row id, or to named row ids\");\n }\n const rows = new Map<string, ReadonlyMap<string | undefined, string>>();\n for (const [service, value] of Object.entries(given)) {\n if (!served.has(service)) {\n fail(`rows names ${service}, which the app does not serve`);\n }\n rows.set(service, variantsIn(service, value));\n }\n return rows;\n}\n\n/** True when two fixtures' principals and rows have the same names: the matrix's rows and columns. */\nexport function sameShape(\n a: { readonly principals: ReadonlyMap<string, unknown>; readonly rows: Rows },\n b: { readonly principals: ReadonlyMap<string, unknown>; readonly rows: Rows },\n): boolean {\n const names = (map: ReadonlyMap<unknown, unknown>): string => [...map.keys()].join(\"\\n\");\n const rows = (of: Rows): string =>\n [...of].map(([service, ids]) => `${service}:${names(ids)}`).join(\"\\n\\n\");\n return names(a.principals) === names(b.principals) && rows(a.rows) === rows(b.rows);\n}\n\n/** The variants of a service's rows: `[undefined]` for a single id, or for a method about no row. */\nexport function variantsOf(rows: Rows, service: string | undefined): (string | undefined)[] {\n const ids = service === undefined ? undefined : rows.get(service);\n return ids === undefined ? [undefined] : [...ids.keys()];\n}\n\n/** The services the matrix covers (default every service the app serves), each served, by name. */\nexport function servicesOf(app: TestApp, given: readonly AnyService[] | undefined): AnyService[] {\n const { services } = app.server.dispatcher.registry;\n if (given === undefined) {\n return [...services.values()].sort((a, b) => byName(a.name, b.name));\n }\n if (!Array.isArray(given)) {\n fail(\"services must be a list of services the app serves\");\n }\n for (const service of given) {\n if (services.get(service.name) !== service) {\n fail(`the app does not serve ${service.name}`);\n }\n }\n return [...new Set(given)].sort((a, b) => byName(a.name, b.name));\n}\n\n/** The methods `exclude` names, each a method of the matrix's services. */\nexport function excludedOf(\n services: readonly AnyService[],\n given: readonly string[] | undefined,\n): Set<string> {\n const known = new Set(\n services.flatMap((service) =>\n Object.keys(service.methods).map((name) => `${service.name}.${name}`),\n ),\n );\n if (given !== undefined && !Array.isArray(given)) {\n fail(\"exclude must be a list of methods, as <service>.<method>\");\n }\n const excluded = new Set<string>();\n for (const name of given ?? []) {\n if (typeof name !== \"string\" || !known.has(name)) {\n fail(\n `exclude names ${String(name)}, which is no method (<service>.<method>) of the matrix's services`,\n );\n }\n excluded.add(name);\n }\n return excluded;\n}\n\n/** The methods of the matrix, one row per variant of the row each is about. */\nfunction methodRows(\n services: readonly AnyService[],\n excluded: ReadonlySet<string>,\n rows: Rows,\n): MethodRow[] {\n const list: MethodRow[] = [];\n for (const service of services) {\n for (const name of Object.keys(service.methods).sort(byName)) {\n const method = service.methods[name];\n const base = `${service.name}.${name}`;\n if (method === undefined || excluded.has(base)) {\n continue;\n }\n const rowService = rowServiceOf(service, method);\n for (const variant of variantsOf(rows, rowService)) {\n list.push({ key: keyOf(base, variant), service, method, rowService, variant });\n }\n }\n }\n return list;\n}\n\n/** The entity subscribes of the matrix: one per service with rows to subscribe to. */\nfunction subscribeRows(services: readonly AnyService[], rows: Rows): SubscribeRow[] {\n return services\n .filter((service) => service.model !== undefined && service.contract.entity !== undefined)\n .map((service) => ({\n service: service.name,\n keys: new Map(\n variantsOf(rows, service.name).map((variant) => [variant, keyOf(service.name, variant)]),\n ),\n }));\n}\n\n/** The collection scopes of the matrix: one per variant of each collection's anchor, `(self)` for a self scope. */\nfunction scopeRows(services: readonly AnyService[], rows: Rows): ScopeRow[] {\n const list: ScopeRow[] = [];\n for (const service of services) {\n for (const collection of [...service.collections.keys()].sort(byName)) {\n const anchor = service.collections.get(collection)?.anchor?.name;\n const base = `${service.name}.${collection}`;\n if (anchor === undefined) {\n list.push({\n key: keyOf(base, \"self\"),\n service: service.name,\n collection,\n anchor,\n variant: undefined,\n });\n continue;\n }\n for (const variant of variantsOf(rows, anchor)) {\n list.push({\n key: keyOf(base, variant),\n service: service.name,\n collection,\n anchor,\n variant,\n });\n }\n }\n }\n return list;\n}\n\n/** Throws when `rows` names no row of a service a row of the matrix is about, listing every such service. */\nfunction checkRowsCover(plan: Plan, rows: Rows): void {\n const needs = new Map<string, Set<string>>();\n const need = (service: string | undefined, what: string): void => {\n if (service !== undefined && !rows.has(service)) {\n needs.set(service, (needs.get(service) ?? new Set()).add(what));\n }\n };\n for (const row of [...plan.queries, ...plan.mutations]) {\n need(row.rowService, `${row.service.name}.${row.method.name}`);\n }\n for (const row of plan.subscribes) {\n need(row.service, `qd:sub ${row.service}`);\n }\n for (const row of plan.scopes) {\n need(row.anchor, `qd:col:sub ${row.service}.${row.collection}`);\n }\n if (needs.size > 0) {\n const missing = [...needs].map(([service, what]) => `${service} (for ${[...what].join(\", \")})`);\n fail(\n `rows names no row of ${missing.join(\"; \")}. Give rows(fixture) a row id of each, or named row ids ({ own: id, other: id }); leave a method out with exclude`,\n );\n }\n}\n\n/** Every row of the matrix: the methods of `services` but those excluded, their subscribes and scopes. */\nexport function planOf(\n services: readonly AnyService[],\n excluded: ReadonlySet<string>,\n rows: Rows,\n): Plan {\n const methods = methodRows(services, excluded, rows);\n const plan: Plan = {\n subscribes: subscribeRows(services, rows),\n scopes: scopeRows(services, rows),\n queries: methods.filter((row) => row.method.kind === \"query\"),\n mutations: methods.filter((row) => row.method.kind === \"mutation\"),\n excluded: [...excluded].sort(byName),\n };\n checkRowsCover(plan, rows);\n return plan;\n}\n","// `snapshotAccessMatrix` (RFC 0003 section 13): who may call what, for every\n// method, entity subscribe and collection scope of an app's services and\n// every principal, recorded once in a file beside the test and compared on\n// every later run, so a changed cell fails until someone accepts it.\n// `describeAccessMatrix` pins hand-written cases of one service; a\n// migration, a policy refactor or a new principal kind wants the whole\n// table, diffed.\n//\n// await snapshotAccessMatrix(app, {\n// principals: (board) => ({ owner: { userId: board.ada }, member: { userId: board.bo } }),\n// reset: async () => {\n// await resetDatabase(prisma);\n// return await seed(prisma);\n// },\n// rows: (board) => ({ projectService: board.p1, taskService: { own: board.t1, other: board.t2 } }),\n// });\n//\n// Each principal, and an anonymous caller, runs in turn: every entity\n// subscribe and collection scope over a socket of its own, then every query,\n// then every mutation, in process, each with a real input: the app's\n// (`inputs`), or one made from the input's JSON Schema with the cell's row\n// where the method's access form reads it (`accessInputs.ts`). A mutation\n// the pipeline did not refuse may have written, so `reset` runs again after\n// it, and every cell sees the rows `reset` makes. What runs is planned\n// before any cell (`accessSnapshotPlan.ts`); the file is\n// `__access__/<test file>.json` (`accessSnapshotFile.ts`).\n\nimport { QuickdrawError } from \"../protocol/errors\";\nimport type { PrincipalOfServices } from \"../server/dispatcher\";\nimport type { AnyService, ServiceMethod } from \"../server/service\";\nimport type { Principal } from \"../server/types\";\nimport { generatedInput, isValidInput } from \"./accessInputs\";\nimport type {\n AccessOutcome,\n AccessSnapshot,\n AccessSnapshotPrincipal,\n AccessSnapshotRow,\n} from \"./accessSnapshotCompare\";\nimport { settleSnapshot, snapshotPathOf, type AccessSnapshotChange } from \"./accessSnapshotFile\";\nimport {\n excludedOf,\n fail,\n isRecord,\n planOf,\n readPrincipals,\n readRows,\n sameShape,\n servicesOf,\n type AccessPrincipals,\n type AccessRows,\n type MethodRow,\n type Plan,\n type Rows,\n} from \"./accessSnapshotPlan\";\nimport type { TestApp, TestConnection } from \"./createTestApp\";\nimport { emitWithAck } from \"./socket\";\n\nexport type { AccessPrincipals, AccessRows };\n\n/** The cell an `inputs` function makes the input of. */\nexport interface AccessSnapshotRef {\n /** The service's name. */\n readonly service: string;\n /** The method's name. */\n readonly method: string;\n readonly kind: ServiceMethod[\"kind\"];\n /** The row variant, when `rows` names variants for the service whose row the method is about. */\n readonly variant: string | undefined;\n /**\n * The row the cell is about, from `rows`: the method's own service's for\n * an `entry` form, the `of` contract's for a `scope` form, and its own\n * for any other form whose input has an `id`; `undefined` for a method\n * about no row.\n */\n readonly row: string | undefined;\n /** The name of the principal the cell runs as. */\n readonly principal: string;\n}\n\n/** Options of {@link snapshotAccessMatrix}. `Fixture` is what `reset` resolves with. */\nexport interface AccessSnapshotOptions<P, Fixture, Name extends string> {\n /**\n * The callers, by name, or a function of the fixture making them (read\n * again after every reset, for a seed that makes new ids); their names\n * must stay the same. An anonymous caller named `\"anonymous\"` is added\n * unless one is `null`.\n */\n readonly principals: AccessPrincipals<P, Fixture, Name>;\n /**\n * Empties the database and seeds it, resolving with what the seed made\n * (the fixture): the app's `resetDatabase` (from `./testing/prisma`) and\n * its seed, writing with the untracked client. Called first, and again\n * after every mutation the pipeline did not refuse.\n */\n readonly reset: () => Fixture | PromiseLike<Fixture>;\n /**\n * The row each service's cells are about, by service name: a row id, or\n * named variants (`{ own: p1, other: p2 }`), each a row of its own in the\n * snapshot. It must name every service whose rows a method's form, an\n * entity subscribe or a collection scope of the matrix reads.\n */\n readonly rows: (fixture: Fixture) => AccessRows;\n /**\n * A method's input for one cell, when the generated one will not do;\n * `undefined` to generate it. An input that fails the method's input\n * schema is recorded as `VALIDATION` and never called.\n */\n readonly inputs?: (ref: AccessSnapshotRef, fixture: Fixture) => unknown;\n /** The services whose methods, subscribes and scopes the matrix holds. Default: every service the app serves. */\n readonly services?: readonly AnyService[];\n /** Methods left out, as `<service>.<method>`: those whose outcome is not the same on every run. */\n readonly exclude?: readonly string[];\n /** The test file the snapshot sits beside. Default: the running test's file, from the test runner. */\n readonly file?: string;\n}\n\n/** What {@link snapshotAccessMatrix} recorded, and what it did with the snapshot file. */\nexport interface AccessSnapshotReport {\n /** The snapshot file. */\n readonly path: string;\n /**\n * `\"written\"`: there was no file; `\"unchanged\"`: the matrix is the stored\n * one; `\"updated\"`: the file was rewritten (cells added or removed in a\n * local run, or changes accepted with `QD_UPDATE_ACCESS_SNAPSHOT=1`).\n */\n readonly change: AccessSnapshotChange;\n /** The matrix this run recorded. */\n readonly snapshot: AccessSnapshot;\n /**\n * The cells never called because no input passed the method's input\n * schema (or named the cell's row where its form reads it), as\n * `<row> as <principal>`: recorded as `VALIDATION`, they pin nothing\n * about access. Give their inputs with `inputs`.\n */\n readonly inconclusive: readonly string[];\n}\n\ntype MethodFunction = (input: unknown) => Promise<unknown>;\n\n/** The outcomes of a mutation the pipeline refused before its handler ran: no reset follows them. */\nconst REFUSALS: ReadonlySet<string> = new Set([\"UNAUTHENTICATED\", \"FORBIDDEN\", \"VALIDATION\"]);\n\n/** The scope an anonymous caller subscribes to in a `\"self\"` collection: it has no user id. */\nconst ANONYMOUS_SCOPE = \"anonymous\";\n\n/** The recorded outcomes of a section: per row key, then principal name. */\ntype Cells = Map<string, Map<string, AccessOutcome>>;\n\n/** One run of the matrix: the current fixture, its principals and rows, and the cells so far. */\ninterface Run<P extends Principal, Fixture> {\n readonly app: TestApp;\n readonly options: AccessSnapshotOptions<P, Fixture, string>;\n readonly served: ReadonlyMap<string, AnyService>;\n readonly plan: Plan;\n fixture: Fixture;\n principals: Map<string, P | null>;\n rows: Rows;\n readonly methods: Cells;\n readonly subscriptions: Cells;\n readonly collections: Cells;\n readonly inconclusive: string[];\n}\n\nfunction record(cells: Cells, key: string, principal: string, outcome: AccessOutcome): void {\n const row = cells.get(key) ?? new Map<string, AccessOutcome>();\n cells.set(key, row.set(principal, outcome));\n}\n\n/** Resets the database, and reads the new fixture's principals and rows; their names must not change. */\nasync function reset<P extends Principal, Fixture>(run: Run<P, Fixture>): Promise<void> {\n const fixture = await run.options.reset();\n const next = {\n principals: readPrincipals(run.options.principals, fixture),\n rows: readRows(run.options.rows(fixture), run.served),\n };\n if (!sameShape(run, next)) {\n fail(\n \"principals and rows must name the same principals, services and variants after every reset\",\n );\n }\n run.fixture = fixture;\n run.principals = next.principals;\n run.rows = next.rows;\n}\n\nfunction rowIdOf(rows: Rows, service: string, variant: string | undefined): string | undefined {\n return rows.get(service)?.get(variant);\n}\n\n/** How a call ended: `\"ok\"`, or the code of the `QuickdrawError` it failed with; anything else is thrown. */\nasync function outcomeOf(call: () => Promise<unknown>): Promise<AccessOutcome> {\n try {\n await call();\n return \"ok\";\n } catch (error) {\n if (error instanceof QuickdrawError) {\n return error.code;\n }\n throw error;\n }\n}\n\n/** The outcome an acknowledgement (or one id's result in it) says: `\"ok\"`, or its error's code. */\nfunction outcomeOfReply(reply: unknown, event: string): AccessOutcome {\n if (isRecord(reply) && reply.ok === true) {\n return \"ok\";\n }\n const code = isRecord(reply) && isRecord(reply.e) ? reply.e.code : undefined;\n if (typeof code !== \"string\") {\n throw new Error(`snapshotAccessMatrix: ${event} answered ${JSON.stringify(reply)}`);\n }\n return code as AccessOutcome;\n}\n\n/** The input of one method cell: the app's, or a generated one; `undefined` when none is usable. */\nasync function inputOf<P extends Principal, Fixture>(\n run: Run<P, Fixture>,\n row: MethodRow,\n name: string,\n): Promise<{ readonly value: unknown } | undefined> {\n const id =\n row.rowService === undefined ? undefined : rowIdOf(run.rows, row.rowService, row.variant);\n const ref: AccessSnapshotRef = {\n service: row.service.name,\n method: row.method.name,\n kind: row.method.kind,\n variant: row.variant,\n row: id,\n principal: name,\n };\n const given: unknown = await run.options.inputs?.(ref, run.fixture);\n if (given !== undefined) {\n return (await isValidInput(row.method, given)) ? { value: given } : undefined;\n }\n const made = await generatedInput(row.method, id);\n return made === undefined ? undefined : { value: made.input };\n}\n\n/** The method a cell calls, through the app's in-process caller acting as `principal`. */\nfunction methodOf(app: TestApp, row: MethodRow, principal: Principal | null): MethodFunction {\n const caller = app.as(principal) as unknown as Readonly<\n Record<string, Readonly<Record<string, MethodFunction>> | undefined>\n >;\n const method = caller[row.service.name]?.[row.method.name];\n if (method === undefined) {\n throw new TypeError(`snapshotAccessMatrix: ${row.service.name} has no ${row.method.name}`);\n }\n return method;\n}\n\n/** Calls one method as one principal and records the outcome; resets after a mutation the pipeline let through. */\nasync function callCell<P extends Principal, Fixture>(\n run: Run<P, Fixture>,\n row: MethodRow,\n name: string,\n): Promise<void> {\n const input = await inputOf(run, row, name);\n if (input === undefined) {\n record(run.methods, row.key, name, \"VALIDATION\");\n run.inconclusive.push(`${row.key} as ${name}`);\n return;\n }\n const method = methodOf(run.app, row, run.principals.get(name) ?? null);\n const outcome = await outcomeOf(() => method(input.value));\n record(run.methods, row.key, name, outcome);\n if (row.method.kind === \"mutation\" && !REFUSALS.has(outcome)) {\n await reset(run);\n }\n}\n\n/** Every entity subscribe of the matrix over `connection`: one `qd:sub` per service, all its variants at once. */\nasync function subscribeEntities<P extends Principal, Fixture>(\n run: Run<P, Fixture>,\n connection: TestConnection,\n name: string,\n): Promise<void> {\n for (const row of run.plan.subscribes) {\n const variants = [...row.keys.keys()];\n const ids = variants.map((variant) => rowIdOf(run.rows, row.service, variant) ?? \"\");\n const reply: unknown = await emitWithAck(connection.socket, \"qd:sub\", { s: row.service, ids });\n const results =\n isRecord(reply) && reply.ok === true && Array.isArray(reply.r) ? reply.r : undefined;\n variants.forEach((variant, index) => {\n const outcome = outcomeOfReply(results === undefined ? reply : results[index], \"qd:sub\");\n record(run.subscriptions, row.keys.get(variant) ?? row.service, name, outcome);\n });\n }\n}\n\n/** Every collection scope of the matrix over `connection`, one `qd:col:sub` each. */\nasync function subscribeScopes<P extends Principal, Fixture>(\n run: Run<P, Fixture>,\n connection: TestConnection,\n name: string,\n): Promise<void> {\n const principal = run.principals.get(name) ?? null;\n for (const row of run.plan.scopes) {\n const scope =\n row.anchor === undefined\n ? (principal?.userId ?? ANONYMOUS_SCOPE)\n : (rowIdOf(run.rows, row.anchor, row.variant) ?? \"\");\n const frame = { s: row.service, c: row.collection, scope, limit: 1 };\n const reply: unknown = await emitWithAck(connection.socket, \"qd:col:sub\", frame);\n record(run.collections, row.key, name, outcomeOfReply(reply, \"qd:col:sub\"));\n }\n}\n\n/** The code a refused connection carries (its `connect_error` data), if it carries one. */\nfunction refusalCode(error: unknown): AccessOutcome | undefined {\n const data: unknown =\n error instanceof Error ? (error as { readonly data?: unknown }).data : undefined;\n const code = isRecord(data) ? data.code : undefined;\n return typeof code === \"string\" ? (code as AccessOutcome) : undefined;\n}\n\n/** Records `code` for every subscribe and scope of one principal: its socket was refused. */\nfunction refuseAll<P extends Principal, Fixture>(\n run: Run<P, Fixture>,\n name: string,\n code: AccessOutcome,\n): void {\n for (const row of run.plan.subscribes) {\n for (const key of row.keys.values()) {\n record(run.subscriptions, key, name, code);\n }\n }\n for (const row of run.plan.scopes) {\n record(run.collections, row.key, name, code);\n }\n}\n\n/** The subscribes and scopes of one principal, over a socket of its own. */\nasync function subscribeAll<P extends Principal, Fixture>(\n run: Run<P, Fixture>,\n name: string,\n): Promise<void> {\n if (run.plan.subscribes.length === 0 && run.plan.scopes.length === 0) {\n return;\n }\n let connection: TestConnection;\n try {\n connection = await run.app.connect(run.principals.get(name) ?? null);\n } catch (error) {\n const code = refusalCode(error);\n if (code === undefined) {\n throw error;\n }\n refuseAll(run, name, code);\n return;\n }\n try {\n await subscribeEntities(run, connection, name);\n await subscribeScopes(run, connection, name);\n } finally {\n connection.close();\n }\n}\n\nfunction rowsOf(cells: Cells): Record<string, AccessSnapshotRow> {\n return Object.fromEntries([...cells].map(([key, row]) => [key, Object.fromEntries(row)]));\n}\n\n/** The snapshot of a finished run, with the principals as the first fixture made them. */\nfunction snapshotOf<P extends Principal, Fixture>(\n run: Run<P, Fixture>,\n principals: ReadonlyMap<string, P | null>,\n): AccessSnapshot {\n const recorded = [...principals].map(([name, principal]): [string, AccessSnapshotPrincipal] => [\n name,\n principal === null ? null : { kind: principal.kind ?? null },\n ]);\n return {\n version: 1,\n principals: Object.fromEntries(recorded),\n methods: rowsOf(run.methods),\n subscriptions: rowsOf(run.subscriptions),\n collections: rowsOf(run.collections),\n excluded: run.plan.excluded,\n };\n}\n\n/** The options, checked as far as they can be before the first reset. */\nfunction checkOptions(options: unknown): void {\n if (\n !isRecord(options) ||\n typeof options.reset !== \"function\" ||\n typeof options.rows !== \"function\"\n ) {\n fail(\"pass { principals, reset, rows }: reset() seeds the rows, rows(fixture) names them\");\n }\n if (options.inputs !== undefined && typeof options.inputs !== \"function\") {\n fail(\"inputs must be a function of the cell and the fixture\");\n }\n}\n\n/**\n * Records who may call what through `app` (from `createTestApp`): every\n * method of `services` (default: every service the app serves), each\n * entity subscribe (`qd:sub`) and each collection scope (`qd:col:sub`), as\n * every principal and anonymously, against the rows `reset` seeds, and\n * compares the matrix with the snapshot file beside the test\n * (`__access__/<test file>.json`, keys sorted: commit it).\n *\n * - A missing file is written. Under CI (`CI=1` or `CI=true`) it fails\n * instead: a snapshot that writes itself pins nothing.\n * - A cell whose outcome changed fails, naming the row (method and\n * variant), the principal and both outcomes, and whether the change opens\n * or closes access. Accept the changes with `QD_UPDATE_ACCESS_SNAPSHOT=1`,\n * which rewrites the file (never under CI).\n * - Cells added or removed (a new method, principal or exclusion) rewrite\n * the file locally, and fail under CI.\n *\n * Outcomes are exact: `\"ok\"`, or the error code. Each principal's `kind` is\n * recorded too, and a changed kind fails like a cell. A cell whose input\n * failed the method's input schema is `VALIDATION`, never called, and\n * listed in the report's `inconclusive`. Leave out methods whose outcome is\n * not the same on every run with `exclude`. One snapshot per test file.\n *\n * @example\n * const report = await snapshotAccessMatrix(app, { principals, reset, rows });\n * expect(report.inconclusive).toEqual([]);\n */\nexport async function snapshotAccessMatrix<\n S extends readonly AnyService[],\n Fixture,\n const Name extends string,\n>(\n app: TestApp<S>,\n options: AccessSnapshotOptions<PrincipalOfServices<S>, Fixture, Name>,\n): Promise<AccessSnapshotReport> {\n checkOptions(options);\n const path = snapshotPathOf(options.file);\n const generic = app as unknown as TestApp;\n const served = generic.server.dispatcher.registry.services;\n const services = servicesOf(generic, options.services);\n const excluded = excludedOf(services, options.exclude);\n const fixture = await options.reset();\n const principals = readPrincipals<PrincipalOfServices<S>, Fixture>(options.principals, fixture);\n const rows = readRows(options.rows(fixture), served);\n const run: Run<PrincipalOfServices<S>, Fixture> = {\n app: generic,\n options: options as AccessSnapshotOptions<PrincipalOfServices<S>, Fixture, string>,\n served,\n plan: planOf(services, excluded, rows),\n fixture,\n principals,\n rows,\n methods: new Map(),\n subscriptions: new Map(),\n collections: new Map(),\n inconclusive: [],\n };\n for (const name of principals.keys()) {\n await subscribeAll(run, name);\n for (const row of [...run.plan.queries, ...run.plan.mutations]) {\n await callCell(run, row, name);\n }\n }\n const snapshot = snapshotOf(run, principals);\n const change = settleSnapshot(path, snapshot, run.inconclusive);\n return { path, change, snapshot, inconclusive: run.inconclusive };\n}\n"],"mappings":"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","names":["io","matches","record","record","matches","existsSync","mkdirSync","readFileSync","writeFileSync","basename","dirname","join","change","join","dirname","basename","claimed","NO_RUNNER","isRecord","isPrincipal","existsSync","readFileSync","mkdirSync","writeFileSync","isRecord","record","outcomeOf","isRecord","checkOptions","change"]}
|