@nxgt/janus 0.8.3 → 0.8.5

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.
@@ -31,6 +31,10 @@ export declare function rejects(promise: Promise<unknown>, what: string): Promis
31
31
  *
32
32
  * The probe says what breaks; `verify:artifacts` says whether a duplicate is
33
33
  * present. Both are needed.
34
+ *
35
+ * `name` is the error's own `name` field, passed rather than read from
36
+ * `cls.name`: a bundler renames a class that collides — `StoreFailure2` in
37
+ * `dist` — and the probe would then never recognise the duplicate.
34
38
  */
35
- export declare function isOurs<T>(error: unknown, cls: abstract new (...args: never[]) => T, what: string): asserts error is T;
39
+ export declare function isOurs<T>(error: unknown, cls: abstract new (...args: never[]) => T, name: string, what: string): asserts error is T;
36
40
  //# sourceMappingURL=assert.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"assert.d.ts","sourceRoot":"","sources":["../../src/conformance/assert.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,uFAAuF;AACvF,wBAAgB,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAO5E;AAED,iGAAiG;AACjG,wBAAgB,MAAM,CAAC,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAM1D;AAED,sCAAsC;AACtC,wBAAgB,EAAE,CAAC,SAAS,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAEzD;AAED;;;;;;;GAOG;AACH,wBAAgB,OAAO,CACtB,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,EACzB,IAAI,EAAE,MAAM,GACV,OAAO,CAAC,OAAO,CAAC,CAOlB;AAED;;;;;;;;;GASG;AACH,wBAAgB,MAAM,CAAC,CAAC,EACvB,KAAK,EAAE,OAAO,EACd,GAAG,EAAE,QAAQ,MAAM,GAAG,IAAI,EAAE,KAAK,EAAE,KAAK,CAAC,EACzC,IAAI,EAAE,MAAM,GACV,OAAO,CAAC,KAAK,IAAI,CAAC,CAWpB"}
1
+ {"version":3,"file":"assert.d.ts","sourceRoot":"","sources":["../../src/conformance/assert.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,uFAAuF;AACvF,wBAAgB,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAO5E;AAED,iGAAiG;AACjG,wBAAgB,MAAM,CAAC,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAM1D;AAED,sCAAsC;AACtC,wBAAgB,EAAE,CAAC,SAAS,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAEzD;AAED;;;;;;;GAOG;AACH,wBAAgB,OAAO,CACtB,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,EACzB,IAAI,EAAE,MAAM,GACV,OAAO,CAAC,OAAO,CAAC,CAOlB;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,MAAM,CAAC,CAAC,EACvB,KAAK,EAAE,OAAO,EACd,GAAG,EAAE,QAAQ,MAAM,GAAG,IAAI,EAAE,KAAK,EAAE,KAAK,CAAC,EACzC,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,GACV,OAAO,CAAC,KAAK,IAAI,CAAC,CAWpB"}
@@ -1 +1 @@
1
- {"version":3,"file":"outage.d.ts","sourceRoot":"","sources":["../../../src/conformance/cases/outage.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAe,eAAe,EAAc,MAAM,UAAU,CAAC;AA4DzE,eAAO,MAAM,WAAW,EAAE,SAAS,eAAe,EAqFjD,CAAC"}
1
+ {"version":3,"file":"outage.d.ts","sourceRoot":"","sources":["../../../src/conformance/cases/outage.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAe,eAAe,EAAc,MAAM,UAAU,CAAC;AAiEzE,eAAO,MAAM,WAAW,EAAE,SAAS,eAAe,EAqFjD,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"users.d.ts","sourceRoot":"","sources":["../../../src/conformance/cases/users.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAYhD,eAAO,MAAM,cAAc,EAAE,SAAS,eAAe,EA8hBpD,CAAC"}
1
+ {"version":3,"file":"users.d.ts","sourceRoot":"","sources":["../../../src/conformance/cases/users.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAYhD,eAAO,MAAM,cAAc,EAAE,SAAS,eAAe,EAkiBpD,CAAC"}
@@ -37,15 +37,15 @@ function rejects(promise, what) {
37
37
  expected a rejection, got ${show(answer)}`);
38
38
  }, (error) => error);
39
39
  }
40
- function isOurs(error, cls, what) {
40
+ function isOurs(error, cls, name, what) {
41
41
  if (error instanceof cls)
42
42
  return;
43
- if (error?.name === cls.name) {
43
+ if (error?.name === name) {
44
44
  throw new Error(`${what}
45
- the error is named ${cls.name} but is not @nxgt/janus's ${cls.name}: two copies of @nxgt/janus are installed. The adapter must list it as a peer dependency, never a dependency`);
45
+ the error is named ${name} but is not @nxgt/janus's ${name}: two copies of @nxgt/janus are installed. The adapter must list it as a peer dependency, never a dependency`);
46
46
  }
47
47
  throw new Error(`${what}
48
- expected ${cls.name}, got ${show(error)}`);
48
+ expected ${name}, got ${show(error)}`);
49
49
  }
50
50
  function differ(actual, expected, path) {
51
51
  if (expected instanceof Date || actual instanceof Date) {
@@ -163,7 +163,7 @@ function outage(slot, method, call, seed) {
163
163
  await context.faults?.fail(slot, method);
164
164
  const error = await rejects(call(context), `${slot}.${method} under an outage should reject: answering an absence turns an outage into a silent lockout`);
165
165
  if (error instanceof JanusError2 || error?.name === "StoreFailure") {
166
- isOurs(error, StoreFailure2, `${slot}.${method} under an outage`);
166
+ isOurs(error, StoreFailure2, "StoreFailure", `${slot}.${method} under an outage`);
167
167
  }
168
168
  ok(error?.code !== "NOT_FOUND", `${slot}.${method} under an outage rejected with NOT_FOUND: an outage is never an absence`);
169
169
  }
@@ -688,7 +688,7 @@ var userStoreCases = [
688
688
  const refused = outcomes.flatMap((o) => o.status === "rejected" ? [o.reason] : []);
689
689
  equal(accepted.length, 1, "insertUser: of twenty concurrent inserts of one login, exactly one should be accepted — a read followed by a write lets several through");
690
690
  for (const error of refused) {
691
- isOurs(error, StoreConflict2, "insertUser should refuse a taken login with StoreConflict");
691
+ isOurs(error, StoreConflict2, "StoreConflict", "insertUser should refuse a taken login with StoreConflict");
692
692
  equal(error.code, "LOGIN_TAKEN", "insertUser: the conflict code");
693
693
  equal(error.login, "contested@example.test", "insertUser: the conflict should name the login");
694
694
  ok(!error.message.includes("contested@example.test"), `insertUser: the conflict's message should not quote the login — a message never carries a value; got ${JSON.stringify(error.message)}`);
@@ -733,7 +733,7 @@ var userStoreCases = [
733
733
  active: true,
734
734
  fields: { email: "overwritten@example.test" }
735
735
  }, 0), "updateUser at a stale version should reject");
736
- isOurs(error, StoreConflict2, "updateUser at a stale version should reject with StoreConflict");
736
+ isOurs(error, StoreConflict2, "StoreConflict", "updateUser at a stale version should reject with StoreConflict");
737
737
  equal(error.code, "VERSION_CONFLICT", "updateUser: the conflict code");
738
738
  equal(error.expectedVersion, 0, "updateUser: expectedVersion");
739
739
  equal(error.actualVersion, 1, "updateUser: actualVersion");
@@ -746,7 +746,7 @@ var userStoreCases = [
746
746
  name: "refuses an update to an unknown id with NotFoundError, told apart from a version conflict",
747
747
  async run({ stores }) {
748
748
  const error = await rejects(stores.users.updateUser(mintId2(), { updatedAt: at("2026-02-01T00:00:00.000Z") }, 0), "updateUser on an unknown id should reject");
749
- isOurs(error, NotFoundError2, "updateUser on an unknown id should reject with NotFoundError, not a version conflict");
749
+ isOurs(error, NotFoundError2, "NotFoundError", "updateUser on an unknown id should reject with NotFoundError, not a version conflict");
750
750
  }
751
751
  },
752
752
  {
@@ -822,7 +822,7 @@ var userStoreCases = [
822
822
  isNull(await stores.users.findUserByLogin("user", old ?? ""), "findUserByLogin for a login the update replaced");
823
823
  equal((await stores.users.findUserByLogin("user", moved))?.id, record.id, "findUserByLogin for the login the update wrote");
824
824
  const error = await rejects(stores.users.updateUser(other.id, { updatedAt: at("2026-02-02T00:00:00.000Z"), logins: [moved] }, 0), "updateUser onto a login another user holds should reject");
825
- isOurs(error, StoreConflict2, "updateUser onto a held login should reject with StoreConflict");
825
+ isOurs(error, StoreConflict2, "StoreConflict", "updateUser onto a held login should reject with StoreConflict");
826
826
  equal(error.code, "LOGIN_TAKEN", "updateUser: the conflict code");
827
827
  equal(await stores.users.findUser(other.id), other, "updateUser refused for a login should have written nothing");
828
828
  }
@@ -1243,7 +1243,7 @@ function outage2(method, call, after) {
1243
1243
  await faults?.fail(method);
1244
1244
  const error = await rejects(call(store), `relations.${method} under an outage should reject`);
1245
1245
  if (error instanceof JanusError2 || error?.name === "StoreFailure") {
1246
- isOurs(error, StoreFailure2, `relations.${method} under an outage`);
1246
+ isOurs(error, StoreFailure2, "StoreFailure", `relations.${method} under an outage`);
1247
1247
  }
1248
1248
  ok(error?.code !== "NOT_FOUND", `relations.${method} under an outage rejected with NOT_FOUND: an outage is never an absence`);
1249
1249
  await after?.(store);
@@ -1343,5 +1343,5 @@ export {
1343
1343
  userStoreCases
1344
1344
  };
1345
1345
 
1346
- //# debugId=DFFC56A4D48D5C0564756E2164756E21
1346
+ //# debugId=7779A65B64EF7C9A64756E2164756E21
1347
1347
  //# sourceMappingURL=index.js.map
@@ -2,17 +2,17 @@
2
2
  "version": 3,
3
3
  "sources": ["../src/conformance/assert.ts", "../src/conformance/fixtures.ts", "../src/conformance/cases/outage.ts", "../src/conformance/cases/sessions.ts", "../src/conformance/cases/tokens.ts", "../src/conformance/cases/users.ts", "../src/conformance/describe.ts", "../src/conformance/reference.ts", "../src/conformance/relations.ts"],
4
4
  "sourcesContent": [
5
- "/**\n * The suite's five assertions.\n *\n * **No assertion library, no test framework**: `bun:test` in the dependency\n * graph of a published library is a dependency every consumer installs, and an\n * adapter author on vitest could not run the suite at all. Each throws a plain\n * `Error` whose message names the port method and what it should have answered\n * — the sentence an adapter author reads first.\n */\n\n/** Fails unless `actual` deep-equals `expected`: dates by instant, `1` never `'1'`. */\nexport function equal(actual: unknown, expected: unknown, what: string): void {\n\tconst difference = differ(actual, expected, '');\n\tif (difference !== null) {\n\t\tthrow new Error(\n\t\t\t`${what}\\n at ${difference.path || '(root)'}: expected ${show(difference.expected)}, got ${show(difference.actual)}`,\n\t\t);\n\t}\n}\n\n/** Fails unless `actual` is `null` — not `undefined`, which is a store that forgot to answer. */\nexport function isNull(actual: unknown, what: string): void {\n\tif (actual !== null) {\n\t\tthrow new Error(\n\t\t\t`${what}\\n expected null, got ${actual === undefined ? 'undefined — an absence is null; undefined is a store that forgot to answer' : show(actual)}`,\n\t\t);\n\t}\n}\n\n/** Fails unless `condition` holds. */\nexport function ok(condition: boolean, what: string): void {\n\tif (!condition) throw new Error(what);\n}\n\n/**\n * The rejection of `promise`, or a failure when it resolves.\n *\n * **Settled where it is created**, with `.then(ok, ko)`: a rejection awaited\n * too late is counted unhandled by Bun and fails the case with the very error\n * it was checking — measured in nxgt-data, where a loaded CI runner failed\n * where an idle laptop passed.\n */\nexport function rejects(\n\tpromise: Promise<unknown>,\n\twhat: string,\n): Promise<unknown> {\n\treturn promise.then(\n\t\t(answer) => {\n\t\t\tthrow new Error(`${what}\\n expected a rejection, got ${show(answer)}`);\n\t\t},\n\t\t(error: unknown) => error,\n\t);\n}\n\n/**\n * The `instanceof` probe: a class that is named like this package's but is not\n * this package's class means **two copies of `@nxgt/janus`** are installed —\n * the adapter depends on it instead of peering it. Then `StoreConflict` stops\n * passing through the core, and a login that is taken is answered as an\n * outage.\n *\n * The probe says what breaks; `verify:artifacts` says whether a duplicate is\n * present. Both are needed.\n */\nexport function isOurs<T>(\n\terror: unknown,\n\tcls: abstract new (...args: never[]) => T,\n\twhat: string,\n): asserts error is T {\n\tif (error instanceof cls) return;\n\n\t// Same name, not the same class: the duplicate the probe exists for.\n\tif ((error as { name?: unknown } | null)?.name === cls.name) {\n\t\tthrow new Error(\n\t\t\t`${what}\\n the error is named ${cls.name} but is not @nxgt/janus's ${cls.name}: two copies of @nxgt/janus are installed. The adapter must list it as a peer dependency, never a dependency`,\n\t\t);\n\t}\n\n\tthrow new Error(`${what}\\n expected ${cls.name}, got ${show(error)}`);\n}\n\ninterface Difference {\n\treadonly path: string;\n\treadonly expected: unknown;\n\treadonly actual: unknown;\n}\n\nfunction differ(\n\tactual: unknown,\n\texpected: unknown,\n\tpath: string,\n): Difference | null {\n\tif (expected instanceof Date || actual instanceof Date) {\n\t\treturn actual instanceof Date &&\n\t\t\texpected instanceof Date &&\n\t\t\tactual.getTime() === expected.getTime()\n\t\t\t? null\n\t\t\t: { path, expected, actual };\n\t}\n\n\tif (Array.isArray(expected) || Array.isArray(actual)) {\n\t\tif (!Array.isArray(expected) || !Array.isArray(actual)) {\n\t\t\treturn { path, expected, actual };\n\t\t}\n\t\tif (expected.length !== actual.length) {\n\t\t\treturn {\n\t\t\t\tpath: `${path}.length`,\n\t\t\t\texpected: expected.length,\n\t\t\t\tactual: actual.length,\n\t\t\t};\n\t\t}\n\t\tfor (let i = 0; i < expected.length; i += 1) {\n\t\t\tconst inner = differ(actual[i], expected[i], `${path}[${i}]`);\n\t\t\tif (inner !== null) return inner;\n\t\t}\n\t\treturn null;\n\t}\n\n\tif (\n\t\ttypeof expected === 'object' &&\n\t\texpected !== null &&\n\t\ttypeof actual === 'object' &&\n\t\tactual !== null\n\t) {\n\t\tconst keys = new Set([...Object.keys(expected), ...Object.keys(actual)]);\n\t\tfor (const key of keys) {\n\t\t\tconst inner = differ(\n\t\t\t\t(actual as Record<string, unknown>)[key],\n\t\t\t\t(expected as Record<string, unknown>)[key],\n\t\t\t\tpath === '' ? key : `${path}.${key}`,\n\t\t\t);\n\t\t\tif (inner !== null) return inner;\n\t\t}\n\t\treturn null;\n\t}\n\n\treturn Object.is(actual, expected) ? null : { path, expected, actual };\n}\n\nfunction show(value: unknown): string {\n\tif (value instanceof Error) return `${value.name}: ${value.message}`;\n\tif (value instanceof Date) return value.toISOString();\n\tif (value === undefined) return 'undefined';\n\tif (typeof value === 'string') return JSON.stringify(value);\n\ttry {\n\t\tconst json = JSON.stringify(value);\n\t\treturn json.length > 200 ? `${json.slice(0, 200)}…` : json;\n\t} catch {\n\t\treturn String(value);\n\t}\n}\n",
5
+ "/**\n * The suite's five assertions.\n *\n * **No assertion library, no test framework**: `bun:test` in the dependency\n * graph of a published library is a dependency every consumer installs, and an\n * adapter author on vitest could not run the suite at all. Each throws a plain\n * `Error` whose message names the port method and what it should have answered\n * — the sentence an adapter author reads first.\n */\n\n/** Fails unless `actual` deep-equals `expected`: dates by instant, `1` never `'1'`. */\nexport function equal(actual: unknown, expected: unknown, what: string): void {\n\tconst difference = differ(actual, expected, '');\n\tif (difference !== null) {\n\t\tthrow new Error(\n\t\t\t`${what}\\n at ${difference.path || '(root)'}: expected ${show(difference.expected)}, got ${show(difference.actual)}`,\n\t\t);\n\t}\n}\n\n/** Fails unless `actual` is `null` — not `undefined`, which is a store that forgot to answer. */\nexport function isNull(actual: unknown, what: string): void {\n\tif (actual !== null) {\n\t\tthrow new Error(\n\t\t\t`${what}\\n expected null, got ${actual === undefined ? 'undefined — an absence is null; undefined is a store that forgot to answer' : show(actual)}`,\n\t\t);\n\t}\n}\n\n/** Fails unless `condition` holds. */\nexport function ok(condition: boolean, what: string): void {\n\tif (!condition) throw new Error(what);\n}\n\n/**\n * The rejection of `promise`, or a failure when it resolves.\n *\n * **Settled where it is created**, with `.then(ok, ko)`: a rejection awaited\n * too late is counted unhandled by Bun and fails the case with the very error\n * it was checking — measured in nxgt-data, where a loaded CI runner failed\n * where an idle laptop passed.\n */\nexport function rejects(\n\tpromise: Promise<unknown>,\n\twhat: string,\n): Promise<unknown> {\n\treturn promise.then(\n\t\t(answer) => {\n\t\t\tthrow new Error(`${what}\\n expected a rejection, got ${show(answer)}`);\n\t\t},\n\t\t(error: unknown) => error,\n\t);\n}\n\n/**\n * The `instanceof` probe: a class that is named like this package's but is not\n * this package's class means **two copies of `@nxgt/janus`** are installed —\n * the adapter depends on it instead of peering it. Then `StoreConflict` stops\n * passing through the core, and a login that is taken is answered as an\n * outage.\n *\n * The probe says what breaks; `verify:artifacts` says whether a duplicate is\n * present. Both are needed.\n *\n * `name` is the error's own `name` field, passed rather than read from\n * `cls.name`: a bundler renames a class that collides — `StoreFailure2` in\n * `dist` — and the probe would then never recognise the duplicate.\n */\nexport function isOurs<T>(\n\terror: unknown,\n\tcls: abstract new (...args: never[]) => T,\n\tname: string,\n\twhat: string,\n): asserts error is T {\n\tif (error instanceof cls) return;\n\n\t// Same name, not the same class: the duplicate the probe exists for.\n\tif ((error as { name?: unknown } | null)?.name === name) {\n\t\tthrow new Error(\n\t\t\t`${what}\\n the error is named ${name} but is not @nxgt/janus's ${name}: two copies of @nxgt/janus are installed. The adapter must list it as a peer dependency, never a dependency`,\n\t\t);\n\t}\n\n\tthrow new Error(`${what}\\n expected ${name}, got ${show(error)}`);\n}\n\ninterface Difference {\n\treadonly path: string;\n\treadonly expected: unknown;\n\treadonly actual: unknown;\n}\n\nfunction differ(\n\tactual: unknown,\n\texpected: unknown,\n\tpath: string,\n): Difference | null {\n\tif (expected instanceof Date || actual instanceof Date) {\n\t\treturn actual instanceof Date &&\n\t\t\texpected instanceof Date &&\n\t\t\tactual.getTime() === expected.getTime()\n\t\t\t? null\n\t\t\t: { path, expected, actual };\n\t}\n\n\tif (Array.isArray(expected) || Array.isArray(actual)) {\n\t\tif (!Array.isArray(expected) || !Array.isArray(actual)) {\n\t\t\treturn { path, expected, actual };\n\t\t}\n\t\tif (expected.length !== actual.length) {\n\t\t\treturn {\n\t\t\t\tpath: `${path}.length`,\n\t\t\t\texpected: expected.length,\n\t\t\t\tactual: actual.length,\n\t\t\t};\n\t\t}\n\t\tfor (let i = 0; i < expected.length; i += 1) {\n\t\t\tconst inner = differ(actual[i], expected[i], `${path}[${i}]`);\n\t\t\tif (inner !== null) return inner;\n\t\t}\n\t\treturn null;\n\t}\n\n\tif (\n\t\ttypeof expected === 'object' &&\n\t\texpected !== null &&\n\t\ttypeof actual === 'object' &&\n\t\tactual !== null\n\t) {\n\t\tconst keys = new Set([...Object.keys(expected), ...Object.keys(actual)]);\n\t\tfor (const key of keys) {\n\t\t\tconst inner = differ(\n\t\t\t\t(actual as Record<string, unknown>)[key],\n\t\t\t\t(expected as Record<string, unknown>)[key],\n\t\t\t\tpath === '' ? key : `${path}.${key}`,\n\t\t\t);\n\t\t\tif (inner !== null) return inner;\n\t\t}\n\t\treturn null;\n\t}\n\n\treturn Object.is(actual, expected) ? null : { path, expected, actual };\n}\n\nfunction show(value: unknown): string {\n\tif (value instanceof Error) return `${value.name}: ${value.message}`;\n\tif (value instanceof Date) return value.toISOString();\n\tif (value === undefined) return 'undefined';\n\tif (typeof value === 'string') return JSON.stringify(value);\n\ttry {\n\t\tconst json = JSON.stringify(value);\n\t\treturn json.length > 200 ? `${json.slice(0, 200)}…` : json;\n\t} catch {\n\t\treturn String(value);\n\t}\n}\n",
6
6
  "import type {\n\tSessionRecord,\n\tTokenRecord,\n\tUserRecord,\n} from '../auth/port/types';\nimport { mintId } from '../ids/id';\n\n/**\n * Records the cases write. Every id is minted, so no two cases — and no two\n * records of one case — ever collide by accident; every collision a case\n * tests is one it wrote on purpose.\n */\n\nexport const at = (iso: string): Date => new Date(iso);\n\n/** A fresh login, so each record holds its own unless a case says otherwise. */\nconst fresh = () => `user-${mintId()}@example.test`;\n\nexport function userRecord(overrides: Partial<UserRecord> = {}): UserRecord {\n\tconst email = fresh();\n\treturn {\n\t\tid: mintId(),\n\t\ttype: 'user',\n\t\tschemaVersion: '1',\n\t\tactive: true,\n\t\tfields: { email, name: { first: 'Ada', last: 'Lovelace' } },\n\t\tlogins: [email],\n\t\tpassword: {\n\t\t\thash: '$scrypt$ln=17,r=8,p=1$c2FsdA==$a2V5',\n\t\t\tupdatedAt: at('2026-01-01T00:00:00.000Z'),\n\t\t},\n\t\tsecondFactor: null,\n\t\temailVerifiedAt: null,\n\t\tversion: 0,\n\t\tcreatedAt: at('2026-01-01T00:00:00.000Z'),\n\t\tupdatedAt: at('2026-01-01T00:00:00.000Z'),\n\t\t...overrides,\n\t};\n}\n\nexport function sessionRecord(\n\toverrides: Partial<SessionRecord> = {},\n): SessionRecord {\n\treturn {\n\t\tid: mintId(),\n\t\ttokenHash: hexOf(mintId()),\n\t\tuserId: mintId(),\n\t\tauthenticatedAt: at('2026-01-01T00:00:00.000Z'),\n\t\texpiresAt: at('2099-01-01T00:00:00.000Z'),\n\t\trevokedAt: null,\n\t\tcreatedAt: at('2026-01-01T00:00:00.000Z'),\n\t\t...overrides,\n\t};\n}\n\nexport function tokenRecord(overrides: Partial<TokenRecord> = {}): TokenRecord {\n\treturn {\n\t\ttokenHash: hexOf(mintId()),\n\t\tkind: 'resetPassword',\n\t\tuserId: mintId(),\n\t\taddress: fresh(),\n\t\tcodeHash: null,\n\t\tattempts: 0,\n\t\texpiresAt: at('2099-01-01T00:00:00.000Z'),\n\t\tspentAt: null,\n\t\tcreatedAt: at('2026-01-01T00:00:00.000Z'),\n\t\t...overrides,\n\t};\n}\n\n/** A 64-character hex string, shaped like a `sha256`, unique per call. */\nfunction hexOf(seed: string): string {\n\treturn seed.replace(/-/g, '').padEnd(64, '0').slice(0, 64);\n}\n",
7
- "import type { JanusStores } from '../../auth/port/types';\nimport { JanusError, StoreFailure } from '../../errors/janus-error';\nimport { isOurs, ok, rejects } from '../assert';\nimport { at, sessionRecord, tokenRecord, userRecord } from '../fixtures';\nimport type { CaseContext, ConformanceCase, PortMethod } from '../types';\n\n/**\n * **The invariant, as cases.** For each of the thirteen methods whose honest\n * answer can be \"nothing\" — `null`, `false`, `0`, an empty page — a store that\n * cannot answer must **reject**, and the rejection must not be `NOT_FOUND`.\n *\n * Every case seeds a record first, so a store that swallows its failure into an\n * absence answers something *false* rather than something merely empty.\n *\n * The rejection is either `@nxgt/janus`'s own `StoreFailure` — the `instanceof`\n * probe, which fails on a second copy of the package — or an error that is no\n * `JanusError` at all, which the core wraps into `STORE_FAILED` itself.\n */\nfunction outage<S extends keyof JanusStores>(\n\tslot: S,\n\tmethod: PortMethod<S>,\n\tcall: (context: CaseContext) => Promise<unknown>,\n\tseed: (context: CaseContext) => Promise<void>,\n): ConformanceCase {\n\treturn {\n\t\tid: `outage.${method}`,\n\t\tgroup: 'outage',\n\t\tname: `${slot}.${method} rejects when the store cannot answer — never null, false, 0 or an empty page`,\n\t\tneeds: 'faults',\n\t\tasync run(context) {\n\t\t\tawait seed(context);\n\t\t\tawait context.faults?.fail(slot, method);\n\n\t\t\tconst error = await rejects(\n\t\t\t\tcall(context),\n\t\t\t\t`${slot}.${method} under an outage should reject: answering an absence turns an outage into a silent lockout`,\n\t\t\t);\n\n\t\t\tif (\n\t\t\t\terror instanceof JanusError ||\n\t\t\t\t(error as { name?: unknown })?.name === 'StoreFailure'\n\t\t\t) {\n\t\t\t\tisOurs(error, StoreFailure, `${slot}.${method} under an outage`);\n\t\t\t}\n\t\t\tok(\n\t\t\t\t(error as { code?: unknown } | null)?.code !== 'NOT_FOUND',\n\t\t\t\t`${slot}.${method} under an outage rejected with NOT_FOUND: an outage is never an absence`,\n\t\t\t);\n\t\t},\n\t};\n}\n\nconst user = userRecord();\nconst session = sessionRecord({ userId: user.id });\nconst token = tokenRecord({ userId: user.id });\nconst now = at('2026-02-01T00:00:00.000Z');\n\n/** Each case writes the same three records, fresh stores every time. */\nconst seed = async ({ stores }: CaseContext) => {\n\tawait stores.users.insertUser(user);\n\tawait stores.sessions.insertSession(session);\n\tawait stores.tokens.insertToken(token);\n};\n\nexport const outageCases: readonly ConformanceCase[] = [\n\toutage(\n\t\t'users',\n\t\t'findUser',\n\t\t({ stores }) => stores.users.findUser(user.id),\n\t\tseed,\n\t),\n\toutage(\n\t\t'users',\n\t\t'findUserByLogin',\n\t\t({ stores }) =>\n\t\t\tstores.users.findUserByLogin(user.type, user.logins[0] ?? ''),\n\t\tseed,\n\t),\n\toutage(\n\t\t'users',\n\t\t'listUsers',\n\t\t({ stores }) =>\n\t\t\tstores.users.listUsers({ type: user.type, after: null, limit: 10 }),\n\t\tseed,\n\t),\n\toutage(\n\t\t'sessions',\n\t\t'findSessionByTokenHash',\n\t\t({ stores }) => stores.sessions.findSessionByTokenHash(session.tokenHash),\n\t\tseed,\n\t),\n\toutage(\n\t\t'sessions',\n\t\t'extendSession',\n\t\t({ stores }) =>\n\t\t\tstores.sessions.extendSession(session.id, at('2099-06-01T00:00:00.000Z')),\n\t\tseed,\n\t),\n\toutage(\n\t\t'sessions',\n\t\t'revokeSession',\n\t\t({ stores }) => stores.sessions.revokeSession(session.id, now),\n\t\tseed,\n\t),\n\toutage(\n\t\t'sessions',\n\t\t'revokeUserSessions',\n\t\t({ stores }) => stores.sessions.revokeUserSessions(user.id, now),\n\t\tseed,\n\t),\n\toutage(\n\t\t'tokens',\n\t\t'consumeToken',\n\t\t({ stores }) =>\n\t\t\tstores.tokens.consumeToken(token.tokenHash, 'resetPassword', now),\n\t\tseed,\n\t),\n\toutage(\n\t\t'tokens',\n\t\t'countAttempt',\n\t\t({ stores }) =>\n\t\t\tstores.tokens.countAttempt(token.tokenHash, 'resetPassword'),\n\t\tseed,\n\t),\n\toutage(\n\t\t'tokens',\n\t\t'spendUserTokens',\n\t\t({ stores }) =>\n\t\t\tstores.tokens.spendUserTokens(user.id, 'resetPassword', now),\n\t\tseed,\n\t),\n\toutage(\n\t\t'users',\n\t\t'deleteUser',\n\t\t({ stores }) => stores.users.deleteUser(user.id),\n\t\tseed,\n\t),\n\toutage(\n\t\t'sessions',\n\t\t'deleteUserSessions',\n\t\t({ stores }) => stores.sessions.deleteUserSessions(user.id),\n\t\tseed,\n\t),\n\toutage(\n\t\t'tokens',\n\t\t'deleteUserTokens',\n\t\t({ stores }) => stores.tokens.deleteUserTokens(user.id),\n\t\tseed,\n\t),\n];\n",
7
+ "import type { JanusStores } from '../../auth/port/types';\nimport { JanusError, StoreFailure } from '../../errors/janus-error';\nimport { isOurs, ok, rejects } from '../assert';\nimport { at, sessionRecord, tokenRecord, userRecord } from '../fixtures';\nimport type { CaseContext, ConformanceCase, PortMethod } from '../types';\n\n/**\n * **The invariant, as cases.** For each of the thirteen methods whose honest\n * answer can be \"nothing\" — `null`, `false`, `0`, an empty page — a store that\n * cannot answer must **reject**, and the rejection must not be `NOT_FOUND`.\n *\n * Every case seeds a record first, so a store that swallows its failure into an\n * absence answers something *false* rather than something merely empty.\n *\n * The rejection is either `@nxgt/janus`'s own `StoreFailure` — the `instanceof`\n * probe, which fails on a second copy of the package — or an error that is no\n * `JanusError` at all, which the core wraps into `STORE_FAILED` itself.\n */\nfunction outage<S extends keyof JanusStores>(\n\tslot: S,\n\tmethod: PortMethod<S>,\n\tcall: (context: CaseContext) => Promise<unknown>,\n\tseed: (context: CaseContext) => Promise<void>,\n): ConformanceCase {\n\treturn {\n\t\tid: `outage.${method}`,\n\t\tgroup: 'outage',\n\t\tname: `${slot}.${method} rejects when the store cannot answer — never null, false, 0 or an empty page`,\n\t\tneeds: 'faults',\n\t\tasync run(context) {\n\t\t\tawait seed(context);\n\t\t\tawait context.faults?.fail(slot, method);\n\n\t\t\tconst error = await rejects(\n\t\t\t\tcall(context),\n\t\t\t\t`${slot}.${method} under an outage should reject: answering an absence turns an outage into a silent lockout`,\n\t\t\t);\n\n\t\t\tif (\n\t\t\t\terror instanceof JanusError ||\n\t\t\t\t(error as { name?: unknown })?.name === 'StoreFailure'\n\t\t\t) {\n\t\t\t\tisOurs(\n\t\t\t\t\terror,\n\t\t\t\t\tStoreFailure,\n\t\t\t\t\t'StoreFailure',\n\t\t\t\t\t`${slot}.${method} under an outage`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tok(\n\t\t\t\t(error as { code?: unknown } | null)?.code !== 'NOT_FOUND',\n\t\t\t\t`${slot}.${method} under an outage rejected with NOT_FOUND: an outage is never an absence`,\n\t\t\t);\n\t\t},\n\t};\n}\n\nconst user = userRecord();\nconst session = sessionRecord({ userId: user.id });\nconst token = tokenRecord({ userId: user.id });\nconst now = at('2026-02-01T00:00:00.000Z');\n\n/** Each case writes the same three records, fresh stores every time. */\nconst seed = async ({ stores }: CaseContext) => {\n\tawait stores.users.insertUser(user);\n\tawait stores.sessions.insertSession(session);\n\tawait stores.tokens.insertToken(token);\n};\n\nexport const outageCases: readonly ConformanceCase[] = [\n\toutage(\n\t\t'users',\n\t\t'findUser',\n\t\t({ stores }) => stores.users.findUser(user.id),\n\t\tseed,\n\t),\n\toutage(\n\t\t'users',\n\t\t'findUserByLogin',\n\t\t({ stores }) =>\n\t\t\tstores.users.findUserByLogin(user.type, user.logins[0] ?? ''),\n\t\tseed,\n\t),\n\toutage(\n\t\t'users',\n\t\t'listUsers',\n\t\t({ stores }) =>\n\t\t\tstores.users.listUsers({ type: user.type, after: null, limit: 10 }),\n\t\tseed,\n\t),\n\toutage(\n\t\t'sessions',\n\t\t'findSessionByTokenHash',\n\t\t({ stores }) => stores.sessions.findSessionByTokenHash(session.tokenHash),\n\t\tseed,\n\t),\n\toutage(\n\t\t'sessions',\n\t\t'extendSession',\n\t\t({ stores }) =>\n\t\t\tstores.sessions.extendSession(session.id, at('2099-06-01T00:00:00.000Z')),\n\t\tseed,\n\t),\n\toutage(\n\t\t'sessions',\n\t\t'revokeSession',\n\t\t({ stores }) => stores.sessions.revokeSession(session.id, now),\n\t\tseed,\n\t),\n\toutage(\n\t\t'sessions',\n\t\t'revokeUserSessions',\n\t\t({ stores }) => stores.sessions.revokeUserSessions(user.id, now),\n\t\tseed,\n\t),\n\toutage(\n\t\t'tokens',\n\t\t'consumeToken',\n\t\t({ stores }) =>\n\t\t\tstores.tokens.consumeToken(token.tokenHash, 'resetPassword', now),\n\t\tseed,\n\t),\n\toutage(\n\t\t'tokens',\n\t\t'countAttempt',\n\t\t({ stores }) =>\n\t\t\tstores.tokens.countAttempt(token.tokenHash, 'resetPassword'),\n\t\tseed,\n\t),\n\toutage(\n\t\t'tokens',\n\t\t'spendUserTokens',\n\t\t({ stores }) =>\n\t\t\tstores.tokens.spendUserTokens(user.id, 'resetPassword', now),\n\t\tseed,\n\t),\n\toutage(\n\t\t'users',\n\t\t'deleteUser',\n\t\t({ stores }) => stores.users.deleteUser(user.id),\n\t\tseed,\n\t),\n\toutage(\n\t\t'sessions',\n\t\t'deleteUserSessions',\n\t\t({ stores }) => stores.sessions.deleteUserSessions(user.id),\n\t\tseed,\n\t),\n\toutage(\n\t\t'tokens',\n\t\t'deleteUserTokens',\n\t\t({ stores }) => stores.tokens.deleteUserTokens(user.id),\n\t\tseed,\n\t),\n];\n",
8
8
  "import { mintId } from '../../ids/id';\nimport { equal, isNull, ok } from '../assert';\nimport { at, sessionRecord } from '../fixtures';\nimport type { ConformanceCase } from '../types';\n\nconst group = 'sessions';\n\nexport const sessionStoreCases: readonly ConformanceCase[] = [\n\t{\n\t\tid: 'sessions.verbatim',\n\t\tgroup,\n\t\tname: 'answers a stored session verbatim — revoked or lapsed — or null once lapsed, and never a changed record',\n\t\tasync run({ stores }) {\n\t\t\tconst standing = sessionRecord();\n\t\t\tconst revoked = sessionRecord({\n\t\t\t\trevokedAt: at('2026-01-02T00:00:00.000Z'),\n\t\t\t});\n\t\t\tconst lapsed = sessionRecord({\n\t\t\t\texpiresAt: at('2020-01-01T00:00:00.000Z'),\n\t\t\t});\n\t\t\tfor (const record of [standing, revoked, lapsed]) {\n\t\t\t\tawait stores.sessions.insertSession(record);\n\t\t\t}\n\n\t\t\tequal(\n\t\t\t\tawait stores.sessions.findSessionByTokenHash(standing.tokenHash),\n\t\t\t\tstanding,\n\t\t\t\t'findSessionByTokenHash for a standing session',\n\t\t\t);\n\t\t\tequal(\n\t\t\t\tawait stores.sessions.findSessionByTokenHash(revoked.tokenHash),\n\t\t\t\trevoked,\n\t\t\t\t'findSessionByTokenHash for a revoked session should answer it verbatim — revocation is the core’s to read',\n\t\t\t);\n\n\t\t\t// A TTL index may already have dropped it: null is allowed, a changed\n\t\t\t// record is not.\n\t\t\tconst found = await stores.sessions.findSessionByTokenHash(\n\t\t\t\tlapsed.tokenHash,\n\t\t\t);\n\t\t\tif (found !== null) {\n\t\t\t\tequal(\n\t\t\t\t\tfound,\n\t\t\t\t\tlapsed,\n\t\t\t\t\t'findSessionByTokenHash for a lapsed session should answer it verbatim, or null',\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tisNull(\n\t\t\t\tawait stores.sessions.findSessionByTokenHash('f'.repeat(64)),\n\t\t\t\t'findSessionByTokenHash for an unknown hash',\n\t\t\t);\n\t\t},\n\t},\n\t{\n\t\tid: 'sessions.idempotentInsert',\n\t\tgroup,\n\t\tname: 'is idempotent under retry: inserting an existing session id writes nothing',\n\t\tasync run({ stores }) {\n\t\t\tconst record = sessionRecord();\n\t\t\tawait stores.sessions.insertSession(record);\n\t\t\tawait stores.sessions.insertSession({\n\t\t\t\t...record,\n\t\t\t\texpiresAt: new Date('2099-06-01T00:00:00.000Z'),\n\t\t\t});\n\n\t\t\tequal(\n\t\t\t\tawait stores.sessions.findSessionByTokenHash(record.tokenHash),\n\t\t\t\trecord,\n\t\t\t\t'insertSession retried with the same id should write nothing',\n\t\t\t);\n\t\t},\n\t},\n\t{\n\t\tid: 'sessions.extend',\n\t\tgroup,\n\t\tname: 'extends a standing session, and never brings back a revoked one',\n\t\tasync run({ stores }) {\n\t\t\tconst standing = sessionRecord();\n\t\t\tconst revoked = sessionRecord({\n\t\t\t\trevokedAt: at('2026-01-02T00:00:00.000Z'),\n\t\t\t});\n\t\t\tawait stores.sessions.insertSession(standing);\n\t\t\tawait stores.sessions.insertSession(revoked);\n\t\t\tconst later = at('2099-06-01T00:00:00.000Z');\n\n\t\t\tequal(\n\t\t\t\tawait stores.sessions.extendSession(standing.id, later),\n\t\t\t\t{ ...standing, expiresAt: later },\n\t\t\t\t'extendSession should answer the session with its new expiresAt',\n\t\t\t);\n\t\t\tisNull(\n\t\t\t\tawait stores.sessions.extendSession(revoked.id, later),\n\t\t\t\t'extendSession on a revoked session — an extension racing a revocation must never bring it back',\n\t\t\t);\n\t\t\tequal(\n\t\t\t\tawait stores.sessions.findSessionByTokenHash(revoked.tokenHash),\n\t\t\t\trevoked,\n\t\t\t\t'extendSession refused on a revoked session should have written nothing',\n\t\t\t);\n\t\t\tisNull(\n\t\t\t\tawait stores.sessions.extendSession(mintId(), later),\n\t\t\t\t'extendSession on an unknown session',\n\t\t\t);\n\t\t},\n\t},\n\t{\n\t\tid: 'sessions.revoke',\n\t\tgroup,\n\t\tname: 'revokes once and keeps the first revokedAt; answers false only when there is no session',\n\t\tasync run({ stores }) {\n\t\t\tconst record = sessionRecord();\n\t\t\tawait stores.sessions.insertSession(record);\n\t\t\tconst first = at('2026-02-01T00:00:00.000Z');\n\n\t\t\tequal(\n\t\t\t\tawait stores.sessions.revokeSession(record.id, first),\n\t\t\t\ttrue,\n\t\t\t\t'revokeSession on a standing session',\n\t\t\t);\n\t\t\tequal(\n\t\t\t\tawait stores.sessions.revokeSession(\n\t\t\t\t\trecord.id,\n\t\t\t\t\tat('2026-03-01T00:00:00.000Z'),\n\t\t\t\t),\n\t\t\t\ttrue,\n\t\t\t\t'revokeSession on a revoked session still answers true: the session exists',\n\t\t\t);\n\t\t\tequal(\n\t\t\t\t(await stores.sessions.findSessionByTokenHash(record.tokenHash))\n\t\t\t\t\t?.revokedAt,\n\t\t\t\tfirst,\n\t\t\t\t'revokeSession twice should keep the first revokedAt',\n\t\t\t);\n\t\t\tequal(\n\t\t\t\tawait stores.sessions.revokeSession(mintId(), first),\n\t\t\t\tfalse,\n\t\t\t\t'revokeSession on an unknown session',\n\t\t\t);\n\t\t},\n\t},\n\t{\n\t\tid: 'sessions.revokeUser',\n\t\tgroup,\n\t\tname: 'revokes every standing session of one user but the one excepted, and counts only what it revoked',\n\t\tasync run({ stores }) {\n\t\t\tconst userId = mintId();\n\t\t\tconst current = sessionRecord({ userId });\n\t\t\tconst other = sessionRecord({ userId });\n\t\t\tconst already = sessionRecord({\n\t\t\t\tuserId,\n\t\t\t\trevokedAt: at('2026-01-02T00:00:00.000Z'),\n\t\t\t});\n\t\t\tconst stranger = sessionRecord();\n\t\t\tfor (const record of [current, other, already, stranger]) {\n\t\t\t\tawait stores.sessions.insertSession(record);\n\t\t\t}\n\t\t\tconst now = at('2026-02-01T00:00:00.000Z');\n\n\t\t\tequal(\n\t\t\t\tawait stores.sessions.revokeUserSessions(userId, now, current.id),\n\t\t\t\t1,\n\t\t\t\t'revokeUserSessions with except: how many this call revoked',\n\t\t\t);\n\t\t\tisNull(\n\t\t\t\t(await stores.sessions.findSessionByTokenHash(current.tokenHash))\n\t\t\t\t\t?.revokedAt ?? null,\n\t\t\t\t'revokeUserSessions should spare the excepted session',\n\t\t\t);\n\t\t\tequal(\n\t\t\t\t(await stores.sessions.findSessionByTokenHash(already.tokenHash))\n\t\t\t\t\t?.revokedAt,\n\t\t\t\talready.revokedAt,\n\t\t\t\t'revokeUserSessions should keep an earlier revokedAt',\n\t\t\t);\n\t\t\tequal(\n\t\t\t\tawait stores.sessions.findSessionByTokenHash(stranger.tokenHash),\n\t\t\t\tstranger,\n\t\t\t\t'revokeUserSessions should not touch another user',\n\t\t\t);\n\t\t\tequal(\n\t\t\t\tawait stores.sessions.revokeUserSessions(userId, now),\n\t\t\t\t1,\n\t\t\t\t'revokeUserSessions without except',\n\t\t\t);\n\t\t\tequal(\n\t\t\t\tawait stores.sessions.revokeUserSessions(mintId(), now),\n\t\t\t\t0,\n\t\t\t\t'revokeUserSessions for a user with none answers 0, not a failure',\n\t\t\t);\n\t\t},\n\t},\n\t{\n\t\tid: 'sessions.deleteUser',\n\t\tgroup,\n\t\tname: 'deletes every session of one user — standing, revoked or lapsed — and counts them',\n\t\tasync run({ stores }) {\n\t\t\tconst userId = mintId();\n\t\t\tconst lapsed = sessionRecord({\n\t\t\t\tuserId,\n\t\t\t\texpiresAt: at('2026-01-02T00:00:00.000Z'),\n\t\t\t});\n\t\t\tconst records = [\n\t\t\t\tsessionRecord({ userId }),\n\t\t\t\tsessionRecord({ userId, revokedAt: at('2026-01-02T00:00:00.000Z') }),\n\t\t\t\tlapsed,\n\t\t\t];\n\t\t\tconst stranger = sessionRecord();\n\t\t\tfor (const record of [...records, stranger]) {\n\t\t\t\tawait stores.sessions.insertSession(record);\n\t\t\t}\n\n\t\t\t// The lapsed one may be gone already: a store with its own expiry —\n\t\t\t// a Redis key TTL — drops it as soon as it lapses, which the port\n\t\t\t// allows. Whether it is still there is what the store answers for it.\n\t\t\tconst lapsedHeld =\n\t\t\t\t(await stores.sessions.findSessionByTokenHash(lapsed.tokenHash)) !==\n\t\t\t\tnull;\n\t\t\tconst expected = lapsedHeld ? 3 : 2;\n\t\t\tconst deleted = await stores.sessions.deleteUserSessions(userId);\n\t\t\tok(\n\t\t\t\tdeleted === expected,\n\t\t\t\t`deleteUserSessions: how many it deleted, revoked and lapsed ones included — ${String(expected)}, as the lapsed one is ${lapsedHeld ? 'still held' : 'already expired'}; got ${String(deleted)}`,\n\t\t\t);\n\t\t\tfor (const record of records) {\n\t\t\t\tisNull(\n\t\t\t\t\tawait stores.sessions.findSessionByTokenHash(record.tokenHash),\n\t\t\t\t\t'findSessionByTokenHash after deleteUserSessions',\n\t\t\t\t);\n\t\t\t}\n\t\t\tequal(\n\t\t\t\tawait stores.sessions.findSessionByTokenHash(stranger.tokenHash),\n\t\t\t\tstranger,\n\t\t\t\t'deleteUserSessions should not touch another user',\n\t\t\t);\n\t\t\tequal(\n\t\t\t\tawait stores.sessions.deleteUserSessions(userId),\n\t\t\t\t0,\n\t\t\t\t'deleteUserSessions for a user with none answers 0, not a failure',\n\t\t\t);\n\t\t},\n\t},\n\t{\n\t\tid: 'sessions.deleteExpired',\n\t\tgroup,\n\t\tname: 'deletes sessions whose expiry is at or before the instant, and only those',\n\t\tneeds: 'deleteExpiredSessions',\n\t\tasync run({ stores }) {\n\t\t\tconst collect = stores.sessions.deleteExpiredSessions;\n\t\t\tok(collect !== undefined, 'deleteExpiredSessions should be present');\n\t\t\tconst lapsed = sessionRecord({\n\t\t\t\texpiresAt: at('2026-01-10T00:00:00.000Z'),\n\t\t\t});\n\t\t\tconst living = sessionRecord({\n\t\t\t\texpiresAt: at('2026-01-10T00:00:00.001Z'),\n\t\t\t});\n\t\t\tawait stores.sessions.insertSession(lapsed);\n\t\t\tawait stores.sessions.insertSession(living);\n\n\t\t\tequal(\n\t\t\t\tawait collect?.call(stores.sessions, at('2026-01-10T00:00:00.000Z')),\n\t\t\t\t1,\n\t\t\t\t'deleteExpiredSessions: how many it deleted',\n\t\t\t);\n\t\t\tisNull(\n\t\t\t\tawait stores.sessions.findSessionByTokenHash(lapsed.tokenHash),\n\t\t\t\t'findSessionByTokenHash after deleteExpiredSessions',\n\t\t\t);\n\t\t\tequal(\n\t\t\t\tawait stores.sessions.findSessionByTokenHash(living.tokenHash),\n\t\t\t\tliving,\n\t\t\t\t'deleteExpiredSessions should keep a session one millisecond short of lapsing',\n\t\t\t);\n\t\t},\n\t},\n];\n",
9
9
  "import { mintId } from '../../ids/id';\nimport { equal, isNull } from '../assert';\nimport { at, tokenRecord } from '../fixtures';\nimport type { ConformanceCase } from '../types';\n\nconst group = 'tokens';\n\nexport const tokenStoreCases: readonly ConformanceCase[] = [\n\t{\n\t\tid: 'tokens.consume',\n\t\tgroup,\n\t\tname: 'answers the token as it was before the call: spentAt null means this call spent it',\n\t\tasync run({ stores }) {\n\t\t\tconst record = tokenRecord();\n\t\t\tawait stores.tokens.insertToken(record);\n\t\t\tconst first = at('2026-02-01T00:00:00.000Z');\n\n\t\t\tequal(\n\t\t\t\tawait stores.tokens.consumeToken(\n\t\t\t\t\trecord.tokenHash,\n\t\t\t\t\t'resetPassword',\n\t\t\t\t\tfirst,\n\t\t\t\t),\n\t\t\t\trecord,\n\t\t\t\t'consumeToken the first time should answer the token as it was — spentAt null',\n\t\t\t);\n\t\t\tequal(\n\t\t\t\tawait stores.tokens.consumeToken(\n\t\t\t\t\trecord.tokenHash,\n\t\t\t\t\t'resetPassword',\n\t\t\t\t\tat('2026-02-02T00:00:00.000Z'),\n\t\t\t\t),\n\t\t\t\t{ ...record, spentAt: first },\n\t\t\t\t'consumeToken the second time should answer it spent at the first call’s instant, and change nothing',\n\t\t\t);\n\t\t},\n\t},\n\t{\n\t\tid: 'tokens.concurrency',\n\t\tgroup,\n\t\tname: 'lets exactly one of twenty concurrent redemptions spend a token — one conditional write, never a read then a write',\n\t\tasync run({ stores }) {\n\t\t\tconst record = tokenRecord();\n\t\t\tawait stores.tokens.insertToken(record);\n\t\t\tconst now = at('2026-02-01T00:00:00.000Z');\n\n\t\t\tconst answers = await Promise.all(\n\t\t\t\tArray.from({ length: 20 }, () =>\n\t\t\t\t\tstores.tokens.consumeToken(record.tokenHash, 'resetPassword', now),\n\t\t\t\t),\n\t\t\t);\n\n\t\t\tequal(\n\t\t\t\tanswers.filter((answer) => answer !== null && answer.spentAt === null)\n\t\t\t\t\t.length,\n\t\t\t\t1,\n\t\t\t\t'consumeToken: of twenty concurrent calls, exactly one should see spentAt null — a reset token redeemed twice is an account takeover',\n\t\t\t);\n\t\t},\n\t},\n\t{\n\t\tid: 'tokens.kind',\n\t\tgroup,\n\t\tname: 'does not know, and does not spend, a token of the other kind',\n\t\tasync run({ stores }) {\n\t\t\tconst record = tokenRecord({ kind: 'verifyEmail' });\n\t\t\tawait stores.tokens.insertToken(record);\n\n\t\t\tisNull(\n\t\t\t\tawait stores.tokens.consumeToken(\n\t\t\t\t\trecord.tokenHash,\n\t\t\t\t\t'resetPassword',\n\t\t\t\t\tat('2026-02-01T00:00:00.000Z'),\n\t\t\t\t),\n\t\t\t\t'consumeToken for a verifyEmail token redeemed as resetPassword',\n\t\t\t);\n\t\t\tconst own = await stores.tokens.consumeToken(\n\t\t\t\trecord.tokenHash,\n\t\t\t\t'verifyEmail',\n\t\t\t\tat('2026-02-02T00:00:00.000Z'),\n\t\t\t);\n\t\t\tequal(\n\t\t\t\town,\n\t\t\t\trecord,\n\t\t\t\t'consumeToken of the other kind should not have spent the token: redeemed as its own kind, it is still unspent',\n\t\t\t);\n\t\t\tisNull(\n\t\t\t\tawait stores.tokens.consumeToken(\n\t\t\t\t\t'0'.repeat(64),\n\t\t\t\t\t'resetPassword',\n\t\t\t\t\tat('2026-02-01T00:00:00.000Z'),\n\t\t\t\t),\n\t\t\t\t'consumeToken for an unknown hash',\n\t\t\t);\n\t\t},\n\t},\n\t{\n\t\tid: 'tokens.countAttempt',\n\t\tgroup,\n\t\tname: 'counts an attempt at a code, and answers the token as it is after the call',\n\t\tasync run({ stores }) {\n\t\t\tconst record = tokenRecord({\n\t\t\t\tkind: 'signInCode',\n\t\t\t\tcodeHash: 'c'.repeat(64),\n\t\t\t});\n\t\t\tawait stores.tokens.insertToken(record);\n\n\t\t\tequal(\n\t\t\t\tawait stores.tokens.countAttempt(record.tokenHash, 'signInCode'),\n\t\t\t\t{ ...record, attempts: 1 },\n\t\t\t\t'countAttempt the first time should answer the token with attempts 1, codeHash as written',\n\t\t\t);\n\t\t\tequal(\n\t\t\t\tawait stores.tokens.countAttempt(record.tokenHash, 'signInCode'),\n\t\t\t\t{ ...record, attempts: 2 },\n\t\t\t\t'countAttempt the second time should answer attempts 2',\n\t\t\t);\n\t\t\tequal(\n\t\t\t\tawait stores.tokens.consumeToken(\n\t\t\t\t\trecord.tokenHash,\n\t\t\t\t\t'signInCode',\n\t\t\t\t\tat('2026-02-01T00:00:00.000Z'),\n\t\t\t\t),\n\t\t\t\t{ ...record, attempts: 2 },\n\t\t\t\t'consumeToken should answer the attempts counted, and spend the token',\n\t\t\t);\n\t\t},\n\t},\n\t{\n\t\tid: 'tokens.countAttemptConcurrency',\n\t\tgroup,\n\t\tname: 'gives twenty concurrent attempts twenty distinct counts — one conditional write, never a read then a write',\n\t\tasync run({ stores }) {\n\t\t\tconst record = tokenRecord({ kind: 'secondFactor' });\n\t\t\tawait stores.tokens.insertToken(record);\n\n\t\t\tconst answers = await Promise.all(\n\t\t\t\tArray.from({ length: 20 }, () =>\n\t\t\t\t\tstores.tokens.countAttempt(record.tokenHash, 'secondFactor'),\n\t\t\t\t),\n\t\t\t);\n\n\t\t\tequal(\n\t\t\t\tanswers\n\t\t\t\t\t.map((answer) => answer?.attempts)\n\t\t\t\t\t.sort((a, b) => (a ?? 0) - (b ?? 0)),\n\t\t\t\tArray.from({ length: 20 }, (_, index) => index + 1),\n\t\t\t\t'countAttempt: twenty concurrent calls should answer 1 to 20, each once — two guesses reading one count is a guess for free',\n\t\t\t);\n\t\t},\n\t},\n\t{\n\t\tid: 'tokens.countAttemptRace',\n\t\tgroup,\n\t\tname: 'never counts an attempt once the token is spent, when attempts and a redemption race',\n\t\tasync run({ stores }) {\n\t\t\tconst record = tokenRecord({ kind: 'signInCode' });\n\t\t\tawait stores.tokens.insertToken(record);\n\t\t\tconst now = at('2026-02-01T00:00:00.000Z');\n\t\t\tconst count = () =>\n\t\t\t\tstores.tokens.countAttempt(record.tokenHash, 'signInCode');\n\n\t\t\tconst answers = await Promise.all([\n\t\t\t\t...Array.from({ length: 10 }, count),\n\t\t\t\tstores.tokens.consumeToken(record.tokenHash, 'signInCode', now),\n\t\t\t\t...Array.from({ length: 10 }, count),\n\t\t\t]);\n\t\t\tconst final = await stores.tokens.consumeToken(\n\t\t\t\trecord.tokenHash,\n\t\t\t\t'signInCode',\n\t\t\t\tnow,\n\t\t\t);\n\t\t\tif (final === null) {\n\t\t\t\tthrow new Error('consumeToken after the race should answer the token');\n\t\t\t}\n\t\t\tconst counted = answers\n\t\t\t\t.slice(0, 10)\n\t\t\t\t.concat(answers.slice(11))\n\t\t\t\t.filter((answer) => answer !== null && answer.spentAt === null)\n\t\t\t\t.map((answer) => answer?.attempts ?? 0)\n\t\t\t\t.sort((a, b) => a - b);\n\n\t\t\tequal(\n\t\t\t\tcounted,\n\t\t\t\tArray.from({ length: final.attempts }, (_, index) => index + 1),\n\t\t\t\t'countAttempt: the attempts answered unspent should be 1 to the final count, each once',\n\t\t\t);\n\t\t\tequal(\n\t\t\t\tanswers\n\t\t\t\t\t.filter((answer) => answer !== null && answer.spentAt !== null)\n\t\t\t\t\t.every((answer) => answer?.attempts === final.attempts),\n\t\t\t\ttrue,\n\t\t\t\t'countAttempt: every answer after the spend should carry the final count — an attempt counted on a spent token is one the limit never saw',\n\t\t\t);\n\t\t},\n\t},\n\t{\n\t\tid: 'tokens.countAttemptSpent',\n\t\tgroup,\n\t\tname: 'does not count an attempt at a spent token, nor at a token of another kind, nor at none',\n\t\tasync run({ stores }) {\n\t\t\tconst spent = tokenRecord({\n\t\t\t\tkind: 'signInCode',\n\t\t\t\tattempts: 3,\n\t\t\t\tspentAt: at('2026-01-02T00:00:00.000Z'),\n\t\t\t});\n\t\t\tconst other = tokenRecord({ kind: 'resetPassword' });\n\t\t\tawait stores.tokens.insertToken(spent);\n\t\t\tawait stores.tokens.insertToken(other);\n\n\t\t\tfor (const call of ['first', 'second']) {\n\t\t\t\tequal(\n\t\t\t\t\tawait stores.tokens.countAttempt(spent.tokenHash, 'signInCode'),\n\t\t\t\t\tspent,\n\t\t\t\t\t`countAttempt on a spent token, the ${call} time, should answer it as it is: attempts still 3, nothing written`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tisNull(\n\t\t\t\tawait stores.tokens.countAttempt(other.tokenHash, 'signInCode'),\n\t\t\t\t'countAttempt for a resetPassword token counted as signInCode',\n\t\t\t);\n\t\t\tequal(\n\t\t\t\tawait stores.tokens.consumeToken(\n\t\t\t\t\tother.tokenHash,\n\t\t\t\t\t'resetPassword',\n\t\t\t\t\tat('2026-02-01T00:00:00.000Z'),\n\t\t\t\t),\n\t\t\t\tother,\n\t\t\t\t'countAttempt of the other kind should not have counted: attempts still 0',\n\t\t\t);\n\t\t\tisNull(\n\t\t\t\tawait stores.tokens.countAttempt('0'.repeat(64), 'signInCode'),\n\t\t\t\t'countAttempt for an unknown hash',\n\t\t\t);\n\t\t},\n\t},\n\t{\n\t\tid: 'tokens.spendUserTokens',\n\t\tgroup,\n\t\tname: 'spends every unspent token of one user and one kind, and counts them, leaving the rest as they were',\n\t\tasync run({ stores }) {\n\t\t\tconst userId = mintId();\n\t\t\tconst first = tokenRecord({ userId, kind: 'signInCode' });\n\t\t\tconst second = tokenRecord({ userId, kind: 'signInCode', attempts: 2 });\n\t\t\tconst spentBefore = at('2026-01-02T00:00:00.000Z');\n\t\t\tconst spent = tokenRecord({\n\t\t\t\tuserId,\n\t\t\t\tkind: 'signInCode',\n\t\t\t\tspentAt: spentBefore,\n\t\t\t});\n\t\t\tconst otherKind = tokenRecord({ userId, kind: 'resetPassword' });\n\t\t\tconst otherUser = tokenRecord({ kind: 'signInCode' });\n\t\t\tfor (const record of [first, second, spent, otherKind, otherUser]) {\n\t\t\t\tawait stores.tokens.insertToken(record);\n\t\t\t}\n\t\t\tconst now = at('2026-02-01T00:00:00.000Z');\n\n\t\t\tequal(\n\t\t\t\tawait stores.tokens.spendUserTokens(userId, 'signInCode', now),\n\t\t\t\t2,\n\t\t\t\t'spendUserTokens: how many it spent — the two unspent signInCode tokens, not the one already spent',\n\t\t\t);\n\t\t\tfor (const record of [first, second]) {\n\t\t\t\tequal(\n\t\t\t\t\tawait stores.tokens.consumeToken(record.tokenHash, 'signInCode', now),\n\t\t\t\t\t{ ...record, spentAt: now },\n\t\t\t\t\t'spendUserTokens should have spent it at `at`, keeping its attempts',\n\t\t\t\t);\n\t\t\t}\n\t\t\tequal(\n\t\t\t\tawait stores.tokens.consumeToken(spent.tokenHash, 'signInCode', now),\n\t\t\t\tspent,\n\t\t\t\t'spendUserTokens should keep the spentAt of a token already spent',\n\t\t\t);\n\t\t\tequal(\n\t\t\t\tawait stores.tokens.consumeToken(\n\t\t\t\t\totherKind.tokenHash,\n\t\t\t\t\t'resetPassword',\n\t\t\t\t\tnow,\n\t\t\t\t),\n\t\t\t\totherKind,\n\t\t\t\t'spendUserTokens should not touch a token of another kind',\n\t\t\t);\n\t\t\tequal(\n\t\t\t\tawait stores.tokens.consumeToken(\n\t\t\t\t\totherUser.tokenHash,\n\t\t\t\t\t'signInCode',\n\t\t\t\t\tnow,\n\t\t\t\t),\n\t\t\t\totherUser,\n\t\t\t\t'spendUserTokens should not touch another user',\n\t\t\t);\n\t\t\tequal(\n\t\t\t\tawait stores.tokens.spendUserTokens(userId, 'signInCode', now),\n\t\t\t\t0,\n\t\t\t\t'spendUserTokens for a user with none left unspent answers 0, not a failure',\n\t\t\t);\n\t\t\tequal(\n\t\t\t\tawait stores.tokens.spendUserTokens(mintId(), 'signInCode', now),\n\t\t\t\t0,\n\t\t\t\t'spendUserTokens for a user with no token at all answers 0',\n\t\t\t);\n\t\t},\n\t},\n\t{\n\t\tid: 'tokens.spendUserTokensExcept',\n\t\tgroup,\n\t\tname: 'spares the token named by except, and spends the rest',\n\t\tasync run({ stores }) {\n\t\t\tconst userId = mintId();\n\t\t\tconst kept = tokenRecord({ userId, kind: 'signInCode' });\n\t\t\tconst others = [\n\t\t\t\ttokenRecord({ userId, kind: 'signInCode' }),\n\t\t\t\ttokenRecord({ userId, kind: 'signInCode' }),\n\t\t\t];\n\t\t\tfor (const record of [kept, ...others]) {\n\t\t\t\tawait stores.tokens.insertToken(record);\n\t\t\t}\n\t\t\tconst now = at('2026-02-01T00:00:00.000Z');\n\n\t\t\tequal(\n\t\t\t\tawait stores.tokens.spendUserTokens(\n\t\t\t\t\tuserId,\n\t\t\t\t\t'signInCode',\n\t\t\t\t\tnow,\n\t\t\t\t\tkept.tokenHash,\n\t\t\t\t),\n\t\t\t\t2,\n\t\t\t\t'spendUserTokens with except: how many it spent — every token but the one named',\n\t\t\t);\n\t\t\tequal(\n\t\t\t\tawait stores.tokens.consumeToken(kept.tokenHash, 'signInCode', now),\n\t\t\t\tkept,\n\t\t\t\t'spendUserTokens should not spend the token named by except',\n\t\t\t);\n\t\t\tfor (const record of others) {\n\t\t\t\tequal(\n\t\t\t\t\t(\n\t\t\t\t\t\tawait stores.tokens.consumeToken(\n\t\t\t\t\t\t\trecord.tokenHash,\n\t\t\t\t\t\t\t'signInCode',\n\t\t\t\t\t\t\tnow,\n\t\t\t\t\t\t)\n\t\t\t\t\t)?.spentAt,\n\t\t\t\t\tnow,\n\t\t\t\t\t'spendUserTokens with except should spend every other token',\n\t\t\t\t);\n\t\t\t}\n\t\t},\n\t},\n\t{\n\t\tid: 'tokens.spendUserTokensRace',\n\t\tgroup,\n\t\tname: \"spends a token once, when spending a user's tokens races a redemption\",\n\t\tasync run({ stores }) {\n\t\t\tconst now = at('2026-02-01T00:00:00.000Z');\n\t\t\tfor (let round = 0; round < 10; round += 1) {\n\t\t\t\tconst record = tokenRecord({ kind: 'signInCode' });\n\t\t\t\tawait stores.tokens.insertToken(record);\n\n\t\t\t\tconst [counted, redeemed] = await Promise.all([\n\t\t\t\t\tstores.tokens.spendUserTokens(record.userId, 'signInCode', now),\n\t\t\t\t\tstores.tokens.consumeToken(record.tokenHash, 'signInCode', now),\n\t\t\t\t]);\n\n\t\t\t\tequal(\n\t\t\t\t\tcounted + (redeemed?.spentAt === null ? 1 : 0),\n\t\t\t\t\t1,\n\t\t\t\t\t'spendUserTokens and consumeToken: exactly one of the two should have spent the token',\n\t\t\t\t);\n\t\t\t}\n\t\t},\n\t},\n\t{\n\t\tid: 'tokens.challenge',\n\t\tgroup,\n\t\tname: \"keeps a second-factor challenge, whose address is '' — nothing was sent for it\",\n\t\tasync run({ stores }) {\n\t\t\tconst record = tokenRecord({ kind: 'secondFactor', address: '' });\n\t\t\tawait stores.tokens.insertToken(record);\n\n\t\t\tequal(\n\t\t\t\tawait stores.tokens.countAttempt(record.tokenHash, 'secondFactor'),\n\t\t\t\t{ ...record, attempts: 1 },\n\t\t\t\t\"countAttempt should answer a challenge with its empty address kept — a store that refuses '' refuses every sign-in with a second factor\",\n\t\t\t);\n\t\t\tequal(\n\t\t\t\tawait stores.tokens.consumeToken(\n\t\t\t\t\trecord.tokenHash,\n\t\t\t\t\t'secondFactor',\n\t\t\t\t\tat('2026-02-01T00:00:00.000Z'),\n\t\t\t\t),\n\t\t\t\t{ ...record, attempts: 1 },\n\t\t\t\t'consumeToken should spend the challenge and answer it as it was',\n\t\t\t);\n\t\t},\n\t},\n\t{\n\t\tid: 'tokens.lapsed',\n\t\tgroup,\n\t\tname: 'spends a lapsed token all the same: expiry is compared by the core, after the call',\n\t\tasync run({ stores }) {\n\t\t\tconst record = tokenRecord({ expiresAt: at('2020-01-01T00:00:00.000Z') });\n\t\t\tawait stores.tokens.insertToken(record);\n\t\t\tconst now = at('2026-02-01T00:00:00.000Z');\n\n\t\t\tconst first = await stores.tokens.consumeToken(\n\t\t\t\trecord.tokenHash,\n\t\t\t\t'resetPassword',\n\t\t\t\tnow,\n\t\t\t);\n\t\t\t// A store may have dropped a lapsed token already; if it answers, it\n\t\t\t// answers it unspent, and spends it.\n\t\t\tif (first !== null) {\n\t\t\t\tequal(\n\t\t\t\t\tfirst,\n\t\t\t\t\trecord,\n\t\t\t\t\t'consumeToken on a lapsed token should answer it as it was',\n\t\t\t\t);\n\t\t\t\tequal(\n\t\t\t\t\t(\n\t\t\t\t\t\tawait stores.tokens.consumeToken(\n\t\t\t\t\t\t\trecord.tokenHash,\n\t\t\t\t\t\t\t'resetPassword',\n\t\t\t\t\t\t\tnow,\n\t\t\t\t\t\t)\n\t\t\t\t\t)?.spentAt,\n\t\t\t\t\tnow,\n\t\t\t\t\t'consumeToken should have spent the lapsed token, so it can never be retried',\n\t\t\t\t);\n\t\t\t}\n\t\t},\n\t},\n\t{\n\t\tid: 'tokens.idempotentInsert',\n\t\tgroup,\n\t\tname: 'is idempotent under retry: inserting an existing token hash writes nothing',\n\t\tasync run({ stores }) {\n\t\t\tconst record = tokenRecord();\n\t\t\tawait stores.tokens.insertToken(record);\n\t\t\tawait stores.tokens.insertToken({\n\t\t\t\t...record,\n\t\t\t\taddress: 'other@example.test',\n\t\t\t});\n\n\t\t\tequal(\n\t\t\t\tawait stores.tokens.consumeToken(\n\t\t\t\t\trecord.tokenHash,\n\t\t\t\t\t'resetPassword',\n\t\t\t\t\tat('2026-02-01T00:00:00.000Z'),\n\t\t\t\t),\n\t\t\t\trecord,\n\t\t\t\t'insertToken retried with the same hash should write nothing',\n\t\t\t);\n\t\t},\n\t},\n\t{\n\t\tid: 'tokens.deleteUser',\n\t\tgroup,\n\t\tname: 'deletes every token of one user, spent or not, of either kind, and counts them',\n\t\tasync run({ stores }) {\n\t\t\tconst userId = mintId();\n\t\t\tconst records = [\n\t\t\t\ttokenRecord({ userId }),\n\t\t\t\ttokenRecord({ userId, kind: 'verifyEmail' }),\n\t\t\t\ttokenRecord({ userId, spentAt: at('2026-01-02T00:00:00.000Z') }),\n\t\t\t];\n\t\t\tconst stranger = tokenRecord();\n\t\t\tfor (const record of [...records, stranger]) {\n\t\t\t\tawait stores.tokens.insertToken(record);\n\t\t\t}\n\t\t\tconst now = at('2026-02-01T00:00:00.000Z');\n\n\t\t\tequal(\n\t\t\t\tawait stores.tokens.deleteUserTokens(userId),\n\t\t\t\t3,\n\t\t\t\t'deleteUserTokens: how many it deleted',\n\t\t\t);\n\t\t\tfor (const record of records) {\n\t\t\t\tisNull(\n\t\t\t\t\tawait stores.tokens.consumeToken(record.tokenHash, record.kind, now),\n\t\t\t\t\t'consumeToken after deleteUserTokens',\n\t\t\t\t);\n\t\t\t}\n\t\t\tequal(\n\t\t\t\tawait stores.tokens.consumeToken(\n\t\t\t\t\tstranger.tokenHash,\n\t\t\t\t\tstranger.kind,\n\t\t\t\t\tnow,\n\t\t\t\t),\n\t\t\t\tstranger,\n\t\t\t\t'deleteUserTokens should not touch another user',\n\t\t\t);\n\t\t\tequal(\n\t\t\t\tawait stores.tokens.deleteUserTokens(userId),\n\t\t\t\t0,\n\t\t\t\t'deleteUserTokens for a user with none answers 0, not a failure',\n\t\t\t);\n\t\t},\n\t},\n];\n",
10
- "import type { UserRecord } from '../../auth/port/types';\nimport { NotFoundError, StoreConflict } from '../../errors/janus-error';\nimport { mintId } from '../../ids/id';\nimport { equal, isNull, isOurs, ok, rejects } from '../assert';\nimport { at, userRecord } from '../fixtures';\nimport type { ConformanceCase } from '../types';\n\nconst group = 'users';\n\n/** A second factor as the core writes it: the secret sealed, opaque to a store. */\nconst secondFactor = {\n\tmethod: 'totp',\n\tsecret: 'v1.2026-09.aXY.Y2lwaGVydGV4dA',\n\tconfirmedAt: null,\n\tlastStep: null,\n} as const;\n\nexport const userStoreCases: readonly ConformanceCase[] = [\n\t{\n\t\tid: 'users.roundTrip',\n\t\tgroup,\n\t\tname: 'round-trips a record byte for byte: nested fields, a 1 that stays a number, a \"1\" that stays a string',\n\t\tasync run({ stores }) {\n\t\t\tconst record = userRecord({\n\t\t\t\tfields: {\n\t\t\t\t\temail: 'Ada@Example.test',\n\t\t\t\t\tname: { first: 'Ada', last: 'Lovelace' },\n\t\t\t\t\tcount: 1,\n\t\t\t\t\tcode: '1',\n\t\t\t\t\tzero: 0,\n\t\t\t\t\tflags: [true, false, null],\n\t\t\t\t\tnote: ' spaced ',\n\t\t\t\t\tunicode: 'Bob — ÿ',\n\t\t\t\t\tnested: { deep: { deeper: [1, { two: 2 }] } },\n\t\t\t\t\ttags: ['a', 'b'],\n\t\t\t\t},\n\t\t\t\temailVerifiedAt: at('2026-01-02T00:00:00.000Z'),\n\t\t\t});\n\n\t\t\tequal(\n\t\t\t\tawait stores.users.insertUser(record),\n\t\t\t\trecord,\n\t\t\t\t'insertUser should answer the record as stored',\n\t\t\t);\n\t\t\tequal(\n\t\t\t\tawait stores.users.findUser(record.id),\n\t\t\t\trecord,\n\t\t\t\t'findUser should answer the record exactly as it was written',\n\t\t\t);\n\t\t},\n\t},\n\t{\n\t\tid: 'users.edgeCharacters',\n\t\tgroup,\n\t\tname: 'round-trips every character the core lets through: control characters, U+FFFF and a surrogate pair',\n\t\tasync run({ stores }) {\n\t\t\tconst edge = 'a\\u0001\\u001f\\u007f\\uFFFF 😀 z';\n\t\t\tconst record = userRecord({\n\t\t\t\tlogins: [edge],\n\t\t\t\tfields: { email: 'ada@example.test', [edge]: [edge, { [edge]: edge }] },\n\t\t\t});\n\n\t\t\tawait stores.users.insertUser(record);\n\t\t\tequal(\n\t\t\t\tawait stores.users.findUser(record.id),\n\t\t\t\trecord,\n\t\t\t\t'findUser should answer every edge character exactly as written',\n\t\t\t);\n\t\t\tequal(\n\t\t\t\t(await stores.users.findUserByLogin('user', edge))?.id,\n\t\t\t\trecord.id,\n\t\t\t\t'findUserByLogin should find a login made of edge characters',\n\t\t\t);\n\t\t},\n\t},\n\t{\n\t\tid: 'users.absence',\n\t\tgroup,\n\t\tname: 'answers null for an absence, never undefined, and an empty page for an empty store',\n\t\tasync run({ stores }) {\n\t\t\tisNull(\n\t\t\t\tawait stores.users.findUser(mintId()),\n\t\t\t\t'findUser for an unknown id',\n\t\t\t);\n\t\t\tisNull(\n\t\t\t\tawait stores.users.findUserByLogin('user', 'nobody@example.test'),\n\t\t\t\t'findUserByLogin for an unknown login',\n\t\t\t);\n\t\t\tequal(\n\t\t\t\tawait stores.users.listUsers({ type: 'user', after: null, limit: 10 }),\n\t\t\t\t{ items: [], nextCursor: null },\n\t\t\t\t'listUsers on an empty store should answer an empty page',\n\t\t\t);\n\t\t},\n\t},\n\t{\n\t\tid: 'users.loginBytes',\n\t\tgroup,\n\t\tname: 'compares logins as bytes, within one type: no case folding, no trimming, no collation',\n\t\tasync run({ stores }) {\n\t\t\tconst upper = userRecord({ logins: ['Ada@Example.test'] });\n\t\t\tconst lower = userRecord({ logins: ['ada@example.test'] });\n\t\t\tconst staff = userRecord({ type: 'staff', logins: ['ada@example.test'] });\n\n\t\t\tfor (const record of [upper, lower, staff]) {\n\t\t\t\tawait stores.users.insertUser(record);\n\t\t\t}\n\n\t\t\tequal(\n\t\t\t\t(await stores.users.findUserByLogin('user', 'Ada@Example.test'))?.id,\n\t\t\t\tupper.id,\n\t\t\t\t'findUserByLogin should find the login with its exact bytes',\n\t\t\t);\n\t\t\tequal(\n\t\t\t\t(await stores.users.findUserByLogin('user', 'ada@example.test'))?.id,\n\t\t\t\tlower.id,\n\t\t\t\t'findUserByLogin should tell \"Ada@…\" from \"ada@…\": normalisation is the core’s',\n\t\t\t);\n\t\t\tequal(\n\t\t\t\t(await stores.users.findUserByLogin('staff', 'ada@example.test'))?.id,\n\t\t\t\tstaff.id,\n\t\t\t\t'uniqueness is of (type, login): the same login under another type is another user',\n\t\t\t);\n\t\t},\n\t},\n\t{\n\t\tid: 'users.idempotentInsert',\n\t\tgroup,\n\t\tname: 'is idempotent under retry: inserting an existing id answers the stored record and writes nothing',\n\t\tasync run({ stores }) {\n\t\t\tconst record = userRecord();\n\t\t\tawait stores.users.insertUser(record);\n\n\t\t\tconst retried = await stores.users.insertUser({\n\t\t\t\t...record,\n\t\t\t\tfields: { email: 'changed@example.test' },\n\t\t\t});\n\n\t\t\tequal(\n\t\t\t\tretried,\n\t\t\t\trecord,\n\t\t\t\t'insertUser retried with the same id should answer the stored record',\n\t\t\t);\n\t\t\tequal(\n\t\t\t\tawait stores.users.findUser(record.id),\n\t\t\t\trecord,\n\t\t\t\t'insertUser retried should write nothing',\n\t\t\t);\n\t\t},\n\t},\n\t{\n\t\tid: 'users.uniqueness',\n\t\tgroup,\n\t\tname: 'lets exactly one of twenty concurrent inserts hold a login: uniqueness is a constraint, not a read',\n\t\tasync run({ stores }) {\n\t\t\tconst records = Array.from({ length: 20 }, () =>\n\t\t\t\tuserRecord({ logins: ['contested@example.test'] }),\n\t\t\t);\n\n\t\t\tconst outcomes = await Promise.allSettled(\n\t\t\t\trecords.map((record) => stores.users.insertUser(record)),\n\t\t\t);\n\t\t\tconst accepted = outcomes.filter((o) => o.status === 'fulfilled');\n\t\t\tconst refused = outcomes.flatMap((o) =>\n\t\t\t\to.status === 'rejected' ? [o.reason as unknown] : [],\n\t\t\t);\n\n\t\t\tequal(\n\t\t\t\taccepted.length,\n\t\t\t\t1,\n\t\t\t\t'insertUser: of twenty concurrent inserts of one login, exactly one should be accepted — a read followed by a write lets several through',\n\t\t\t);\n\t\t\tfor (const error of refused) {\n\t\t\t\tisOurs(\n\t\t\t\t\terror,\n\t\t\t\t\tStoreConflict,\n\t\t\t\t\t'insertUser should refuse a taken login with StoreConflict',\n\t\t\t\t);\n\t\t\t\tequal(error.code, 'LOGIN_TAKEN', 'insertUser: the conflict code');\n\t\t\t\tequal(\n\t\t\t\t\terror.login,\n\t\t\t\t\t'contested@example.test',\n\t\t\t\t\t'insertUser: the conflict should name the login',\n\t\t\t\t);\n\t\t\t\tok(\n\t\t\t\t\t!error.message.includes('contested@example.test'),\n\t\t\t\t\t`insertUser: the conflict's message should not quote the login — a message never carries a value; got ${JSON.stringify(error.message)}`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tlet stored = 0;\n\t\t\tfor (const record of records) {\n\t\t\t\tif ((await stores.users.findUser(record.id)) !== null) stored += 1;\n\t\t\t}\n\t\t\tequal(stored, 1, 'insertUser: a refused insert should write nothing');\n\t\t},\n\t},\n\t{\n\t\tid: 'users.versionIncrements',\n\t\tgroup,\n\t\tname: 'applies an update at the expected version, and answers the record written with its version one higher',\n\t\tasync run({ stores }) {\n\t\t\tconst record = userRecord();\n\t\t\tawait stores.users.insertUser(record);\n\n\t\t\tconst written = await stores.users.updateUser(\n\t\t\t\trecord.id,\n\t\t\t\t{ updatedAt: at('2026-02-01T00:00:00.000Z'), active: false },\n\t\t\t\t0,\n\t\t\t);\n\t\t\tconst expected: UserRecord = {\n\t\t\t\t...record,\n\t\t\t\tactive: false,\n\t\t\t\tversion: 1,\n\t\t\t\tupdatedAt: at('2026-02-01T00:00:00.000Z'),\n\t\t\t};\n\n\t\t\tequal(\n\t\t\t\twritten,\n\t\t\t\texpected,\n\t\t\t\t'updateUser should answer the record as written',\n\t\t\t);\n\t\t\tequal(\n\t\t\t\tawait stores.users.findUser(record.id),\n\t\t\t\texpected,\n\t\t\t\t'findUser after updateUser',\n\t\t\t);\n\t\t},\n\t},\n\t{\n\t\tid: 'users.versionConflict',\n\t\tgroup,\n\t\tname: 'refuses a stale version with both versions, and leaves the record identical byte for byte',\n\t\tasync run({ stores }) {\n\t\t\tconst record = userRecord();\n\t\t\tawait stores.users.insertUser(record);\n\t\t\tawait stores.users.updateUser(\n\t\t\t\trecord.id,\n\t\t\t\t{ updatedAt: at('2026-02-01T00:00:00.000Z'), active: false },\n\t\t\t\t0,\n\t\t\t);\n\t\t\tconst before = await stores.users.findUser(record.id);\n\n\t\t\tconst error = await rejects(\n\t\t\t\tstores.users.updateUser(\n\t\t\t\t\trecord.id,\n\t\t\t\t\t{\n\t\t\t\t\t\tupdatedAt: at('2026-03-01T00:00:00.000Z'),\n\t\t\t\t\t\tactive: true,\n\t\t\t\t\t\tfields: { email: 'overwritten@example.test' },\n\t\t\t\t\t},\n\t\t\t\t\t0,\n\t\t\t\t),\n\t\t\t\t'updateUser at a stale version should reject',\n\t\t\t);\n\n\t\t\tisOurs(\n\t\t\t\terror,\n\t\t\t\tStoreConflict,\n\t\t\t\t'updateUser at a stale version should reject with StoreConflict',\n\t\t\t);\n\t\t\tequal(error.code, 'VERSION_CONFLICT', 'updateUser: the conflict code');\n\t\t\tequal(error.expectedVersion, 0, 'updateUser: expectedVersion');\n\t\t\tequal(error.actualVersion, 1, 'updateUser: actualVersion');\n\t\t\t// A partial write that also reports a conflict is the worst of both.\n\t\t\tequal(\n\t\t\t\tawait stores.users.findUser(record.id),\n\t\t\t\tbefore,\n\t\t\t\t'updateUser refused for its version should have written nothing',\n\t\t\t);\n\t\t},\n\t},\n\t{\n\t\tid: 'users.unknownUpdate',\n\t\tgroup,\n\t\tname: 'refuses an update to an unknown id with NotFoundError, told apart from a version conflict',\n\t\tasync run({ stores }) {\n\t\t\tconst error = await rejects(\n\t\t\t\tstores.users.updateUser(\n\t\t\t\t\tmintId(),\n\t\t\t\t\t{ updatedAt: at('2026-02-01T00:00:00.000Z') },\n\t\t\t\t\t0,\n\t\t\t\t),\n\t\t\t\t'updateUser on an unknown id should reject',\n\t\t\t);\n\n\t\t\tisOurs(\n\t\t\t\terror,\n\t\t\t\tNotFoundError,\n\t\t\t\t'updateUser on an unknown id should reject with NotFoundError, not a version conflict',\n\t\t\t);\n\t\t},\n\t},\n\t{\n\t\tid: 'users.omission',\n\t\tgroup,\n\t\tname: 'omission — the Kratos PUT trap: an update leaves every field it does not name exactly as it was',\n\t\tasync run({ stores }) {\n\t\t\tconst record = userRecord({\n\t\t\t\tfields: { email: 'kept@example.test', plan: 'pro' },\n\t\t\t\tsecondFactor: {\n\t\t\t\t\t...secondFactor,\n\t\t\t\t\tconfirmedAt: at('2026-01-03T00:00:00.000Z'),\n\t\t\t\t\tlastStep: 59_000_000,\n\t\t\t\t},\n\t\t\t\temailVerifiedAt: at('2026-01-02T00:00:00.000Z'),\n\t\t\t});\n\t\t\tawait stores.users.insertUser(record);\n\n\t\t\tconst written = await stores.users.updateUser(\n\t\t\t\trecord.id,\n\t\t\t\t{ updatedAt: at('2026-02-01T00:00:00.000Z'), schemaVersion: '2' },\n\t\t\t\t0,\n\t\t\t);\n\n\t\t\tequal(\n\t\t\t\twritten,\n\t\t\t\t{\n\t\t\t\t\t...record,\n\t\t\t\t\tschemaVersion: '2',\n\t\t\t\t\tversion: 1,\n\t\t\t\t\tupdatedAt: at('2026-02-01T00:00:00.000Z'),\n\t\t\t\t},\n\t\t\t\t'updateUser naming only schemaVersion should leave active, fields, logins, password, secondFactor and emailVerifiedAt untouched',\n\t\t\t);\n\t\t},\n\t},\n\t{\n\t\tid: 'users.passwordSlot',\n\t\tgroup,\n\t\tname: 'keeps a password the patch does not name, and removes one the patch names null',\n\t\tasync run({ stores }) {\n\t\t\tconst record = userRecord();\n\t\t\tawait stores.users.insertUser(record);\n\n\t\t\tconst kept = await stores.users.updateUser(\n\t\t\t\trecord.id,\n\t\t\t\t{ updatedAt: at('2026-02-01T00:00:00.000Z') },\n\t\t\t\t0,\n\t\t\t);\n\t\t\tequal(\n\t\t\t\tkept.password,\n\t\t\t\trecord.password,\n\t\t\t\t'updateUser not naming password should keep it',\n\t\t\t);\n\n\t\t\tconst removed = await stores.users.updateUser(\n\t\t\t\trecord.id,\n\t\t\t\t{ updatedAt: at('2026-02-02T00:00:00.000Z'), password: null },\n\t\t\t\t1,\n\t\t\t);\n\t\t\tisNull(\n\t\t\t\tremoved.password,\n\t\t\t\t'updateUser with password: null should remove the password',\n\t\t\t);\n\t\t},\n\t},\n\t{\n\t\tid: 'users.secondFactorSlot',\n\t\tgroup,\n\t\tname: 'round-trips a second factor, keeps it when a patch does not name it, and removes it when the patch names null',\n\t\tasync run({ stores }) {\n\t\t\tconst record = userRecord({ secondFactor });\n\t\t\tequal(\n\t\t\t\tawait stores.users.insertUser(record),\n\t\t\t\trecord,\n\t\t\t\t'insertUser should answer a pending second factor as written: confirmedAt and lastStep null',\n\t\t\t);\n\n\t\t\tconst confirmed = {\n\t\t\t\t...secondFactor,\n\t\t\t\tconfirmedAt: at('2026-02-01T00:00:00.000Z'),\n\t\t\t\tlastStep: 59_000_000,\n\t\t\t};\n\t\t\tequal(\n\t\t\t\t(\n\t\t\t\t\tawait stores.users.updateUser(\n\t\t\t\t\t\trecord.id,\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tupdatedAt: at('2026-02-01T00:00:00.000Z'),\n\t\t\t\t\t\t\tsecondFactor: confirmed,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t0,\n\t\t\t\t\t)\n\t\t\t\t).secondFactor,\n\t\t\t\tconfirmed,\n\t\t\t\t'updateUser naming secondFactor should replace it whole',\n\t\t\t);\n\t\t\tequal(\n\t\t\t\t(\n\t\t\t\t\tawait stores.users.updateUser(\n\t\t\t\t\t\trecord.id,\n\t\t\t\t\t\t{ updatedAt: at('2026-02-02T00:00:00.000Z') },\n\t\t\t\t\t\t1,\n\t\t\t\t\t)\n\t\t\t\t).secondFactor,\n\t\t\t\tconfirmed,\n\t\t\t\t'updateUser not naming secondFactor should keep it',\n\t\t\t);\n\t\t\tequal(\n\t\t\t\t(await stores.users.findUser(record.id))?.secondFactor,\n\t\t\t\tconfirmed,\n\t\t\t\t'findUser should answer the second factor as written',\n\t\t\t);\n\t\t\tisNull(\n\t\t\t\t(\n\t\t\t\t\tawait stores.users.updateUser(\n\t\t\t\t\t\trecord.id,\n\t\t\t\t\t\t{ updatedAt: at('2026-02-03T00:00:00.000Z'), secondFactor: null },\n\t\t\t\t\t\t2,\n\t\t\t\t\t)\n\t\t\t\t).secondFactor,\n\t\t\t\t'updateUser with secondFactor: null should remove the second factor',\n\t\t\t);\n\t\t},\n\t},\n\t{\n\t\tid: 'users.loginsMove',\n\t\tgroup,\n\t\tname: 'moves logins on update: the old one is free, the new one found, one held elsewhere refused',\n\t\tasync run({ stores }) {\n\t\t\tconst record = userRecord();\n\t\t\tconst other = userRecord();\n\t\t\tawait stores.users.insertUser(record);\n\t\t\tawait stores.users.insertUser(other);\n\t\t\tconst [old] = record.logins;\n\t\t\tconst moved = 'moved@example.test';\n\n\t\t\tawait stores.users.updateUser(\n\t\t\t\trecord.id,\n\t\t\t\t{ updatedAt: at('2026-02-01T00:00:00.000Z'), logins: [moved] },\n\t\t\t\t0,\n\t\t\t);\n\n\t\t\tisNull(\n\t\t\t\tawait stores.users.findUserByLogin('user', old ?? ''),\n\t\t\t\t'findUserByLogin for a login the update replaced',\n\t\t\t);\n\t\t\tequal(\n\t\t\t\t(await stores.users.findUserByLogin('user', moved))?.id,\n\t\t\t\trecord.id,\n\t\t\t\t'findUserByLogin for the login the update wrote',\n\t\t\t);\n\n\t\t\tconst error = await rejects(\n\t\t\t\tstores.users.updateUser(\n\t\t\t\t\tother.id,\n\t\t\t\t\t{ updatedAt: at('2026-02-02T00:00:00.000Z'), logins: [moved] },\n\t\t\t\t\t0,\n\t\t\t\t),\n\t\t\t\t'updateUser onto a login another user holds should reject',\n\t\t\t);\n\t\t\tisOurs(\n\t\t\t\terror,\n\t\t\t\tStoreConflict,\n\t\t\t\t'updateUser onto a held login should reject with StoreConflict',\n\t\t\t);\n\t\t\tequal(error.code, 'LOGIN_TAKEN', 'updateUser: the conflict code');\n\t\t\tequal(\n\t\t\t\tawait stores.users.findUser(other.id),\n\t\t\t\tother,\n\t\t\t\t'updateUser refused for a login should have written nothing',\n\t\t\t);\n\t\t},\n\t},\n\t{\n\t\tid: 'users.pagination',\n\t\tgroup,\n\t\tname: 'pages 25 users of one type by 10 in ascending id order, with no gap, no repeat and no other type, and ends on a null cursor',\n\t\tasync run({ stores }) {\n\t\t\tconst records = Array.from({ length: 25 }, () => userRecord());\n\t\t\tconst others = Array.from({ length: 5 }, () =>\n\t\t\t\tuserRecord({ type: 'staff' }),\n\t\t\t);\n\t\t\t// Written newest first, and interleaved with another type, so neither\n\t\t\t// insertion order nor the whole collection is the answer.\n\t\t\tfor (const [index, record] of [...records].reverse().entries()) {\n\t\t\t\tawait stores.users.insertUser(record);\n\t\t\t\tconst other = others[index];\n\t\t\t\tif (other !== undefined) await stores.users.insertUser(other);\n\t\t\t}\n\t\t\tconst expected = records.map((record) => record.id).sort();\n\n\t\t\tconst seen: string[] = [];\n\t\t\tconst sizes: number[] = [];\n\t\t\tlet after: string | null = null;\n\t\t\tfor (let page = 0; page < 10; page += 1) {\n\t\t\t\tconst answer = await stores.users.listUsers({\n\t\t\t\t\ttype: 'user',\n\t\t\t\t\tafter,\n\t\t\t\t\tlimit: 10,\n\t\t\t\t});\n\t\t\t\tseen.push(...answer.items.map((item) => item.id));\n\t\t\t\tsizes.push(answer.items.length);\n\t\t\t\tafter = answer.nextCursor;\n\t\t\t\tif (after === null) break;\n\t\t\t}\n\n\t\t\tequal(sizes, [10, 10, 5], 'listUsers: page sizes for 25 users by 10');\n\t\t\tequal(\n\t\t\t\tseen,\n\t\t\t\texpected,\n\t\t\t\t'listUsers: every id of the type once, in ascending order',\n\t\t\t);\n\n\t\t\t// The cursor need not name a stored user.\n\t\t\tconst between = await stores.users.listUsers({\n\t\t\t\ttype: 'user',\n\t\t\t\tafter: '00000000-0000-7000-8000-000000000000',\n\t\t\t\tlimit: 3,\n\t\t\t});\n\t\t\tok(\n\t\t\t\tbetween.items[0]?.id === expected[0],\n\t\t\t\t'listUsers: a cursor naming no stored user should start after it, not fail',\n\t\t\t);\n\t\t},\n\t},\n\t{\n\t\tid: 'users.delete',\n\t\tgroup,\n\t\tname: 'deletes a user and frees their logins, answers false for nobody, and touches no other user',\n\t\tasync run({ stores }) {\n\t\t\tconst record = userRecord();\n\t\t\tconst other = userRecord();\n\t\t\tawait stores.users.insertUser(record);\n\t\t\tawait stores.users.insertUser(other);\n\t\t\tconst [login] = record.logins;\n\n\t\t\tequal(\n\t\t\t\tawait stores.users.deleteUser(record.id),\n\t\t\t\ttrue,\n\t\t\t\t'deleteUser for a stored user should answer true',\n\t\t\t);\n\t\t\tisNull(\n\t\t\t\tawait stores.users.findUser(record.id),\n\t\t\t\t'findUser after deleteUser',\n\t\t\t);\n\t\t\tisNull(\n\t\t\t\tawait stores.users.findUserByLogin(record.type, login ?? ''),\n\t\t\t\t'findUserByLogin for a deleted user’s login',\n\t\t\t);\n\t\t\tequal(\n\t\t\t\tawait stores.users.deleteUser(record.id),\n\t\t\t\tfalse,\n\t\t\t\t'deleteUser replayed should answer false, not fail: a deletion interrupted half-way is replayed',\n\t\t\t);\n\t\t\tequal(\n\t\t\t\tawait stores.users.findUser(other.id),\n\t\t\t\tother,\n\t\t\t\t'deleteUser should not touch another user',\n\t\t\t);\n\t\t\t// The login is free for a new account: the index forgot it.\n\t\t\tconst successor = userRecord({ logins: [login ?? ''] });\n\t\t\tequal(\n\t\t\t\tawait stores.users.insertUser(successor),\n\t\t\t\tsuccessor,\n\t\t\t\t'insertUser onto a deleted user’s login should succeed',\n\t\t\t);\n\t\t},\n\t},\n];\n",
10
+ "import type { UserRecord } from '../../auth/port/types';\nimport { NotFoundError, StoreConflict } from '../../errors/janus-error';\nimport { mintId } from '../../ids/id';\nimport { equal, isNull, isOurs, ok, rejects } from '../assert';\nimport { at, userRecord } from '../fixtures';\nimport type { ConformanceCase } from '../types';\n\nconst group = 'users';\n\n/** A second factor as the core writes it: the secret sealed, opaque to a store. */\nconst secondFactor = {\n\tmethod: 'totp',\n\tsecret: 'v1.2026-09.aXY.Y2lwaGVydGV4dA',\n\tconfirmedAt: null,\n\tlastStep: null,\n} as const;\n\nexport const userStoreCases: readonly ConformanceCase[] = [\n\t{\n\t\tid: 'users.roundTrip',\n\t\tgroup,\n\t\tname: 'round-trips a record byte for byte: nested fields, a 1 that stays a number, a \"1\" that stays a string',\n\t\tasync run({ stores }) {\n\t\t\tconst record = userRecord({\n\t\t\t\tfields: {\n\t\t\t\t\temail: 'Ada@Example.test',\n\t\t\t\t\tname: { first: 'Ada', last: 'Lovelace' },\n\t\t\t\t\tcount: 1,\n\t\t\t\t\tcode: '1',\n\t\t\t\t\tzero: 0,\n\t\t\t\t\tflags: [true, false, null],\n\t\t\t\t\tnote: ' spaced ',\n\t\t\t\t\tunicode: 'Bob — ÿ',\n\t\t\t\t\tnested: { deep: { deeper: [1, { two: 2 }] } },\n\t\t\t\t\ttags: ['a', 'b'],\n\t\t\t\t},\n\t\t\t\temailVerifiedAt: at('2026-01-02T00:00:00.000Z'),\n\t\t\t});\n\n\t\t\tequal(\n\t\t\t\tawait stores.users.insertUser(record),\n\t\t\t\trecord,\n\t\t\t\t'insertUser should answer the record as stored',\n\t\t\t);\n\t\t\tequal(\n\t\t\t\tawait stores.users.findUser(record.id),\n\t\t\t\trecord,\n\t\t\t\t'findUser should answer the record exactly as it was written',\n\t\t\t);\n\t\t},\n\t},\n\t{\n\t\tid: 'users.edgeCharacters',\n\t\tgroup,\n\t\tname: 'round-trips every character the core lets through: control characters, U+FFFF and a surrogate pair',\n\t\tasync run({ stores }) {\n\t\t\tconst edge = 'a\\u0001\\u001f\\u007f\\uFFFF 😀 z';\n\t\t\tconst record = userRecord({\n\t\t\t\tlogins: [edge],\n\t\t\t\tfields: { email: 'ada@example.test', [edge]: [edge, { [edge]: edge }] },\n\t\t\t});\n\n\t\t\tawait stores.users.insertUser(record);\n\t\t\tequal(\n\t\t\t\tawait stores.users.findUser(record.id),\n\t\t\t\trecord,\n\t\t\t\t'findUser should answer every edge character exactly as written',\n\t\t\t);\n\t\t\tequal(\n\t\t\t\t(await stores.users.findUserByLogin('user', edge))?.id,\n\t\t\t\trecord.id,\n\t\t\t\t'findUserByLogin should find a login made of edge characters',\n\t\t\t);\n\t\t},\n\t},\n\t{\n\t\tid: 'users.absence',\n\t\tgroup,\n\t\tname: 'answers null for an absence, never undefined, and an empty page for an empty store',\n\t\tasync run({ stores }) {\n\t\t\tisNull(\n\t\t\t\tawait stores.users.findUser(mintId()),\n\t\t\t\t'findUser for an unknown id',\n\t\t\t);\n\t\t\tisNull(\n\t\t\t\tawait stores.users.findUserByLogin('user', 'nobody@example.test'),\n\t\t\t\t'findUserByLogin for an unknown login',\n\t\t\t);\n\t\t\tequal(\n\t\t\t\tawait stores.users.listUsers({ type: 'user', after: null, limit: 10 }),\n\t\t\t\t{ items: [], nextCursor: null },\n\t\t\t\t'listUsers on an empty store should answer an empty page',\n\t\t\t);\n\t\t},\n\t},\n\t{\n\t\tid: 'users.loginBytes',\n\t\tgroup,\n\t\tname: 'compares logins as bytes, within one type: no case folding, no trimming, no collation',\n\t\tasync run({ stores }) {\n\t\t\tconst upper = userRecord({ logins: ['Ada@Example.test'] });\n\t\t\tconst lower = userRecord({ logins: ['ada@example.test'] });\n\t\t\tconst staff = userRecord({ type: 'staff', logins: ['ada@example.test'] });\n\n\t\t\tfor (const record of [upper, lower, staff]) {\n\t\t\t\tawait stores.users.insertUser(record);\n\t\t\t}\n\n\t\t\tequal(\n\t\t\t\t(await stores.users.findUserByLogin('user', 'Ada@Example.test'))?.id,\n\t\t\t\tupper.id,\n\t\t\t\t'findUserByLogin should find the login with its exact bytes',\n\t\t\t);\n\t\t\tequal(\n\t\t\t\t(await stores.users.findUserByLogin('user', 'ada@example.test'))?.id,\n\t\t\t\tlower.id,\n\t\t\t\t'findUserByLogin should tell \"Ada@…\" from \"ada@…\": normalisation is the core’s',\n\t\t\t);\n\t\t\tequal(\n\t\t\t\t(await stores.users.findUserByLogin('staff', 'ada@example.test'))?.id,\n\t\t\t\tstaff.id,\n\t\t\t\t'uniqueness is of (type, login): the same login under another type is another user',\n\t\t\t);\n\t\t},\n\t},\n\t{\n\t\tid: 'users.idempotentInsert',\n\t\tgroup,\n\t\tname: 'is idempotent under retry: inserting an existing id answers the stored record and writes nothing',\n\t\tasync run({ stores }) {\n\t\t\tconst record = userRecord();\n\t\t\tawait stores.users.insertUser(record);\n\n\t\t\tconst retried = await stores.users.insertUser({\n\t\t\t\t...record,\n\t\t\t\tfields: { email: 'changed@example.test' },\n\t\t\t});\n\n\t\t\tequal(\n\t\t\t\tretried,\n\t\t\t\trecord,\n\t\t\t\t'insertUser retried with the same id should answer the stored record',\n\t\t\t);\n\t\t\tequal(\n\t\t\t\tawait stores.users.findUser(record.id),\n\t\t\t\trecord,\n\t\t\t\t'insertUser retried should write nothing',\n\t\t\t);\n\t\t},\n\t},\n\t{\n\t\tid: 'users.uniqueness',\n\t\tgroup,\n\t\tname: 'lets exactly one of twenty concurrent inserts hold a login: uniqueness is a constraint, not a read',\n\t\tasync run({ stores }) {\n\t\t\tconst records = Array.from({ length: 20 }, () =>\n\t\t\t\tuserRecord({ logins: ['contested@example.test'] }),\n\t\t\t);\n\n\t\t\tconst outcomes = await Promise.allSettled(\n\t\t\t\trecords.map((record) => stores.users.insertUser(record)),\n\t\t\t);\n\t\t\tconst accepted = outcomes.filter((o) => o.status === 'fulfilled');\n\t\t\tconst refused = outcomes.flatMap((o) =>\n\t\t\t\to.status === 'rejected' ? [o.reason as unknown] : [],\n\t\t\t);\n\n\t\t\tequal(\n\t\t\t\taccepted.length,\n\t\t\t\t1,\n\t\t\t\t'insertUser: of twenty concurrent inserts of one login, exactly one should be accepted — a read followed by a write lets several through',\n\t\t\t);\n\t\t\tfor (const error of refused) {\n\t\t\t\tisOurs(\n\t\t\t\t\terror,\n\t\t\t\t\tStoreConflict,\n\t\t\t\t\t'StoreConflict',\n\t\t\t\t\t'insertUser should refuse a taken login with StoreConflict',\n\t\t\t\t);\n\t\t\t\tequal(error.code, 'LOGIN_TAKEN', 'insertUser: the conflict code');\n\t\t\t\tequal(\n\t\t\t\t\terror.login,\n\t\t\t\t\t'contested@example.test',\n\t\t\t\t\t'insertUser: the conflict should name the login',\n\t\t\t\t);\n\t\t\t\tok(\n\t\t\t\t\t!error.message.includes('contested@example.test'),\n\t\t\t\t\t`insertUser: the conflict's message should not quote the login — a message never carries a value; got ${JSON.stringify(error.message)}`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tlet stored = 0;\n\t\t\tfor (const record of records) {\n\t\t\t\tif ((await stores.users.findUser(record.id)) !== null) stored += 1;\n\t\t\t}\n\t\t\tequal(stored, 1, 'insertUser: a refused insert should write nothing');\n\t\t},\n\t},\n\t{\n\t\tid: 'users.versionIncrements',\n\t\tgroup,\n\t\tname: 'applies an update at the expected version, and answers the record written with its version one higher',\n\t\tasync run({ stores }) {\n\t\t\tconst record = userRecord();\n\t\t\tawait stores.users.insertUser(record);\n\n\t\t\tconst written = await stores.users.updateUser(\n\t\t\t\trecord.id,\n\t\t\t\t{ updatedAt: at('2026-02-01T00:00:00.000Z'), active: false },\n\t\t\t\t0,\n\t\t\t);\n\t\t\tconst expected: UserRecord = {\n\t\t\t\t...record,\n\t\t\t\tactive: false,\n\t\t\t\tversion: 1,\n\t\t\t\tupdatedAt: at('2026-02-01T00:00:00.000Z'),\n\t\t\t};\n\n\t\t\tequal(\n\t\t\t\twritten,\n\t\t\t\texpected,\n\t\t\t\t'updateUser should answer the record as written',\n\t\t\t);\n\t\t\tequal(\n\t\t\t\tawait stores.users.findUser(record.id),\n\t\t\t\texpected,\n\t\t\t\t'findUser after updateUser',\n\t\t\t);\n\t\t},\n\t},\n\t{\n\t\tid: 'users.versionConflict',\n\t\tgroup,\n\t\tname: 'refuses a stale version with both versions, and leaves the record identical byte for byte',\n\t\tasync run({ stores }) {\n\t\t\tconst record = userRecord();\n\t\t\tawait stores.users.insertUser(record);\n\t\t\tawait stores.users.updateUser(\n\t\t\t\trecord.id,\n\t\t\t\t{ updatedAt: at('2026-02-01T00:00:00.000Z'), active: false },\n\t\t\t\t0,\n\t\t\t);\n\t\t\tconst before = await stores.users.findUser(record.id);\n\n\t\t\tconst error = await rejects(\n\t\t\t\tstores.users.updateUser(\n\t\t\t\t\trecord.id,\n\t\t\t\t\t{\n\t\t\t\t\t\tupdatedAt: at('2026-03-01T00:00:00.000Z'),\n\t\t\t\t\t\tactive: true,\n\t\t\t\t\t\tfields: { email: 'overwritten@example.test' },\n\t\t\t\t\t},\n\t\t\t\t\t0,\n\t\t\t\t),\n\t\t\t\t'updateUser at a stale version should reject',\n\t\t\t);\n\n\t\t\tisOurs(\n\t\t\t\terror,\n\t\t\t\tStoreConflict,\n\t\t\t\t'StoreConflict',\n\t\t\t\t'updateUser at a stale version should reject with StoreConflict',\n\t\t\t);\n\t\t\tequal(error.code, 'VERSION_CONFLICT', 'updateUser: the conflict code');\n\t\t\tequal(error.expectedVersion, 0, 'updateUser: expectedVersion');\n\t\t\tequal(error.actualVersion, 1, 'updateUser: actualVersion');\n\t\t\t// A partial write that also reports a conflict is the worst of both.\n\t\t\tequal(\n\t\t\t\tawait stores.users.findUser(record.id),\n\t\t\t\tbefore,\n\t\t\t\t'updateUser refused for its version should have written nothing',\n\t\t\t);\n\t\t},\n\t},\n\t{\n\t\tid: 'users.unknownUpdate',\n\t\tgroup,\n\t\tname: 'refuses an update to an unknown id with NotFoundError, told apart from a version conflict',\n\t\tasync run({ stores }) {\n\t\t\tconst error = await rejects(\n\t\t\t\tstores.users.updateUser(\n\t\t\t\t\tmintId(),\n\t\t\t\t\t{ updatedAt: at('2026-02-01T00:00:00.000Z') },\n\t\t\t\t\t0,\n\t\t\t\t),\n\t\t\t\t'updateUser on an unknown id should reject',\n\t\t\t);\n\n\t\t\tisOurs(\n\t\t\t\terror,\n\t\t\t\tNotFoundError,\n\t\t\t\t'NotFoundError',\n\t\t\t\t'updateUser on an unknown id should reject with NotFoundError, not a version conflict',\n\t\t\t);\n\t\t},\n\t},\n\t{\n\t\tid: 'users.omission',\n\t\tgroup,\n\t\tname: 'omission — the Kratos PUT trap: an update leaves every field it does not name exactly as it was',\n\t\tasync run({ stores }) {\n\t\t\tconst record = userRecord({\n\t\t\t\tfields: { email: 'kept@example.test', plan: 'pro' },\n\t\t\t\tsecondFactor: {\n\t\t\t\t\t...secondFactor,\n\t\t\t\t\tconfirmedAt: at('2026-01-03T00:00:00.000Z'),\n\t\t\t\t\tlastStep: 59_000_000,\n\t\t\t\t},\n\t\t\t\temailVerifiedAt: at('2026-01-02T00:00:00.000Z'),\n\t\t\t});\n\t\t\tawait stores.users.insertUser(record);\n\n\t\t\tconst written = await stores.users.updateUser(\n\t\t\t\trecord.id,\n\t\t\t\t{ updatedAt: at('2026-02-01T00:00:00.000Z'), schemaVersion: '2' },\n\t\t\t\t0,\n\t\t\t);\n\n\t\t\tequal(\n\t\t\t\twritten,\n\t\t\t\t{\n\t\t\t\t\t...record,\n\t\t\t\t\tschemaVersion: '2',\n\t\t\t\t\tversion: 1,\n\t\t\t\t\tupdatedAt: at('2026-02-01T00:00:00.000Z'),\n\t\t\t\t},\n\t\t\t\t'updateUser naming only schemaVersion should leave active, fields, logins, password, secondFactor and emailVerifiedAt untouched',\n\t\t\t);\n\t\t},\n\t},\n\t{\n\t\tid: 'users.passwordSlot',\n\t\tgroup,\n\t\tname: 'keeps a password the patch does not name, and removes one the patch names null',\n\t\tasync run({ stores }) {\n\t\t\tconst record = userRecord();\n\t\t\tawait stores.users.insertUser(record);\n\n\t\t\tconst kept = await stores.users.updateUser(\n\t\t\t\trecord.id,\n\t\t\t\t{ updatedAt: at('2026-02-01T00:00:00.000Z') },\n\t\t\t\t0,\n\t\t\t);\n\t\t\tequal(\n\t\t\t\tkept.password,\n\t\t\t\trecord.password,\n\t\t\t\t'updateUser not naming password should keep it',\n\t\t\t);\n\n\t\t\tconst removed = await stores.users.updateUser(\n\t\t\t\trecord.id,\n\t\t\t\t{ updatedAt: at('2026-02-02T00:00:00.000Z'), password: null },\n\t\t\t\t1,\n\t\t\t);\n\t\t\tisNull(\n\t\t\t\tremoved.password,\n\t\t\t\t'updateUser with password: null should remove the password',\n\t\t\t);\n\t\t},\n\t},\n\t{\n\t\tid: 'users.secondFactorSlot',\n\t\tgroup,\n\t\tname: 'round-trips a second factor, keeps it when a patch does not name it, and removes it when the patch names null',\n\t\tasync run({ stores }) {\n\t\t\tconst record = userRecord({ secondFactor });\n\t\t\tequal(\n\t\t\t\tawait stores.users.insertUser(record),\n\t\t\t\trecord,\n\t\t\t\t'insertUser should answer a pending second factor as written: confirmedAt and lastStep null',\n\t\t\t);\n\n\t\t\tconst confirmed = {\n\t\t\t\t...secondFactor,\n\t\t\t\tconfirmedAt: at('2026-02-01T00:00:00.000Z'),\n\t\t\t\tlastStep: 59_000_000,\n\t\t\t};\n\t\t\tequal(\n\t\t\t\t(\n\t\t\t\t\tawait stores.users.updateUser(\n\t\t\t\t\t\trecord.id,\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tupdatedAt: at('2026-02-01T00:00:00.000Z'),\n\t\t\t\t\t\t\tsecondFactor: confirmed,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t0,\n\t\t\t\t\t)\n\t\t\t\t).secondFactor,\n\t\t\t\tconfirmed,\n\t\t\t\t'updateUser naming secondFactor should replace it whole',\n\t\t\t);\n\t\t\tequal(\n\t\t\t\t(\n\t\t\t\t\tawait stores.users.updateUser(\n\t\t\t\t\t\trecord.id,\n\t\t\t\t\t\t{ updatedAt: at('2026-02-02T00:00:00.000Z') },\n\t\t\t\t\t\t1,\n\t\t\t\t\t)\n\t\t\t\t).secondFactor,\n\t\t\t\tconfirmed,\n\t\t\t\t'updateUser not naming secondFactor should keep it',\n\t\t\t);\n\t\t\tequal(\n\t\t\t\t(await stores.users.findUser(record.id))?.secondFactor,\n\t\t\t\tconfirmed,\n\t\t\t\t'findUser should answer the second factor as written',\n\t\t\t);\n\t\t\tisNull(\n\t\t\t\t(\n\t\t\t\t\tawait stores.users.updateUser(\n\t\t\t\t\t\trecord.id,\n\t\t\t\t\t\t{ updatedAt: at('2026-02-03T00:00:00.000Z'), secondFactor: null },\n\t\t\t\t\t\t2,\n\t\t\t\t\t)\n\t\t\t\t).secondFactor,\n\t\t\t\t'updateUser with secondFactor: null should remove the second factor',\n\t\t\t);\n\t\t},\n\t},\n\t{\n\t\tid: 'users.loginsMove',\n\t\tgroup,\n\t\tname: 'moves logins on update: the old one is free, the new one found, one held elsewhere refused',\n\t\tasync run({ stores }) {\n\t\t\tconst record = userRecord();\n\t\t\tconst other = userRecord();\n\t\t\tawait stores.users.insertUser(record);\n\t\t\tawait stores.users.insertUser(other);\n\t\t\tconst [old] = record.logins;\n\t\t\tconst moved = 'moved@example.test';\n\n\t\t\tawait stores.users.updateUser(\n\t\t\t\trecord.id,\n\t\t\t\t{ updatedAt: at('2026-02-01T00:00:00.000Z'), logins: [moved] },\n\t\t\t\t0,\n\t\t\t);\n\n\t\t\tisNull(\n\t\t\t\tawait stores.users.findUserByLogin('user', old ?? ''),\n\t\t\t\t'findUserByLogin for a login the update replaced',\n\t\t\t);\n\t\t\tequal(\n\t\t\t\t(await stores.users.findUserByLogin('user', moved))?.id,\n\t\t\t\trecord.id,\n\t\t\t\t'findUserByLogin for the login the update wrote',\n\t\t\t);\n\n\t\t\tconst error = await rejects(\n\t\t\t\tstores.users.updateUser(\n\t\t\t\t\tother.id,\n\t\t\t\t\t{ updatedAt: at('2026-02-02T00:00:00.000Z'), logins: [moved] },\n\t\t\t\t\t0,\n\t\t\t\t),\n\t\t\t\t'updateUser onto a login another user holds should reject',\n\t\t\t);\n\t\t\tisOurs(\n\t\t\t\terror,\n\t\t\t\tStoreConflict,\n\t\t\t\t'StoreConflict',\n\t\t\t\t'updateUser onto a held login should reject with StoreConflict',\n\t\t\t);\n\t\t\tequal(error.code, 'LOGIN_TAKEN', 'updateUser: the conflict code');\n\t\t\tequal(\n\t\t\t\tawait stores.users.findUser(other.id),\n\t\t\t\tother,\n\t\t\t\t'updateUser refused for a login should have written nothing',\n\t\t\t);\n\t\t},\n\t},\n\t{\n\t\tid: 'users.pagination',\n\t\tgroup,\n\t\tname: 'pages 25 users of one type by 10 in ascending id order, with no gap, no repeat and no other type, and ends on a null cursor',\n\t\tasync run({ stores }) {\n\t\t\tconst records = Array.from({ length: 25 }, () => userRecord());\n\t\t\tconst others = Array.from({ length: 5 }, () =>\n\t\t\t\tuserRecord({ type: 'staff' }),\n\t\t\t);\n\t\t\t// Written newest first, and interleaved with another type, so neither\n\t\t\t// insertion order nor the whole collection is the answer.\n\t\t\tfor (const [index, record] of [...records].reverse().entries()) {\n\t\t\t\tawait stores.users.insertUser(record);\n\t\t\t\tconst other = others[index];\n\t\t\t\tif (other !== undefined) await stores.users.insertUser(other);\n\t\t\t}\n\t\t\tconst expected = records.map((record) => record.id).sort();\n\n\t\t\tconst seen: string[] = [];\n\t\t\tconst sizes: number[] = [];\n\t\t\tlet after: string | null = null;\n\t\t\tfor (let page = 0; page < 10; page += 1) {\n\t\t\t\tconst answer = await stores.users.listUsers({\n\t\t\t\t\ttype: 'user',\n\t\t\t\t\tafter,\n\t\t\t\t\tlimit: 10,\n\t\t\t\t});\n\t\t\t\tseen.push(...answer.items.map((item) => item.id));\n\t\t\t\tsizes.push(answer.items.length);\n\t\t\t\tafter = answer.nextCursor;\n\t\t\t\tif (after === null) break;\n\t\t\t}\n\n\t\t\tequal(sizes, [10, 10, 5], 'listUsers: page sizes for 25 users by 10');\n\t\t\tequal(\n\t\t\t\tseen,\n\t\t\t\texpected,\n\t\t\t\t'listUsers: every id of the type once, in ascending order',\n\t\t\t);\n\n\t\t\t// The cursor need not name a stored user.\n\t\t\tconst between = await stores.users.listUsers({\n\t\t\t\ttype: 'user',\n\t\t\t\tafter: '00000000-0000-7000-8000-000000000000',\n\t\t\t\tlimit: 3,\n\t\t\t});\n\t\t\tok(\n\t\t\t\tbetween.items[0]?.id === expected[0],\n\t\t\t\t'listUsers: a cursor naming no stored user should start after it, not fail',\n\t\t\t);\n\t\t},\n\t},\n\t{\n\t\tid: 'users.delete',\n\t\tgroup,\n\t\tname: 'deletes a user and frees their logins, answers false for nobody, and touches no other user',\n\t\tasync run({ stores }) {\n\t\t\tconst record = userRecord();\n\t\t\tconst other = userRecord();\n\t\t\tawait stores.users.insertUser(record);\n\t\t\tawait stores.users.insertUser(other);\n\t\t\tconst [login] = record.logins;\n\n\t\t\tequal(\n\t\t\t\tawait stores.users.deleteUser(record.id),\n\t\t\t\ttrue,\n\t\t\t\t'deleteUser for a stored user should answer true',\n\t\t\t);\n\t\t\tisNull(\n\t\t\t\tawait stores.users.findUser(record.id),\n\t\t\t\t'findUser after deleteUser',\n\t\t\t);\n\t\t\tisNull(\n\t\t\t\tawait stores.users.findUserByLogin(record.type, login ?? ''),\n\t\t\t\t'findUserByLogin for a deleted user’s login',\n\t\t\t);\n\t\t\tequal(\n\t\t\t\tawait stores.users.deleteUser(record.id),\n\t\t\t\tfalse,\n\t\t\t\t'deleteUser replayed should answer false, not fail: a deletion interrupted half-way is replayed',\n\t\t\t);\n\t\t\tequal(\n\t\t\t\tawait stores.users.findUser(other.id),\n\t\t\t\tother,\n\t\t\t\t'deleteUser should not touch another user',\n\t\t\t);\n\t\t\t// The login is free for a new account: the index forgot it.\n\t\t\tconst successor = userRecord({ logins: [login ?? ''] });\n\t\t\tequal(\n\t\t\t\tawait stores.users.insertUser(successor),\n\t\t\t\tsuccessor,\n\t\t\t\t'insertUser onto a deleted user’s login should succeed',\n\t\t\t);\n\t\t},\n\t},\n];\n",
11
11
  "import { outageCases } from './cases/outage';\nimport { sessionStoreCases } from './cases/sessions';\nimport { tokenStoreCases } from './cases/tokens';\nimport { userStoreCases } from './cases/users';\nimport type {\n\tConformanceCase,\n\tConformanceHarness,\n\tConformanceRunner,\n\tOpenedStores,\n} from './types';\n\n/** Every case, in the order they are described. */\nexport const allCases: readonly ConformanceCase[] = [\n\t...userStoreCases,\n\t...sessionStoreCases,\n\t...tokenStoreCases,\n\t...outageCases,\n];\n\n/** Why a case did not run. A skip is always reported with its reason, never silent. */\nexport const SKIP_REASONS = {\n\tfaults:\n\t\t'faults not provided: the outage invariant is not proven for this adapter',\n\tdeleteExpiredSessions:\n\t\t'stores.sessions does not implement the optional deleteExpiredSessions',\n} as const;\n\n/**\n * Runs one case against one freshly opened set of stores, and closes them,\n * pass or fail. Answers the reason when the case cannot run on these stores.\n *\n * The runner-less layer: a loop over `allCases` calling this is a conformance\n * run with no test framework at all.\n */\nexport async function runCase(\n\tconformanceCase: ConformanceCase,\n\tharness: ConformanceHarness,\n): Promise<{ readonly skipped: string } | { readonly passed: true }> {\n\tconst opened: OpenedStores = await harness.open();\n\n\ttry {\n\t\tif (conformanceCase.needs === 'faults' && opened.faults === undefined) {\n\t\t\treturn { skipped: SKIP_REASONS.faults };\n\t\t}\n\t\tif (\n\t\t\tconformanceCase.needs === 'deleteExpiredSessions' &&\n\t\t\topened.stores.sessions.deleteExpiredSessions === undefined\n\t\t) {\n\t\t\treturn { skipped: SKIP_REASONS.deleteExpiredSessions };\n\t\t}\n\n\t\tawait conformanceCase.run({\n\t\t\tstores: opened.stores,\n\t\t\tfaults: opened.faults ?? null,\n\t\t});\n\t\treturn { passed: true };\n\t} finally {\n\t\tawait opened.close?.();\n\t}\n}\n\n/**\n * Describes the whole suite under the adapter's test runner.\n *\n * ```ts\n * import { describe, it } from 'bun:test';\n * describeJanusStores({ name: 'my adapter', harness, runner: { describe, it } });\n * ```\n *\n * `runner` may be left out under jest, or vitest with `globals: true`: the\n * suite then reads `describe` and `it` from `globalThis`. **Not under `bun\n * test`**, measured: Bun gives a test file `describe` and `it` as bare\n * identifiers, and not as properties of `globalThis` — so pass them.\n *\n * Whether a case can run depends on the stores its harness opens, which is only\n * known once they are open. So every case is described as a test; one that\n * cannot run passes **and says so in its name**, and a run without `faults`\n * is written above the suite, where it cannot be scrolled past.\n */\nexport function describeJanusStores(options: {\n\treadonly name: string;\n\treadonly harness: ConformanceHarness;\n\treadonly runner?: ConformanceRunner;\n\t/** Case ids to skip, each with the reason — reported, never silent. */\n\treadonly skip?: Readonly<Record<string, string>>;\n\t/** Declared up front, so the report can say so before the first case runs. */\n\treadonly faults?: boolean;\n}): void {\n\tdescribeSuite({\n\t\ttitle: `${options.name} — @nxgt/janus conformance`,\n\t\tcases: allCases,\n\t\trun: (conformanceCase) => runCase(conformanceCase, options.harness),\n\t\trunner: options.runner ?? fromGlobals('describeJanusStores'),\n\t\tskip: options.skip ?? {},\n\t\tfaults: options.faults,\n\t});\n}\n\n/** What any suite's case declares, as far as describing it goes. */\ninterface DescribedCase {\n\treadonly id: string;\n\treadonly group: string;\n\treadonly name: string;\n\treadonly needs?: string;\n}\n\n/**\n * Describes one suite's cases, grouped, under a runner. Shared by every suite\n * this module exports, so a skip, an unproven outage and a missing runner read\n * the same in each.\n */\nexport function describeSuite<C extends DescribedCase>(options: {\n\treadonly title: string;\n\treadonly cases: readonly C[];\n\treadonly run: (\n\t\tconformanceCase: C,\n\t) => Promise<{ readonly skipped: string } | { readonly passed: true }>;\n\treadonly runner: ConformanceRunner;\n\treadonly skip: Readonly<Record<string, string>>;\n\treadonly faults: boolean | undefined;\n}): void {\n\tconst { runner, skip, cases } = options;\n\tconst groups = [...new Set(cases.map((c) => c.group))];\n\n\tconst title =\n\t\toptions.faults === false\n\t\t\t? `${options.title} (WITHOUT faults: ${SKIP_REASONS.faults})`\n\t\t\t: options.title;\n\n\trunner.describe(title, () => {\n\t\tfor (const group of groups) {\n\t\t\trunner.describe(group, () => {\n\t\t\t\tfor (const conformanceCase of cases.filter((c) => c.group === group)) {\n\t\t\t\t\tconst reason = skip[conformanceCase.id];\n\t\t\t\t\tif (reason !== undefined) {\n\t\t\t\t\t\trunner.it.skip(\n\t\t\t\t\t\t\t`${conformanceCase.name} — skipped: ${reason}`,\n\t\t\t\t\t\t\tasync () => {},\n\t\t\t\t\t\t);\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\tif (conformanceCase.needs === 'faults' && options.faults === false) {\n\t\t\t\t\t\trunner.it.skip(\n\t\t\t\t\t\t\t`${conformanceCase.name} — skipped: ${SKIP_REASONS.faults}`,\n\t\t\t\t\t\t\tasync () => {},\n\t\t\t\t\t\t);\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\trunner.it(conformanceCase.name, async () => {\n\t\t\t\t\t\tconst outcome = await options.run(conformanceCase);\n\t\t\t\t\t\tif ('skipped' in outcome) {\n\t\t\t\t\t\t\tprocess.emitWarning(\n\t\t\t\t\t\t\t\t`${conformanceCase.id} skipped: ${outcome.skipped}`,\n\t\t\t\t\t\t\t\t{ code: 'JANUS_CONFORMANCE_SKIPPED' },\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\t});\n}\n\nexport function fromGlobals(where: string): ConformanceRunner {\n\tconst globals = globalThis as {\n\t\tdescribe?: ConformanceRunner['describe'];\n\t\tit?: ConformanceRunner['it'];\n\t};\n\n\tif (\n\t\ttypeof globals.describe !== 'function' ||\n\t\ttypeof globals.it !== 'function'\n\t) {\n\t\tthrow new TypeError(\n\t\t\t`${where}: no test runner on globalThis — pass runner: { describe, it } (under bun test: import them from 'bun:test')`,\n\t\t);\n\t}\n\n\treturn { describe: globals.describe, it: globals.it };\n}\n",
12
12
  "import { createMemoryStores } from '../auth/port/memory';\nimport type { JanusStores } from '../auth/port/types';\nimport { StoreFailure } from '../errors/janus-error';\nimport type { ConformanceHarness, StoreFaults } from './types';\n\n/**\n * The harness for the reference store: what `self.spec.ts` runs the suite\n * against, and **the example an adapter author copies**.\n *\n * Its faults are a wrapper, because an in-memory map has no network to cut —\n * which is exactly why the doc on `StoreFaults` says an adapter must not do\n * this: a wrapper proves the wrapper. For the reference store there is nothing\n * underneath to prove, and it fails the way a correct adapter does, with\n * `StoreFailure`.\n */\nexport function referenceHarness(): ConformanceHarness {\n\treturn {\n\t\tasync open() {\n\t\t\tconst failing = new Set<string>();\n\t\t\tconst stores = withFaults(createMemoryStores(), failing);\n\n\t\t\tconst faults: StoreFaults = {\n\t\t\t\tasync fail(slot, method) {\n\t\t\t\t\tfailing.add(`${slot}.${method}`);\n\t\t\t\t},\n\t\t\t};\n\n\t\t\treturn { stores, faults };\n\t\t},\n\t};\n}\n\nfunction withFaults(\n\tstores: JanusStores,\n\tfailing: ReadonlySet<string>,\n): JanusStores {\n\tconst wrap = <S extends object>(slot: string, store: S): S => {\n\t\tconst wrapped: Record<string, unknown> = {};\n\t\tfor (const [method, fn] of Object.entries(store)) {\n\t\t\twrapped[method] = (...args: unknown[]) => {\n\t\t\t\tif (failing.has(`${slot}.${method}`)) {\n\t\t\t\t\treturn Promise.reject(\n\t\t\t\t\t\tnew StoreFailure(`${slot}.${method}: the store could not answer`, {\n\t\t\t\t\t\t\tslot: slot as keyof JanusStores,\n\t\t\t\t\t\t\toperation: method,\n\t\t\t\t\t\t}),\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\treturn (fn as (...a: unknown[]) => unknown).apply(store, args);\n\t\t\t};\n\t\t}\n\t\treturn wrapped as S;\n\t};\n\n\treturn {\n\t\tusers: wrap('users', stores.users),\n\t\tsessions: wrap('sessions', stores.sessions),\n\t\ttokens: wrap('tokens', stores.tokens),\n\t};\n}\n",
13
- "/**\n * The conformance suite of the relation store port — what an adapter author\n * runs against `RelationStore`, as `describeJanusStores` is run against the\n * user port.\n *\n * ```ts\n * import { describe, it } from 'bun:test';\n * import { describeRelationStores } from '@nxgt/janus/conformance';\n *\n * describeRelationStores({ name: 'my adapter', harness, runner: { describe, it } });\n * ```\n */\n\nimport { JanusError, StoreFailure } from '../errors/janus-error';\nimport { mintId } from '../ids/id';\nimport { createMemoryRelations } from '../permissions/port/memory';\nimport type { RelationStore } from '../permissions/port/types';\nimport { formatSubject } from '../subjects/notation';\nimport type {\n\tEntity,\n\tRelationTuple,\n\tSubject,\n\tSubjectSet,\n} from '../subjects/subject';\nimport { equal, isOurs, ok, rejects } from './assert';\nimport { describeSuite, fromGlobals, SKIP_REASONS } from './describe';\nimport type { ConformanceRunner } from './types';\n\n/** A method of the relation store. */\nexport type RelationMethod = keyof RelationStore & string;\n\n/** How the suite makes one relation store method fail, for the outage cases. */\nexport interface RelationFaults {\n\t/**\n\t * Fails `method`, and only it: the other methods keep answering, because\n\t * `outage.write` reads the store back to prove the rejected write changed\n\t * nothing.\n\t */\n\tfail(method: RelationMethod): Promise<void>;\n}\n\nexport interface OpenedRelations {\n\t/** Empty: every case writes what it reads. */\n\treadonly store: RelationStore;\n\treadonly faults?: RelationFaults;\n\tclose?(): Promise<void>;\n}\n\nexport interface RelationHarness {\n\t/** Called once per case, so no case sees another's tuples. */\n\topen(): Promise<OpenedRelations>;\n}\n\nexport interface RelationContext {\n\treadonly store: RelationStore;\n\treadonly faults: RelationFaults | null;\n}\n\nexport interface RelationCase {\n\treadonly id: string;\n\treadonly group: 'relations' | 'outage';\n\treadonly name: string;\n\treadonly needs?: 'faults';\n\trun(context: RelationContext): Promise<void>;\n}\n\n// ─── Fixtures ─────────────────────────────────────────────────────────────\n\nconst entity = (type: string, id: string = mintId()): Entity => ({ type, id });\nconst set = (type: string, id: string, relation: string): SubjectSet => ({\n\ttype,\n\tid,\n\trelation,\n});\nconst tuple = (\n\tobject: Entity,\n\trelation: string,\n\tsubject: Subject,\n): RelationTuple => ({ object, relation, subject });\n\n/** Order-free, so a store may answer in any order. */\nconst sorted = (subjects: readonly Subject[]) =>\n\tsubjects.map(formatSubject).sort();\n\n// ─── The cases ────────────────────────────────────────────────────────────\n\nconst group = 'relations';\n\nexport const relationStoreCases: readonly RelationCase[] = [\n\t{\n\t\tid: 'relations.roundTrip',\n\t\tgroup,\n\t\tname: 'holds exactly the tuples written, byte for byte: staff:u1 is not patient:u1, and a set is not its entity',\n\t\tasync run({ store }) {\n\t\t\tconst record = entity('record', 'R:1 — ÿ');\n\t\t\tconst direct = tuple(record, 'viewer', entity('staff', 'u1'));\n\t\t\tconst inherited = tuple(record, 'viewer', set('team', 't1', 'member'));\n\t\t\tawait store.write({ add: [direct, inherited] });\n\n\t\t\tequal(await store.has(direct), true, 'has for a written tuple');\n\t\t\tequal(await store.has(inherited), true, 'has for a written subject set');\n\t\t\tequal(\n\t\t\t\tawait store.has(tuple(record, 'viewer', entity('patient', 'u1'))),\n\t\t\t\tfalse,\n\t\t\t\t'has for the same id under another subject type: types are part of the subject',\n\t\t\t);\n\t\t\tequal(\n\t\t\t\tawait store.has(tuple(record, 'viewer', entity('team', 't1'))),\n\t\t\t\tfalse,\n\t\t\t\t'has for the entity of a stored subject set: a set is not its entity',\n\t\t\t);\n\t\t\tequal(\n\t\t\t\tawait store.has(\n\t\t\t\t\ttuple(entity('record', 'r:1 — ÿ'), 'viewer', direct.subject),\n\t\t\t\t),\n\t\t\t\tfalse,\n\t\t\t\t'has for an id differing in one character: ids are compared as written',\n\t\t\t);\n\t\t},\n\t},\n\t{\n\t\tid: 'relations.edgeCharacters',\n\t\tgroup,\n\t\tname: 'round-trips every character the core lets through in an id: control characters, U+FFFF and a surrogate pair',\n\t\tasync run({ store }) {\n\t\t\t// The core refuses a NUL and a lone surrogate before a store is\n\t\t\t// asked; everything else must come back exactly as written.\n\t\t\tconst edge = 'a\\u0001\\u001f\\u007f\\uFFFF 😀 z';\n\t\t\tconst record = entity('record', edge);\n\t\t\tconst written = tuple(record, 'viewer', set('team', edge, 'member'));\n\t\t\tconst direct = tuple(record, 'viewer', entity('staff', edge));\n\t\t\tawait store.write({ add: [written, direct] });\n\n\t\t\tequal(await store.has(written), true, 'has for ids of edge characters');\n\t\t\t// Read back through every index: an adapter that mangles an id the\n\t\t\t// same way on write and on lookup still fails here.\n\t\t\tequal(\n\t\t\t\tawait store.findSubjectSets(record, 'viewer'),\n\t\t\t\t[set('team', edge, 'member')],\n\t\t\t\t'findSubjectSets answers the set id as written',\n\t\t\t);\n\t\t\tequal(\n\t\t\t\tawait store.findEntities(record, 'viewer'),\n\t\t\t\t[entity('staff', edge)],\n\t\t\t\t'findEntities answers the entity id as written',\n\t\t\t);\n\t\t\tequal(\n\t\t\t\tawait store.findObjects({\n\t\t\t\t\ttype: 'record',\n\t\t\t\t\trelation: 'viewer',\n\t\t\t\t\tsubject: direct.subject,\n\t\t\t\t\tafter: null,\n\t\t\t\t\tlimit: 10,\n\t\t\t\t}),\n\t\t\t\t{ items: [edge], nextCursor: null },\n\t\t\t\t'findObjects answers the object id as written',\n\t\t\t);\n\t\t\tequal(\n\t\t\t\tawait store.has(\n\t\t\t\t\ttuple(\n\t\t\t\t\t\tentity('record', edge.replace('😀', '😁')),\n\t\t\t\t\t\t'viewer',\n\t\t\t\t\t\twritten.subject,\n\t\t\t\t\t),\n\t\t\t\t),\n\t\t\t\tfalse,\n\t\t\t\t'has for an id differing in one astral character',\n\t\t\t);\n\t\t},\n\t},\n\t{\n\t\tid: 'relations.undefinedRelation',\n\t\tgroup,\n\t\tname: 'reads a subject whose relation is undefined as its entity, not as a set',\n\t\tasync run({ store }) {\n\t\t\tconst record = entity('record');\n\t\t\tconst staff = entity('staff');\n\t\t\t// A caller that spreads an optional field hands the port this shape.\n\t\t\tconst spread = { ...staff, relation: undefined } as unknown as Subject;\n\t\t\tawait store.write({ add: [tuple(record, 'viewer', spread)] });\n\n\t\t\tequal(\n\t\t\t\tawait store.has(tuple(record, 'viewer', staff)),\n\t\t\t\ttrue,\n\t\t\t\t'has for the entity, after writing it with relation: undefined',\n\t\t\t);\n\t\t\tequal(\n\t\t\t\tawait store.findEntities(record, 'viewer'),\n\t\t\t\t[staff],\n\t\t\t\t'findEntities: the tuple names an entity',\n\t\t\t);\n\t\t\tequal(\n\t\t\t\tawait store.findSubjectSets(record, 'viewer'),\n\t\t\t\t[],\n\t\t\t\t'findSubjectSets: relation: undefined is no set',\n\t\t\t);\n\t\t\tequal(\n\t\t\t\tawait store.findObjects({\n\t\t\t\t\ttype: 'record',\n\t\t\t\t\trelation: 'viewer',\n\t\t\t\t\tsubject: spread,\n\t\t\t\t\tafter: null,\n\t\t\t\t\tlimit: 10,\n\t\t\t\t}),\n\t\t\t\t{ items: [record.id], nextCursor: null },\n\t\t\t\t'findObjects for the subject written with relation: undefined',\n\t\t\t);\n\t\t\tequal(\n\t\t\t\tawait store.findObjects({\n\t\t\t\t\ttype: 'record',\n\t\t\t\t\trelation: 'viewer',\n\t\t\t\t\tsubject: set('staff', staff.id, 'x'),\n\t\t\t\t\tafter: null,\n\t\t\t\t\tlimit: 10,\n\t\t\t\t}),\n\t\t\t\t{ items: [], nextCursor: null },\n\t\t\t\t'findObjects for a set of that entity: the entity is not a set',\n\t\t\t);\n\t\t\tawait store.write({ remove: [tuple(record, 'viewer', spread)] });\n\t\t\tequal(\n\t\t\t\tawait store.has(tuple(record, 'viewer', staff)),\n\t\t\t\tfalse,\n\t\t\t\t'has after removing it with relation: undefined',\n\t\t\t);\n\t\t},\n\t},\n\t{\n\t\tid: 'relations.absence',\n\t\tgroup,\n\t\tname: 'answers false, [], an empty page and 0 for an empty store — never null or undefined',\n\t\tasync run({ store }) {\n\t\t\tconst record = entity('record');\n\t\t\tconst staff = entity('staff');\n\n\t\t\tequal(await store.has(tuple(record, 'viewer', staff)), false, 'has');\n\t\t\tequal(\n\t\t\t\tawait store.findSubjectSets(record, 'viewer'),\n\t\t\t\t[],\n\t\t\t\t'findSubjectSets',\n\t\t\t);\n\t\t\tequal(await store.findEntities(record, 'viewer'), [], 'findEntities');\n\t\t\tequal(\n\t\t\t\tawait store.findObjects({\n\t\t\t\t\ttype: 'record',\n\t\t\t\t\trelation: 'viewer',\n\t\t\t\t\tsubject: staff,\n\t\t\t\t\tafter: null,\n\t\t\t\t\tlimit: 10,\n\t\t\t\t}),\n\t\t\t\t{ items: [], nextCursor: null },\n\t\t\t\t'findObjects on an empty store',\n\t\t\t);\n\t\t\tequal(await store.deleteEntity(staff), 0, 'deleteEntity');\n\t\t},\n\t},\n\t{\n\t\tid: 'relations.idempotentWrite',\n\t\tgroup,\n\t\tname: 'is idempotent under retry: adding a stored tuple and removing an absent one write nothing',\n\t\tasync run({ store }) {\n\t\t\tconst record = entity('record');\n\t\t\tconst viewer = tuple(record, 'viewer', entity('team'));\n\t\t\tawait store.write({ add: [viewer] });\n\t\t\tawait store.write({ add: [viewer] });\n\t\t\tawait store.write({ remove: [tuple(record, 'viewer', entity('team'))] });\n\n\t\t\tequal(\n\t\t\t\t(await store.findEntities(record, 'viewer')).length,\n\t\t\t\t1,\n\t\t\t\t'findEntities after the same tuple was added twice',\n\t\t\t);\n\t\t},\n\t},\n\t{\n\t\tid: 'relations.uniqueness',\n\t\tgroup,\n\t\tname: 'keeps one tuple when twenty concurrent writes add it: uniqueness is a constraint, not a read',\n\t\tasync run({ store }) {\n\t\t\tconst record = entity('record');\n\t\t\tconst parent = entity('folder');\n\t\t\tawait Promise.all(\n\t\t\t\tArray.from({ length: 20 }, () =>\n\t\t\t\t\tstore.write({ add: [tuple(record, 'parent', parent)] }),\n\t\t\t\t),\n\t\t\t);\n\n\t\t\tequal(\n\t\t\t\tawait store.findEntities(record, 'parent'),\n\t\t\t\t[parent],\n\t\t\t\t'findEntities after twenty concurrent adds of one tuple',\n\t\t\t);\n\t\t},\n\t},\n\t{\n\t\tid: 'relations.removeThenAdd',\n\t\tgroup,\n\t\tname: 'applies one write’s removals and additions together',\n\t\tasync run({ store }) {\n\t\t\tconst record = entity('record');\n\t\t\tconst before = tuple(record, 'owner', entity('staff', 'a'));\n\t\t\tconst after = tuple(record, 'owner', entity('staff', 'b'));\n\t\t\tawait store.write({ add: [before] });\n\n\t\t\tawait store.write({ remove: [before], add: [after] });\n\n\t\t\tequal(await store.has(before), false, 'the removed tuple');\n\t\t\tequal(await store.has(after), true, 'the added tuple');\n\t\t},\n\t},\n\t{\n\t\tid: 'relations.oneHop',\n\t\tgroup,\n\t\tname: 'answers one hop: the subject sets and the entities holding one relation on one object, and nothing else',\n\t\tasync run({ store }) {\n\t\t\tconst record = entity('record');\n\t\t\tconst staff = entity('staff');\n\t\t\tconst team = entity('team');\n\t\t\tconst members = set('team', team.id, 'member');\n\t\t\tconst leads = set('team', team.id, 'lead');\n\t\t\tawait store.write({\n\t\t\t\tadd: [\n\t\t\t\t\ttuple(record, 'viewer', staff),\n\t\t\t\t\ttuple(record, 'viewer', team),\n\t\t\t\t\ttuple(record, 'viewer', members),\n\t\t\t\t\ttuple(record, 'viewer', leads),\n\t\t\t\t\t// Another relation, and another object: neither is an answer.\n\t\t\t\t\ttuple(record, 'editor', set('team', team.id, 'admin')),\n\t\t\t\t\ttuple(entity('record'), 'viewer', set('team', 'other', 'member')),\n\t\t\t\t],\n\t\t\t});\n\n\t\t\tequal(\n\t\t\t\tsorted(await store.findSubjectSets(record, 'viewer')),\n\t\t\t\tsorted([members, leads]),\n\t\t\t\t'findSubjectSets: the sets only, of this object and this relation',\n\t\t\t);\n\t\t\tequal(\n\t\t\t\tsorted(await store.findEntities(record, 'viewer')),\n\t\t\t\tsorted([staff, team]),\n\t\t\t\t'findEntities: the single entities only, of this object and this relation',\n\t\t\t);\n\t\t},\n\t},\n\t{\n\t\tid: 'relations.objects',\n\t\tgroup,\n\t\tname: 'pages 25 objects by 10 in ascending id order, for one type, relation and exact subject, and ends on a null cursor',\n\t\tasync run({ store }) {\n\t\t\tconst staff = entity('staff');\n\t\t\tconst ids = Array.from(\n\t\t\t\t{ length: 25 },\n\t\t\t\t(_, n) => `r${String(n).padStart(2, '0')}`,\n\t\t\t);\n\t\t\t// Written newest first, beside noise the answer must leave out.\n\t\t\tfor (const id of [...ids].reverse()) {\n\t\t\t\tawait store.write({\n\t\t\t\t\tadd: [\n\t\t\t\t\t\ttuple(entity('record', id), 'viewer', staff),\n\t\t\t\t\t\ttuple(entity('record', `${id}x`), 'editor', staff),\n\t\t\t\t\t\ttuple(entity('folder', id), 'viewer', staff),\n\t\t\t\t\t\ttuple(\n\t\t\t\t\t\t\tentity('record', `${id}y`),\n\t\t\t\t\t\t\t'viewer',\n\t\t\t\t\t\t\tset('staff', staff.id, 'x'),\n\t\t\t\t\t\t),\n\t\t\t\t\t],\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tconst seen: string[] = [];\n\t\t\tconst sizes: number[] = [];\n\t\t\tlet after: string | null = null;\n\t\t\tfor (let page = 0; page < 10; page += 1) {\n\t\t\t\tconst answer = await store.findObjects({\n\t\t\t\t\ttype: 'record',\n\t\t\t\t\trelation: 'viewer',\n\t\t\t\t\tsubject: staff,\n\t\t\t\t\tafter,\n\t\t\t\t\tlimit: 10,\n\t\t\t\t});\n\t\t\t\tseen.push(...answer.items);\n\t\t\t\tsizes.push(answer.items.length);\n\t\t\t\tafter = answer.nextCursor;\n\t\t\t\tif (after === null) break;\n\t\t\t}\n\n\t\t\tequal(sizes, [10, 10, 5], 'findObjects: page sizes for 25 objects by 10');\n\t\t\tequal(seen, ids, 'findObjects: every id once, in ascending order');\n\t\t\tconst between = await store.findObjects({\n\t\t\t\ttype: 'record',\n\t\t\t\trelation: 'viewer',\n\t\t\t\tsubject: staff,\n\t\t\t\tafter: 'r04a',\n\t\t\t\tlimit: 2,\n\t\t\t});\n\t\t\tequal(\n\t\t\t\tbetween.items,\n\t\t\t\t['r05', 'r06'],\n\t\t\t\t'findObjects: a cursor naming no stored object should start after it',\n\t\t\t);\n\t\t},\n\t},\n\t{\n\t\tid: 'relations.deleteEntity',\n\t\tgroup,\n\t\tname: 'deletes every tuple naming an entity — as object, as subject, as a set’s entity — and counts them',\n\t\tasync run({ store }) {\n\t\t\tconst team = entity('team');\n\t\t\tconst other = entity('team');\n\t\t\tconst kept = [\n\t\t\t\ttuple(other, 'member', entity('staff')),\n\t\t\t\ttuple(entity('record'), 'viewer', set('team', other.id, 'member')),\n\t\t\t];\n\t\t\tawait store.write({\n\t\t\t\tadd: [\n\t\t\t\t\ttuple(team, 'member', entity('staff')),\n\t\t\t\t\ttuple(entity('record'), 'team', team),\n\t\t\t\t\ttuple(entity('record'), 'viewer', set('team', team.id, 'member')),\n\t\t\t\t\t...kept,\n\t\t\t\t],\n\t\t\t});\n\n\t\t\tequal(\n\t\t\t\tawait store.deleteEntity(team),\n\t\t\t\t3,\n\t\t\t\t'deleteEntity: how many it deleted',\n\t\t\t);\n\t\t\tfor (const survivor of kept) {\n\t\t\t\tequal(\n\t\t\t\t\tawait store.has(survivor),\n\t\t\t\t\ttrue,\n\t\t\t\t\t'deleteEntity should not touch another entity',\n\t\t\t\t);\n\t\t\t}\n\t\t\tequal(\n\t\t\t\tawait store.deleteEntity(team),\n\t\t\t\t0,\n\t\t\t\t'deleteEntity replayed answers 0, not a failure',\n\t\t\t);\n\t\t},\n\t},\n];\n\n// ─── Outages ──────────────────────────────────────────────────────────────\n\n/**\n * For each method, a store that cannot answer must **reject** — never\n * `false`, `[]`, an empty page or `0`. A relation store that answers `false`\n * for an outage denies everybody everything and says nothing; one that\n * resolves a write it did not make leaves a revoked access standing.\n */\nfunction outage(\n\tmethod: RelationMethod,\n\tcall: (store: RelationStore) => Promise<unknown>,\n\tafter?: (store: RelationStore) => Promise<void>,\n): RelationCase {\n\treturn {\n\t\tid: `outage.${method}`,\n\t\tgroup: 'outage',\n\t\tname: `relations.${method} rejects when the store cannot answer — never false, [], an empty page or 0`,\n\t\tneeds: 'faults',\n\t\tasync run({ store, faults }) {\n\t\t\tawait store.write({ add: [seeded] });\n\t\t\tawait faults?.fail(method);\n\n\t\t\tconst error = await rejects(\n\t\t\t\tcall(store),\n\t\t\t\t`relations.${method} under an outage should reject`,\n\t\t\t);\n\t\t\tif (\n\t\t\t\terror instanceof JanusError ||\n\t\t\t\t(error as { name?: unknown })?.name === 'StoreFailure'\n\t\t\t) {\n\t\t\t\tisOurs(error, StoreFailure, `relations.${method} under an outage`);\n\t\t\t}\n\t\t\tok(\n\t\t\t\t(error as { code?: unknown } | null)?.code !== 'NOT_FOUND',\n\t\t\t\t`relations.${method} under an outage rejected with NOT_FOUND: an outage is never an absence`,\n\t\t\t);\n\t\t\tawait after?.(store);\n\t\t},\n\t};\n}\n\nconst seededObject: Entity = { type: 'record', id: 'seeded' };\nconst seededSubject: Entity = { type: 'staff', id: 'seeded' };\nconst seeded = tuple(seededObject, 'viewer', seededSubject);\n\nexport const relationOutageCases: readonly RelationCase[] = [\n\toutage(\n\t\t'write',\n\t\t(store) =>\n\t\t\tstore.write({\n\t\t\t\tremove: [seeded],\n\t\t\t\tadd: [tuple(seededObject, 'owner', seededSubject)],\n\t\t\t}),\n\t\t// A rejected write is one that did nothing: all of it, or none of it.\n\t\tasync (store) => {\n\t\t\tequal(\n\t\t\t\tawait store.has(seeded),\n\t\t\t\ttrue,\n\t\t\t\t'relations.write rejected, and still removed a tuple: a write is all or nothing',\n\t\t\t);\n\t\t\tequal(\n\t\t\t\tawait store.has(tuple(seededObject, 'owner', seededSubject)),\n\t\t\t\tfalse,\n\t\t\t\t'relations.write rejected, and still added a tuple: a write is all or nothing',\n\t\t\t);\n\t\t},\n\t),\n\toutage('has', (store) => store.has(seeded)),\n\toutage('findSubjectSets', (store) =>\n\t\tstore.findSubjectSets(seededObject, 'viewer'),\n\t),\n\toutage('findEntities', (store) => store.findEntities(seededObject, 'viewer')),\n\toutage('findObjects', (store) =>\n\t\tstore.findObjects({\n\t\t\ttype: 'record',\n\t\t\trelation: 'viewer',\n\t\t\tsubject: seededSubject,\n\t\t\tafter: null,\n\t\t\tlimit: 10,\n\t\t}),\n\t),\n\toutage('deleteEntity', (store) => store.deleteEntity(seededSubject)),\n];\n\nexport const allRelationCases: readonly RelationCase[] = [\n\t...relationStoreCases,\n\t...relationOutageCases,\n];\n\n// ─── Running them ─────────────────────────────────────────────────────────\n\n/** Runs one case against a freshly opened store, and closes it, pass or fail. */\nexport async function runRelationCase(\n\trelationCase: RelationCase,\n\tharness: RelationHarness,\n): Promise<{ readonly skipped: string } | { readonly passed: true }> {\n\tconst opened = await harness.open();\n\n\ttry {\n\t\tif (relationCase.needs === 'faults' && opened.faults === undefined) {\n\t\t\treturn { skipped: SKIP_REASONS.faults };\n\t\t}\n\t\tawait relationCase.run({\n\t\t\tstore: opened.store,\n\t\t\tfaults: opened.faults ?? null,\n\t\t});\n\t\treturn { passed: true };\n\t} finally {\n\t\tawait opened.close?.();\n\t}\n}\n\n/** Describes the whole relation suite under the adapter's test runner. */\nexport function describeRelationStores(options: {\n\treadonly name: string;\n\treadonly harness: RelationHarness;\n\treadonly runner?: ConformanceRunner;\n\t/** Case ids to skip, each with the reason — reported, never silent. */\n\treadonly skip?: Readonly<Record<string, string>>;\n\treadonly faults?: boolean;\n}): void {\n\tdescribeSuite({\n\t\ttitle: `${options.name} — @nxgt/janus relation conformance`,\n\t\tcases: allRelationCases,\n\t\trun: (relationCase) => runRelationCase(relationCase, options.harness),\n\t\trunner: options.runner ?? fromGlobals('describeRelationStores'),\n\t\tskip: options.skip ?? {},\n\t\tfaults: options.faults,\n\t});\n}\n\n/** The reference store, with faults: what the suite proves itself against. */\nexport function referenceRelationHarness(): RelationHarness {\n\treturn {\n\t\tasync open() {\n\t\t\tconst failing = new Set<string>();\n\t\t\tconst inner = createMemoryRelations();\n\t\t\tconst store = Object.fromEntries(\n\t\t\t\tObject.entries(inner).map(([method, fn]) => [\n\t\t\t\t\tmethod,\n\t\t\t\t\t(...args: unknown[]) =>\n\t\t\t\t\t\tfailing.has(method)\n\t\t\t\t\t\t\t? Promise.reject(\n\t\t\t\t\t\t\t\t\tnew StoreFailure(\n\t\t\t\t\t\t\t\t\t\t`relations.${method}: the store could not answer`,\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\tslot: 'relations',\n\t\t\t\t\t\t\t\t\t\t\toperation: method,\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t: (fn as (...a: unknown[]) => unknown).apply(inner, args),\n\t\t\t\t]),\n\t\t\t) as unknown as RelationStore;\n\n\t\t\treturn {\n\t\t\t\tstore,\n\t\t\t\tfaults: {\n\t\t\t\t\tasync fail(method) {\n\t\t\t\t\t\tfailing.add(method);\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t};\n\t\t},\n\t};\n}\n"
13
+ "/**\n * The conformance suite of the relation store port — what an adapter author\n * runs against `RelationStore`, as `describeJanusStores` is run against the\n * user port.\n *\n * ```ts\n * import { describe, it } from 'bun:test';\n * import { describeRelationStores } from '@nxgt/janus/conformance';\n *\n * describeRelationStores({ name: 'my adapter', harness, runner: { describe, it } });\n * ```\n */\n\nimport { JanusError, StoreFailure } from '../errors/janus-error';\nimport { mintId } from '../ids/id';\nimport { createMemoryRelations } from '../permissions/port/memory';\nimport type { RelationStore } from '../permissions/port/types';\nimport { formatSubject } from '../subjects/notation';\nimport type {\n\tEntity,\n\tRelationTuple,\n\tSubject,\n\tSubjectSet,\n} from '../subjects/subject';\nimport { equal, isOurs, ok, rejects } from './assert';\nimport { describeSuite, fromGlobals, SKIP_REASONS } from './describe';\nimport type { ConformanceRunner } from './types';\n\n/** A method of the relation store. */\nexport type RelationMethod = keyof RelationStore & string;\n\n/** How the suite makes one relation store method fail, for the outage cases. */\nexport interface RelationFaults {\n\t/**\n\t * Fails `method`, and only it: the other methods keep answering, because\n\t * `outage.write` reads the store back to prove the rejected write changed\n\t * nothing.\n\t */\n\tfail(method: RelationMethod): Promise<void>;\n}\n\nexport interface OpenedRelations {\n\t/** Empty: every case writes what it reads. */\n\treadonly store: RelationStore;\n\treadonly faults?: RelationFaults;\n\tclose?(): Promise<void>;\n}\n\nexport interface RelationHarness {\n\t/** Called once per case, so no case sees another's tuples. */\n\topen(): Promise<OpenedRelations>;\n}\n\nexport interface RelationContext {\n\treadonly store: RelationStore;\n\treadonly faults: RelationFaults | null;\n}\n\nexport interface RelationCase {\n\treadonly id: string;\n\treadonly group: 'relations' | 'outage';\n\treadonly name: string;\n\treadonly needs?: 'faults';\n\trun(context: RelationContext): Promise<void>;\n}\n\n// ─── Fixtures ─────────────────────────────────────────────────────────────\n\nconst entity = (type: string, id: string = mintId()): Entity => ({ type, id });\nconst set = (type: string, id: string, relation: string): SubjectSet => ({\n\ttype,\n\tid,\n\trelation,\n});\nconst tuple = (\n\tobject: Entity,\n\trelation: string,\n\tsubject: Subject,\n): RelationTuple => ({ object, relation, subject });\n\n/** Order-free, so a store may answer in any order. */\nconst sorted = (subjects: readonly Subject[]) =>\n\tsubjects.map(formatSubject).sort();\n\n// ─── The cases ────────────────────────────────────────────────────────────\n\nconst group = 'relations';\n\nexport const relationStoreCases: readonly RelationCase[] = [\n\t{\n\t\tid: 'relations.roundTrip',\n\t\tgroup,\n\t\tname: 'holds exactly the tuples written, byte for byte: staff:u1 is not patient:u1, and a set is not its entity',\n\t\tasync run({ store }) {\n\t\t\tconst record = entity('record', 'R:1 — ÿ');\n\t\t\tconst direct = tuple(record, 'viewer', entity('staff', 'u1'));\n\t\t\tconst inherited = tuple(record, 'viewer', set('team', 't1', 'member'));\n\t\t\tawait store.write({ add: [direct, inherited] });\n\n\t\t\tequal(await store.has(direct), true, 'has for a written tuple');\n\t\t\tequal(await store.has(inherited), true, 'has for a written subject set');\n\t\t\tequal(\n\t\t\t\tawait store.has(tuple(record, 'viewer', entity('patient', 'u1'))),\n\t\t\t\tfalse,\n\t\t\t\t'has for the same id under another subject type: types are part of the subject',\n\t\t\t);\n\t\t\tequal(\n\t\t\t\tawait store.has(tuple(record, 'viewer', entity('team', 't1'))),\n\t\t\t\tfalse,\n\t\t\t\t'has for the entity of a stored subject set: a set is not its entity',\n\t\t\t);\n\t\t\tequal(\n\t\t\t\tawait store.has(\n\t\t\t\t\ttuple(entity('record', 'r:1 — ÿ'), 'viewer', direct.subject),\n\t\t\t\t),\n\t\t\t\tfalse,\n\t\t\t\t'has for an id differing in one character: ids are compared as written',\n\t\t\t);\n\t\t},\n\t},\n\t{\n\t\tid: 'relations.edgeCharacters',\n\t\tgroup,\n\t\tname: 'round-trips every character the core lets through in an id: control characters, U+FFFF and a surrogate pair',\n\t\tasync run({ store }) {\n\t\t\t// The core refuses a NUL and a lone surrogate before a store is\n\t\t\t// asked; everything else must come back exactly as written.\n\t\t\tconst edge = 'a\\u0001\\u001f\\u007f\\uFFFF 😀 z';\n\t\t\tconst record = entity('record', edge);\n\t\t\tconst written = tuple(record, 'viewer', set('team', edge, 'member'));\n\t\t\tconst direct = tuple(record, 'viewer', entity('staff', edge));\n\t\t\tawait store.write({ add: [written, direct] });\n\n\t\t\tequal(await store.has(written), true, 'has for ids of edge characters');\n\t\t\t// Read back through every index: an adapter that mangles an id the\n\t\t\t// same way on write and on lookup still fails here.\n\t\t\tequal(\n\t\t\t\tawait store.findSubjectSets(record, 'viewer'),\n\t\t\t\t[set('team', edge, 'member')],\n\t\t\t\t'findSubjectSets answers the set id as written',\n\t\t\t);\n\t\t\tequal(\n\t\t\t\tawait store.findEntities(record, 'viewer'),\n\t\t\t\t[entity('staff', edge)],\n\t\t\t\t'findEntities answers the entity id as written',\n\t\t\t);\n\t\t\tequal(\n\t\t\t\tawait store.findObjects({\n\t\t\t\t\ttype: 'record',\n\t\t\t\t\trelation: 'viewer',\n\t\t\t\t\tsubject: direct.subject,\n\t\t\t\t\tafter: null,\n\t\t\t\t\tlimit: 10,\n\t\t\t\t}),\n\t\t\t\t{ items: [edge], nextCursor: null },\n\t\t\t\t'findObjects answers the object id as written',\n\t\t\t);\n\t\t\tequal(\n\t\t\t\tawait store.has(\n\t\t\t\t\ttuple(\n\t\t\t\t\t\tentity('record', edge.replace('😀', '😁')),\n\t\t\t\t\t\t'viewer',\n\t\t\t\t\t\twritten.subject,\n\t\t\t\t\t),\n\t\t\t\t),\n\t\t\t\tfalse,\n\t\t\t\t'has for an id differing in one astral character',\n\t\t\t);\n\t\t},\n\t},\n\t{\n\t\tid: 'relations.undefinedRelation',\n\t\tgroup,\n\t\tname: 'reads a subject whose relation is undefined as its entity, not as a set',\n\t\tasync run({ store }) {\n\t\t\tconst record = entity('record');\n\t\t\tconst staff = entity('staff');\n\t\t\t// A caller that spreads an optional field hands the port this shape.\n\t\t\tconst spread = { ...staff, relation: undefined } as unknown as Subject;\n\t\t\tawait store.write({ add: [tuple(record, 'viewer', spread)] });\n\n\t\t\tequal(\n\t\t\t\tawait store.has(tuple(record, 'viewer', staff)),\n\t\t\t\ttrue,\n\t\t\t\t'has for the entity, after writing it with relation: undefined',\n\t\t\t);\n\t\t\tequal(\n\t\t\t\tawait store.findEntities(record, 'viewer'),\n\t\t\t\t[staff],\n\t\t\t\t'findEntities: the tuple names an entity',\n\t\t\t);\n\t\t\tequal(\n\t\t\t\tawait store.findSubjectSets(record, 'viewer'),\n\t\t\t\t[],\n\t\t\t\t'findSubjectSets: relation: undefined is no set',\n\t\t\t);\n\t\t\tequal(\n\t\t\t\tawait store.findObjects({\n\t\t\t\t\ttype: 'record',\n\t\t\t\t\trelation: 'viewer',\n\t\t\t\t\tsubject: spread,\n\t\t\t\t\tafter: null,\n\t\t\t\t\tlimit: 10,\n\t\t\t\t}),\n\t\t\t\t{ items: [record.id], nextCursor: null },\n\t\t\t\t'findObjects for the subject written with relation: undefined',\n\t\t\t);\n\t\t\tequal(\n\t\t\t\tawait store.findObjects({\n\t\t\t\t\ttype: 'record',\n\t\t\t\t\trelation: 'viewer',\n\t\t\t\t\tsubject: set('staff', staff.id, 'x'),\n\t\t\t\t\tafter: null,\n\t\t\t\t\tlimit: 10,\n\t\t\t\t}),\n\t\t\t\t{ items: [], nextCursor: null },\n\t\t\t\t'findObjects for a set of that entity: the entity is not a set',\n\t\t\t);\n\t\t\tawait store.write({ remove: [tuple(record, 'viewer', spread)] });\n\t\t\tequal(\n\t\t\t\tawait store.has(tuple(record, 'viewer', staff)),\n\t\t\t\tfalse,\n\t\t\t\t'has after removing it with relation: undefined',\n\t\t\t);\n\t\t},\n\t},\n\t{\n\t\tid: 'relations.absence',\n\t\tgroup,\n\t\tname: 'answers false, [], an empty page and 0 for an empty store — never null or undefined',\n\t\tasync run({ store }) {\n\t\t\tconst record = entity('record');\n\t\t\tconst staff = entity('staff');\n\n\t\t\tequal(await store.has(tuple(record, 'viewer', staff)), false, 'has');\n\t\t\tequal(\n\t\t\t\tawait store.findSubjectSets(record, 'viewer'),\n\t\t\t\t[],\n\t\t\t\t'findSubjectSets',\n\t\t\t);\n\t\t\tequal(await store.findEntities(record, 'viewer'), [], 'findEntities');\n\t\t\tequal(\n\t\t\t\tawait store.findObjects({\n\t\t\t\t\ttype: 'record',\n\t\t\t\t\trelation: 'viewer',\n\t\t\t\t\tsubject: staff,\n\t\t\t\t\tafter: null,\n\t\t\t\t\tlimit: 10,\n\t\t\t\t}),\n\t\t\t\t{ items: [], nextCursor: null },\n\t\t\t\t'findObjects on an empty store',\n\t\t\t);\n\t\t\tequal(await store.deleteEntity(staff), 0, 'deleteEntity');\n\t\t},\n\t},\n\t{\n\t\tid: 'relations.idempotentWrite',\n\t\tgroup,\n\t\tname: 'is idempotent under retry: adding a stored tuple and removing an absent one write nothing',\n\t\tasync run({ store }) {\n\t\t\tconst record = entity('record');\n\t\t\tconst viewer = tuple(record, 'viewer', entity('team'));\n\t\t\tawait store.write({ add: [viewer] });\n\t\t\tawait store.write({ add: [viewer] });\n\t\t\tawait store.write({ remove: [tuple(record, 'viewer', entity('team'))] });\n\n\t\t\tequal(\n\t\t\t\t(await store.findEntities(record, 'viewer')).length,\n\t\t\t\t1,\n\t\t\t\t'findEntities after the same tuple was added twice',\n\t\t\t);\n\t\t},\n\t},\n\t{\n\t\tid: 'relations.uniqueness',\n\t\tgroup,\n\t\tname: 'keeps one tuple when twenty concurrent writes add it: uniqueness is a constraint, not a read',\n\t\tasync run({ store }) {\n\t\t\tconst record = entity('record');\n\t\t\tconst parent = entity('folder');\n\t\t\tawait Promise.all(\n\t\t\t\tArray.from({ length: 20 }, () =>\n\t\t\t\t\tstore.write({ add: [tuple(record, 'parent', parent)] }),\n\t\t\t\t),\n\t\t\t);\n\n\t\t\tequal(\n\t\t\t\tawait store.findEntities(record, 'parent'),\n\t\t\t\t[parent],\n\t\t\t\t'findEntities after twenty concurrent adds of one tuple',\n\t\t\t);\n\t\t},\n\t},\n\t{\n\t\tid: 'relations.removeThenAdd',\n\t\tgroup,\n\t\tname: 'applies one write’s removals and additions together',\n\t\tasync run({ store }) {\n\t\t\tconst record = entity('record');\n\t\t\tconst before = tuple(record, 'owner', entity('staff', 'a'));\n\t\t\tconst after = tuple(record, 'owner', entity('staff', 'b'));\n\t\t\tawait store.write({ add: [before] });\n\n\t\t\tawait store.write({ remove: [before], add: [after] });\n\n\t\t\tequal(await store.has(before), false, 'the removed tuple');\n\t\t\tequal(await store.has(after), true, 'the added tuple');\n\t\t},\n\t},\n\t{\n\t\tid: 'relations.oneHop',\n\t\tgroup,\n\t\tname: 'answers one hop: the subject sets and the entities holding one relation on one object, and nothing else',\n\t\tasync run({ store }) {\n\t\t\tconst record = entity('record');\n\t\t\tconst staff = entity('staff');\n\t\t\tconst team = entity('team');\n\t\t\tconst members = set('team', team.id, 'member');\n\t\t\tconst leads = set('team', team.id, 'lead');\n\t\t\tawait store.write({\n\t\t\t\tadd: [\n\t\t\t\t\ttuple(record, 'viewer', staff),\n\t\t\t\t\ttuple(record, 'viewer', team),\n\t\t\t\t\ttuple(record, 'viewer', members),\n\t\t\t\t\ttuple(record, 'viewer', leads),\n\t\t\t\t\t// Another relation, and another object: neither is an answer.\n\t\t\t\t\ttuple(record, 'editor', set('team', team.id, 'admin')),\n\t\t\t\t\ttuple(entity('record'), 'viewer', set('team', 'other', 'member')),\n\t\t\t\t],\n\t\t\t});\n\n\t\t\tequal(\n\t\t\t\tsorted(await store.findSubjectSets(record, 'viewer')),\n\t\t\t\tsorted([members, leads]),\n\t\t\t\t'findSubjectSets: the sets only, of this object and this relation',\n\t\t\t);\n\t\t\tequal(\n\t\t\t\tsorted(await store.findEntities(record, 'viewer')),\n\t\t\t\tsorted([staff, team]),\n\t\t\t\t'findEntities: the single entities only, of this object and this relation',\n\t\t\t);\n\t\t},\n\t},\n\t{\n\t\tid: 'relations.objects',\n\t\tgroup,\n\t\tname: 'pages 25 objects by 10 in ascending id order, for one type, relation and exact subject, and ends on a null cursor',\n\t\tasync run({ store }) {\n\t\t\tconst staff = entity('staff');\n\t\t\tconst ids = Array.from(\n\t\t\t\t{ length: 25 },\n\t\t\t\t(_, n) => `r${String(n).padStart(2, '0')}`,\n\t\t\t);\n\t\t\t// Written newest first, beside noise the answer must leave out.\n\t\t\tfor (const id of [...ids].reverse()) {\n\t\t\t\tawait store.write({\n\t\t\t\t\tadd: [\n\t\t\t\t\t\ttuple(entity('record', id), 'viewer', staff),\n\t\t\t\t\t\ttuple(entity('record', `${id}x`), 'editor', staff),\n\t\t\t\t\t\ttuple(entity('folder', id), 'viewer', staff),\n\t\t\t\t\t\ttuple(\n\t\t\t\t\t\t\tentity('record', `${id}y`),\n\t\t\t\t\t\t\t'viewer',\n\t\t\t\t\t\t\tset('staff', staff.id, 'x'),\n\t\t\t\t\t\t),\n\t\t\t\t\t],\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tconst seen: string[] = [];\n\t\t\tconst sizes: number[] = [];\n\t\t\tlet after: string | null = null;\n\t\t\tfor (let page = 0; page < 10; page += 1) {\n\t\t\t\tconst answer = await store.findObjects({\n\t\t\t\t\ttype: 'record',\n\t\t\t\t\trelation: 'viewer',\n\t\t\t\t\tsubject: staff,\n\t\t\t\t\tafter,\n\t\t\t\t\tlimit: 10,\n\t\t\t\t});\n\t\t\t\tseen.push(...answer.items);\n\t\t\t\tsizes.push(answer.items.length);\n\t\t\t\tafter = answer.nextCursor;\n\t\t\t\tif (after === null) break;\n\t\t\t}\n\n\t\t\tequal(sizes, [10, 10, 5], 'findObjects: page sizes for 25 objects by 10');\n\t\t\tequal(seen, ids, 'findObjects: every id once, in ascending order');\n\t\t\tconst between = await store.findObjects({\n\t\t\t\ttype: 'record',\n\t\t\t\trelation: 'viewer',\n\t\t\t\tsubject: staff,\n\t\t\t\tafter: 'r04a',\n\t\t\t\tlimit: 2,\n\t\t\t});\n\t\t\tequal(\n\t\t\t\tbetween.items,\n\t\t\t\t['r05', 'r06'],\n\t\t\t\t'findObjects: a cursor naming no stored object should start after it',\n\t\t\t);\n\t\t},\n\t},\n\t{\n\t\tid: 'relations.deleteEntity',\n\t\tgroup,\n\t\tname: 'deletes every tuple naming an entity — as object, as subject, as a set’s entity — and counts them',\n\t\tasync run({ store }) {\n\t\t\tconst team = entity('team');\n\t\t\tconst other = entity('team');\n\t\t\tconst kept = [\n\t\t\t\ttuple(other, 'member', entity('staff')),\n\t\t\t\ttuple(entity('record'), 'viewer', set('team', other.id, 'member')),\n\t\t\t];\n\t\t\tawait store.write({\n\t\t\t\tadd: [\n\t\t\t\t\ttuple(team, 'member', entity('staff')),\n\t\t\t\t\ttuple(entity('record'), 'team', team),\n\t\t\t\t\ttuple(entity('record'), 'viewer', set('team', team.id, 'member')),\n\t\t\t\t\t...kept,\n\t\t\t\t],\n\t\t\t});\n\n\t\t\tequal(\n\t\t\t\tawait store.deleteEntity(team),\n\t\t\t\t3,\n\t\t\t\t'deleteEntity: how many it deleted',\n\t\t\t);\n\t\t\tfor (const survivor of kept) {\n\t\t\t\tequal(\n\t\t\t\t\tawait store.has(survivor),\n\t\t\t\t\ttrue,\n\t\t\t\t\t'deleteEntity should not touch another entity',\n\t\t\t\t);\n\t\t\t}\n\t\t\tequal(\n\t\t\t\tawait store.deleteEntity(team),\n\t\t\t\t0,\n\t\t\t\t'deleteEntity replayed answers 0, not a failure',\n\t\t\t);\n\t\t},\n\t},\n];\n\n// ─── Outages ──────────────────────────────────────────────────────────────\n\n/**\n * For each method, a store that cannot answer must **reject** — never\n * `false`, `[]`, an empty page or `0`. A relation store that answers `false`\n * for an outage denies everybody everything and says nothing; one that\n * resolves a write it did not make leaves a revoked access standing.\n */\nfunction outage(\n\tmethod: RelationMethod,\n\tcall: (store: RelationStore) => Promise<unknown>,\n\tafter?: (store: RelationStore) => Promise<void>,\n): RelationCase {\n\treturn {\n\t\tid: `outage.${method}`,\n\t\tgroup: 'outage',\n\t\tname: `relations.${method} rejects when the store cannot answer — never false, [], an empty page or 0`,\n\t\tneeds: 'faults',\n\t\tasync run({ store, faults }) {\n\t\t\tawait store.write({ add: [seeded] });\n\t\t\tawait faults?.fail(method);\n\n\t\t\tconst error = await rejects(\n\t\t\t\tcall(store),\n\t\t\t\t`relations.${method} under an outage should reject`,\n\t\t\t);\n\t\t\tif (\n\t\t\t\terror instanceof JanusError ||\n\t\t\t\t(error as { name?: unknown })?.name === 'StoreFailure'\n\t\t\t) {\n\t\t\t\tisOurs(\n\t\t\t\t\terror,\n\t\t\t\t\tStoreFailure,\n\t\t\t\t\t'StoreFailure',\n\t\t\t\t\t`relations.${method} under an outage`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tok(\n\t\t\t\t(error as { code?: unknown } | null)?.code !== 'NOT_FOUND',\n\t\t\t\t`relations.${method} under an outage rejected with NOT_FOUND: an outage is never an absence`,\n\t\t\t);\n\t\t\tawait after?.(store);\n\t\t},\n\t};\n}\n\nconst seededObject: Entity = { type: 'record', id: 'seeded' };\nconst seededSubject: Entity = { type: 'staff', id: 'seeded' };\nconst seeded = tuple(seededObject, 'viewer', seededSubject);\n\nexport const relationOutageCases: readonly RelationCase[] = [\n\toutage(\n\t\t'write',\n\t\t(store) =>\n\t\t\tstore.write({\n\t\t\t\tremove: [seeded],\n\t\t\t\tadd: [tuple(seededObject, 'owner', seededSubject)],\n\t\t\t}),\n\t\t// A rejected write is one that did nothing: all of it, or none of it.\n\t\tasync (store) => {\n\t\t\tequal(\n\t\t\t\tawait store.has(seeded),\n\t\t\t\ttrue,\n\t\t\t\t'relations.write rejected, and still removed a tuple: a write is all or nothing',\n\t\t\t);\n\t\t\tequal(\n\t\t\t\tawait store.has(tuple(seededObject, 'owner', seededSubject)),\n\t\t\t\tfalse,\n\t\t\t\t'relations.write rejected, and still added a tuple: a write is all or nothing',\n\t\t\t);\n\t\t},\n\t),\n\toutage('has', (store) => store.has(seeded)),\n\toutage('findSubjectSets', (store) =>\n\t\tstore.findSubjectSets(seededObject, 'viewer'),\n\t),\n\toutage('findEntities', (store) => store.findEntities(seededObject, 'viewer')),\n\toutage('findObjects', (store) =>\n\t\tstore.findObjects({\n\t\t\ttype: 'record',\n\t\t\trelation: 'viewer',\n\t\t\tsubject: seededSubject,\n\t\t\tafter: null,\n\t\t\tlimit: 10,\n\t\t}),\n\t),\n\toutage('deleteEntity', (store) => store.deleteEntity(seededSubject)),\n];\n\nexport const allRelationCases: readonly RelationCase[] = [\n\t...relationStoreCases,\n\t...relationOutageCases,\n];\n\n// ─── Running them ─────────────────────────────────────────────────────────\n\n/** Runs one case against a freshly opened store, and closes it, pass or fail. */\nexport async function runRelationCase(\n\trelationCase: RelationCase,\n\tharness: RelationHarness,\n): Promise<{ readonly skipped: string } | { readonly passed: true }> {\n\tconst opened = await harness.open();\n\n\ttry {\n\t\tif (relationCase.needs === 'faults' && opened.faults === undefined) {\n\t\t\treturn { skipped: SKIP_REASONS.faults };\n\t\t}\n\t\tawait relationCase.run({\n\t\t\tstore: opened.store,\n\t\t\tfaults: opened.faults ?? null,\n\t\t});\n\t\treturn { passed: true };\n\t} finally {\n\t\tawait opened.close?.();\n\t}\n}\n\n/** Describes the whole relation suite under the adapter's test runner. */\nexport function describeRelationStores(options: {\n\treadonly name: string;\n\treadonly harness: RelationHarness;\n\treadonly runner?: ConformanceRunner;\n\t/** Case ids to skip, each with the reason — reported, never silent. */\n\treadonly skip?: Readonly<Record<string, string>>;\n\treadonly faults?: boolean;\n}): void {\n\tdescribeSuite({\n\t\ttitle: `${options.name} — @nxgt/janus relation conformance`,\n\t\tcases: allRelationCases,\n\t\trun: (relationCase) => runRelationCase(relationCase, options.harness),\n\t\trunner: options.runner ?? fromGlobals('describeRelationStores'),\n\t\tskip: options.skip ?? {},\n\t\tfaults: options.faults,\n\t});\n}\n\n/** The reference store, with faults: what the suite proves itself against. */\nexport function referenceRelationHarness(): RelationHarness {\n\treturn {\n\t\tasync open() {\n\t\t\tconst failing = new Set<string>();\n\t\t\tconst inner = createMemoryRelations();\n\t\t\tconst store = Object.fromEntries(\n\t\t\t\tObject.entries(inner).map(([method, fn]) => [\n\t\t\t\t\tmethod,\n\t\t\t\t\t(...args: unknown[]) =>\n\t\t\t\t\t\tfailing.has(method)\n\t\t\t\t\t\t\t? Promise.reject(\n\t\t\t\t\t\t\t\t\tnew StoreFailure(\n\t\t\t\t\t\t\t\t\t\t`relations.${method}: the store could not answer`,\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\tslot: 'relations',\n\t\t\t\t\t\t\t\t\t\t\toperation: method,\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t: (fn as (...a: unknown[]) => unknown).apply(inner, args),\n\t\t\t\t]),\n\t\t\t) as unknown as RelationStore;\n\n\t\t\treturn {\n\t\t\t\tstore,\n\t\t\t\tfaults: {\n\t\t\t\t\tasync fail(method) {\n\t\t\t\t\t\tfailing.add(method);\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t};\n\t\t},\n\t};\n}\n"
14
14
  ],
15
- "mappings": "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",
16
- "debugId": "DFFC56A4D48D5C0564756E2164756E21",
15
+ "mappings": "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",
16
+ "debugId": "7779A65B64EF7C9A64756E2164756E21",
17
17
  "names": []
18
18
  }
@@ -1 +1 @@
1
- {"version":3,"file":"relations.d.ts","sourceRoot":"","sources":["../../src/conformance/relations.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAKH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAU/D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC;AAEjD,sCAAsC;AACtC,MAAM,MAAM,cAAc,GAAG,MAAM,aAAa,GAAG,MAAM,CAAC;AAE1D,gFAAgF;AAChF,MAAM,WAAW,cAAc;IAC9B;;;;OAIG;IACH,IAAI,CAAC,MAAM,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC5C;AAED,MAAM,WAAW,eAAe;IAC/B,8CAA8C;IAC9C,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC;IAC9B,QAAQ,CAAC,MAAM,CAAC,EAAE,cAAc,CAAC;IACjC,KAAK,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB;AAED,MAAM,WAAW,eAAe;IAC/B,8DAA8D;IAC9D,IAAI,IAAI,OAAO,CAAC,eAAe,CAAC,CAAC;CACjC;AAED,MAAM,WAAW,eAAe;IAC/B,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC;IAC9B,QAAQ,CAAC,MAAM,EAAE,cAAc,GAAG,IAAI,CAAC;CACvC;AAED,MAAM,WAAW,YAAY;IAC5B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,KAAK,EAAE,WAAW,GAAG,QAAQ,CAAC;IACvC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,CAAC,EAAE,QAAQ,CAAC;IAC1B,GAAG,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC7C;AAwBD,eAAO,MAAM,kBAAkB,EAAE,SAAS,YAAY,EAiWrD,CAAC;AA+CF,eAAO,MAAM,mBAAmB,EAAE,SAAS,YAAY,EAqCtD,CAAC;AAEF,eAAO,MAAM,gBAAgB,EAAE,SAAS,YAAY,EAGnD,CAAC;AAIF,iFAAiF;AACjF,wBAAsB,eAAe,CACpC,YAAY,EAAE,YAAY,EAC1B,OAAO,EAAE,eAAe,GACtB,OAAO,CAAC;IAAE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,QAAQ,CAAC,MAAM,EAAE,IAAI,CAAA;CAAE,CAAC,CAenE;AAED,0EAA0E;AAC1E,wBAAgB,sBAAsB,CAAC,OAAO,EAAE;IAC/C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,eAAe,CAAC;IAClC,QAAQ,CAAC,MAAM,CAAC,EAAE,iBAAiB,CAAC;IACpC,uEAAuE;IACvE,QAAQ,CAAC,IAAI,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IACjD,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC;CAC1B,GAAG,IAAI,CASP;AAED,8EAA8E;AAC9E,wBAAgB,wBAAwB,IAAI,eAAe,CAiC1D"}
1
+ {"version":3,"file":"relations.d.ts","sourceRoot":"","sources":["../../src/conformance/relations.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAKH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAU/D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC;AAEjD,sCAAsC;AACtC,MAAM,MAAM,cAAc,GAAG,MAAM,aAAa,GAAG,MAAM,CAAC;AAE1D,gFAAgF;AAChF,MAAM,WAAW,cAAc;IAC9B;;;;OAIG;IACH,IAAI,CAAC,MAAM,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC5C;AAED,MAAM,WAAW,eAAe;IAC/B,8CAA8C;IAC9C,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC;IAC9B,QAAQ,CAAC,MAAM,CAAC,EAAE,cAAc,CAAC;IACjC,KAAK,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB;AAED,MAAM,WAAW,eAAe;IAC/B,8DAA8D;IAC9D,IAAI,IAAI,OAAO,CAAC,eAAe,CAAC,CAAC;CACjC;AAED,MAAM,WAAW,eAAe;IAC/B,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC;IAC9B,QAAQ,CAAC,MAAM,EAAE,cAAc,GAAG,IAAI,CAAC;CACvC;AAED,MAAM,WAAW,YAAY;IAC5B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,KAAK,EAAE,WAAW,GAAG,QAAQ,CAAC;IACvC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,CAAC,EAAE,QAAQ,CAAC;IAC1B,GAAG,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC7C;AAwBD,eAAO,MAAM,kBAAkB,EAAE,SAAS,YAAY,EAiWrD,CAAC;AAoDF,eAAO,MAAM,mBAAmB,EAAE,SAAS,YAAY,EAqCtD,CAAC;AAEF,eAAO,MAAM,gBAAgB,EAAE,SAAS,YAAY,EAGnD,CAAC;AAIF,iFAAiF;AACjF,wBAAsB,eAAe,CACpC,YAAY,EAAE,YAAY,EAC1B,OAAO,EAAE,eAAe,GACtB,OAAO,CAAC;IAAE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,QAAQ,CAAC,MAAM,EAAE,IAAI,CAAA;CAAE,CAAC,CAenE;AAED,0EAA0E;AAC1E,wBAAgB,sBAAsB,CAAC,OAAO,EAAE;IAC/C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,eAAe,CAAC;IAClC,QAAQ,CAAC,MAAM,CAAC,EAAE,iBAAiB,CAAC;IACpC,uEAAuE;IACvE,QAAQ,CAAC,IAAI,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IACjD,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC;CAC1B,GAAG,IAAI,CASP;AAED,8EAA8E;AAC9E,wBAAgB,wBAAwB,IAAI,eAAe,CAiC1D"}
@@ -527,7 +527,9 @@ class Reverse {
527
527
  async lookup(type, relation, id) {
528
528
  const def = type.relations.get(relation);
529
529
  if (def?.kind !== "fromField" || def.lookup === undefined) {
530
- throw new TypeError(`list: ${type.name}.${relation} is read from a field, and has no lookup to find the ${type.name}s naming ${id} — fromField('${def?.kind === "fromField" ? def.field : relation}', '${def?.kind === "fromField" ? def.subject : ""}', { lookup })`);
530
+ const field = def?.kind === "fromField" ? def.field : relation;
531
+ const subject = def?.kind === "fromField" ? def.subject : "subject";
532
+ throw new TypeError(`list: ${type.name}.${relation} is read from a field, and has no lookup to find the ${type.name}s naming a subject of type '${subject}' — fromField('${field}', '${subject}', { lookup })`);
531
533
  }
532
534
  const ids = await def.lookup(id);
533
535
  if (!Array.isArray(ids) || ids.some((each) => typeof each !== "string")) {
@@ -726,5 +728,5 @@ export {
726
728
  when
727
729
  };
728
730
 
729
- //# debugId=A29B25AF106A2FDE64756E2164756E21
731
+ //# debugId=E842D9EC7EB9FE0964756E2164756E21
730
732
  //# sourceMappingURL=index.js.map
@@ -5,11 +5,11 @@
5
5
  "/**\n * A model, resolved: every string parsed once, every reference checked, every\n * refusal a `TypeError` naming where it is.\n *\n * The types refuse most of these first. This is what refuses them for a model\n * built at run time or written in JavaScript, and what refuses what the types\n * cannot see: names, and a permission that reaches itself without crossing a\n * relation.\n */\n\nimport type { Subject } from '../subjects/subject';\nimport type { ModelConfig } from './model';\n\n/** Who may hold a stored relation: a subject type, or a subject set. */\nexport type Holder =\n\t| { readonly kind: 'type'; readonly type: string }\n\t| { readonly kind: 'set'; readonly type: string; readonly relation: string };\n\n/**\n * Whether a stored relation admits `subject` as a holder: an entity of a\n * declared type, or a set of a declared `type#relation`. One rule for what\n * `grant()` writes and what `can()` and `list()` follow — a tuple the model\n * does not admit grants nothing, however it was stored.\n */\nexport function admits(holders: readonly Holder[], subject: Subject): boolean {\n\treturn holders.some((holder) =>\n\t\tholder.kind === 'type'\n\t\t\t? !('relation' in subject) && holder.type === subject.type\n\t\t\t: 'relation' in subject &&\n\t\t\t\tholder.type === subject.type &&\n\t\t\t\tholder.relation === subject.relation,\n\t);\n}\n\nexport type ResolvedRelation =\n\t| { readonly kind: 'stored'; readonly holders: readonly Holder[] }\n\t| {\n\t\t\treadonly kind: 'fromField';\n\t\t\treadonly field: string;\n\t\t\treadonly subject: string;\n\t\t\t/** What `list()` reverses it with. Absent: `list()` cannot reach through it. */\n\t\t\treadonly lookup?: (subjectId: string) => Promise<readonly string[]>;\n\t };\n\n/** One rule of a permission. `test`, when present, must pass for it to grant. */\nexport type ResolvedRule = (\n\t| { readonly kind: 'name'; readonly name: string }\n\t| {\n\t\t\treadonly kind: 'arrow';\n\t\t\treadonly relation: string;\n\t\t\treadonly target: string;\n\t }\n) & { readonly test?: (ctx: never) => boolean };\n\nexport interface ResolvedObjectType {\n\treadonly name: string;\n\treadonly relations: ReadonlyMap<string, ResolvedRelation>;\n\treadonly permissions: ReadonlyMap<string, readonly ResolvedRule[]>;\n}\n\nexport interface ResolvedModel {\n\treadonly subjects: ReadonlySet<string>;\n\treadonly types: ReadonlyMap<string, ResolvedObjectType>;\n}\n\n/** camelCase, as every name in this package — and never `#`, `-`, `>` or `:`, which the notation uses. */\nconst NAME = /^[a-z][A-Za-z0-9]*$/;\n/** A field `fromField` reads: a top-level property. */\nconst FIELD = /^[A-Za-z_$][A-Za-z0-9_$]*$/;\n\nconst isRecord = (value: unknown): value is Record<string, unknown> =>\n\ttypeof value === 'object' && value !== null && !Array.isArray(value);\n\n/** The keys the model had before 0.2, and their names since. */\nconst RENAMED: Readonly<Record<string, string>> = {\n\trelations: 'related',\n\tpermissions: 'permits',\n};\n\ntype Refuse = (message: string) => TypeError;\n\n/** The names each object type declares, collected before any rule is read. */\ninterface DeclaredNames {\n\treadonly relationNames: ReadonlyMap<string, ReadonlySet<string>>;\n\treadonly permissionNames: ReadonlyMap<string, ReadonlySet<string>>;\n}\n\nexport function resolveModel(\n\tconfig: ModelConfig,\n\twhere: string,\n): ResolvedModel {\n\tconst refuse: Refuse = (message) => new TypeError(`${where}: ${message}`);\n\n\tif (!isRecord(config)) throw refuse('pass { subjects, types }');\n\tconst subjects = subjectTypesOf(config.subjects, refuse);\n\tconst typeNames = objectTypeNamesOf(config.types, refuse);\n\tconst declared = collectNames(config.types, refuse);\n\tconst types = resolveTypes(config.types, {\n\t\trefuse,\n\t\tsubjects,\n\t\ttypeNames,\n\t\tdeclared,\n\t});\n\n\trefuseLoops(types, refuse);\n\trefuseDataBeyondRoot(types, refuse);\n\n\treturn { subjects, types };\n}\n\n/** The subject types: camelCase names, as `auth.types` gives them. */\nfunction subjectTypesOf(\n\tvalue: ModelConfig['subjects'],\n\trefuse: Refuse,\n): Set<string> {\n\t// Checked all the same: JavaScript callers pass anything.\n\tif (!Array.isArray(value)) {\n\t\tthrow refuse(\n\t\t\t'subjects must be an array of subject type names — auth.types from janus(), or your own',\n\t\t);\n\t}\n\tfor (const subject of value as readonly unknown[]) {\n\t\tif (typeof subject !== 'string' || !NAME.test(subject)) {\n\t\t\tthrow refuse(\n\t\t\t\t`the subject type \"${String(subject)}\" must be a camelCase name`,\n\t\t\t);\n\t\t}\n\t}\n\treturn new Set<string>(value);\n}\n\n/**\n * The object types' names: camelCase, and at least one. A user type may be\n * one too — its users are then objects the model grants relations on.\n */\nfunction objectTypeNamesOf(\n\tvalue: ModelConfig['types'],\n\trefuse: Refuse,\n): Set<string> {\n\tif (!isRecord(value) || Object.keys(value).length === 0) {\n\t\tthrow refuse('types declares no object type');\n\t}\n\tconst typeNames = new Set(Object.keys(value));\n\tfor (const name of typeNames) {\n\t\tif (!NAME.test(name)) {\n\t\t\tthrow refuse(\n\t\t\t\t`the object type \"${name}\" must be a camelCase name — letters and digits, starting with a lowercase letter`,\n\t\t\t);\n\t\t}\n\t}\n\treturn typeNames;\n}\n\n/**\n * Every type's relation and permission names, first: a subject set or an\n * arrow may name a relation of a type declared further down.\n */\nfunction collectNames(\n\ttypes: ModelConfig['types'],\n\trefuse: Refuse,\n): DeclaredNames {\n\tconst relationNames = new Map<string, Set<string>>();\n\tconst permissionNames = new Map<string, Set<string>>();\n\tfor (const [name, def] of Object.entries(types)) {\n\t\tconst at = `types.${name}`;\n\t\tif (!isRecord(def)) throw refuse(`${at} must be an object`);\n\t\tfor (const key of Object.keys(def)) {\n\t\t\tif (key === 'related' || key === 'permits') continue;\n\t\t\tthrow refuse(\n\t\t\t\tObject.hasOwn(RENAMED, key)\n\t\t\t\t\t? `${at}.${key} is now ${RENAMED[key]}: rename the key`\n\t\t\t\t\t: `${at}.${key} is not a key of an object type: related or permits`,\n\t\t\t);\n\t\t}\n\t\tconst relations = namesIn(def.related, `${at}.related`, refuse);\n\t\tconst permissions = namesIn(def.permits, `${at}.permits`, refuse);\n\t\tfor (const permission of permissions) {\n\t\t\tif (relations.has(permission)) {\n\t\t\t\tthrow refuse(\n\t\t\t\t\t`${at}: \"${permission}\" names a relation and a permission; rename one`,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t\trelationNames.set(name, relations);\n\t\tpermissionNames.set(name, permissions);\n\t}\n\treturn { relationNames, permissionNames };\n}\n\n/** Each object type's relations and permissions, every rule parsed once. */\nfunction resolveTypes(\n\tdefs: ModelConfig['types'],\n\tcontext: {\n\t\treadonly refuse: Refuse;\n\t\treadonly subjects: ReadonlySet<string>;\n\t\treadonly typeNames: ReadonlySet<string>;\n\t\treadonly declared: DeclaredNames;\n\t},\n): Map<string, ResolvedObjectType> {\n\tconst { refuse, subjects, typeNames } = context;\n\tconst { relationNames, permissionNames } = context.declared;\n\tconst isSubjectType = (type: string) =>\n\t\tsubjects.has(type) || typeNames.has(type);\n\tconst namesOf = (type: string) =>\n\t\tnew Set([\n\t\t\t...(relationNames.get(type) ?? []),\n\t\t\t...(permissionNames.get(type) ?? []),\n\t\t]);\n\n\tconst types = new Map<string, ResolvedObjectType>();\n\tfor (const [name, def] of Object.entries(defs)) {\n\t\tconst at = `types.${name}`;\n\t\tconst relations = new Map<string, ResolvedRelation>();\n\n\t\tfor (const [relation, holders] of Object.entries(def.related ?? {})) {\n\t\t\tconst here = `${at}.related.${relation}`;\n\t\t\trelations.set(\n\t\t\t\trelation,\n\t\t\t\tresolveRelation(holders, here, {\n\t\t\t\t\trefuse,\n\t\t\t\t\tisSubjectType,\n\t\t\t\t\trelationNames,\n\t\t\t\t}),\n\t\t\t);\n\t\t}\n\n\t\tconst permissions = new Map<string, readonly ResolvedRule[]>();\n\t\tfor (const [permission, rules] of Object.entries(def.permits ?? {})) {\n\t\t\tconst here = `${at}.permits.${permission}`;\n\t\t\tif (!Array.isArray(rules) || rules.length === 0) {\n\t\t\t\tthrow refuse(`${here} must be a non-empty array of rules`);\n\t\t\t}\n\t\t\tpermissions.set(\n\t\t\t\tpermission,\n\t\t\t\trules.map((rule: unknown, index: number) =>\n\t\t\t\t\tresolveRule(rule, `${here}[${index}]`, {\n\t\t\t\t\t\trefuse,\n\t\t\t\t\t\town: namesOf(name),\n\t\t\t\t\t\trelations,\n\t\t\t\t\t\ttypeNames,\n\t\t\t\t\t\tnamesOf,\n\t\t\t\t\t\tself: name,\n\t\t\t\t\t}),\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\n\t\ttypes.set(name, { name, relations, permissions });\n\t}\n\treturn types;\n}\n\nfunction namesIn(value: unknown, at: string, refuse: Refuse): Set<string> {\n\tif (value === undefined) return new Set();\n\tif (!isRecord(value)) throw refuse(`${at} must be an object`);\n\tfor (const name of Object.keys(value)) {\n\t\tif (!NAME.test(name)) {\n\t\t\tthrow refuse(\n\t\t\t\t`${at}: \"${name}\" must be a camelCase name — letters and digits, starting with a lowercase letter`,\n\t\t\t);\n\t\t}\n\t}\n\treturn new Set(Object.keys(value));\n}\n\nfunction resolveRelation(\n\tvalue: unknown,\n\there: string,\n\t{\n\t\trefuse,\n\t\tisSubjectType,\n\t\trelationNames,\n\t}: {\n\t\trefuse: Refuse;\n\t\tisSubjectType: (type: string) => boolean;\n\t\trelationNames: ReadonlyMap<string, ReadonlySet<string>>;\n\t},\n): ResolvedRelation {\n\tif (isRecord(value) && value.kind === 'fromField') {\n\t\tconst { field, subject, lookup } = value;\n\t\tif (typeof field !== 'string' || !FIELD.test(field)) {\n\t\t\tthrow refuse(`${here}: fromField must name a top-level field`);\n\t\t}\n\t\tif (typeof subject !== 'string' || !isSubjectType(subject)) {\n\t\t\tthrow refuse(\n\t\t\t\t`${here}: fromField names \"${String(subject)}\", which is not a subject type`,\n\t\t\t);\n\t\t}\n\t\tif (lookup !== undefined && typeof lookup !== 'function') {\n\t\t\tthrow refuse(`${here}: fromField's lookup must be a function`);\n\t\t}\n\t\treturn lookup === undefined\n\t\t\t? { kind: 'fromField', field, subject }\n\t\t\t: {\n\t\t\t\t\tkind: 'fromField',\n\t\t\t\t\tfield,\n\t\t\t\t\tsubject,\n\t\t\t\t\tlookup: lookup as (subjectId: string) => Promise<readonly string[]>,\n\t\t\t\t};\n\t}\n\n\tif (!Array.isArray(value) || value.length === 0) {\n\t\tthrow refuse(\n\t\t\t`${here} must be a non-empty array of subject types, or fromField()`,\n\t\t);\n\t}\n\tconst holders = value.map((holder: unknown): Holder => {\n\t\tif (typeof holder !== 'string') {\n\t\t\tthrow refuse(`${here}: a holder must be a string`);\n\t\t}\n\t\tconst hash = holder.indexOf('#');\n\t\tif (hash < 0) {\n\t\t\tif (!isSubjectType(holder)) {\n\t\t\t\tthrow refuse(`${here}: \"${holder}\" is not a subject type`);\n\t\t\t}\n\t\t\treturn { kind: 'type', type: holder };\n\t\t}\n\t\tconst type = holder.slice(0, hash);\n\t\tconst relation = holder.slice(hash + 1);\n\t\tif (!relationNames.get(type)?.has(relation)) {\n\t\t\tthrow refuse(\n\t\t\t\t`${here}: \"${holder}\" is not a subject set — it must name an object type and one of its relations`,\n\t\t\t);\n\t\t}\n\t\treturn { kind: 'set', type, relation };\n\t});\n\treturn { kind: 'stored', holders };\n}\n\nfunction resolveRule(\n\tvalue: unknown,\n\there: string,\n\tcontext: {\n\t\trefuse: Refuse;\n\t\town: ReadonlySet<string>;\n\t\trelations: ReadonlyMap<string, ResolvedRelation>;\n\t\ttypeNames: ReadonlySet<string>;\n\t\tnamesOf: (type: string) => ReadonlySet<string>;\n\t\tself: string;\n\t},\n): ResolvedRule {\n\tconst { refuse } = context;\n\n\tif (isRecord(value) && value.kind === 'when') {\n\t\tif (typeof value.test !== 'function') {\n\t\t\tthrow refuse(`${here}: when() takes a function as its test`);\n\t\t}\n\t\tconst inner = resolveRule(value.rule, here, context);\n\t\treturn { ...inner, test: value.test as (ctx: never) => boolean };\n\t}\n\tif (typeof value !== 'string') {\n\t\tthrow refuse(`${here}: a rule is a name, an arrow, or when()`);\n\t}\n\n\tconst arrow = value.indexOf('->');\n\tif (arrow < 0) {\n\t\tif (!context.own.has(value)) {\n\t\t\tthrow refuse(\n\t\t\t\t`${here}: \"${value}\" is not a relation or a permission of ${context.self}`,\n\t\t\t);\n\t\t}\n\t\treturn { kind: 'name', name: value };\n\t}\n\n\tconst relation = value.slice(0, arrow);\n\tconst target = value.slice(arrow + 2);\n\tconst through = context.relations.get(relation);\n\tif (through === undefined) {\n\t\tthrow refuse(\n\t\t\t`${here}: \"${value}\" goes through \"${relation}\", which is not a relation of ${context.self}`,\n\t\t);\n\t}\n\tconst targets =\n\t\tthrough.kind === 'fromField'\n\t\t\t? [through.subject]\n\t\t\t: through.holders.map((holder) =>\n\t\t\t\t\tholder.kind === 'type' ? holder.type : null,\n\t\t\t\t);\n\tfor (const type of targets) {\n\t\t// A subject set, or a user type, has no permissions to follow.\n\t\tif (type === null || !context.typeNames.has(type)) {\n\t\t\tthrow refuse(\n\t\t\t\t`${here}: \"${value}\" goes through \"${relation}\", which can hold ${type === null ? 'a subject set' : `a ${type}`}; an arrow follows object types only`,\n\t\t\t);\n\t\t}\n\t\tif (!context.namesOf(type).has(target)) {\n\t\t\tthrow refuse(\n\t\t\t\t`${here}: \"${value}\" names \"${target}\", which ${type} does not declare`,\n\t\t\t);\n\t\t}\n\t}\n\treturn { kind: 'arrow', relation, target };\n}\n\n/**\n * A permission that reaches itself through names alone — `view: ['edit']`,\n * `edit: ['view']` — never reaches a relation, so no data could end the walk.\n * Refused here rather than cut at run time: it is a model's bug, not a\n * user's data.\n */\nfunction refuseLoops(\n\ttypes: ReadonlyMap<string, ResolvedObjectType>,\n\trefuse: Refuse,\n): void {\n\tfor (const type of types.values()) {\n\t\tconst visiting: string[] = [];\n\t\tconst done = new Set<string>();\n\n\t\tconst visit = (permission: string): void => {\n\t\t\tif (done.has(permission)) return;\n\t\t\tconst loop = visiting.indexOf(permission);\n\t\t\tif (loop >= 0) {\n\t\t\t\tthrow refuse(\n\t\t\t\t\t`types.${type.name}.permits: ${[...visiting.slice(loop), permission].join(' → ')} is a loop no relation ends`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tvisiting.push(permission);\n\t\t\tfor (const rule of type.permissions.get(permission) ?? []) {\n\t\t\t\tif (rule.kind === 'name' && type.permissions.has(rule.name)) {\n\t\t\t\t\tvisit(rule.name);\n\t\t\t\t}\n\t\t\t}\n\t\t\tvisiting.pop();\n\t\t\tdone.add(permission);\n\t\t};\n\n\t\tfor (const permission of type.permissions.keys()) visit(permission);\n\t}\n}\n\n/**\n * A `fromField` is read from the object `can()` was given — the route loaded\n * it (decided 2026-09-24). An object reached through a subject set or an arrow\n * was loaded by nobody, so a rule that needs its data could never be decided.\n * Refused here, where it is a sentence, rather than at the first check that\n * reaches it, where it would be a denial nobody can explain.\n */\nfunction refuseDataBeyondRoot(\n\ttypes: ReadonlyMap<string, ResolvedObjectType>,\n\trefuse: Refuse,\n): void {\n\t/** The field `name` of `type` reads, directly or through its own rules; `null` when none. */\n\tconst fieldRead = (type: ResolvedObjectType, name: string): string | null => {\n\t\tconst relation = type.relations.get(name);\n\t\tif (relation !== undefined) {\n\t\t\treturn relation.kind === 'fromField' ? relation.field : null;\n\t\t}\n\t\tfor (const rule of type.permissions.get(name) ?? []) {\n\t\t\tconst field =\n\t\t\t\trule.kind === 'name'\n\t\t\t\t\t? fieldRead(type, rule.name)\n\t\t\t\t\t: // An arrow reads its own relation on this object.\n\t\t\t\t\t\tfieldRead(type, rule.relation);\n\t\t\tif (field !== null) return field;\n\t\t}\n\t\treturn null;\n\t};\n\n\tfor (const type of types.values()) {\n\t\tfor (const [relation, def] of type.relations) {\n\t\t\tif (def.kind !== 'stored') continue;\n\t\t\tfor (const holder of def.holders) {\n\t\t\t\tif (holder.kind !== 'set') continue;\n\t\t\t\tconst target = types.get(holder.type);\n\t\t\t\tconst field =\n\t\t\t\t\ttarget === undefined ? null : fieldRead(target, holder.relation);\n\t\t\t\tif (field !== null) {\n\t\t\t\t\tthrow refuse(\n\t\t\t\t\t\t`types.${type.name}.related.${relation}: \"${holder.type}#${holder.relation}\" reads ${holder.type}.${field}, and a subject set reaches ${holder.type}s nobody passed to can() — store that relation instead of reading it`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tfor (const [permission, rules] of type.permissions) {\n\t\t\tfor (const rule of rules) {\n\t\t\t\tif (rule.kind !== 'arrow') continue;\n\t\t\t\tconst through = type.relations.get(rule.relation);\n\t\t\t\tconst targets =\n\t\t\t\t\tthrough?.kind === 'fromField'\n\t\t\t\t\t\t? [through.subject]\n\t\t\t\t\t\t: (through?.holders ?? []).map((holder) => holder.type);\n\t\t\t\tfor (const name of targets) {\n\t\t\t\t\tconst target = types.get(name);\n\t\t\t\t\tconst field =\n\t\t\t\t\t\ttarget === undefined ? null : fieldRead(target, rule.target);\n\t\t\t\t\tif (field !== null) {\n\t\t\t\t\t\tthrow refuse(\n\t\t\t\t\t\t\t`types.${type.name}.permits.${permission}: \"${rule.relation}->${rule.target}\" reaches ${name}.${rule.target}, which reads ${name}.${field}, and only the object passed to can() carries its data — store that relation instead of reading it`,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n",
6
6
  "/** Reading what a caller passed to `can()`, `list()`, `grant()` and `revoke()`. */\n\nimport { isStorable, UNSTORABLE } from '../stores/storable';\nimport { isSetOf, type Subject } from '../subjects/subject';\nimport { admits, type ResolvedModel, type ResolvedObjectType } from './resolve';\n\n/** What no part of an id may hold: the notation would read it two ways. */\nconst RESERVED = /[@#()]/;\n\nconst isRecord = (value: unknown): value is Record<string, unknown> =>\n\ttypeof value === 'object' && value !== null;\n\nexport function idOf(value: unknown, what: string, where: string): string {\n\tif (typeof value !== 'string' || value === '' || RESERVED.test(value)) {\n\t\tthrow new TypeError(\n\t\t\t`${where}: ${what} must be a non-empty string without @, # or parentheses`,\n\t\t);\n\t}\n\treturn value;\n}\n\nexport function typeOf(\n\tmodel: ResolvedModel,\n\tname: string,\n\twhere: string,\n): ResolvedObjectType {\n\tconst type = model.types.get(name);\n\tif (type === undefined) {\n\t\tthrow new TypeError(\n\t\t\t`${where}: \"${name}\" is not an object type of the model`,\n\t\t);\n\t}\n\treturn type;\n}\n\nexport function objectOf(\n\tmodel: ResolvedModel,\n\tvalue: unknown,\n\twhere: string,\n): {\n\treadonly type: string;\n\treadonly id: string;\n\treadonly data: Readonly<Record<string, unknown>>;\n} {\n\tif (!isRecord(value) || typeof value.type !== 'string') {\n\t\tthrow new TypeError(\n\t\t\t`${where}: the object must be { type, id, …its fields }`,\n\t\t);\n\t}\n\ttypeOf(model, value.type, where);\n\treturn {\n\t\ttype: value.type,\n\t\tid: idOf(value.id, 'the object id', where),\n\t\tdata: value,\n\t};\n}\n\n/**\n * The subject as the store compares it: `{ type, id }` for a user or an\n * object, and `{ type, id, relation }` for a subject set.\n *\n * Decided by the type, not the shape: a user's fields are flat on it, and one\n * named `relation` must not make a user read as a set. A value of a user type\n * is that user — unless `setOf()` made it, the one way to write a set on a user\n * type the model also declares as an object type. A value of an object type is\n * a set when `relation` is given.\n */\nexport function subjectOf(\n\tmodel: ResolvedModel,\n\tvalue: unknown,\n\twhere: string,\n): Subject {\n\tif (!isRecord(value) || typeof value.type !== 'string') {\n\t\tthrow new TypeError(\n\t\t\t`${where}: the subject must be a user, or { type, id }`,\n\t\t);\n\t}\n\tconst id = idOf(value.id, 'the subject id', where);\n\tconst isUserType = model.subjects.has(value.type);\n\tconst isSet = isSetOf(value);\n\tif (isUserType && !isSet) return { type: value.type, id };\n\tif (isUserType && isSet && !model.types.has(value.type)) {\n\t\tthrow new TypeError(\n\t\t\t`${where}: ${value.type} is a user type the model does not declare as an object type, so ${value.type}#${String(value.relation)} is no subject set`,\n\t\t);\n\t}\n\n\tconst type = typeOf(model, value.type, where);\n\tif (typeof value.relation !== 'string') return { type: type.name, id };\n\tif (!type.relations.has(value.relation)) {\n\t\tthrow new TypeError(\n\t\t\t`${where}: \"${value.relation}\" is not a relation of ${type.name}, so ${type.name}#${value.relation} is no subject set`,\n\t\t);\n\t}\n\treturn { type: type.name, id, relation: value.relation };\n}\n\n/** A tuple `grant` or `revoke` may write: a stored relation, and a holder it admits. */\nexport function tupleOf(\n\tmodel: ResolvedModel,\n\tobject: unknown,\n\trelation: string,\n\tsubject: unknown,\n\twhere: string,\n) {\n\tconst target = objectOf(model, object, where);\n\tconst type = typeOf(model, target.type, where);\n\tconst def = type.relations.get(relation);\n\tif (def === undefined) {\n\t\tthrow new TypeError(\n\t\t\t`${where}: \"${relation}\" is not a relation of ${type.name}`,\n\t\t);\n\t}\n\tif (def.kind === 'fromField') {\n\t\tthrow new TypeError(\n\t\t\t`${where}: ${type.name}.${relation} is read from ${def.field}; there is nothing to store — change the ${type.name} instead`,\n\t\t);\n\t}\n\n\tconst who = subjectOf(model, subject, where);\n\t// A tuple no store can keep is refused before one is asked: the same\n\t// answer on every adapter, not STORE_FAILED on PostgreSQL alone.\n\tfor (const [what, id] of [\n\t\t['the object id', target.id],\n\t\t['the subject id', who.id],\n\t] as const) {\n\t\tif (!isStorable(id)) throw new TypeError(`${where}: ${what} ${UNSTORABLE}`);\n\t}\n\tif (!admits(def.holders, who)) {\n\t\tthrow new TypeError(\n\t\t\t`${where}: ${type.name}.${relation} is not held by ${'relation' in who ? `${who.type}#${who.relation}` : who.type}`,\n\t\t);\n\t}\n\n\treturn {\n\t\tobject: { type: target.type, id: target.id },\n\t\trelation,\n\t\tsubject: who,\n\t};\n}\n",
7
7
  "/**\n * The permission model: which object types exist, which relations they hold,\n * and which permissions those relations grant — written in TypeScript, and\n * typed from itself.\n *\n * **ReBAC, embedded.** Zanzibar's data model — relations between objects and\n * subjects, permissions computed from them — without its infrastructure: the\n * database is the application's own, so reads follow writes and there is\n * nothing to cache or sequence. Two things go beyond Zanzibar's descendants:\n *\n * - **`fromField`**, a relation read from the object's own data — a record's\n * `doctorId` — rather than a tuple to keep in sync with it. Two sources of\n * truth for one fact is the first trap of a Zanzibar deployment;\n * - **`when`**, a condition written in TypeScript and typed: its `ctx` is what\n * `can()` then requires, and only for the permissions whose rules reach it.\n *\n * The model is a flat `const` literal, and everything the compiler can check\n * about it is checked here: a relation naming a subject type that does not\n * exist, a permission naming a relation that does not exist, an arrow to a\n * permission its target does not have. What only running it can check —\n * names, cycles — is refused by {@link defineModel} with a `TypeError`.\n */\n\nimport type { CursorPage } from '../pagination/cursor-page';\nimport type { NotASet, SetOf } from '../subjects/subject';\nimport { type ResolvedModel, resolveModel } from './resolve';\n\n// ─── The two building blocks ──────────────────────────────────────────────\n\n/**\n * The ids of the objects whose field names this subject id — what `list()`\n * needs to reverse a `fromField`: `(doctorId) => db.records.ids({ doctorId })`.\n * Unpaged; a failure throws, as a store's does.\n */\nexport type Lookup = (subjectId: string) => Promise<readonly string[]>;\n\n/**\n * A relation read from the object's own data: `fromField('doctorId', 'staff')`\n * holds for the subject of type `staff` whose id is `object.doctorId`.\n *\n * Nothing is stored. `can()` receives the object — the route has already\n * loaded it — and the compiler requires the field on it. `list()` cannot read\n * a field of objects it has not found yet, so it asks `lookup` instead; a\n * `list()` that would need one it was not given is a compile error.\n */\nexport interface FromField<\n\tField extends string = string,\n\tSubject extends string = string,\n> {\n\treadonly kind: 'fromField';\n\treadonly field: Field;\n\treadonly subject: Subject;\n\treadonly lookup?: Lookup;\n}\n\n/** A `fromField` `list()` can reverse. */\nexport interface ReversibleFromField<\n\tField extends string = string,\n\tSubject extends string = string,\n> extends FromField<Field, Subject> {\n\treadonly lookup: Lookup;\n}\n\nexport function fromField<\n\tconst Field extends string,\n\tconst Subject extends string,\n>(field: Field, subject: Subject): FromField<Field, Subject>;\nexport function fromField<\n\tconst Field extends string,\n\tconst Subject extends string,\n>(\n\tfield: Field,\n\tsubject: Subject,\n\toptions: { readonly lookup: Lookup },\n): ReversibleFromField<Field, Subject>;\nexport function fromField(\n\tfield: string,\n\tsubject: string,\n\toptions?: { readonly lookup: Lookup },\n): FromField {\n\treturn Object.freeze(\n\t\toptions === undefined\n\t\t\t? { kind: 'fromField' as const, field, subject }\n\t\t\t: { kind: 'fromField' as const, field, subject, lookup: options.lookup },\n\t);\n}\n\n/**\n * A rule that grants only when `test(ctx)` is true: `when('doctors', (ctx:\n * { onShift: boolean }) => ctx.onShift)`.\n *\n * `rule` is any rule of the same object type — a relation, a permission, an\n * arrow. The test is synchronous and pure: it decides on what the caller\n * passes, and reads nothing, so it can never fail the way a store can.\n */\nexport interface When<Rule extends string = string, Ctx = never> {\n\treadonly kind: 'when';\n\treadonly rule: Rule;\n\treadonly test: (ctx: Ctx) => boolean;\n}\n\nexport function when<const Rule extends string, Ctx>(\n\trule: Rule,\n\ttest: (ctx: Ctx) => boolean,\n): When<Rule, Ctx> {\n\treturn Object.freeze({ kind: 'when', rule, test });\n}\n\n// ─── The shape of a model ─────────────────────────────────────────────────\n\n/**\n * Who may hold a relation: subject types — `'staff'`, a user type, or `'team'`,\n * an object type — and subject sets, `'team#members'`: every member of a team.\n * Or a relation read from the object's data.\n */\nexport type RelationDef = readonly string[] | FromField;\n\n/**\n * One way to hold a permission: a relation or a permission of the same object\n * type (`'doctors'`, `'manage'`), an arrow to a permission of a related object\n * (`'teams->view'`: who can view the record's teams), or one of those under a\n * condition.\n */\nexport type RuleDef = string | When<string, never>;\n\nexport interface ObjectTypeDef {\n\treadonly related?: { readonly [name: string]: RelationDef };\n\t/** Each permission is the union of its rules. */\n\treadonly permits?: { readonly [name: string]: readonly RuleDef[] };\n}\n\nexport interface ModelConfig {\n\t/**\n\t * The user types that can be subjects — pass `auth.types` from `janus()`,\n\t * so a user type and a subject type are one name.\n\t */\n\treadonly subjects: readonly string[];\n\treadonly types: { readonly [name: string]: ObjectTypeDef };\n}\n\n// ─── Reading a model's types ──────────────────────────────────────────────\n\ntype TypesOf<C extends ModelConfig> = C['types'];\n\n/** The object types a model declares. */\nexport type ObjectTypeOf<C extends ModelConfig> = keyof TypesOf<C> & string;\n\n/** The user types a model accepts as subjects. */\nexport type UserTypeOf<C extends ModelConfig> = C['subjects'][number];\n\ntype RelationsOf<Ts, T> = T extends keyof Ts\n\t? Ts[T] extends { readonly related: infer R }\n\t\t? keyof R & string\n\t\t: never\n\t: never;\n\ntype PermissionsOf<Ts, T> = T extends keyof Ts\n\t? Ts[T] extends { readonly permits: infer P }\n\t\t? keyof P & string\n\t\t: never\n\t: never;\n\ntype NamesOf<Ts, T> = RelationsOf<Ts, T> | PermissionsOf<Ts, T>;\n\ntype RelationDefOf<Ts, T, R> = T extends keyof Ts\n\t? Ts[T] extends { readonly related: infer Rs }\n\t\t? R extends keyof Rs\n\t\t\t? Rs[R]\n\t\t\t: never\n\t\t: never\n\t: never;\n\n/** The relations of `T` that are stored as tuples: every one but its `fromField`s. */\ntype StoredRelationsOf<Ts, T> = {\n\t[R in RelationsOf<Ts, T>]: RelationDefOf<Ts, T, R> extends FromField\n\t\t? never\n\t\t: R;\n}[RelationsOf<Ts, T>];\n\n/**\n * `'team#members'` for every stored relation of every object type. Not a\n * `fromField`: a subject set reaches objects nobody passed to `can()`, so there\n * is no data to read the field from.\n */\ntype SubjectSetOf<Ts> = {\n\t[T in keyof Ts & string]: `${T}#${StoredRelationsOf<Ts, T>}`;\n}[keyof Ts & string];\n\ntype SubjectRefOf<S extends string, Ts> =\n\t| S\n\t| (keyof Ts & string)\n\t| SubjectSetOf<Ts>;\n\n/** The object types an arrow through `R` reaches: its direct subject types. */\ntype ArrowTargets<Ts, T, R> =\n\tRelationDefOf<Ts, T, R> extends FromField<string, infer Sub>\n\t\t? Sub\n\t\t: RelationDefOf<Ts, T, R> extends readonly (infer E)[]\n\t\t\t? [Extract<E, `${string}#${string}`>] extends [never]\n\t\t\t\t? E\n\t\t\t\t: never\n\t\t\t: never;\n\n/** The names every one of `Targets` declares. */\ntype CommonNames<Ts, Targets> =\n\tNamesOf<Ts, Targets> extends infer N\n\t\t? N extends string\n\t\t\t? [Targets] extends [TypesNaming<Ts, N>]\n\t\t\t\t? N\n\t\t\t\t: never\n\t\t\t: never\n\t\t: never;\n\ntype TypesNaming<Ts, N> = {\n\t[X in keyof Ts]: N extends NamesOf<Ts, X> ? X : never;\n}[keyof Ts];\n\n/** `'teams->view'`, for each relation whose targets are all object types. */\ntype ArrowsOf<Ts, T> = {\n\t[R in RelationsOf<Ts, T>]: [ArrowTargets<Ts, T, R>] extends [never]\n\t\t? never\n\t\t: [ArrowTargets<Ts, T, R>] extends [keyof Ts]\n\t\t\t? `${R}->${CommonNames<Ts, ArrowTargets<Ts, T, R>>}`\n\t\t\t: never;\n}[RelationsOf<Ts, T>];\n\n/** Every string a rule of `T` may be. */\ntype RuleRefOf<Ts, T> = NamesOf<Ts, T> | ArrowsOf<Ts, T>;\n\n/** What `can()` accepts for an object type: its relations and its permissions. */\nexport type CheckableOf<\n\tC extends ModelConfig,\n\tT extends ObjectTypeOf<C>,\n> = NamesOf<TypesOf<C>, T>;\n\n/** The fields an object of type `T` must carry: those its `fromField`s read. */\nexport type FieldsOf<C extends ModelConfig, T extends ObjectTypeOf<C>> = {\n\t[R in RelationsOf<TypesOf<C>, T>]: RelationDefOf<\n\t\tTypesOf<C>,\n\t\tT,\n\t\tR\n\t> extends FromField<infer F, string>\n\t\t? F\n\t\t: never;\n}[RelationsOf<TypesOf<C>, T>];\n\n/**\n * An object, as `can()` takes it: its type and id, and **every field a\n * `fromField` of its type reads** — required, so an object passed without\n * them is a compile error rather than a silent denial. `null` is a field\n * holding nobody.\n */\nexport type ObjectRef<C extends ModelConfig, T extends ObjectTypeOf<C>> = {\n\treadonly type: T;\n\treadonly id: string;\n} & { readonly [F in FieldsOf<C, T>]: string | null };\n\n/**\n * A subject: a user from `janus()` as it is, an object, or a subject set —\n * one `setOf()` made on an object type and one of its relations. A set on a\n * user type the model does not also declare under `types` has no relation to\n * name, and is refused here as at run time.\n */\nexport type SubjectRef<C extends ModelConfig> =\n\t| ({\n\t\t\treadonly type: UserTypeOf<C> | ObjectTypeOf<C>;\n\t\t\treadonly id: string;\n\t } & NotASet)\n\t| {\n\t\t\t[T in ObjectTypeOf<C>]: SetOf<T, RelationsOf<TypesOf<C>, T> & string>;\n\t }[ObjectTypeOf<C>];\n\n// ─── The context a check requires ─────────────────────────────────────────\n\ntype UnionToIntersection<U> = (\n\tU extends unknown\n\t\t? (union: U) => void\n\t\t: never\n) extends (intersection: infer I) => void\n\t? I\n\t: never;\n\ntype CtxOfRule<E> = E extends When<string, infer X> ? X : never;\n\ntype NameOfRule<E> = E extends string\n\t? E\n\t: E extends When<infer R, never>\n\t\t? R\n\t\t: never;\n\ntype CtxOfName<Ts, T, N, Seen> = N extends `${infer R}->${infer P}`\n\t? CtxOfPermission<Ts, ArrowTargets<Ts, T, R>, P, Seen>\n\t: CtxOfPermission<Ts, T, N, Seen>;\n\n/**\n * The union of the `ctx` types a permission's rules reach — through its own\n * rules, the permissions they name, and arrows into other types. `Seen` stops\n * the walk on a cycle.\n */\ntype CtxOfPermission<Ts, T, P, Seen> = T extends keyof Ts & string\n\t? P extends string\n\t\t? `${T}.${P}` extends Seen\n\t\t\t? never\n\t\t\t: Ts[T] extends { readonly permits: infer Ps }\n\t\t\t\t? P extends keyof Ps\n\t\t\t\t\t? Ps[P] extends readonly (infer E)[]\n\t\t\t\t\t\t? CtxOfRule<E> | CtxOfName<Ts, T, NameOfRule<E>, Seen | `${T}.${P}`>\n\t\t\t\t\t\t: never\n\t\t\t\t\t: never\n\t\t\t\t: never\n\t\t: never\n\t: never;\n\n/**\n * What `can(…, permission, object)` requires as `ctx`: every condition its\n * rules can reach, intersected. `never` when none — and then `can()` takes no\n * `ctx` at all.\n */\nexport type CtxOf<\n\tC extends ModelConfig,\n\tT extends ObjectTypeOf<C>,\n\tP extends string,\n> = [CtxOfPermission<TypesOf<C>, T, P, never>] extends [never]\n\t? never\n\t: UnionToIntersection<CtxOfPermission<TypesOf<C>, T, P, never>>;\n\n/**\n * The options of a check: `ctx` required exactly when a condition is\n * reachable.\n *\n * Loose when `T` or `P` is its whole constraint — what the compiler falls back\n * to when the argument was wrong. Requiring `ctx` there would report a missing\n * argument instead of the wrong type or permission that caused it; the\n * refusal on that argument is the one worth reading. A `when` reached with no\n * `ctx` still throws at run time.\n */\nexport type CheckArgs<\n\tC extends ModelConfig,\n\tT extends ObjectTypeOf<C>,\n\tP extends string,\n> = [ObjectTypeOf<C>] extends [T]\n\t? [ObjectTypeOf<C>] extends [never]\n\t\t? [options?: { readonly ctx?: unknown }]\n\t\t: IsSingle<ObjectTypeOf<C>> extends true\n\t\t\t? // One object type: `T` is its constraint and right; `P` may not be.\n\t\t\t\tPermissionArgs<C, T, P>\n\t\t\t: [options?: { readonly ctx?: unknown }]\n\t: PermissionArgs<C, T, P>;\n\n/** `CheckArgs` once `T` is known right: loose when `P` is its whole constraint. */\ntype PermissionArgs<\n\tC extends ModelConfig,\n\tT extends ObjectTypeOf<C>,\n\tP extends string,\n> = [CheckableOf<C, T>] extends [P]\n\t? IsSingle<CheckableOf<C, T>> extends true\n\t\t? Strict<C, T, P>\n\t\t: [options?: { readonly ctx?: unknown }]\n\t: Strict<C, T, P>;\n\ntype Strict<\n\tC extends ModelConfig,\n\tT extends ObjectTypeOf<C>,\n\tP extends string,\n> = [CtxOf<C, T, P>] extends [never]\n\t? [options?: { readonly ctx?: never }]\n\t: [options: { readonly ctx: CtxOf<C, T, P> }];\n\n/** Whether `U` is one type rather than a union of several. */\ntype IsSingle<U> = [U] extends [UnionToIntersection<U>] ? true : false;\n\n/**\n * The signature of `can()`, typed from the model: the permission must be one\n * the object's type declares, the object must carry every field its\n * `fromField`s read, and `ctx` is required exactly when a condition is\n * reachable. `null` is anonymous, and answers `false`.\n */\nexport type Can<C extends ModelConfig> = <\n\tT extends ObjectTypeOf<C>,\n\tP extends CheckableOf<C, T>,\n>(\n\tsubject: SubjectRef<C> | null,\n\tpermission: P,\n\tobject: ObjectRef<C, T>,\n\t...options: CheckArgs<C, T, P>\n) => Promise<boolean>;\n\n// ─── What list() can reverse ──────────────────────────────────────────────\n\n/** `'record.doctor'` when relation `R` of `T` is a `fromField` with no `lookup`. */\ntype GapOfRelation<Ts, T, R> =\n\tRelationDefOf<Ts, T, R> extends { readonly lookup: Lookup }\n\t\t? never\n\t\t: RelationDefOf<Ts, T, R> extends FromField\n\t\t\t? `${T & string}.${R & string}`\n\t\t\t: never;\n\ntype GapOfName<Ts, T, N, Seen> = N extends `${infer R}->${infer P}`\n\t?\n\t\t\t| GapOfRelation<Ts, T, R>\n\t\t\t| GapOfPermission<Ts, ArrowTargets<Ts, T, R>, P, Seen>\n\t: GapOfPermission<Ts, T, N, Seen>;\n\n/**\n * The `fromField`s without a `lookup` that `list(…, P, T)` would have to\n * reverse — through `P`'s rules, the names they reach, and arrows. A subject\n * set never reaches one: `defineModel` refuses that.\n */\ntype GapOfPermission<Ts, T, P, Seen> = T extends keyof Ts & string\n\t? P extends string\n\t\t? `${T}.${P}` extends Seen\n\t\t\t? never\n\t\t\t: P extends RelationsOf<Ts, T>\n\t\t\t\t? GapOfRelation<Ts, T, P>\n\t\t\t\t: Ts[T] extends { readonly permits: infer Ps }\n\t\t\t\t\t? P extends keyof Ps\n\t\t\t\t\t\t? Ps[P] extends readonly (infer E)[]\n\t\t\t\t\t\t\t? GapOfName<Ts, T, NameOfRule<E>, Seen | `${T}.${P}`>\n\t\t\t\t\t\t\t: never\n\t\t\t\t\t\t: never\n\t\t\t\t\t: never\n\t\t: never\n\t: never;\n\n/** Every `fromField` without a `lookup` that `list(…, P, T)` would reach; `never` when none. */\nexport type LookupGap<\n\tC extends ModelConfig,\n\tT extends ObjectTypeOf<C>,\n\tP extends string,\n> = GapOfPermission<TypesOf<C>, T, P, never>;\n\n/**\n * What a permission must also be for `list()`: reversible. Checked name by\n * name, so that while `P` is still every name of `T` — an editor asking what\n * to complete — the names `list()` can answer survive the intersection, and\n * only those.\n */\ntype ListCheck<\n\tC extends ModelConfig,\n\tT extends ObjectTypeOf<C>,\n\tP extends string,\n> = P extends string\n\t? [LookupGap<C, T, P>] extends [never]\n\t\t? P\n\t\t: Refusal<\n\t\t\t\t`list cannot reverse ${LookupGap<C, T, P>}: give that fromField a lookup`,\n\t\t\t\tnever\n\t\t\t>\n\t: never;\n\n/** Where a page of `list()` starts, and how much it holds. */\nexport interface ListPage {\n\t/** The `nextCursor` of the previous page; absent or `null` for the first. */\n\treadonly after?: string | null;\n\t/** Between 1 and 100; 20 when absent. */\n\treadonly limit?: number;\n}\n\n/** `CheckArgs`, with a page. */\ntype ListArgs<\n\tC extends ModelConfig,\n\tT extends ObjectTypeOf<C>,\n\tP extends string,\n> =\n\tCheckArgs<C, T, P> extends [infer O]\n\t\t? [options: O & ListPage]\n\t\t: CheckArgs<C, T, P> extends [options?: infer O]\n\t\t\t? [options?: O & ListPage]\n\t\t\t: never;\n\n/**\n * The signature of `list()`: the ids of the objects of `type` on which\n * `subject` holds `permission`, in ascending order, by pages. Typed like\n * `can()`, and refuses a permission that reaches a `fromField` with no\n * `lookup`: nothing could find the objects whose field names the subject.\n */\nexport type List<C extends ModelConfig> = <\n\tT extends ObjectTypeOf<C>,\n\tP extends CheckableOf<C, T>,\n>(\n\tsubject: SubjectRef<C> | null,\n\tpermission: P & ListCheck<C, T, P>,\n\ttype: T,\n\t...options: ListArgs<C, T, P>\n) => Promise<CursorPage<string>>;\n\n/** The relations of an object type that `grant` can write: not its `fromField`s. */\nexport type GrantableOf<\n\tC extends ModelConfig,\n\tT extends ObjectTypeOf<C>,\n> = StoredRelationsOf<TypesOf<C>, T>;\n\n/**\n * Who may be granted relation `R` on an object of type `T`: an entity of each\n * subject type it names, and a subject set for each set it names — made by\n * `setOf()` when the set is on a user type, since a user passed as it is stays\n * that user.\n */\nexport type HolderOf<C extends ModelConfig, T extends ObjectTypeOf<C>, R> =\n\tRelationDefOf<TypesOf<C>, T, R> extends readonly (infer E)[]\n\t\t? E extends `${infer SetType}#${infer SetRelation}`\n\t\t\t? SetType extends UserTypeOf<C>\n\t\t\t\t? SetOf<SetType, SetRelation>\n\t\t\t\t: {\n\t\t\t\t\t\treadonly type: SetType;\n\t\t\t\t\t\treadonly id: string;\n\t\t\t\t\t\treadonly relation: SetRelation;\n\t\t\t\t\t}\n\t\t\t: { readonly type: E; readonly id: string } & NotASet\n\t\t: never;\n\n/** Writes one tuple, or removes it: typed like `can()`. */\nexport type Grant<C extends ModelConfig> = <\n\tT extends ObjectTypeOf<C>,\n\tR extends GrantableOf<C, T>,\n>(\n\tobject: { readonly type: T; readonly id: string },\n\trelation: R,\n\tsubject: HolderOf<C, T, R>,\n) => Promise<void>;\n\n/** What `permissions()` answers. */\nexport interface Permissions<C extends ModelConfig> {\n\treadonly model: PermissionModel<C>;\n\t/**\n\t * Whether `subject` holds `permission` on `object`: `true` or `false`, and\n\t * **a failure throws** — a store that cannot answer is `STORE_FAILED`, never\n\t * a denial. `null` is anonymous, and `false` before any store call.\n\t */\n\treadonly can: Can<C>;\n\t/**\n\t * The ids of the objects of `type` on which `subject` holds `permission`,\n\t * ascending, by pages — what `can()` answers `true` for, found without\n\t * naming them. `null` is anonymous, and an empty page before any store call.\n\t * A failure throws, as for `can()`.\n\t */\n\treadonly list: List<C>;\n\t/** Stores that `subject` holds `relation` on `object`. Idempotent. */\n\treadonly grant: Grant<C>;\n\t/** Removes it. Idempotent: revoking what is not held is not an error. */\n\treadonly revoke: Grant<C>;\n}\n\n/** The configuration a model was defined from. */\nexport type ConfigOf<M> = M extends PermissionModel<infer C> ? C : never;\n\n// ─── The checks, as types ─────────────────────────────────────────────────\n\ntype Refusal<Text extends string, Expected> = {\n\treadonly [K in Text]: Expected;\n};\n\n/**\n * The same names, spelled out: a union the compiler prints as its members —\n * `\"patient\" | \"staff\" | \"team#members\"` — rather than as the alias that\n * computed it, so an error lists what the name could have been.\n */\ntype Spelled<U> = [U] extends [infer V extends string]\n\t? { [K in V]: K }[V]\n\t: never;\n\n/**\n * What `defineModel` offers and accepts for each object type, given the\n * subject types `S` and every object type `Ts`: the constraint of its `types`.\n *\n * **A constraint, so that an editor completes it.** The names a relation, a\n * rule, a `fromField` or a `when` may take are unions of literals here, and an\n * editor reads a type parameter's constraint to offer them — `'patient'`,\n * `'team#members'`, `'teams->view'`. A check intersected into the parameter\n * instead (`C & Checked<C>`) refuses the same mistakes, but meets the literal\n * being typed and completes nothing: measured with the language service.\n *\n * A permission's own name is not among its rules: `view: ['view']` adds\n * nothing and is a loop no relation ends, so it is neither offered nor\n * accepted. A loop through another permission is `defineModel`'s to refuse.\n *\n * A wrong name is unassignable **on that name** — on the whole `fromField(…)`\n * or `when(…)` call for those two — and the error lists the ones it could\n * have been, with \"Did you mean\" when one is close.\n */\nexport type ModelTypesOf<S extends string, Ts> = {\n\treadonly [T in keyof Ts]: {\n\t\treadonly related?: {\n\t\t\treadonly [name: string]:\n\t\t\t\t| readonly Spelled<SubjectRefOf<S, Ts>>[]\n\t\t\t\t| FromField<string, Spelled<S | (keyof Ts & string)>>;\n\t\t};\n\t\treadonly permits?: {\n\t\t\treadonly [P in PermissionsOf<Ts, T>]: P extends RelationsOf<Ts, T>\n\t\t\t\t? Refusal<\n\t\t\t\t\t\t`\"${P}\" names a relation and a permission of ${T & string}; rename one`,\n\t\t\t\t\t\tnever\n\t\t\t\t\t>\n\t\t\t\t: readonly (\n\t\t\t\t\t\t| Spelled<Exclude<RuleRefOf<Ts, T>, P>>\n\t\t\t\t\t\t| When<Spelled<Exclude<RuleRefOf<Ts, T>, P>>, never>\n\t\t\t\t\t)[];\n\t\t};\n\t} & {\n\t\t// `permission:` beside `relations` would be dropped by the constraint\n\t\t// above and refused only when defineModel runs.\n\t\treadonly [K in Exclude<keyof Ts[T], 'related' | 'permits'>]: Refusal<\n\t\t\tK extends 'relations'\n\t\t\t\t? `${T & string}.relations is now related: rename the key`\n\t\t\t\t: K extends 'permissions'\n\t\t\t\t\t? `${T & string}.permissions is now permits: rename the key`\n\t\t\t\t\t: `${T & string}.${K & string} is not a key of an object type: related or permits`,\n\t\t\tnever\n\t\t>;\n\t};\n};\n\n// ─── Defining one ─────────────────────────────────────────────────────────\n\n/** A model, checked and resolved. What `permissions()` will take. */\nexport interface PermissionModel<C extends ModelConfig = ModelConfig> {\n\t/** The user types it accepts as subjects. */\n\treadonly subjects: readonly UserTypeOf<C>[];\n\t/** The object types it declares. */\n\treadonly types: readonly ObjectTypeOf<C>[];\n\t/** The definition, as written — the very object passed to defineModel. */\n\treadonly definition: C;\n}\n\n// Keyed by the frozen model itself: nothing outside this module can reach it.\nconst RESOLVED = new WeakMap<object, ResolvedModel>();\n\n/**\n * Checks a model and resolves it. Connects to nothing.\n *\n * ```ts\n * export const model = defineModel({\n * subjects: auth.types,\n * types: {\n * team: {\n * related: { members: ['staff', 'team#members'], leads: ['staff'] },\n * permits: { manage: ['leads'], view: ['members', 'manage'] },\n * },\n * record: {\n * related: {\n * doctors: fromField('doctorId', 'staff'),\n * teams: ['team'],\n * },\n * permits: {\n * view: ['doctors', 'teams->view'],\n * edit: [when('doctors', (ctx: { onShift: boolean }) => ctx.onShift)],\n * },\n * },\n * },\n * });\n * ```\n *\n * Refuses with a `TypeError` what only running it can see: a name that is not\n * camelCase, a permission that reaches itself without crossing a relation —\n * which no data could ever end. A user type may also be an object type: its\n * users are then objects too, and a set on it is written with `setOf()`.\n */\nexport function defineModel<\n\tconst Subjects extends readonly string[],\n\tconst Ts extends ModelConfig['types'] & ModelTypesOf<Subjects[number], Ts>,\n>(config: {\n\treadonly subjects: Subjects;\n\treadonly types: Ts;\n}): PermissionModel<{ readonly subjects: Subjects; readonly types: Ts }>;\nexport function defineModel<const C extends ModelConfig>(\n\tconfig: C,\n): PermissionModel<C> {\n\tconst resolved = resolveModel(config, 'defineModel');\n\tconst model: PermissionModel<C> = Object.freeze({\n\t\tsubjects: [...resolved.subjects] as UserTypeOf<C>[],\n\t\ttypes: [...resolved.types.keys()] as ObjectTypeOf<C>[],\n\t\tdefinition: config,\n\t});\n\tRESOLVED.set(model, resolved);\n\treturn model;\n}\n\n/** The resolved form of a model this module defined. Internal. */\nexport function resolvedOf(model: object): ResolvedModel {\n\tconst resolved = RESOLVED.get(model);\n\tif (resolved === undefined) {\n\t\tthrow new TypeError(\n\t\t\t'permissions: this model was not made by defineModel() — pass what defineModel() answered',\n\t\t);\n\t}\n\treturn resolved;\n}\n",
8
- "import { PermissionDepthError } from '../errors/janus-error';\nimport type { CursorPage } from '../pagination/cursor-page';\nimport { MAX_PAGE_SIZE } from '../pagination/cursor-page';\nimport { isStorable } from '../stores/storable';\nimport type { Subject } from '../subjects/subject';\nimport type { RelationStore } from './port/types';\nimport {\n\tadmits,\n\ttype ResolvedModel,\n\ttype ResolvedObjectType,\n\ttype ResolvedRule,\n} from './resolve';\n\n/**\n * One `list()`: the objects a subject holds a name on, found backwards —\n * from the subject to the tuples naming it, through the sets and arrows the\n * model declares, to the objects.\n *\n * **A least fixpoint.** `objects(type, name)` is a union of what its rules\n * reach, and a rule can reach its own name again — a folder viewable through\n * its parent, a team member through a team. Such a name, met again on the\n * current path, answers what the previous round found; rounds repeat until\n * none adds an id. That is exactly the set of objects with a derivation that\n * does not loop — what `can()`'s cut finds, one object at a time. A round\n * that met no loop is final.\n *\n * **Depth.** Each round past the first follows the loops one relation\n * further; more than `maxDepth` rounds is `PERMISSION_DEPTH`, as crossing more\n * than `maxDepth` relations is for `can()`.\n *\n * **Cost.** Every page of `findObjects` for every id each step reaches, every\n * round. Linear in what the subject can reach — fine for the objects of one\n * user, not for a subject set holding most of the database.\n */\nexport class Reverse {\n\tprivate previous = new Map<string, ReadonlySet<string>>();\n\tprivate current = new Map<string, ReadonlySet<string>>();\n\tprivate readonly path = new Set<string>();\n\tprivate looped = false;\n\n\tconstructor(\n\t\tprivate readonly model: ResolvedModel,\n\t\tprivate readonly store: RelationStore,\n\t\tprivate readonly maxDepth: number,\n\t\tprivate readonly ctx: unknown,\n\t\tprivate readonly subject: Subject,\n\t\tprivate readonly question: string,\n\t) {}\n\n\tasync objects(type: string, name: string): Promise<ReadonlySet<string>> {\n\t\tfor (let round = 0; round <= this.maxDepth; round += 1) {\n\t\t\tthis.current = new Map();\n\t\t\tthis.looped = false;\n\t\t\tconst found = await this.reach(type, name);\n\t\t\tif (!this.looped || this.same()) return found;\n\t\t\tthis.previous = this.current;\n\t\t}\n\t\tthrow new PermissionDepthError(\n\t\t\t`list: listing ${this.question} crossed more than ${this.maxDepth} relations without an answer`,\n\t\t\t{ permission: this.question, maxDepth: this.maxDepth },\n\t\t);\n\t}\n\n\t/** Whether this round found what the previous one did: nothing more to find. */\n\tprivate same(): boolean {\n\t\tfor (const [key, ids] of this.current) {\n\t\t\tif ((this.previous.get(key)?.size ?? 0) !== ids.size) return false;\n\t\t}\n\t\treturn true;\n\t}\n\n\t/** The ids of the objects of `typeName` on which the subject holds `name`. */\n\tprivate async reach(\n\t\ttypeName: string,\n\t\tname: string,\n\t): Promise<ReadonlySet<string>> {\n\t\tconst key = `${typeName}#${name}`;\n\t\tconst done = this.current.get(key);\n\t\tif (done !== undefined) return done;\n\t\tif (this.path.has(key)) {\n\t\t\tthis.looped = true;\n\t\t\treturn this.previous.get(key) ?? new Set();\n\t\t}\n\n\t\tconst type = this.model.types.get(typeName);\n\t\tif (type === undefined) return new Set();\n\n\t\tthis.path.add(key);\n\t\ttry {\n\t\t\tconst found = type.permissions.has(name)\n\t\t\t\t? await this.permission(type, name)\n\t\t\t\t: await this.relation(type, name);\n\t\t\tthis.current.set(key, found);\n\t\t\treturn found;\n\t\t} finally {\n\t\t\tthis.path.delete(key);\n\t\t}\n\t}\n\n\tprivate async relation(\n\t\ttype: ResolvedObjectType,\n\t\tname: string,\n\t): Promise<Set<string>> {\n\t\tconst relation = type.relations.get(name);\n\t\tif (relation === undefined) return new Set();\n\n\t\tif (relation.kind === 'fromField') {\n\t\t\tconst subject = this.subject;\n\t\t\treturn 'relation' in subject || subject.type !== relation.subject\n\t\t\t\t? new Set()\n\t\t\t\t: new Set(await this.lookup(type, name, subject.id));\n\t\t}\n\n\t\t// A direct tuple counts only when the model admits the subject here.\n\t\tconst found = new Set(\n\t\t\tadmits(relation.holders, this.subject)\n\t\t\t\t? await this.holding(type.name, name, this.subject)\n\t\t\t\t: [],\n\t\t);\n\t\tfor (const holder of relation.holders) {\n\t\t\tif (holder.kind !== 'set') continue;\n\t\t\tfor (const id of await this.reach(holder.type, holder.relation)) {\n\t\t\t\tconst set = { type: holder.type, id, relation: holder.relation };\n\t\t\t\tfor (const object of await this.holding(type.name, name, set)) {\n\t\t\t\t\tfound.add(object);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn found;\n\t}\n\n\tprivate async permission(\n\t\ttype: ResolvedObjectType,\n\t\tname: string,\n\t): Promise<Set<string>> {\n\t\tconst found = new Set<string>();\n\t\tfor (const rule of type.permissions.get(name) ?? []) {\n\t\t\tif (rule.test !== undefined && !this.passes(rule, type, name)) continue;\n\n\t\t\tif (rule.kind === 'name') {\n\t\t\t\tfor (const id of await this.reach(type.name, rule.name)) found.add(id);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tfor (const id of await this.arrow(type, rule.relation, rule.target)) {\n\t\t\t\tfound.add(id);\n\t\t\t}\n\t\t}\n\t\treturn found;\n\t}\n\n\t/** The objects of `type` whose `relation` reaches an object on which the subject holds `target`. */\n\tprivate async arrow(\n\t\ttype: ResolvedObjectType,\n\t\trelation: string,\n\t\ttarget: string,\n\t): Promise<Set<string>> {\n\t\tconst through = type.relations.get(relation);\n\t\tconst found = new Set<string>();\n\t\tif (through === undefined) return found;\n\n\t\tif (through.kind === 'fromField') {\n\t\t\tfor (const id of await this.reach(through.subject, target)) {\n\t\t\t\tfor (const object of await this.lookup(type, relation, id)) {\n\t\t\t\t\tfound.add(object);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn found;\n\t\t}\n\t\tfor (const holder of through.holders) {\n\t\t\t// An arrow follows entities of an object type — a user type too, when\n\t\t\t// the model also declares it under types.\n\t\t\tif (holder.kind !== 'type' || !this.model.types.has(holder.type)) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tfor (const id of await this.reach(holder.type, target)) {\n\t\t\t\tconst entity = { type: holder.type, id };\n\t\t\t\tfor (const object of await this.holding(type.name, relation, entity)) {\n\t\t\t\t\tfound.add(object);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn found;\n\t}\n\n\t/** Every id of every page of `findObjects`. */\n\tprivate async holding(\n\t\ttype: string,\n\t\trelation: string,\n\t\tsubject: Subject,\n\t): Promise<string[]> {\n\t\tconst ids: string[] = [];\n\t\tlet after: string | null = null;\n\t\tdo {\n\t\t\tconst page: CursorPage<string> = await this.store.findObjects({\n\t\t\t\ttype,\n\t\t\t\trelation,\n\t\t\t\tsubject,\n\t\t\t\tafter,\n\t\t\t\tlimit: MAX_PAGE_SIZE,\n\t\t\t});\n\t\t\tids.push(...page.items);\n\t\t\tafter = page.nextCursor;\n\t\t} while (after !== null);\n\t\treturn ids;\n\t}\n\n\t/** The objects whose field names `id`, from the `fromField`'s lookup. */\n\tprivate async lookup(\n\t\ttype: ResolvedObjectType,\n\t\trelation: string,\n\t\tid: string,\n\t): Promise<readonly string[]> {\n\t\tconst def = type.relations.get(relation);\n\t\tif (def?.kind !== 'fromField' || def.lookup === undefined) {\n\t\t\tthrow new TypeError(\n\t\t\t\t`list: ${type.name}.${relation} is read from a field, and has no lookup to find the ${type.name}s naming ${id} — fromField('${def?.kind === 'fromField' ? def.field : relation}', '${def?.kind === 'fromField' ? def.subject : ''}', { lookup })`,\n\t\t\t);\n\t\t}\n\t\tconst ids = await def.lookup(id);\n\t\tif (!Array.isArray(ids) || ids.some((each) => typeof each !== 'string')) {\n\t\t\tthrow new TypeError(\n\t\t\t\t`list: the lookup of ${type.name}.${relation} must answer an array of ids`,\n\t\t\t);\n\t\t}\n\t\t// An id no store can keep is held by nobody, as can() answers it.\n\t\treturn ids.filter(isStorable);\n\t}\n\n\t/** The condition, run on the caller's `ctx`, as for `can()`. */\n\tprivate passes(\n\t\trule: ResolvedRule,\n\t\ttype: ResolvedObjectType,\n\t\tname: string,\n\t): boolean {\n\t\tif (this.ctx === undefined) {\n\t\t\tthrow new TypeError(\n\t\t\t\t`list: ${type.name}.${name} reaches a condition, and no ctx was passed — pass { ctx }`,\n\t\t\t);\n\t\t}\n\t\treturn (rule.test as (ctx: unknown) => boolean)(this.ctx) === true;\n\t}\n}\n",
8
+ "import { PermissionDepthError } from '../errors/janus-error';\nimport type { CursorPage } from '../pagination/cursor-page';\nimport { MAX_PAGE_SIZE } from '../pagination/cursor-page';\nimport { isStorable } from '../stores/storable';\nimport type { Subject } from '../subjects/subject';\nimport type { RelationStore } from './port/types';\nimport {\n\tadmits,\n\ttype ResolvedModel,\n\ttype ResolvedObjectType,\n\ttype ResolvedRule,\n} from './resolve';\n\n/**\n * One `list()`: the objects a subject holds a name on, found backwards —\n * from the subject to the tuples naming it, through the sets and arrows the\n * model declares, to the objects.\n *\n * **A least fixpoint.** `objects(type, name)` is a union of what its rules\n * reach, and a rule can reach its own name again — a folder viewable through\n * its parent, a team member through a team. Such a name, met again on the\n * current path, answers what the previous round found; rounds repeat until\n * none adds an id. That is exactly the set of objects with a derivation that\n * does not loop — what `can()`'s cut finds, one object at a time. A round\n * that met no loop is final.\n *\n * **Depth.** Each round past the first follows the loops one relation\n * further; more than `maxDepth` rounds is `PERMISSION_DEPTH`, as crossing more\n * than `maxDepth` relations is for `can()`.\n *\n * **Cost.** Every page of `findObjects` for every id each step reaches, every\n * round. Linear in what the subject can reach — fine for the objects of one\n * user, not for a subject set holding most of the database.\n */\nexport class Reverse {\n\tprivate previous = new Map<string, ReadonlySet<string>>();\n\tprivate current = new Map<string, ReadonlySet<string>>();\n\tprivate readonly path = new Set<string>();\n\tprivate looped = false;\n\n\tconstructor(\n\t\tprivate readonly model: ResolvedModel,\n\t\tprivate readonly store: RelationStore,\n\t\tprivate readonly maxDepth: number,\n\t\tprivate readonly ctx: unknown,\n\t\tprivate readonly subject: Subject,\n\t\tprivate readonly question: string,\n\t) {}\n\n\tasync objects(type: string, name: string): Promise<ReadonlySet<string>> {\n\t\tfor (let round = 0; round <= this.maxDepth; round += 1) {\n\t\t\tthis.current = new Map();\n\t\t\tthis.looped = false;\n\t\t\tconst found = await this.reach(type, name);\n\t\t\tif (!this.looped || this.same()) return found;\n\t\t\tthis.previous = this.current;\n\t\t}\n\t\tthrow new PermissionDepthError(\n\t\t\t`list: listing ${this.question} crossed more than ${this.maxDepth} relations without an answer`,\n\t\t\t{ permission: this.question, maxDepth: this.maxDepth },\n\t\t);\n\t}\n\n\t/** Whether this round found what the previous one did: nothing more to find. */\n\tprivate same(): boolean {\n\t\tfor (const [key, ids] of this.current) {\n\t\t\tif ((this.previous.get(key)?.size ?? 0) !== ids.size) return false;\n\t\t}\n\t\treturn true;\n\t}\n\n\t/** The ids of the objects of `typeName` on which the subject holds `name`. */\n\tprivate async reach(\n\t\ttypeName: string,\n\t\tname: string,\n\t): Promise<ReadonlySet<string>> {\n\t\tconst key = `${typeName}#${name}`;\n\t\tconst done = this.current.get(key);\n\t\tif (done !== undefined) return done;\n\t\tif (this.path.has(key)) {\n\t\t\tthis.looped = true;\n\t\t\treturn this.previous.get(key) ?? new Set();\n\t\t}\n\n\t\tconst type = this.model.types.get(typeName);\n\t\tif (type === undefined) return new Set();\n\n\t\tthis.path.add(key);\n\t\ttry {\n\t\t\tconst found = type.permissions.has(name)\n\t\t\t\t? await this.permission(type, name)\n\t\t\t\t: await this.relation(type, name);\n\t\t\tthis.current.set(key, found);\n\t\t\treturn found;\n\t\t} finally {\n\t\t\tthis.path.delete(key);\n\t\t}\n\t}\n\n\tprivate async relation(\n\t\ttype: ResolvedObjectType,\n\t\tname: string,\n\t): Promise<Set<string>> {\n\t\tconst relation = type.relations.get(name);\n\t\tif (relation === undefined) return new Set();\n\n\t\tif (relation.kind === 'fromField') {\n\t\t\tconst subject = this.subject;\n\t\t\treturn 'relation' in subject || subject.type !== relation.subject\n\t\t\t\t? new Set()\n\t\t\t\t: new Set(await this.lookup(type, name, subject.id));\n\t\t}\n\n\t\t// A direct tuple counts only when the model admits the subject here.\n\t\tconst found = new Set(\n\t\t\tadmits(relation.holders, this.subject)\n\t\t\t\t? await this.holding(type.name, name, this.subject)\n\t\t\t\t: [],\n\t\t);\n\t\tfor (const holder of relation.holders) {\n\t\t\tif (holder.kind !== 'set') continue;\n\t\t\tfor (const id of await this.reach(holder.type, holder.relation)) {\n\t\t\t\tconst set = { type: holder.type, id, relation: holder.relation };\n\t\t\t\tfor (const object of await this.holding(type.name, name, set)) {\n\t\t\t\t\tfound.add(object);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn found;\n\t}\n\n\tprivate async permission(\n\t\ttype: ResolvedObjectType,\n\t\tname: string,\n\t): Promise<Set<string>> {\n\t\tconst found = new Set<string>();\n\t\tfor (const rule of type.permissions.get(name) ?? []) {\n\t\t\tif (rule.test !== undefined && !this.passes(rule, type, name)) continue;\n\n\t\t\tif (rule.kind === 'name') {\n\t\t\t\tfor (const id of await this.reach(type.name, rule.name)) found.add(id);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tfor (const id of await this.arrow(type, rule.relation, rule.target)) {\n\t\t\t\tfound.add(id);\n\t\t\t}\n\t\t}\n\t\treturn found;\n\t}\n\n\t/** The objects of `type` whose `relation` reaches an object on which the subject holds `target`. */\n\tprivate async arrow(\n\t\ttype: ResolvedObjectType,\n\t\trelation: string,\n\t\ttarget: string,\n\t): Promise<Set<string>> {\n\t\tconst through = type.relations.get(relation);\n\t\tconst found = new Set<string>();\n\t\tif (through === undefined) return found;\n\n\t\tif (through.kind === 'fromField') {\n\t\t\tfor (const id of await this.reach(through.subject, target)) {\n\t\t\t\tfor (const object of await this.lookup(type, relation, id)) {\n\t\t\t\t\tfound.add(object);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn found;\n\t\t}\n\t\tfor (const holder of through.holders) {\n\t\t\t// An arrow follows entities of an object type — a user type too, when\n\t\t\t// the model also declares it under types.\n\t\t\tif (holder.kind !== 'type' || !this.model.types.has(holder.type)) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tfor (const id of await this.reach(holder.type, target)) {\n\t\t\t\tconst entity = { type: holder.type, id };\n\t\t\t\tfor (const object of await this.holding(type.name, relation, entity)) {\n\t\t\t\t\tfound.add(object);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn found;\n\t}\n\n\t/** Every id of every page of `findObjects`. */\n\tprivate async holding(\n\t\ttype: string,\n\t\trelation: string,\n\t\tsubject: Subject,\n\t): Promise<string[]> {\n\t\tconst ids: string[] = [];\n\t\tlet after: string | null = null;\n\t\tdo {\n\t\t\tconst page: CursorPage<string> = await this.store.findObjects({\n\t\t\t\ttype,\n\t\t\t\trelation,\n\t\t\t\tsubject,\n\t\t\t\tafter,\n\t\t\t\tlimit: MAX_PAGE_SIZE,\n\t\t\t});\n\t\t\tids.push(...page.items);\n\t\t\tafter = page.nextCursor;\n\t\t} while (after !== null);\n\t\treturn ids;\n\t}\n\n\t/** The objects whose field names `id`, from the `fromField`'s lookup. */\n\tprivate async lookup(\n\t\ttype: ResolvedObjectType,\n\t\trelation: string,\n\t\tid: string,\n\t): Promise<readonly string[]> {\n\t\tconst def = type.relations.get(relation);\n\t\tif (def?.kind !== 'fromField' || def.lookup === undefined) {\n\t\t\tconst field = def?.kind === 'fromField' ? def.field : relation;\n\t\t\tconst subject = def?.kind === 'fromField' ? def.subject : 'subject';\n\t\t\t// The subject's type, never its id: a message reports a shape.\n\t\t\tthrow new TypeError(\n\t\t\t\t`list: ${type.name}.${relation} is read from a field, and has no lookup to find the ${type.name}s naming a subject of type '${subject}' — fromField('${field}', '${subject}', { lookup })`,\n\t\t\t);\n\t\t}\n\t\tconst ids = await def.lookup(id);\n\t\tif (!Array.isArray(ids) || ids.some((each) => typeof each !== 'string')) {\n\t\t\tthrow new TypeError(\n\t\t\t\t`list: the lookup of ${type.name}.${relation} must answer an array of ids`,\n\t\t\t);\n\t\t}\n\t\t// An id no store can keep is held by nobody, as can() answers it.\n\t\treturn ids.filter(isStorable);\n\t}\n\n\t/** The condition, run on the caller's `ctx`, as for `can()`. */\n\tprivate passes(\n\t\trule: ResolvedRule,\n\t\ttype: ResolvedObjectType,\n\t\tname: string,\n\t): boolean {\n\t\tif (this.ctx === undefined) {\n\t\t\tthrow new TypeError(\n\t\t\t\t`list: ${type.name}.${name} reaches a condition, and no ctx was passed — pass { ctx }`,\n\t\t\t);\n\t\t}\n\t\treturn (rule.test as (ctx: unknown) => boolean)(this.ctx) === true;\n\t}\n}\n",
9
9
  "/** The walk behind `can()`: from an object, through its rules, to a subject. */\n\nimport { PermissionDepthError } from '../errors/janus-error';\nimport { isStorable } from '../stores/storable';\nimport { formatEntity } from '../subjects/notation';\nimport type { Entity, Subject } from '../subjects/subject';\nimport type { RelationStore } from './port/types';\nimport {\n\tadmits,\n\ttype ResolvedModel,\n\ttype ResolvedObjectType,\n\ttype ResolvedRule,\n} from './resolve';\n\n/** An object on the walk: its entity, and its data when the caller passed it. */\nexport interface Node {\n\treadonly entity: Entity;\n\treadonly data: Readonly<Record<string, unknown>> | null;\n}\n\n/** One check: its context, its path, and the depth it may reach. */\nexport class Walk {\n\t/** The nodes on the current path. The walk is sequential, so one set is the stack. */\n\tprivate readonly path = new Set<string>();\n\n\tconstructor(\n\t\tprivate readonly model: ResolvedModel,\n\t\tprivate readonly store: RelationStore,\n\t\tprivate readonly maxDepth: number,\n\t\tprivate readonly ctx: unknown,\n\t\tprivate readonly question: string,\n\t) {}\n\n\t/** Whether `subject` holds `name` — a relation or a permission — on `node`. */\n\tasync holds(\n\t\tsubject: Subject,\n\t\tnode: Node,\n\t\tname: string,\n\t\tdepth: number,\n\t): Promise<boolean> {\n\t\tif (depth > this.maxDepth) {\n\t\t\tthrow new PermissionDepthError(\n\t\t\t\t`can: checking ${this.question} crossed more than ${this.maxDepth} relations without an answer`,\n\t\t\t\t{ permission: this.question, maxDepth: this.maxDepth },\n\t\t\t);\n\t\t}\n\n\t\tconst key = `${formatEntity(node.entity)}#${name}`;\n\t\t// A cycle in the data: this branch grants nothing, and it is not an error.\n\t\tif (this.path.has(key)) return false;\n\n\t\tconst type = this.model.types.get(node.entity.type);\n\t\t// A stored tuple naming a type the model no longer declares grants nothing.\n\t\tif (type === undefined) return false;\n\n\t\tthis.path.add(key);\n\t\ttry {\n\t\t\treturn type.permissions.has(name)\n\t\t\t\t? await this.permission(subject, type, node, name, depth)\n\t\t\t\t: await this.relation(subject, type, node, name, depth);\n\t\t} finally {\n\t\t\tthis.path.delete(key);\n\t\t}\n\t}\n\n\tprivate async relation(\n\t\tsubject: Subject,\n\t\ttype: ResolvedObjectType,\n\t\tnode: Node,\n\t\tname: string,\n\t\tdepth: number,\n\t): Promise<boolean> {\n\t\tconst relation = type.relations.get(name);\n\t\tif (relation === undefined) return false;\n\n\t\tif (relation.kind === 'fromField') {\n\t\t\tconst id = fieldOf(node, relation.field, `${type.name}.${name}`);\n\t\t\treturn (\n\t\t\t\tid !== null &&\n\t\t\t\t!('relation' in subject) &&\n\t\t\t\tsubject.type === relation.subject &&\n\t\t\t\tsubject.id === id\n\t\t\t);\n\t\t}\n\n\t\t// What the model does not admit here grants nothing, however it was stored.\n\t\tif (\n\t\t\tadmits(relation.holders, subject) &&\n\t\t\t(await this.store.has({ object: node.entity, relation: name, subject }))\n\t\t) {\n\t\t\treturn true;\n\t\t}\n\t\tfor (const set of await this.store.findSubjectSets(node.entity, name)) {\n\t\t\tif (!admits(relation.holders, set)) continue;\n\t\t\tconst through = { entity: { type: set.type, id: set.id }, data: null };\n\t\t\tif (await this.holds(subject, through, set.relation, depth + 1)) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n\tprivate async permission(\n\t\tsubject: Subject,\n\t\ttype: ResolvedObjectType,\n\t\tnode: Node,\n\t\tname: string,\n\t\tdepth: number,\n\t): Promise<boolean> {\n\t\tfor (const rule of type.permissions.get(name) ?? []) {\n\t\t\tif (rule.test !== undefined && !this.passes(rule, type, name)) continue;\n\n\t\t\tif (rule.kind === 'name') {\n\t\t\t\tif (await this.holds(subject, node, rule.name, depth)) return true;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tfor (const target of await this.targets(type, node, rule.relation)) {\n\t\t\t\tif (await this.holds(subject, target, rule.target, depth + 1)) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n\t/** The condition, run on the caller's `ctx`. Its absence is a caller's bug, not a denial. */\n\tprivate passes(\n\t\trule: ResolvedRule,\n\t\ttype: ResolvedObjectType,\n\t\tname: string,\n\t): boolean {\n\t\tif (this.ctx === undefined) {\n\t\t\tthrow new TypeError(\n\t\t\t\t`can: ${type.name}.${name} reaches a condition, and no ctx was passed — pass { ctx }`,\n\t\t\t);\n\t\t}\n\t\treturn (rule.test as (ctx: unknown) => boolean)(this.ctx) === true;\n\t}\n\n\t/** The objects an arrow through `relation` reaches from `node`. */\n\tprivate async targets(\n\t\ttype: ResolvedObjectType,\n\t\tnode: Node,\n\t\trelation: string,\n\t): Promise<Node[]> {\n\t\tconst through = type.relations.get(relation);\n\t\tif (through === undefined) return [];\n\n\t\tif (through.kind === 'fromField') {\n\t\t\tconst id = fieldOf(node, through.field, `${type.name}.${relation}`);\n\t\t\treturn id === null\n\t\t\t\t? []\n\t\t\t\t: [{ entity: { type: through.subject, id }, data: null }];\n\t\t}\n\t\t// An entity of a type the model does not admit here is no target.\n\t\treturn (await this.store.findEntities(node.entity, relation))\n\t\t\t.filter((entity) => admits(through.holders, entity))\n\t\t\t.map((entity) => ({\n\t\t\t\tentity: { type: entity.type, id: entity.id },\n\t\t\t\tdata: null,\n\t\t\t}));\n\t}\n}\n\n/**\n * The id a `fromField` reads, or `null` for nobody — an id no store can keep\n * included, so none is asked about it. A missing field is the caller's bug.\n */\nfunction fieldOf(node: Node, field: string, what: string): string | null {\n\tif (node.data === null) {\n\t\t// resolveModel refuses a model that could get here.\n\t\tthrow new TypeError(\n\t\t\t`can: ${what} reads ${field} from an object nobody passed`,\n\t\t);\n\t}\n\tconst value = node.data[field];\n\tif (value === null) return null;\n\tif (typeof value !== 'string') {\n\t\tthrow new TypeError(\n\t\t\t`can: ${what} reads ${field}, which the object ${value === undefined ? 'does not carry — pass the loaded object, spread' : 'holds as something other than a string id'}`,\n\t\t);\n\t}\n\treturn isStorable(value) ? value : null;\n}\n",
10
10
  "/**\n * The engine: `permissions({ model, store })`, the traversal behind `can()`,\n * and the same traversal run backwards behind `list()` — `walk.ts` and\n * `reverse.ts`; what a caller passes is read in `input.ts`.\n *\n * **The invariant, permission side.** A denial is `false` — never a thrown\n * error, which is how Keto's historical endpoint answers and why a denial and\n * an outage look alike there. A failure throws — never `false`, which would\n * deny everybody everything during an outage and say nothing. The store is\n * reached only through `guardRelations`, and `outage.spec.ts` refuses a `catch`\n * anywhere in this directory.\n *\n * **What is walked.** A relation holds when the tuple is stored, or through a\n * subject set holding it (`team:t1#member`), or — for a `fromField` — when the\n * object's field names the subject. A permission holds when any of its rules\n * does: a name of the same object, an arrow to a related object's permission,\n * either under a condition. The walk is sequential and stops at the first\n * grant, so a check reads no more than it needs.\n *\n * **Cycles and depth.** A node already on the current path — a team member of\n * a team member of itself — is cut: that branch grants nothing, and it is not\n * an error, because it is data. Crossing more than `maxDepth` relations *is*\n * an error, `PERMISSION_DEPTH`: an evaluation that stopped half-way decided\n * nothing, and `false` would hide it.\n */\n\nimport type { CursorPage } from '../pagination/cursor-page';\nimport { pageLimit } from '../pagination/cursor-page';\nimport { guardRelations } from '../stores/guard';\nimport { isStorable } from '../stores/storable';\nimport { objectOf, subjectOf, tupleOf, typeOf } from './input';\nimport type { ModelConfig, PermissionModel, Permissions } from './model';\nimport { resolvedOf } from './model';\nimport type { RelationStore } from './port/types';\nimport { Reverse } from './reverse';\nimport { Walk } from './walk';\n\n/** Deep enough for any hierarchy a person draws; OpenFGA's default too. */\nconst DEFAULT_MAX_DEPTH = 25;\n\nconst REQUIRED = [\n\t'write',\n\t'has',\n\t'findSubjectSets',\n\t'findEntities',\n\t'findObjects',\n\t'deleteEntity',\n] as const;\n\nexport interface PermissionsOptions<C extends ModelConfig> {\n\t/** What `defineModel()` answered. */\n\treadonly model: PermissionModel<C>;\n\t/** Where tuples live. `createMemoryRelations()` in tests. */\n\treadonly store: RelationStore;\n\t/** How many relations a check may cross. `25` when absent. */\n\treadonly maxDepth?: number;\n}\n\n/**\n * Binds a model to a relation store. Connects to nothing.\n *\n * ```ts\n * const access = permissions({ model, store: createMemoryRelations() });\n * await access.grant({ type: 'team', id: 't1' }, 'members', staff);\n * await access.can(staff, 'view', { type: 'record', ...record }, { ctx: { onShift } });\n * ```\n */\nexport function permissions<C extends ModelConfig>(\n\toptions: PermissionsOptions<C>,\n): Permissions<C> {\n\tconst where = 'permissions';\n\tconst model = resolvedOf(options.model);\n\tconst maxDepth = options.maxDepth ?? DEFAULT_MAX_DEPTH;\n\tif (!Number.isInteger(maxDepth) || maxDepth < 1) {\n\t\tthrow new TypeError(`${where}: maxDepth must be a positive integer`);\n\t}\n\tconst raw = options.store as unknown as Record<string, unknown> | undefined;\n\tfor (const method of REQUIRED) {\n\t\tif (typeof raw?.[method] !== 'function') {\n\t\t\tthrow new TypeError(`${where}: store.${method} is missing`);\n\t\t}\n\t}\n\tconst store = guardRelations(options.store);\n\n\tconst check = async (\n\t\tsubject: unknown,\n\t\tpermission: string,\n\t\tobject: unknown,\n\t\toptions?: { readonly ctx?: unknown },\n\t): Promise<boolean> => {\n\t\t// Anonymous, before anything else — and before the store.\n\t\tif (subject === null || subject === undefined) return false;\n\n\t\tconst root = objectOf(model, object, 'can');\n\t\tconst type = typeOf(model, root.type, 'can');\n\t\tif (!type.relations.has(permission) && !type.permissions.has(permission)) {\n\t\t\tthrow new TypeError(\n\t\t\t\t`can: \"${permission}\" is not a relation or a permission of ${type.name}`,\n\t\t\t);\n\t\t}\n\n\t\tconst who = subjectOf(model, subject, 'can');\n\t\t// An id no store can keep is held by nobody, and no store is asked:\n\t\t// the same answer on every adapter, as for an anonymous subject.\n\t\tif (!isStorable(root.id) || !isStorable(who.id)) return false;\n\n\t\treturn new Walk(\n\t\t\tmodel,\n\t\t\tstore,\n\t\t\tmaxDepth,\n\t\t\toptions?.ctx,\n\t\t\t`${type.name}#${permission}`,\n\t\t).holds(\n\t\t\twho,\n\t\t\t{ entity: { type: root.type, id: root.id }, data: root.data },\n\t\t\tpermission,\n\t\t\t0,\n\t\t);\n\t};\n\n\tconst list = async (\n\t\tsubject: unknown,\n\t\tpermission: string,\n\t\ttypeName: unknown,\n\t\toptions?: {\n\t\t\treadonly ctx?: unknown;\n\t\t\treadonly after?: string | null;\n\t\t\treadonly limit?: number;\n\t\t},\n\t): Promise<CursorPage<string>> => {\n\t\tconst limit = pageLimit(options?.limit, 'list');\n\t\tconst after = options?.after ?? null;\n\t\tif (after !== null && typeof after !== 'string') {\n\t\t\tthrow new TypeError(\n\t\t\t\t'list: after must be the nextCursor of a page, or null',\n\t\t\t);\n\t\t}\n\t\t// Anonymous holds nothing, and the store is not asked.\n\t\tif (subject === null || subject === undefined) {\n\t\t\treturn { items: [], nextCursor: null };\n\t\t}\n\n\t\tif (typeof typeName !== 'string') {\n\t\t\tthrow new TypeError('list: the type must be an object type of the model');\n\t\t}\n\t\tconst type = typeOf(model, typeName, 'list');\n\t\tif (!type.relations.has(permission) && !type.permissions.has(permission)) {\n\t\t\tthrow new TypeError(\n\t\t\t\t`list: \"${permission}\" is not a relation or a permission of ${type.name}`,\n\t\t\t);\n\t\t}\n\n\t\tconst who = subjectOf(model, subject, 'list');\n\t\t// A subject no store can keep holds nothing, and no store is asked.\n\t\tif (!isStorable(who.id)) return { items: [], nextCursor: null };\n\n\t\tconst ids = await new Reverse(\n\t\t\tmodel,\n\t\t\tstore,\n\t\t\tmaxDepth,\n\t\t\toptions?.ctx,\n\t\t\twho,\n\t\t\t`${type.name}#${permission}`,\n\t\t).objects(type.name, permission);\n\n\t\tconst rest = [...ids].sort().filter((id) => after === null || id > after);\n\t\tconst items = rest.slice(0, limit);\n\t\tconst last = items.at(-1);\n\t\treturn {\n\t\t\titems,\n\t\t\tnextCursor: rest.length > limit && last !== undefined ? last : null,\n\t\t};\n\t};\n\n\tconst change =\n\t\t(operation: 'grant' | 'revoke') =>\n\t\tasync (object: unknown, relation: string, subject: unknown) => {\n\t\t\tconst tuple = tupleOf(model, object, relation, subject, operation);\n\t\t\tawait store.write(\n\t\t\t\toperation === 'grant' ? { add: [tuple] } : { remove: [tuple] },\n\t\t\t);\n\t\t};\n\n\treturn Object.freeze({\n\t\tmodel: options.model,\n\t\tcan: check as Permissions<C>['can'],\n\t\tlist: list as Permissions<C>['list'],\n\t\tgrant: change('grant') as Permissions<C>['grant'],\n\t\trevoke: change('revoke') as Permissions<C>['revoke'],\n\t});\n}\n"
11
11
  ],
12
- "mappings": "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",
13
- "debugId": "A29B25AF106A2FDE64756E2164756E21",
12
+ "mappings": "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",
13
+ "debugId": "E842D9EC7EB9FE0964756E2164756E21",
14
14
  "names": []
15
15
  }
@@ -1 +1 @@
1
- {"version":3,"file":"reverse.d.ts","sourceRoot":"","sources":["../../src/permissions/reverse.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAClD,OAAO,EAEN,KAAK,aAAa,EAGlB,MAAM,WAAW,CAAC;AAEnB;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,qBAAa,OAAO;IAOlB,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,GAAG;IACpB,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,QAAQ;IAX1B,OAAO,CAAC,QAAQ,CAA0C;IAC1D,OAAO,CAAC,OAAO,CAA0C;IACzD,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAqB;IAC1C,OAAO,CAAC,MAAM,CAAS;gBAGL,KAAK,EAAE,aAAa,EACpB,KAAK,EAAE,aAAa,EACpB,QAAQ,EAAE,MAAM,EAChB,GAAG,EAAE,OAAO,EACZ,OAAO,EAAE,OAAO,EAChB,QAAQ,EAAE,MAAM;IAG5B,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;IAcvE,gFAAgF;IAChF,OAAO,CAAC,IAAI;IAOZ,8EAA8E;YAChE,KAAK;YA2BL,QAAQ;YAgCR,UAAU;IAmBxB,oGAAoG;YACtF,KAAK;IAiCnB,+CAA+C;YACjC,OAAO;IAqBrB,yEAAyE;YAC3D,MAAM;IAqBpB,gEAAgE;IAChE,OAAO,CAAC,MAAM;CAYd"}
1
+ {"version":3,"file":"reverse.d.ts","sourceRoot":"","sources":["../../src/permissions/reverse.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAClD,OAAO,EAEN,KAAK,aAAa,EAGlB,MAAM,WAAW,CAAC;AAEnB;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,qBAAa,OAAO;IAOlB,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,GAAG;IACpB,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,QAAQ;IAX1B,OAAO,CAAC,QAAQ,CAA0C;IAC1D,OAAO,CAAC,OAAO,CAA0C;IACzD,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAqB;IAC1C,OAAO,CAAC,MAAM,CAAS;gBAGL,KAAK,EAAE,aAAa,EACpB,KAAK,EAAE,aAAa,EACpB,QAAQ,EAAE,MAAM,EAChB,GAAG,EAAE,OAAO,EACZ,OAAO,EAAE,OAAO,EAChB,QAAQ,EAAE,MAAM;IAG5B,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;IAcvE,gFAAgF;IAChF,OAAO,CAAC,IAAI;IAOZ,8EAA8E;YAChE,KAAK;YA2BL,QAAQ;YAgCR,UAAU;IAmBxB,oGAAoG;YACtF,KAAK;IAiCnB,+CAA+C;YACjC,OAAO;IAqBrB,yEAAyE;YAC3D,MAAM;IAwBpB,gEAAgE;IAChE,OAAO,CAAC,MAAM;CAYd"}
@@ -92,7 +92,7 @@ How the messages are shaped:
92
92
  - [`permissions: store.<method> is missing`](#permissions-storemethod-is-missing)
93
93
  - [`can: <type>.<relation> reads <field>, which the object does not carry …`](#can-typerelation-reads-field-which-the-object-does-not-carry--pass-the-loaded-object-spread)
94
94
  - [`can: <type>.<name> reaches a condition, and no ctx was passed — pass { ctx }`](#can-typename-reaches-a-condition-and-no-ctx-was-passed--pass--ctx-)
95
- - [`list: <type>.<relation> is read from a field, and has no lookup …`](#list-typerelation-is-read-from-a-field-and-has-no-lookup-to-find-the-types-naming-id--)
95
+ - [`list: <type>.<relation> is read from a field, and has no lookup …`](#list-typerelation-is-read-from-a-field-and-has-no-lookup-to-find-the-types-naming-a-subject-of-type-subject-type--)
96
96
  - [`list: the lookup of <type>.<relation> must answer an array of ids`](#list-the-lookup-of-typerelation-must-answer-an-array-of-ids)
97
97
  - [`grant: <type>.<relation> is read from <field>; there is nothing to store …`](#grant-typerelation-is-read-from-field-there-is-nothing-to-store--change-the-type-instead)
98
98
  - [`grant: <type>.<relation> is not held by <holder>`](#grant-typerelation-is-not-held-by-holder)
@@ -107,6 +107,7 @@ How the messages are shaped:
107
107
  - [`describeJanusStores: no test runner on globalThis …`](#describejanusstores-no-test-runner-on-globalthis--pass-runner--describe-it--under-bun-test-import-them-from-buntest)
108
108
  - [`JANUS_CONFORMANCE_SKIPPED` — `faults not provided: the outage invariant is not proven for this adapter`](#janus_conformance_skipped--faults-not-provided-the-outage-invariant-is-not-proven-for-this-adapter)
109
109
  - [`the error is named <Class> but is not @nxgt/janus's <Class>: two copies of @nxgt/janus are installed …`](#the-error-is-named-class-but-is-not-nxgtjanuss-class-two-copies-of-nxgtjanus-are-installed-the-adapter-must-list-it-as-a-peer-dependency-never-a-dependency)
110
+ - [`expected <Class>, got <value>`](#expected-class-got-value)
110
111
  - [`expected null, got undefined — an absence is null; undefined is a store that forgot to answer`](#expected-null-got-undefined--an-absence-is-null-undefined-is-a-store-that-forgot-to-answer)
111
112
 
112
113
  ---
@@ -1017,7 +1018,7 @@ Also `list: <type>.<name> reaches a condition, and no ctx was passed — pass {
1017
1018
  await access.can(grace, 'edit', { type: 'record', ...record }, { ctx: { onShift: true } });
1018
1019
  ```
1019
1020
 
1020
- ### `list: <type>.<relation> is read from a field, and has no lookup to find the <type>s naming <id> — …`
1021
+ ### `list: <type>.<relation> is read from a field, and has no lookup to find the <type>s naming a subject of type '<subject type>' — …`
1021
1022
 
1022
1023
  **When:** `access.list(subject, permission, type)` through a `fromField` relation.
1023
1024
  **Why:** `list()` walks backwards from the subject, so it cannot read a field of objects it has not found yet. It asks your `lookup` for the ids of the objects whose field names the subject.
@@ -1167,10 +1168,30 @@ A process warning, and the outage cases reported as skipped.
1167
1168
 
1168
1169
  ### `the error is named <Class> but is not @nxgt/janus's <Class>: two copies of @nxgt/janus are installed. The adapter must list it as a peer dependency, never a dependency`
1169
1170
 
1170
- **When:** a conformance case that checks the class of an error — the outage and conflict cases.
1171
- **Why:** the adapter imports its own copy of `@nxgt/janus`, so its `StoreFailure` or `StoreConflict` is not the core's, and `instanceof` fails.
1171
+ **When:** a conformance case that checks the class of an error — the outage, conflict and not-found cases.
1172
+ **Why:** the adapter imports its own copy of `@nxgt/janus`, so its `StoreFailure`, `StoreConflict` or `NotFoundError` is not the core's, and `instanceof` fails.
1172
1173
  **Fix:** move `@nxgt/janus` to `peerDependencies` (and `devDependencies` for the tests), then reinstall.
1173
1174
 
1175
+ ### `expected <Class>, got <value>`
1176
+
1177
+ The case's own sentence first — `users.findUser under an outage`, `insertUser should refuse a taken login with StoreConflict`.
1178
+
1179
+ **When:** a conformance case that checks the class of an error, and the adapter threw — or answered — something else.
1180
+ **Why:** the port names the class: an outage is `StoreFailure`, a taken login `StoreConflict`, an update of an unknown id `NotFoundError`. A driver's own error, or an answer where a rejection was due, fails the case.
1181
+ **Fix:** wrap the driver's failure in the core's class, with the driver's error as `cause`:
1182
+
1183
+ ```ts
1184
+ try {
1185
+ return await collection.findOne({ _id: id });
1186
+ } catch (cause) {
1187
+ throw new StoreFailure('users.findUser: the store could not answer', {
1188
+ slot: 'users',
1189
+ operation: 'findUser',
1190
+ cause,
1191
+ });
1192
+ }
1193
+ ```
1194
+
1174
1195
  ### `expected null, got undefined — an absence is null; undefined is a store that forgot to answer`
1175
1196
 
1176
1197
  **When:** a conformance case on a `find*` method.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nxgt/janus",
3
- "version": "0.8.3",
3
+ "version": "0.8.5",
4
4
  "description": "Embeddable, type-safe identities and permissions: bring your own database",
5
5
  "license": "MIT",
6
6
  "type": "module",