@nxgt/janus 0.17.2 → 0.19.0

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.
Files changed (93) hide show
  1. package/README.md +107 -27
  2. package/dist/auth/config/index.d.ts +1 -1
  3. package/dist/auth/config/index.d.ts.map +1 -1
  4. package/dist/auth/config/janus-config.d.ts +31 -0
  5. package/dist/auth/config/janus-config.d.ts.map +1 -1
  6. package/dist/auth/config/resolve-config.d.ts.map +1 -1
  7. package/dist/auth/config/resolve-throttle.d.ts +30 -0
  8. package/dist/auth/config/resolve-throttle.d.ts.map +1 -0
  9. package/dist/auth/config/resolved-config.d.ts +5 -0
  10. package/dist/auth/config/resolved-config.d.ts.map +1 -1
  11. package/dist/auth/config/warn-throttle-window.d.ts +14 -0
  12. package/dist/auth/config/warn-throttle-window.d.ts.map +1 -0
  13. package/dist/auth/counter-key.d.ts +19 -0
  14. package/dist/auth/counter-key.d.ts.map +1 -0
  15. package/dist/auth/email-flows/reset-password.d.ts.map +1 -1
  16. package/dist/auth/email-flows/verify-email.d.ts.map +1 -1
  17. package/dist/auth/index.d.ts +1 -1
  18. package/dist/auth/index.d.ts.map +1 -1
  19. package/dist/auth/janus.d.ts.map +1 -1
  20. package/dist/auth/magic-link.d.ts.map +1 -1
  21. package/dist/auth/mail-requests.d.ts +51 -0
  22. package/dist/auth/mail-requests.d.ts.map +1 -0
  23. package/dist/auth/port/assert-stores.d.ts.map +1 -1
  24. package/dist/auth/port/memory/users.d.ts.map +1 -1
  25. package/dist/auth/port/types/stores.d.ts +5 -0
  26. package/dist/auth/port/types/stores.d.ts.map +1 -1
  27. package/dist/auth/port/types/users.d.ts +17 -0
  28. package/dist/auth/port/types/users.d.ts.map +1 -1
  29. package/dist/auth/sign-in-attempts.d.ts +3 -6
  30. package/dist/auth/sign-in-attempts.d.ts.map +1 -1
  31. package/dist/auth/sign-in-code.d.ts +3 -2
  32. package/dist/auth/sign-in-code.d.ts.map +1 -1
  33. package/dist/auth/step-up/request.d.ts.map +1 -1
  34. package/dist/auth/types/email-flows.d.ts +16 -6
  35. package/dist/auth/types/email-flows.d.ts.map +1 -1
  36. package/dist/auth/types/magic-link.d.ts +4 -2
  37. package/dist/auth/types/magic-link.d.ts.map +1 -1
  38. package/dist/auth/types/step-up.d.ts +4 -1
  39. package/dist/auth/types/step-up.d.ts.map +1 -1
  40. package/dist/auth/types/user-type.d.ts +15 -0
  41. package/dist/auth/types/user-type.d.ts.map +1 -1
  42. package/dist/auth/users/find-many.d.ts +29 -0
  43. package/dist/auth/users/find-many.d.ts.map +1 -0
  44. package/dist/auth/users/record-flows.d.ts.map +1 -1
  45. package/dist/chunks/{index-6fxq0kzf.js → index-4khsm7mw.js} +2 -2
  46. package/dist/chunks/{index-7xe5x3eg.js → index-6bjfv4xv.js} +9 -3
  47. package/dist/chunks/{index-7xe5x3eg.js.map → index-6bjfv4xv.js.map} +3 -3
  48. package/dist/chunks/{index-k136102s.js → index-cntabs9d.js} +2 -2
  49. package/dist/chunks/{index-ztng6018.js → index-kppkcbn5.js} +10 -3
  50. package/dist/chunks/{index-ztng6018.js.map → index-kppkcbn5.js.map} +4 -4
  51. package/dist/conformance/cases/outage.d.ts.map +1 -1
  52. package/dist/conformance/cases/users/batch.d.ts +8 -0
  53. package/dist/conformance/cases/users/batch.d.ts.map +1 -0
  54. package/dist/conformance/cases/users/index.d.ts.map +1 -1
  55. package/dist/conformance/describe.d.ts +2 -1
  56. package/dist/conformance/describe.d.ts.map +1 -1
  57. package/dist/conformance/index.d.ts +1 -1
  58. package/dist/conformance/index.d.ts.map +1 -1
  59. package/dist/conformance/index.js +106 -46
  60. package/dist/conformance/index.js.map +7 -6
  61. package/dist/conformance/types.d.ts +10 -2
  62. package/dist/conformance/types.d.ts.map +1 -1
  63. package/dist/errors/janus-error/codes.d.ts +10 -0
  64. package/dist/errors/janus-error/codes.d.ts.map +1 -1
  65. package/dist/errors/janus-error/index.d.ts +1 -1
  66. package/dist/errors/janus-error/index.d.ts.map +1 -1
  67. package/dist/errors/janus-error/options.d.ts +4 -3
  68. package/dist/errors/janus-error/options.d.ts.map +1 -1
  69. package/dist/errors/janus-error/refusals.d.ts +8 -0
  70. package/dist/errors/janus-error/refusals.d.ts.map +1 -1
  71. package/dist/errors/janus-error/status.d.ts +1 -1
  72. package/dist/errors/janus-error/status.d.ts.map +1 -1
  73. package/dist/index.d.ts +1 -1
  74. package/dist/index.d.ts.map +1 -1
  75. package/dist/index.js +171 -30
  76. package/dist/index.js.map +18 -14
  77. package/dist/permissions/index.js +3 -3
  78. package/docs/README.md +1 -1
  79. package/docs/guide/adapters.md +44 -4
  80. package/docs/guide/email-flows.md +164 -4
  81. package/docs/guide/errors.md +12 -3
  82. package/docs/guide/magic-link.md +41 -5
  83. package/docs/guide/passwords.md +2 -1
  84. package/docs/guide/sign-in-code.md +46 -7
  85. package/docs/guide/step-up.md +38 -7
  86. package/docs/guide/users.md +49 -0
  87. package/docs/roadmap.md +26 -15
  88. package/docs/troubleshooting.md +127 -5
  89. package/package.json +1 -1
  90. package/dist/auth/config/resolve-sign-in.d.ts +0 -5
  91. package/dist/auth/config/resolve-sign-in.d.ts.map +0 -1
  92. /package/dist/chunks/{index-6fxq0kzf.js.map → index-4khsm7mw.js.map} +0 -0
  93. /package/dist/chunks/{index-k136102s.js.map → index-cntabs9d.js.map} +0 -0
@@ -14,12 +14,9 @@
14
14
  *
15
15
  * Counted in an attempt window (`one-time/window.ts`), in `secondFactor`
16
16
  * tokens stored under no user: the `userId` of each is a keyed hash of the
17
- * login, never the login. The key is derived from the sealing keys when
18
- * `secondFactor` is configured; without them it is a fixed one, and the hash
19
- * only keeps the login out of plain sight — safe because a `secondFactor`
20
- * token is redeemed only by the second factor's flows, which do not exist
21
- * without the keys. A sign-in that opens a session spends the link it
22
- * counts on, and the login's count **restarts** from zero.
17
+ * login, never the login (`counter-key.ts`). A sign-in that opens a session
18
+ * spends the link it counts on, and the login's count **restarts** from
19
+ * zero.
23
20
  *
24
21
  * A store that cannot count throws `STORE_FAILED`: never a refusal, and
25
22
  * never a sign-in let through uncounted.
@@ -1 +1 @@
1
- {"version":3,"file":"sign-in-attempts.d.ts","sourceRoot":"","sources":["../../src/auth/sign-in-attempts.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAC7C,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAGzC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AA8C/C;;;GAGG;AACH,wBAAsB,kBAAkB,CACvC,OAAO,EAAE,OAAO,EAChB,IAAI,EAAE,YAAY,EAClB,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,GACX,OAAO,CAAC,IAAI,CAAC,CAgBf;AAED;;;;;;GAMG;AACH,wBAAsB,kBAAkB,CACvC,OAAO,EAAE,OAAO,EAChB,IAAI,EAAE,YAAY,EAClB,MAAM,EAAE,UAAU,EAClB,KAAK,EAAE,MAAM,GACX,OAAO,CAAC,IAAI,CAAC,CAWf"}
1
+ {"version":3,"file":"sign-in-attempts.d.ts","sourceRoot":"","sources":["../../src/auth/sign-in-attempts.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAC7C,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAGzC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAgC/C;;;GAGG;AACH,wBAAsB,kBAAkB,CACvC,OAAO,EAAE,OAAO,EAChB,IAAI,EAAE,YAAY,EAClB,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,GACX,OAAO,CAAC,IAAI,CAAC,CAgBf;AAED;;;;;;GAMG;AACH,wBAAsB,kBAAkB,CACvC,OAAO,EAAE,OAAO,EAChB,IAAI,EAAE,YAAY,EAClB,MAAM,EAAE,UAAU,EAClB,KAAK,EAAE,MAAM,GACX,OAAO,CAAC,IAAI,CAAC,CAWf"}
@@ -13,8 +13,9 @@ import type { SignInCodeApi, SignInResult } from './types';
13
13
  * spends the challenge. **At most one code is live per user**: `request`
14
14
  * spends every other once it issued its own, so concurrent requests cannot
15
15
  * each keep one. Yet anybody who knows an e-mail can ask for another — and
16
- * each request cancels the code before — so the application rate-limits
17
- * `request`, per address. The code's hash is keyed by the challenge, so the
16
+ * each request cancels the code before — so `request` is counted per
17
+ * address (`mail-requests.ts`), and the application rate-limits it per
18
+ * client. The code's hash is keyed by the challenge, so the
18
19
  * tokens alone do not reveal it.
19
20
  */
20
21
  export declare function signInCodeFlows(context: Context, type: ResolvedType, at: At, finish: Finish): SignInCodeApi<AnyUser, SignInResult<AnyUser>>['signInCode'];
@@ -1 +1 @@
1
- {"version":3,"file":"sign-in-code.d.ts","sourceRoot":"","sources":["../../src/auth/sign-in-code.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,MAAM,CAAC;AAC/B,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAC7C,OAAO,EAAE,KAAK,OAAO,EAAE,KAAK,OAAO,EAAsB,MAAM,WAAW,CAAC;AAE3E,OAAO,EACN,KAAK,MAAM,EAIX,MAAM,iBAAiB,CAAC;AAWzB,OAAO,KAAK,EAEX,aAAa,EAEb,YAAY,EACZ,MAAM,SAAS,CAAC;AAEjB;;;;;;;;;;;;;GAaG;AACH,wBAAgB,eAAe,CAC9B,OAAO,EAAE,OAAO,EAChB,IAAI,EAAE,YAAY,EAClB,EAAE,EAAE,EAAE,EACN,MAAM,EAAE,MAAM,GACZ,aAAa,CAAC,OAAO,EAAE,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC,YAAY,CAAC,CAgB7D"}
1
+ {"version":3,"file":"sign-in-code.d.ts","sourceRoot":"","sources":["../../src/auth/sign-in-code.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,MAAM,CAAC;AAC/B,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAC7C,OAAO,EAAE,KAAK,OAAO,EAAE,KAAK,OAAO,EAAsB,MAAM,WAAW,CAAC;AAE3E,OAAO,EACN,KAAK,MAAM,EAIX,MAAM,iBAAiB,CAAC;AAYzB,OAAO,KAAK,EAEX,aAAa,EAEb,YAAY,EACZ,MAAM,SAAS,CAAC;AAEjB;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,eAAe,CAC9B,OAAO,EAAE,OAAO,EAChB,IAAI,EAAE,YAAY,EAClB,EAAE,EAAE,EAAE,EACN,MAAM,EAAE,MAAM,GACZ,aAAa,CAAC,OAAO,EAAE,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC,YAAY,CAAC,CAqB7D"}
@@ -1 +1 @@
1
- {"version":3,"file":"request.d.ts","sourceRoot":"","sources":["../../../src/auth/step-up/request.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAC9C,OAAO,EACN,KAAK,OAAO,EACZ,KAAK,OAAO,EAKZ,MAAM,YAAY,CAAC;AAKpB,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AAEpE,wEAAwE;AACxE,MAAM,MAAM,YAAY,GAAG,aAAa,CAAC,OAAO,CAAC,GAAG,WAAW,CAAC,OAAO,CAAC,CAAC;AAEzE,sEAAsE;AACtE,wBAAsB,aAAa,CAClC,OAAO,EAAE,OAAO,EAChB,IAAI,EAAE,YAAY,EAClB,IAAI,EAAE,OAAO,EACb,KAAK,EAAE,MAAM,GACX,OAAO,CAAC,YAAY,CAAC,CAqBvB"}
1
+ {"version":3,"file":"request.d.ts","sourceRoot":"","sources":["../../../src/auth/step-up/request.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAC9C,OAAO,EACN,KAAK,OAAO,EACZ,KAAK,OAAO,EAKZ,MAAM,YAAY,CAAC;AAMpB,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AAEpE,wEAAwE;AACxE,MAAM,MAAM,YAAY,GAAG,aAAa,CAAC,OAAO,CAAC,GAAG,WAAW,CAAC,OAAO,CAAC,CAAC;AAEzE,sEAAsE;AACtE,wBAAsB,aAAa,CAClC,OAAO,EAAE,OAAO,EAChB,IAAI,EAAE,YAAY,EAClB,IAAI,EAAE,OAAO,EACb,KAAK,EAAE,MAAM,GACX,OAAO,CAAC,YAAY,CAAC,CAqBvB"}
@@ -43,10 +43,12 @@ export interface SignInCodeApi<U, Answer = SignedIn<U>> {
43
43
  * the visitor which**: answer the same page either way, and in the same
44
44
  * time — send the e-mail off the request's path.
45
45
  *
46
- * **Rate-limit it, per e-mail and per client.** Every call issues a new
47
- * challenge with five attempts of its own, and spends the earlier ones:
48
- * only the last code sent works, and a new `request` is five guesses
49
- * more — the five attempts bound one challenge, not one account.
46
+ * Every call issues a new challenge with five attempts of its own, and
47
+ * spends the earlier ones: only the last code sent works, and a new
48
+ * `request` is five guesses more. **Throttled per address**, whether
49
+ * anybody holds it or not: past five requests in 10 minutes
50
+ * (`janus({ mail: { throttle } })`), `MAIL_THROTTLED` with
51
+ * `retryAfter`, and no code. Rate-limit it per client too.
50
52
  */
51
53
  request(email: string): Promise<IssuedCode<U> | null>;
52
54
  /**
@@ -68,7 +70,12 @@ export interface SignInCodeApi<U, Answer = SignedIn<U>> {
68
70
  /** What a user type with an e-mail answers besides. */
69
71
  export interface VerifyEmailApi<U> {
70
72
  readonly verifyEmail: {
71
- /** Issues a token for the user's current e-mail. Sending it is yours. */
73
+ /**
74
+ * Issues a token for the user's current e-mail. Sending it is yours.
75
+ * **Throttled per user**: past five in 10 minutes
76
+ * (`janus({ mail: { throttle } })`), `MAIL_THROTTLED` with
77
+ * `retryAfter`, and no token.
78
+ */
72
79
  send(user: UserRef): Promise<IssuedToken>;
73
80
  /**
74
81
  * Redeems a token and marks the e-mail verified. A token sent to an
@@ -84,7 +91,10 @@ export interface ResetPasswordApi<U> {
84
91
  * Issues a reset token for the user of this type holding this e-mail, or
85
92
  * answers `null` when there is none. **Never tell the visitor which**:
86
93
  * answer the same page either way. The user's earlier reset tokens are
87
- * spent: only the last one sent works.
94
+ * spent: only the last one sent works. **Throttled per address**,
95
+ * whether anybody holds it or not: past five requests in 10 minutes
96
+ * (`janus({ mail: { throttle } })`), `MAIL_THROTTLED` with
97
+ * `retryAfter`, and no token.
88
98
  */
89
99
  request(email: string): Promise<(IssuedToken & {
90
100
  readonly user: U;
@@ -1 +1 @@
1
- {"version":3,"file":"email-flows.d.ts","sourceRoot":"","sources":["../../../src/auth/types/email-flows.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,aAAa,EAAgB,MAAM,WAAW,CAAC;AACvE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AAEtC,0EAA0E;AAC1E,MAAM,WAAW,WAAW;IAC3B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,iCAAiC;IACjC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,SAAS,EAAE,IAAI,CAAC;CACzB;AAED,oFAAoF;AACpF,MAAM,WAAW,UAAU,CAAC,CAAC;IAC5B,mFAAmF;IACnF,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB;;;;OAIG;IACH,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,uCAAuC;IACvC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,SAAS,EAAE,IAAI,CAAC;IACzB,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC;CACjB;AAED;;;;;;GAMG;AACH,MAAM,WAAW,aAAa,CAAC,CAAC,EAAE,MAAM,GAAG,QAAQ,CAAC,CAAC,CAAC;IACrD,QAAQ,CAAC,UAAU,EAAE;QACpB;;;;;;;;;;WAUG;QACH,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;QACtD;;;;;;;;;;;;WAYG;QACH,OAAO,CACN,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE,aAAa,GACrB,OAAO,CAAC,MAAM,CAAC,CAAC;KACnB,CAAC;CACF;AAED,uDAAuD;AACvD,MAAM,WAAW,cAAc,CAAC,CAAC;IAChC,QAAQ,CAAC,WAAW,EAAE;QACrB,yEAAyE;QACzE,IAAI,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;QAC1C;;;WAGG;QACH,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;KACnC,CAAC;CACF;AAED,sEAAsE;AACtE,MAAM,WAAW,gBAAgB,CAAC,CAAC;IAClC,QAAQ,CAAC,aAAa,EAAE;QACvB;;;;;WAKG;QACH,OAAO,CACN,KAAK,EAAE,MAAM,GACX,OAAO,CAAC,CAAC,WAAW,GAAG;YAAE,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAA;SAAE,CAAC,GAAG,IAAI,CAAC,CAAC;QACxD;;;;;;WAMG;QACH,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;KACrD,CAAC;CACF"}
1
+ {"version":3,"file":"email-flows.d.ts","sourceRoot":"","sources":["../../../src/auth/types/email-flows.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,aAAa,EAAgB,MAAM,WAAW,CAAC;AACvE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AAEtC,0EAA0E;AAC1E,MAAM,WAAW,WAAW;IAC3B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,iCAAiC;IACjC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,SAAS,EAAE,IAAI,CAAC;CACzB;AAED,oFAAoF;AACpF,MAAM,WAAW,UAAU,CAAC,CAAC;IAC5B,mFAAmF;IACnF,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB;;;;OAIG;IACH,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,uCAAuC;IACvC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,SAAS,EAAE,IAAI,CAAC;IACzB,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC;CACjB;AAED;;;;;;GAMG;AACH,MAAM,WAAW,aAAa,CAAC,CAAC,EAAE,MAAM,GAAG,QAAQ,CAAC,CAAC,CAAC;IACrD,QAAQ,CAAC,UAAU,EAAE;QACpB;;;;;;;;;;;;WAYG;QACH,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;QACtD;;;;;;;;;;;;WAYG;QACH,OAAO,CACN,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE,aAAa,GACrB,OAAO,CAAC,MAAM,CAAC,CAAC;KACnB,CAAC;CACF;AAED,uDAAuD;AACvD,MAAM,WAAW,cAAc,CAAC,CAAC;IAChC,QAAQ,CAAC,WAAW,EAAE;QACrB;;;;;WAKG;QACH,IAAI,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;QAC1C;;;WAGG;QACH,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;KACnC,CAAC;CACF;AAED,sEAAsE;AACtE,MAAM,WAAW,gBAAgB,CAAC,CAAC;IAClC,QAAQ,CAAC,aAAa,EAAE;QACvB;;;;;;;;WAQG;QACH,OAAO,CACN,KAAK,EAAE,MAAM,GACX,OAAO,CAAC,CAAC,WAAW,GAAG;YAAE,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAA;SAAE,CAAC,GAAG,IAAI,CAAC,CAAC;QACxD;;;;;;WAMG;QACH,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;KACrD,CAAC;CACF"}
@@ -23,8 +23,10 @@ export interface MagicLinkApi<U, Answer = SignedIn<U>> {
23
23
  *
24
24
  * Put `token` in a link to a page of yours, and **only in the e-mail**.
25
25
  * The user's earlier links are spent: only the last one sent works.
26
- * **Rate-limit it, per e-mail and per client**: every call sends an
27
- * e-mail.
26
+ * **Throttled per address**, whether anybody holds it or not: past
27
+ * five requests in 10 minutes (`janus({ mail: { throttle } })`),
28
+ * `MAIL_THROTTLED` with `retryAfter`, and no token. Rate-limit it per
29
+ * client too: one client can ask for many addresses.
28
30
  */
29
31
  request(email: string): Promise<(IssuedToken & {
30
32
  readonly user: U;
@@ -1 +1 @@
1
- {"version":3,"file":"magic-link.d.ts","sourceRoot":"","sources":["../../../src/auth/types/magic-link.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,KAAK,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAEzD;;;;;;GAMG;AACH,MAAM,WAAW,YAAY,CAAC,CAAC,EAAE,MAAM,GAAG,QAAQ,CAAC,CAAC,CAAC;IACpD,QAAQ,CAAC,SAAS,EAAE;QACnB;;;;;;;;;;WAUG;QACH,OAAO,CACN,KAAK,EAAE,MAAM,GACX,OAAO,CAAC,CAAC,WAAW,GAAG;YAAE,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAA;SAAE,CAAC,GAAG,IAAI,CAAC,CAAC;QACxD;;;;;;;;;;;;;;WAcG;QACH,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;KACjE,CAAC;CACF"}
1
+ {"version":3,"file":"magic-link.d.ts","sourceRoot":"","sources":["../../../src/auth/types/magic-link.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,KAAK,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAEzD;;;;;;GAMG;AACH,MAAM,WAAW,YAAY,CAAC,CAAC,EAAE,MAAM,GAAG,QAAQ,CAAC,CAAC,CAAC;IACpD,QAAQ,CAAC,SAAS,EAAE;QACnB;;;;;;;;;;;;WAYG;QACH,OAAO,CACN,KAAK,EAAE,MAAM,GACX,OAAO,CAAC,CAAC,WAAW,GAAG;YAAE,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAA;SAAE,CAAC,GAAG,IAAI,CAAC,CAAC;QACxD;;;;;;;;;;;;;;WAcG;QACH,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;KACjE,CAAC;CACF"}
@@ -53,7 +53,10 @@ export interface StepUpApi<U, Issued = StepUpByEmail<U>> {
53
53
  * step-up is live per user**: the ones issued before stop working.
54
54
  *
55
55
  * `NOT_FOUND` for no such user of this type, or one with no e-mail;
56
- * `USER_INACTIVE` for an inactive one.
56
+ * `USER_INACTIVE` for an inactive one. A code to e-mail is **throttled
57
+ * per user**: past five in 10 minutes (`janus({ mail: { throttle } })`),
58
+ * `MAIL_THROTTLED` with `retryAfter`, and no challenge. A challenge for
59
+ * the app sends nothing, and is not counted.
57
60
  */
58
61
  request(user: UserRef): Promise<Issued>;
59
62
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"step-up.d.ts","sourceRoot":"","sources":["../../../src/auth/types/step-up.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACtD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AAEtC,mFAAmF;AACnF,MAAM,WAAW,aAAa,CAAC,CAAC;IAC/B,QAAQ,CAAC,GAAG,EAAE,OAAO,CAAC;IACtB,gFAAgF;IAChF,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB;;;;OAIG;IACH,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,uCAAuC;IACvC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,SAAS,EAAE,IAAI,CAAC;IACzB,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC;CACjB;AAED;;;;GAIG;AACH,MAAM,WAAW,WAAW,CAAC,CAAC;IAC7B,QAAQ,CAAC,GAAG,EAAE,cAAc,CAAC;IAC7B,6EAA6E;IAC7E,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,SAAS,EAAE,IAAI,CAAC;IACzB,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC;CACjB;AAED;;;;;;;;;GASG;AACH,MAAM,WAAW,SAAS,CAAC,CAAC,EAAE,MAAM,GAAG,aAAa,CAAC,CAAC,CAAC;IACtD,QAAQ,CAAC,MAAM,EAAE;QAChB;;;;;;;;WAQG;QACH,OAAO,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;QACxC;;;;;;;;;;;;;;;;WAgBG;QACH,OAAO,CACN,OAAO,EAAE,WAAW,EACpB,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,MAAM,GACV,OAAO,CAAC,OAAO,CAAC,CAAC;KACpB,CAAC;CACF"}
1
+ {"version":3,"file":"step-up.d.ts","sourceRoot":"","sources":["../../../src/auth/types/step-up.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACtD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AAEtC,mFAAmF;AACnF,MAAM,WAAW,aAAa,CAAC,CAAC;IAC/B,QAAQ,CAAC,GAAG,EAAE,OAAO,CAAC;IACtB,gFAAgF;IAChF,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB;;;;OAIG;IACH,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,uCAAuC;IACvC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,SAAS,EAAE,IAAI,CAAC;IACzB,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC;CACjB;AAED;;;;GAIG;AACH,MAAM,WAAW,WAAW,CAAC,CAAC;IAC7B,QAAQ,CAAC,GAAG,EAAE,cAAc,CAAC;IAC7B,6EAA6E;IAC7E,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,SAAS,EAAE,IAAI,CAAC;IACzB,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC;CACjB;AAED;;;;;;;;;GASG;AACH,MAAM,WAAW,SAAS,CAAC,CAAC,EAAE,MAAM,GAAG,aAAa,CAAC,CAAC,CAAC;IACtD,QAAQ,CAAC,MAAM,EAAE;QAChB;;;;;;;;;;;WAWG;QACH,OAAO,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;QACxC;;;;;;;;;;;;;;;;WAgBG;QACH,OAAO,CACN,OAAO,EAAE,WAAW,EACpB,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,MAAM,GACV,OAAO,CAAC,OAAO,CAAC,CAAC;KACpB,CAAC;CACF"}
@@ -22,6 +22,21 @@ export interface UserTypeApi<U, In> {
22
22
  }): Promise<U>;
23
23
  /** The user of this type, or `null` — for a malformed id, an unknown one, or one of another type. */
24
24
  find(id: string): Promise<U | null>;
25
+ /**
26
+ * The users of this type holding these ids, **in the order the ids were
27
+ * given** — one query when the users store implements `findUsers`, a few
28
+ * `find`s at a time when it does not. For a list of rows, where one `find`
29
+ * per row would fill the connection pool.
30
+ *
31
+ * An id `find` answers `null` for — malformed, unknown, or another type's —
32
+ * is **left out**, so the answer may be shorter than `ids`: match by
33
+ * `user.id`, never by position. A repeated id is answered once, at its
34
+ * first place. An empty list answers `[]` without reaching the store. Any
35
+ * length is read, 100 ids per query.
36
+ *
37
+ * Rejects with `STORE_FAILED` only: an absence is never an error here.
38
+ */
39
+ findMany(ids: readonly string[]): Promise<U[]>;
25
40
  /** The user of this type, or `NOT_FOUND`. */
26
41
  get(id: string): Promise<U>;
27
42
  /** One page of users of this type, in creation order. A cursor this package did not mint is `INVALID_CURSOR`. */
@@ -1 +1 @@
1
- {"version":3,"file":"user-type.d.ts","sourceRoot":"","sources":["../../../src/auth/types/user-type.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,8BAA8B,CAAC;AAC/D,OAAO,KAAK,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AAEpD,oCAAoC;AACpC,MAAM,WAAW,WAAW,CAAC,CAAC,EAAE,EAAE;IACjC;;;;;;;OAOG;IACH,MAAM,CACL,KAAK,EAAE,EAAE,GAAG;QAAE,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAA;KAAE,GACnE,OAAO,CAAC,CAAC,CAAC,CAAC;IAEd,qGAAqG;IACrG,IAAI,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;IAEpC,6CAA6C;IAC7C,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;IAE5B,iHAAiH;IACjH,IAAI,CAAC,IAAI,CAAC,EAAE;QACX,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QAC/B,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;KACxB,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC;IAE3B;;;;OAIG;IACH,MAAM,CAAC,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,CAAC,EAAE,CAAC,EAAE,OAAO,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;IAE9E,iFAAiF;IACjF,SAAS,CAAC,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;IAE9E;;;;;;;;;;;OAWG;IACH,MAAM,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CACxC"}
1
+ {"version":3,"file":"user-type.d.ts","sourceRoot":"","sources":["../../../src/auth/types/user-type.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,8BAA8B,CAAC;AAC/D,OAAO,KAAK,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AAEpD,oCAAoC;AACpC,MAAM,WAAW,WAAW,CAAC,CAAC,EAAE,EAAE;IACjC;;;;;;;OAOG;IACH,MAAM,CACL,KAAK,EAAE,EAAE,GAAG;QAAE,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAA;KAAE,GACnE,OAAO,CAAC,CAAC,CAAC,CAAC;IAEd,qGAAqG;IACrG,IAAI,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;IAEpC;;;;;;;;;;;;;OAaG;IACH,QAAQ,CAAC,GAAG,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC;IAE/C,6CAA6C;IAC7C,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;IAE5B,iHAAiH;IACjH,IAAI,CAAC,IAAI,CAAC,EAAE;QACX,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QAC/B,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;KACxB,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC;IAE3B;;;;OAIG;IACH,MAAM,CAAC,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,CAAC,EAAE,CAAC,EAAE,OAAO,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;IAE9E,iFAAiF;IACjF,SAAS,CAAC,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;IAE9E;;;;;;;;;;;OAWG;IACH,MAAM,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CACxC"}
@@ -0,0 +1,29 @@
1
+ /**
2
+ * `findMany`: several users of one type by id, in one query when the users
3
+ * store implements the optional `findUsers`, and with `findUser`, a few ids at
4
+ * a time, when it does not.
5
+ */
6
+ import type { Context } from '../context';
7
+ import type { UserRecord } from '../port/types';
8
+ /**
9
+ * The most ids one `findUsers` call is given. A longer list is read in
10
+ * several calls, one after another, so no query grows with the caller's list.
11
+ */
12
+ export declare const FIND_MANY_BATCH = 100;
13
+ /**
14
+ * How many `findUser` calls run at once when the store has no `findUsers`:
15
+ * enough to keep a 100-row list quick, few enough to leave the connection
16
+ * pool to the rest of the application.
17
+ */
18
+ export declare const FIND_MANY_CONCURRENCY = 10;
19
+ /**
20
+ * The users of this type holding these ids, **in the order the ids were
21
+ * given**, each once — at its first occurrence. An id that is malformed, held
22
+ * by nobody or held by a user of another type is left out: an absence is a
23
+ * shorter list, never a rejection. A failure throws.
24
+ *
25
+ * An empty list — or one with no well-formed id — answers `[]` without
26
+ * reaching the store.
27
+ */
28
+ export declare function findManyRecords(context: Context, ids: readonly string[], type: string, where: string): Promise<UserRecord[]>;
29
+ //# sourceMappingURL=find-many.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"find-many.d.ts","sourceRoot":"","sources":["../../../src/auth/users/find-many.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAEhD;;;GAGG;AACH,eAAO,MAAM,eAAe,MAAM,CAAC;AAEnC;;;;GAIG;AACH,eAAO,MAAM,qBAAqB,KAAK,CAAC;AAExC;;;;;;;;GAQG;AACH,wBAAsB,eAAe,CACpC,OAAO,EAAE,OAAO,EAChB,GAAG,EAAE,SAAS,MAAM,EAAE,EACtB,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,GACX,OAAO,CAAC,UAAU,EAAE,CAAC,CAuBvB"}
@@ -1 +1 @@
1
- {"version":3,"file":"record-flows.d.ts","sourceRoot":"","sources":["../../../src/auth/users/record-flows.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC;AAChC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAC9C,OAAO,EACN,KAAK,OAAO,EACZ,KAAK,OAAO,EAKZ,MAAM,YAAY,CAAC;AACpB,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAE5C,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,cAAc,CAAC;AAI1C;;;GAGG;AACH,wBAAgB,WAAW,CAC1B,OAAO,EAAE,OAAO,EAChB,IAAI,EAAE,YAAY,EAClB,EAAE,EAAE,EAAE,GACJ,WAAW,CAAC,OAAO,EAAE,KAAK,CAAC,CA0D7B"}
1
+ {"version":3,"file":"record-flows.d.ts","sourceRoot":"","sources":["../../../src/auth/users/record-flows.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC;AAChC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAC9C,OAAO,EACN,KAAK,OAAO,EACZ,KAAK,OAAO,EAKZ,MAAM,YAAY,CAAC;AACpB,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAG5C,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,cAAc,CAAC;AAI1C;;;GAGG;AACH,wBAAgB,WAAW,CAC1B,OAAO,EAAE,OAAO,EAChB,IAAI,EAAE,YAAY,EAClB,EAAE,EAAE,EAAE,GACJ,WAAW,CAAC,OAAO,EAAE,KAAK,CAAC,CAoE7B"}
@@ -2,7 +2,7 @@ import {
2
2
  JanusError2,
3
3
  InvalidCursorError2,
4
4
  StoreFailure2
5
- } from "./index-ztng6018.js";
5
+ } from "./index-kppkcbn5.js";
6
6
 
7
7
  // src/pagination/cursor-page.ts
8
8
  var DEFAULT_PAGE_SIZE2 = 20;
@@ -72,4 +72,4 @@ var UNSTORABLE = "holds a NUL character or a lone surrogate, which no store can
72
72
  export { guardStore, guardRelations, isStorable, UNSTORABLE, DEFAULT_PAGE_SIZE2, MAX_PAGE_SIZE2, pageLimit2, invalidCursor2 };
73
73
 
74
74
  //# debugId=7AD3830DC22148E664756E2164756E21
75
- //# sourceMappingURL=index-6fxq0kzf.js.map
75
+ //# sourceMappingURL=index-4khsm7mw.js.map
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  StoreConflict2,
3
3
  NotFoundError2
4
- } from "./index-ztng6018.js";
4
+ } from "./index-kppkcbn5.js";
5
5
 
6
6
  // src/ids/id.ts
7
7
  var HEX = Array.from({ length: 256 }, (_, i) => i.toString(16).padStart(2, "0"));
@@ -268,6 +268,12 @@ function memoryUserStore() {
268
268
  const stored = byId.get(id);
269
269
  return stored === undefined ? null : copy(stored);
270
270
  },
271
+ async findUsers(ids) {
272
+ return [...new Set(ids)].flatMap((id) => {
273
+ const stored = byId.get(id);
274
+ return stored === undefined ? [] : [copy(stored)];
275
+ });
276
+ },
271
277
  async findUserByLogin(type, login) {
272
278
  const id = byLogin.get(keyOf(type, login));
273
279
  const stored = id === undefined ? undefined : byId.get(id);
@@ -306,5 +312,5 @@ function createMemoryStores2() {
306
312
  }
307
313
  export { mintId2, isId2, mintedAt2, createMemoryStores2 };
308
314
 
309
- //# debugId=0777A8A648CFB0FA64756E2164756E21
310
- //# sourceMappingURL=index-7xe5x3eg.js.map
315
+ //# debugId=D2F28CB1297A405F64756E2164756E21
316
+ //# sourceMappingURL=index-6bjfv4xv.js.map
@@ -8,10 +8,10 @@
8
8
  "import type { TokenRecord, TokenStore } from '../types';\nimport { copy } from './copy';\n\n/** The token store in memory, by token hash. */\nexport function memoryTokenStore(): TokenStore {\n\tconst byTokenHash = new Map<string, TokenRecord>();\n\n\treturn {\n\t\tasync insertToken(record) {\n\t\t\tif (byTokenHash.has(record.tokenHash)) return;\n\t\t\tbyTokenHash.set(record.tokenHash, copy(record));\n\t\t},\n\n\t\tasync consumeToken(tokenHash, kind, at) {\n\t\t\t// No `await` between this read and the write below: on one event loop\n\t\t\t// that is what makes the pair a single conditional write.\n\t\t\tconst stored = byTokenHash.get(tokenHash);\n\t\t\tif (stored === undefined || stored.kind !== kind) return null;\n\n\t\t\tconst before = copy(stored);\n\t\t\tif (stored.spentAt === null) {\n\t\t\t\tbyTokenHash.set(tokenHash, { ...stored, spentAt: new Date(at) });\n\t\t\t}\n\n\t\t\treturn before;\n\t\t},\n\n\t\tasync countAttempt(tokenHash, kind) {\n\t\t\t// The same single conditional write as consumeToken: no `await`\n\t\t\t// between the read and the write.\n\t\t\tconst stored = byTokenHash.get(tokenHash);\n\t\t\tif (stored === undefined || stored.kind !== kind) return null;\n\t\t\tif (stored.spentAt !== null) return copy(stored);\n\n\t\t\tconst counted = { ...stored, attempts: stored.attempts + 1 };\n\t\t\tbyTokenHash.set(tokenHash, counted);\n\t\t\treturn copy(counted);\n\t\t},\n\n\t\tasync spendUserTokens(userId, kind, at, except) {\n\t\t\tlet spent = 0;\n\n\t\t\tfor (const [tokenHash, stored] of byTokenHash) {\n\t\t\t\tif (\n\t\t\t\t\ttokenHash !== except &&\n\t\t\t\t\tstored.userId === userId &&\n\t\t\t\t\tstored.kind === kind &&\n\t\t\t\t\tstored.spentAt === null\n\t\t\t\t) {\n\t\t\t\t\tbyTokenHash.set(tokenHash, { ...stored, spentAt: new Date(at) });\n\t\t\t\t\tspent += 1;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn spent;\n\t\t},\n\n\t\tasync deleteUserTokens(userId) {\n\t\t\tlet deleted = 0;\n\n\t\t\tfor (const [tokenHash, stored] of byTokenHash) {\n\t\t\t\tif (stored.userId === userId) {\n\t\t\t\t\tbyTokenHash.delete(tokenHash);\n\t\t\t\t\tdeleted += 1;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn deleted;\n\t\t},\n\t};\n}\n",
9
9
  "import { StoreConflict } from '../../../errors/janus-error';\nimport type { Id } from '../../../ids/id';\nimport type { UserRecord } from '../types';\n\n/** What the in-memory user store holds: the records, and the unique index on their logins. */\nexport interface UserIndex {\n\treadonly byId: Map<Id, UserRecord>;\n\t/** The unique index: (type, login) key → the id holding it. */\n\treadonly byLogin: Map<string, Id>;\n}\n\n/** The unique key of one login. `\\u0000` cannot occur in a type name the core accepts. */\nexport const keyOf = (type: string, login: string): string =>\n\t`${type}\\u0000${login}`;\n\n/** The first of `logins` held by a user of `type` other than `id`. */\nexport const takenBy = (\n\t{ byLogin }: UserIndex,\n\ttype: string,\n\tlogins: readonly string[],\n\tid: Id,\n): string | undefined =>\n\tlogins.find((login) => {\n\t\tconst holder = byLogin.get(keyOf(type, login));\n\t\treturn holder !== undefined && holder !== id;\n\t});\n\n/** The conflict a login held by another user of `type` is refused with. */\nexport const taken = (operation: string, type: string, login: string) =>\n\tnew StoreConflict(\n\t\t'login',\n\t\t`${operation}: the login is taken by another ${type}`,\n\t\t{ login, userType: type, operation },\n\t);\n\n/** Points every login of `record` at its id. */\nexport function indexLogins({ byLogin }: UserIndex, record: UserRecord): void {\n\tfor (const login of record.logins) {\n\t\tbyLogin.set(keyOf(record.type, login), record.id);\n\t}\n}\n\n/** Frees every login of `record`. */\nexport function dropLogins({ byLogin }: UserIndex, record: UserRecord): void {\n\tfor (const login of record.logins) {\n\t\tbyLogin.delete(keyOf(record.type, login));\n\t}\n}\n",
10
10
  "import { NotFoundError, StoreConflict } from '../../../errors/janus-error';\nimport type { Id } from '../../../ids/id';\nimport type { UserPatch, UserRecord } from '../types';\nimport { copy } from './copy';\nimport {\n\tdropLogins,\n\tindexLogins,\n\ttaken,\n\ttakenBy,\n\ttype UserIndex,\n} from './user-index';\n\n/**\n * `updateUser` in memory: refused for an unknown id, a version that moved or\n * a login held by another user — checked, then written, in one synchronous\n * step.\n */\nexport function updateStored(\n\tindex: UserIndex,\n\tid: Id,\n\tpatch: UserPatch,\n\tifVersion: number,\n): UserRecord {\n\tconst stored = index.byId.get(id);\n\n\tif (stored === undefined) {\n\t\tthrow new NotFoundError('updateUser: no user has this id', {\n\t\t\tuserId: id,\n\t\t\toperation: 'updateUser',\n\t\t});\n\t}\n\n\tif (stored.version !== ifVersion) {\n\t\tthrow new StoreConflict(\n\t\t\t'version',\n\t\t\t`updateUser: expected version ${ifVersion}, found ${stored.version}`,\n\t\t\t{\n\t\t\t\tuserId: id,\n\t\t\t\texpectedVersion: ifVersion,\n\t\t\t\tactualVersion: stored.version,\n\t\t\t\toperation: 'updateUser',\n\t\t\t},\n\t\t);\n\t}\n\n\tif (patch.logins !== undefined) {\n\t\tconst collision = takenBy(index, stored.type, patch.logins, id);\n\t\tif (collision !== undefined) {\n\t\t\tthrow taken('updateUser', stored.type, collision);\n\t\t}\n\t}\n\n\tconst written = applyPatch(stored, copy(patch));\n\n\tindex.byId.set(id, written);\n\tif (patch.logins !== undefined) {\n\t\tdropLogins(index, stored);\n\t\tindexLogins(index, written);\n\t}\n\n\treturn copy(written);\n}\n\n/**\n * The record a patch produces: the fields it names, replaced whole; the fields\n * it does not name, untouched.\n *\n * Reads each field by name rather than spreading the patch, so a key the port\n * does not declare — `version`, `id`, `type`, `createdAt`, or a `snake_case`\n * typo from JavaScript — never reaches the record. A key present as\n * `undefined` is absent, never an erasure.\n */\nfunction applyPatch(stored: UserRecord, patch: UserPatch): UserRecord {\n\treturn {\n\t\t...stored,\n\t\tschemaVersion: patch.schemaVersion ?? stored.schemaVersion,\n\t\tactive: patch.active ?? stored.active,\n\t\tfields: patch.fields ?? stored.fields,\n\t\tlogins: patch.logins ?? stored.logins,\n\t\tpassword: patch.password === undefined ? stored.password : patch.password,\n\t\tsecondFactor:\n\t\t\tpatch.secondFactor === undefined\n\t\t\t\t? stored.secondFactor\n\t\t\t\t: patch.secondFactor,\n\t\temailVerifiedAt:\n\t\t\tpatch.emailVerifiedAt === undefined\n\t\t\t\t? stored.emailVerifiedAt\n\t\t\t\t: patch.emailVerifiedAt,\n\t\tversion: stored.version + 1,\n\t\tupdatedAt: patch.updatedAt,\n\t};\n}\n",
11
- "import type { Id } from '../../../ids/id';\nimport type { UserRecord, UserStore } from '../types';\nimport { copy } from './copy';\nimport {\n\tdropLogins,\n\tindexLogins,\n\tkeyOf,\n\ttaken,\n\ttakenBy,\n\ttype UserIndex,\n} from './user-index';\nimport { updateStored } from './user-update';\n\n/** The user store in memory: the records by id, and the unique index on logins. */\nexport function memoryUserStore(): UserStore {\n\tconst index: UserIndex = {\n\t\tbyId: new Map<Id, UserRecord>(),\n\t\tbyLogin: new Map<string, Id>(),\n\t};\n\tconst { byId, byLogin } = index;\n\n\treturn {\n\t\tasync insertUser(record) {\n\t\t\tconst stored = byId.get(record.id);\n\t\t\tif (stored !== undefined) return copy(stored);\n\n\t\t\tconst collision = takenBy(index, record.type, record.logins, record.id);\n\t\t\tif (collision !== undefined) {\n\t\t\t\tthrow taken('insertUser', record.type, collision);\n\t\t\t}\n\n\t\t\tconst written = copy(record);\n\t\t\tbyId.set(written.id, written);\n\t\t\tindexLogins(index, written);\n\n\t\t\treturn copy(written);\n\t\t},\n\n\t\tasync findUser(id) {\n\t\t\tconst stored = byId.get(id);\n\t\t\treturn stored === undefined ? null : copy(stored);\n\t\t},\n\n\t\tasync findUserByLogin(type, login) {\n\t\t\tconst id = byLogin.get(keyOf(type, login));\n\t\t\tconst stored = id === undefined ? undefined : byId.get(id);\n\t\t\treturn stored === undefined ? null : copy(stored);\n\t\t},\n\n\t\tasync listUsers({ type, after, limit }) {\n\t\t\t// A Map keeps insertion order, not id order: a retried insert or an\n\t\t\t// id minted on another machine can land out of sequence.\n\t\t\tconst ids = [...byId.values()]\n\t\t\t\t.filter((user) => user.type === type)\n\t\t\t\t.map((user) => user.id)\n\t\t\t\t.filter((id) => after === null || id > after)\n\t\t\t\t.sort();\n\t\t\tconst pageIds = ids.slice(0, limit);\n\t\t\tconst last = pageIds.at(-1);\n\n\t\t\treturn {\n\t\t\t\titems: pageIds.map((id) => copy(byId.get(id) as UserRecord)),\n\t\t\t\tnextCursor: ids.length > limit && last !== undefined ? last : null,\n\t\t\t};\n\t\t},\n\n\t\tasync updateUser(id, patch, ifVersion) {\n\t\t\treturn updateStored(index, id, patch, ifVersion);\n\t\t},\n\n\t\tasync deleteUser(id) {\n\t\t\tconst stored = byId.get(id);\n\t\t\tif (stored === undefined) return false;\n\n\t\t\tbyId.delete(id);\n\t\t\tdropLogins(index, stored);\n\t\t\treturn true;\n\t\t},\n\t};\n}\n",
11
+ "import type { Id } from '../../../ids/id';\nimport type { UserRecord, UserStore } from '../types';\nimport { copy } from './copy';\nimport {\n\tdropLogins,\n\tindexLogins,\n\tkeyOf,\n\ttaken,\n\ttakenBy,\n\ttype UserIndex,\n} from './user-index';\nimport { updateStored } from './user-update';\n\n/** The user store in memory: the records by id, and the unique index on logins. */\nexport function memoryUserStore(): UserStore {\n\tconst index: UserIndex = {\n\t\tbyId: new Map<Id, UserRecord>(),\n\t\tbyLogin: new Map<string, Id>(),\n\t};\n\tconst { byId, byLogin } = index;\n\n\treturn {\n\t\tasync insertUser(record) {\n\t\t\tconst stored = byId.get(record.id);\n\t\t\tif (stored !== undefined) return copy(stored);\n\n\t\t\tconst collision = takenBy(index, record.type, record.logins, record.id);\n\t\t\tif (collision !== undefined) {\n\t\t\t\tthrow taken('insertUser', record.type, collision);\n\t\t\t}\n\n\t\t\tconst written = copy(record);\n\t\t\tbyId.set(written.id, written);\n\t\t\tindexLogins(index, written);\n\n\t\t\treturn copy(written);\n\t\t},\n\n\t\tasync findUser(id) {\n\t\t\tconst stored = byId.get(id);\n\t\t\treturn stored === undefined ? null : copy(stored);\n\t\t},\n\n\t\tasync findUsers(ids) {\n\t\t\treturn [...new Set(ids)].flatMap((id) => {\n\t\t\t\tconst stored = byId.get(id);\n\t\t\t\treturn stored === undefined ? [] : [copy(stored)];\n\t\t\t});\n\t\t},\n\n\t\tasync findUserByLogin(type, login) {\n\t\t\tconst id = byLogin.get(keyOf(type, login));\n\t\t\tconst stored = id === undefined ? undefined : byId.get(id);\n\t\t\treturn stored === undefined ? null : copy(stored);\n\t\t},\n\n\t\tasync listUsers({ type, after, limit }) {\n\t\t\t// A Map keeps insertion order, not id order: a retried insert or an\n\t\t\t// id minted on another machine can land out of sequence.\n\t\t\tconst ids = [...byId.values()]\n\t\t\t\t.filter((user) => user.type === type)\n\t\t\t\t.map((user) => user.id)\n\t\t\t\t.filter((id) => after === null || id > after)\n\t\t\t\t.sort();\n\t\t\tconst pageIds = ids.slice(0, limit);\n\t\t\tconst last = pageIds.at(-1);\n\n\t\t\treturn {\n\t\t\t\titems: pageIds.map((id) => copy(byId.get(id) as UserRecord)),\n\t\t\t\tnextCursor: ids.length > limit && last !== undefined ? last : null,\n\t\t\t};\n\t\t},\n\n\t\tasync updateUser(id, patch, ifVersion) {\n\t\t\treturn updateStored(index, id, patch, ifVersion);\n\t\t},\n\n\t\tasync deleteUser(id) {\n\t\t\tconst stored = byId.get(id);\n\t\t\tif (stored === undefined) return false;\n\n\t\t\tbyId.delete(id);\n\t\t\tdropLogins(index, stored);\n\t\t\treturn true;\n\t\t},\n\t};\n}\n",
12
12
  "import type { JanusStores } from '../types';\nimport { memorySessionStore } from './sessions';\nimport { memoryTokenStore } from './tokens';\nimport { memoryUserStore } from './users';\n\n/**\n * The reference implementation of the store port, in memory.\n *\n * **Shipped and documented, not a test helper.** It is what a consumer uses in\n * their own unit tests, and what an adapter author compares against when a\n * conformance case they do not understand turns red. So it keeps the six rules\n * for real rather than approximately:\n *\n * - uniqueness is a constraint — an index checked and written inside the same\n * synchronous step, which is what atomic means on one event loop;\n * - `consumeToken` reads and writes with no `await` between the two, so twenty\n * concurrent calls see exactly one unspent token;\n * - every record is **copied in and copied out**, so a caller that mutates what\n * it passed or what it got back cannot reach the store — the in-memory\n * version of \"bytes round-trip\";\n * - a patch applies only the fields it names, and only the fields the port\n * declares: a stray `version` or `id` in a patch from JavaScript is ignored,\n * not written.\n *\n * Every method is `async` even though none waits on anything: a caller that\n * forgot an `await` must fail here the way it would against a real database.\n */\nexport function createMemoryStores(): JanusStores {\n\treturn {\n\t\tusers: memoryUserStore(),\n\t\tsessions: memorySessionStore(),\n\t\ttokens: memoryTokenStore(),\n\t};\n}\n"
13
13
  ],
14
- "mappings": "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",
15
- "debugId": "0777A8A648CFB0FA64756E2164756E21",
14
+ "mappings": "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",
15
+ "debugId": "D2F28CB1297A405F64756E2164756E21",
16
16
  "names": []
17
17
  }
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  isSubjectSet2,
3
3
  formatTuple2
4
- } from "./index-ztng6018.js";
4
+ } from "./index-kppkcbn5.js";
5
5
 
6
6
  // src/permissions/port/memory.ts
7
7
  function createMemoryRelations2() {
@@ -77,4 +77,4 @@ function copyTuple(tuple) {
77
77
  export { createMemoryRelations2 };
78
78
 
79
79
  //# debugId=0BA3AA406E650E8464756E2164756E21
80
- //# sourceMappingURL=index-k136102s.js.map
80
+ //# sourceMappingURL=index-cntabs9d.js.map
@@ -80,6 +80,11 @@ class StepUpRequiredError2 extends JanusError2 {
80
80
  code = "STEP_UP_REQUIRED";
81
81
  }
82
82
 
83
+ class MailThrottledError2 extends JanusError2 {
84
+ name = "MailThrottledError";
85
+ code = "MAIL_THROTTLED";
86
+ }
87
+
83
88
  class InvalidCursorError2 extends JanusError2 {
84
89
  name = "InvalidCursorError";
85
90
  code = "INVALID_CURSOR";
@@ -122,6 +127,8 @@ function statusOf2(code) {
122
127
  case "USER_INACTIVE":
123
128
  case "STEP_UP_REQUIRED":
124
129
  return 403;
130
+ case "MAIL_THROTTLED":
131
+ return 429;
125
132
  case "UNSUPPORTED":
126
133
  return 501;
127
134
  case "PERMISSION_DEPTH":
@@ -208,7 +215,7 @@ function parseSubject2(text) {
208
215
  return relation === undefined ? { type, id } : setOf2({ type, id }, relation);
209
216
  }
210
217
 
211
- export { JanusError2, UserInvalidError2, CredentialError2, UserInactiveError2, TokenError2, SecondFactorError2, StepUpRequiredError2, InvalidCursorError2, UnsupportedError2, PermissionDepthError2, statusOf2, StoreFailure2, StoreConflict2, NotFoundError2, isSubjectSet2, subjectOf2, setOf2, isSetOf2, formatEntity2, formatSubject2, formatTuple2, parseTuple2, parseSubject2 };
218
+ export { JanusError2, UserInvalidError2, CredentialError2, UserInactiveError2, TokenError2, SecondFactorError2, StepUpRequiredError2, MailThrottledError2, InvalidCursorError2, UnsupportedError2, PermissionDepthError2, statusOf2, StoreFailure2, StoreConflict2, NotFoundError2, isSubjectSet2, subjectOf2, setOf2, isSetOf2, formatEntity2, formatSubject2, formatTuple2, parseTuple2, parseSubject2 };
212
219
 
213
- //# debugId=4E81B0D2228C154C64756E2164756E21
214
- //# sourceMappingURL=index-ztng6018.js.map
220
+ //# debugId=2BB721119E78839E64756E2164756E21
221
+ //# sourceMappingURL=index-kppkcbn5.js.map
@@ -3,13 +3,13 @@
3
3
  "sources": ["../src/errors/janus-error/base.ts", "../src/errors/janus-error/refusals.ts", "../src/errors/janus-error/status.ts", "../src/errors/janus-error/store.ts", "../src/subjects/subject.ts", "../src/subjects/notation.ts"],
4
4
  "sourcesContent": [
5
5
  "import type { JanusErrorCode } from './codes';\nimport type { CredentialRefusal, Issue, JanusErrorOptions } from './options';\n\n/**\n * The base of everything this package throws at call time.\n *\n * It extends `Error` and not `TypeError`, and the rule behind that is\n * `nxgt-data`'s: *extend whichever class the refusals it replaces already\n * threw, so no consumer's `catch` stops working*. These replace nothing — the\n * package is new — and `DataError`, `RedisError` and `S3Error` all extend\n * `Error`, so nobody has to order their `catch` blocks.\n *\n * **There is exactly one definition of this class**, and that matters more here\n * than it looks: an adapter in another package throws `StoreFailure` and this\n * package tests it with `instanceof`. Two copies and the product is wrong about\n * what an outage is. `build.ts` shares the module across entry points with\n * `splitting: true`, and `scripts/verify-artifacts.ts` fails the build if any\n * class name appears in two entry bundles of the packed tarball.\n */\nexport class JanusError extends Error {\n\toverride name = 'JanusError';\n\treadonly code: JanusErrorCode = 'STORE_FAILED';\n\treadonly userId: string | undefined;\n\treadonly userType: string | undefined;\n\treadonly login: string | undefined;\n\treadonly reason: CredentialRefusal | undefined;\n\treadonly hashPrefix: string | undefined;\n\treadonly expectedVersion: number | undefined;\n\treadonly actualVersion: number | undefined;\n\treadonly issues: readonly Issue[] | undefined;\n\treadonly minLength: number | undefined;\n\treadonly operation: string | undefined;\n\treadonly slot: 'users' | 'sessions' | 'tokens' | 'relations' | undefined;\n\treadonly permission: string | undefined;\n\treadonly maxDepth: number | undefined;\n\treadonly attemptsLeft: number | undefined;\n\treadonly retryAfter: number | undefined;\n\n\tconstructor(message: string, options?: JanusErrorOptions) {\n\t\tsuper(message, { cause: options?.cause });\n\t\tthis.userId = options?.userId;\n\t\tthis.userType = options?.userType;\n\t\tthis.login = options?.login;\n\t\tthis.reason = options?.reason;\n\t\tthis.hashPrefix = options?.hashPrefix;\n\t\tthis.expectedVersion = options?.expectedVersion;\n\t\tthis.actualVersion = options?.actualVersion;\n\t\tthis.issues = options?.issues;\n\t\tthis.minLength = options?.minLength;\n\t\tthis.operation = options?.operation;\n\t\tthis.slot = options?.slot;\n\t\tthis.permission = options?.permission;\n\t\tthis.maxDepth = options?.maxDepth;\n\t\tthis.attemptsLeft = options?.attemptsLeft;\n\t\tthis.retryAfter = options?.retryAfter;\n\t}\n}\n",
6
- "import { JanusError } from './base';\nimport type { JanusErrorCode } from './codes';\nimport type { JanusErrorOptions } from './options';\n\n/** The fields failed the user type's schema. */\nexport class UserInvalidError extends JanusError {\n\toverride name = 'UserInvalidError';\n\toverride readonly code = 'USER_INVALID' as const;\n}\n\n/** A password too short, credentials that do not match, or a hash format nobody reads. */\nexport class CredentialError extends JanusError {\n\toverride name = 'CredentialError';\n\toverride readonly code: JanusErrorCode;\n\n\tconstructor(\n\t\tcode: Extract<\n\t\t\tJanusErrorCode,\n\t\t\t'PASSWORD_TOO_SHORT' | 'CREDENTIALS_INVALID' | 'HASH_UNSUPPORTED'\n\t\t>,\n\t\tmessage: string,\n\t\toptions?: JanusErrorOptions,\n\t) {\n\t\tsuper(message, options);\n\t\tthis.code = code;\n\t}\n}\n\n/** The user is inactive, and the password given was the right one. */\nexport class UserInactiveError extends JanusError {\n\toverride name = 'UserInactiveError';\n\toverride readonly code = 'USER_INACTIVE' as const;\n}\n\n/**\n * A one-time token that is unknown, already spent, lapsed, or sent to an\n * e-mail the user no longer has — or a one-time code that does not match.\n */\nexport class TokenError extends JanusError {\n\toverride name = 'TokenError';\n\toverride readonly code: JanusErrorCode;\n\n\tconstructor(\n\t\tcode: Extract<\n\t\t\tJanusErrorCode,\n\t\t\t| 'TOKEN_UNKNOWN'\n\t\t\t| 'TOKEN_SPENT'\n\t\t\t| 'TOKEN_EXPIRED'\n\t\t\t| 'TOKEN_STALE'\n\t\t\t| 'CODE_INVALID'\n\t\t>,\n\t\tmessage: string,\n\t\toptions?: JanusErrorOptions,\n\t) {\n\t\tsuper(message, options);\n\t\tthis.code = code;\n\t}\n}\n\n/** A second factor asked to change from a state it is not in. */\nexport class SecondFactorError extends JanusError {\n\toverride name = 'SecondFactorError';\n\toverride readonly code: JanusErrorCode;\n\n\tconstructor(\n\t\tcode: Extract<\n\t\t\tJanusErrorCode,\n\t\t\t'SECOND_FACTOR_NOT_ENROLLED' | 'SECOND_FACTOR_ACTIVE'\n\t\t>,\n\t\tmessage: string,\n\t\toptions?: JanusErrorOptions,\n\t) {\n\t\tsuper(message, options);\n\t\tthis.code = code;\n\t}\n}\n\n/**\n * The session proved who it is longer ago than the action asks: confirm it\n * with a step-up, then send the request again.\n */\nexport class StepUpRequiredError extends JanusError {\n\toverride name = 'StepUpRequiredError';\n\toverride readonly code = 'STEP_UP_REQUIRED' as const;\n}\n\n/** A cursor this store did not mint, or one for another ordering. */\nexport class InvalidCursorError extends JanusError {\n\toverride name = 'InvalidCursorError';\n\toverride readonly code = 'INVALID_CURSOR' as const;\n}\n\n/** The wired store does not implement the optional capability asked for. */\nexport class UnsupportedError extends JanusError {\n\toverride name = 'UnsupportedError';\n\toverride readonly code = 'UNSUPPORTED' as const;\n}\n\n/** A permission check walked deeper than `maxDepth` without an answer. */\nexport class PermissionDepthError extends JanusError {\n\toverride name = 'PermissionDepthError';\n\toverride readonly code = 'PERMISSION_DEPTH' as const;\n}\n",
7
- "import type { JanusErrorCode } from './codes';\n\n/**\n * Every HTTP status `statusOf` answers: a union of literals, so a framework\n * whose response takes a narrower type than `number` accepts it as it is.\n */\nexport type JanusErrorStatus = 400 | 401 | 403 | 404 | 409 | 500 | 501 | 503;\n\n/**\n * The HTTP status each code deserves — the one table the integrations share,\n * so a Hono route and a GraphQL field answer the same code the same way.\n * Exhaustive: a code added to `JanusErrorCode` stops this file compiling\n * instead of answering `undefined`.\n *\n * `STORE_FAILED` is 503 and nothing else — **an outage is not a negative\n * answer**, and a 401 or a 404 would tell every user they do not exist.\n *\n * ```ts\n * if (error instanceof JanusError) return Response.json({ code: error.code }, { status: statusOf(error.code) });\n * ```\n */\nexport function statusOf(code: JanusErrorCode): JanusErrorStatus {\n\tswitch (code) {\n\t\tcase 'STORE_FAILED':\n\t\t\treturn 503;\n\t\tcase 'NOT_FOUND':\n\t\t\treturn 404;\n\t\tcase 'LOGIN_TAKEN':\n\t\tcase 'VERSION_CONFLICT':\n\t\tcase 'SECOND_FACTOR_NOT_ENROLLED':\n\t\tcase 'SECOND_FACTOR_ACTIVE':\n\t\t\treturn 409;\n\t\tcase 'USER_INVALID':\n\t\tcase 'PASSWORD_TOO_SHORT':\n\t\tcase 'HASH_UNSUPPORTED':\n\t\tcase 'INVALID_CURSOR':\n\t\tcase 'TOKEN_UNKNOWN':\n\t\tcase 'TOKEN_SPENT':\n\t\tcase 'TOKEN_EXPIRED':\n\t\tcase 'TOKEN_STALE':\n\t\t\treturn 400;\n\t\tcase 'CREDENTIALS_INVALID':\n\t\tcase 'CODE_INVALID':\n\t\t\treturn 401;\n\t\tcase 'USER_INACTIVE':\n\t\tcase 'STEP_UP_REQUIRED':\n\t\t\treturn 403;\n\t\tcase 'UNSUPPORTED':\n\t\t\treturn 501;\n\t\tcase 'PERMISSION_DEPTH':\n\t\t\treturn 500;\n\t}\n}\n",
6
+ "import { JanusError } from './base';\nimport type { JanusErrorCode } from './codes';\nimport type { JanusErrorOptions } from './options';\n\n/** The fields failed the user type's schema. */\nexport class UserInvalidError extends JanusError {\n\toverride name = 'UserInvalidError';\n\toverride readonly code = 'USER_INVALID' as const;\n}\n\n/** A password too short, credentials that do not match, or a hash format nobody reads. */\nexport class CredentialError extends JanusError {\n\toverride name = 'CredentialError';\n\toverride readonly code: JanusErrorCode;\n\n\tconstructor(\n\t\tcode: Extract<\n\t\t\tJanusErrorCode,\n\t\t\t'PASSWORD_TOO_SHORT' | 'CREDENTIALS_INVALID' | 'HASH_UNSUPPORTED'\n\t\t>,\n\t\tmessage: string,\n\t\toptions?: JanusErrorOptions,\n\t) {\n\t\tsuper(message, options);\n\t\tthis.code = code;\n\t}\n}\n\n/** The user is inactive, and the password given was the right one. */\nexport class UserInactiveError extends JanusError {\n\toverride name = 'UserInactiveError';\n\toverride readonly code = 'USER_INACTIVE' as const;\n}\n\n/**\n * A one-time token that is unknown, already spent, lapsed, or sent to an\n * e-mail the user no longer has — or a one-time code that does not match.\n */\nexport class TokenError extends JanusError {\n\toverride name = 'TokenError';\n\toverride readonly code: JanusErrorCode;\n\n\tconstructor(\n\t\tcode: Extract<\n\t\t\tJanusErrorCode,\n\t\t\t| 'TOKEN_UNKNOWN'\n\t\t\t| 'TOKEN_SPENT'\n\t\t\t| 'TOKEN_EXPIRED'\n\t\t\t| 'TOKEN_STALE'\n\t\t\t| 'CODE_INVALID'\n\t\t>,\n\t\tmessage: string,\n\t\toptions?: JanusErrorOptions,\n\t) {\n\t\tsuper(message, options);\n\t\tthis.code = code;\n\t}\n}\n\n/** A second factor asked to change from a state it is not in. */\nexport class SecondFactorError extends JanusError {\n\toverride name = 'SecondFactorError';\n\toverride readonly code: JanusErrorCode;\n\n\tconstructor(\n\t\tcode: Extract<\n\t\t\tJanusErrorCode,\n\t\t\t'SECOND_FACTOR_NOT_ENROLLED' | 'SECOND_FACTOR_ACTIVE'\n\t\t>,\n\t\tmessage: string,\n\t\toptions?: JanusErrorOptions,\n\t) {\n\t\tsuper(message, options);\n\t\tthis.code = code;\n\t}\n}\n\n/**\n * The session proved who it is longer ago than the action asks: confirm it\n * with a step-up, then send the request again.\n */\nexport class StepUpRequiredError extends JanusError {\n\toverride name = 'StepUpRequiredError';\n\toverride readonly code = 'STEP_UP_REQUIRED' as const;\n}\n\n/**\n * Too many e-mails asked for one address, or one user, in this window:\n * nothing was issued. Wait `retryAfter` seconds, then ask again.\n */\nexport class MailThrottledError extends JanusError {\n\toverride name = 'MailThrottledError';\n\toverride readonly code = 'MAIL_THROTTLED' as const;\n}\n\n/** A cursor this store did not mint, or one for another ordering. */\nexport class InvalidCursorError extends JanusError {\n\toverride name = 'InvalidCursorError';\n\toverride readonly code = 'INVALID_CURSOR' as const;\n}\n\n/** The wired store does not implement the optional capability asked for. */\nexport class UnsupportedError extends JanusError {\n\toverride name = 'UnsupportedError';\n\toverride readonly code = 'UNSUPPORTED' as const;\n}\n\n/** A permission check walked deeper than `maxDepth` without an answer. */\nexport class PermissionDepthError extends JanusError {\n\toverride name = 'PermissionDepthError';\n\toverride readonly code = 'PERMISSION_DEPTH' as const;\n}\n",
7
+ "import type { JanusErrorCode } from './codes';\n\n/**\n * Every HTTP status `statusOf` answers: a union of literals, so a framework\n * whose response takes a narrower type than `number` accepts it as it is.\n */\nexport type JanusErrorStatus =\n\t| 400\n\t| 401\n\t| 403\n\t| 404\n\t| 409\n\t| 429\n\t| 500\n\t| 501\n\t| 503;\n\n/**\n * The HTTP status each code deserves — the one table the integrations share,\n * so a Hono route and a GraphQL field answer the same code the same way.\n * Exhaustive: a code added to `JanusErrorCode` stops this file compiling\n * instead of answering `undefined`.\n *\n * `STORE_FAILED` is 503 and nothing else — **an outage is not a negative\n * answer**, and a 401 or a 404 would tell every user they do not exist.\n *\n * ```ts\n * if (error instanceof JanusError) return Response.json({ code: error.code }, { status: statusOf(error.code) });\n * ```\n */\nexport function statusOf(code: JanusErrorCode): JanusErrorStatus {\n\tswitch (code) {\n\t\tcase 'STORE_FAILED':\n\t\t\treturn 503;\n\t\tcase 'NOT_FOUND':\n\t\t\treturn 404;\n\t\tcase 'LOGIN_TAKEN':\n\t\tcase 'VERSION_CONFLICT':\n\t\tcase 'SECOND_FACTOR_NOT_ENROLLED':\n\t\tcase 'SECOND_FACTOR_ACTIVE':\n\t\t\treturn 409;\n\t\tcase 'USER_INVALID':\n\t\tcase 'PASSWORD_TOO_SHORT':\n\t\tcase 'HASH_UNSUPPORTED':\n\t\tcase 'INVALID_CURSOR':\n\t\tcase 'TOKEN_UNKNOWN':\n\t\tcase 'TOKEN_SPENT':\n\t\tcase 'TOKEN_EXPIRED':\n\t\tcase 'TOKEN_STALE':\n\t\t\treturn 400;\n\t\tcase 'CREDENTIALS_INVALID':\n\t\tcase 'CODE_INVALID':\n\t\t\treturn 401;\n\t\tcase 'USER_INACTIVE':\n\t\tcase 'STEP_UP_REQUIRED':\n\t\t\treturn 403;\n\t\tcase 'MAIL_THROTTLED':\n\t\t\treturn 429;\n\t\tcase 'UNSUPPORTED':\n\t\t\treturn 501;\n\t\tcase 'PERMISSION_DEPTH':\n\t\t\treturn 500;\n\t}\n}\n",
8
8
  "import { JanusError } from './base';\nimport type { JanusErrorCode } from './codes';\nimport type { JanusErrorOptions } from './options';\n\n/**\n * The store could not answer.\n *\n * **This is the class an adapter throws**, and it is exported for that reason:\n * an adapter defines no error class of its own, so `instanceof` holds across\n * the two packages. Any other throw from a store is treated as a failure too —\n * throwing this one is how an adapter says so precisely, and sets `cause`.\n */\nexport class StoreFailure extends JanusError {\n\toverride name = 'StoreFailure';\n\toverride readonly code = 'STORE_FAILED' as const;\n}\n\n/**\n * A uniqueness or a version constraint the store refused.\n *\n * Also thrown by an adapter, and also for the `instanceof` reason. `on` says\n * which constraint, because the two are answered differently: a login\n * collision is the caller's to fix, a version conflict is a retry.\n */\nexport class StoreConflict extends JanusError {\n\toverride name = 'StoreConflict';\n\toverride readonly code: JanusErrorCode;\n\treadonly on: 'login' | 'version';\n\n\tconstructor(\n\t\ton: 'login' | 'version',\n\t\tmessage: string,\n\t\toptions?: JanusErrorOptions,\n\t) {\n\t\tsuper(message, options);\n\t\tthis.on = on;\n\t\tthis.code = on === 'login' ? 'LOGIN_TAKEN' : 'VERSION_CONFLICT';\n\t}\n}\n\n/** There is no such record, and the store said so. */\nexport class NotFoundError extends JanusError {\n\toverride name = 'NotFoundError';\n\toverride readonly code = 'NOT_FOUND' as const;\n}\n",
9
9
  "/**\n * The id every decision in this package hangs on: a user's `id`, as `janus()`\n * mints it.\n *\n * In Ory, the equality between a Kratos identity id and Keto's `subject_id` is\n * a comment and a convention, restated in three repositories and enforced\n * nowhere. Here a user **is** a subject — see {@link subjectOf} — and that\n * shared vocabulary is the whole reason users and permissions are one package\n * rather than two: two packages would make this contract implicit, and an\n * implicit contract between independently versioned packages breaks silently.\n *\n * Opaque: compared with `===`, carried in a URL, logged, never parsed.\n */\nexport type SubjectId = string;\n\n/**\n * Something a permission is about or held by — a user, a record, a team — by\n * its type and its id.\n *\n * **Typed, unlike Keto's subjects.** One application has patients and staff,\n * and an object can hold a relation too (a record's team), so an id alone does\n * not say who. `type` is a user type of `janus()` or an object type of the\n * permission model, and the same word as a user's own `type`.\n */\nexport interface Entity {\n\treadonly type: string;\n\treadonly id: string;\n}\n\n/**\n * Everyone who holds `relation` on an entity — `team:t1#member` — which is how\n * a permission is inherited rather than granted.\n *\n * A tuple whose subject is a subject set lets a whole group be given access\n * with one write: granting a record's `viewer` to `team:t1#member` means every\n * member of that team can view it, and no member holds a tuple on the record.\n */\nexport interface SubjectSet extends Entity {\n\treadonly relation: string;\n}\n\n/**\n * Who a tuple is about: one entity, or everyone who holds a relation on one.\n * {@link isSubjectSet} tells them apart.\n */\nexport type Subject = Entity | SubjectSet;\n\n/**\n * A relation tuple: `subject` holds `relation` on `object`.\n *\n * `relation` is Zanzibar's word, and a tuple is Zanzibar's unit. What is not\n * carried over is Keto's `namespace`/`object` pair: here the object is an\n * {@link Entity}, with the `type` and `id` a user already has.\n */\nexport interface RelationTuple {\n\treadonly object: Entity;\n\treadonly relation: string;\n\treadonly subject: Subject;\n}\n\n/**\n * Whether this subject is a set rather than one entity. Narrows.\n *\n * It reads the shape, so pass a user through {@link subjectOf} first: a user\n * whose fields include a string `relation` would otherwise read as a set.\n */\nexport function isSubjectSet(subject: Subject): subject is SubjectSet {\n\treturn typeof (subject as { relation?: unknown }).relation === 'string';\n}\n\n/**\n * The subject a user is: their `type` and `id`, and nothing else.\n *\n * One line, and the entire join between the two sides of the package. It\n * takes the narrowest shape it reads, so the permissions side never has to\n * know what a user is, and it copies those two fields so none of the user's\n * own fields ever reaches a tuple.\n */\nexport function subjectOf(user: {\n\treadonly type: string;\n\treadonly id: SubjectId;\n}): Entity {\n\treturn { type: user.type, id: user.id };\n}\n\n/**\n * The mark `setOf()` puts on a set: a symbol property, so it survives a spread\n * and `Object.assign`, and no value read from a database or from JSON can\n * carry it. Registered with `Symbol.for`, so two copies of this module — two\n * bundles, two entry points — still agree on it.\n */\nconst SET_OF: unique symbol = Symbol.for('@nxgt/janus/setOf');\n\n/**\n * A subject set `setOf()` made: everyone who holds `relation` on `type:id`.\n *\n * Marked, because a user is passed to `can()` and `grant()` as it is, fields\n * flat on it: a user whose fields include `relation` must stay that user, and\n * never read as the set of whoever holds that relation on them. For an object\n * type, `{ type, id, relation }` is a set as written; for a user type — one\n * the model also declares as an object type — only `setOf()` makes one.\n *\n * A spread keeps the mark. `JSON.stringify` and `structuredClone` drop it:\n * through either, a set comes back as a user — call `setOf()` again, or\n * `parseSubject()` on its notation.\n */\nexport type SetOf<\n\tType extends string = string,\n\tRelation extends string = string,\n> = SubjectSet & {\n\treadonly type: Type;\n\treadonly relation: Relation;\n\treadonly [SET_OF]: true;\n};\n\n/**\n * A user or an object, never a set `setOf()` made: where a relation admits\n * `staff` but not `staff#managers`, a set passed there is refused at compile\n * time as it is at run time.\n */\nexport type NotASet = { readonly [SET_OF]?: never };\n\n/**\n * Everyone who holds `relation` on this user or object — `staff:s1#managers`.\n *\n * ```ts\n * await access.grant(record, 'viewers', setOf(ada, 'managers'));\n * ```\n *\n * Copies `type` and `id` only, like {@link subjectOf}: none of a user's own\n * fields reaches a tuple.\n */\nexport function setOf<const Type extends string, const Relation extends string>(\n\tentity: { readonly type: Type; readonly id: SubjectId },\n\trelation: Relation,\n): SetOf<Type, Relation> {\n\tif (\n\t\ttypeof entity !== 'object' ||\n\t\tentity === null ||\n\t\ttypeof entity.type !== 'string' ||\n\t\ttypeof entity.id !== 'string'\n\t) {\n\t\tthrow new TypeError('setOf: pass a user or { type, id }, then a relation');\n\t}\n\tif (typeof relation !== 'string' || relation === '') {\n\t\tthrow new TypeError('setOf: the relation must be a non-empty string');\n\t}\n\treturn Object.freeze({\n\t\ttype: entity.type,\n\t\tid: entity.id,\n\t\trelation,\n\t\t[SET_OF]: true as const,\n\t});\n}\n\n/**\n * Whether `setOf()` made this value, or a spread of one — what `can()` and\n * `grant()` read to tell a set on a user type from a user.\n */\nexport function isSetOf(value: unknown): value is SetOf {\n\treturn (\n\t\ttypeof value === 'object' &&\n\t\tvalue !== null &&\n\t\t(value as { readonly [SET_OF]?: unknown })[SET_OF] === true\n\t);\n}\n",
10
10
  "import {\n\ttype Entity,\n\tisSubjectSet,\n\ttype RelationTuple,\n\ttype SetOf,\n\ttype Subject,\n\tsetOf,\n} from './subject';\n\n/**\n * Zanzibar's notation, with typed subjects:\n *\n * ```\n * record:r1#viewer@staff:u1\n * record:r1#viewer@team:t1#member\n * ```\n *\n * It exists for **messages, logs and documentation**, not as a wire format:\n * nothing in this package parses a tuple off the network, and a tuple that\n * crosses a boundary crosses it as an object. Keeping the notation is worth it\n * because every piece of Zanzibar writing uses it, so an error message in it is\n * an error message a reader has already learned to read.\n *\n * A type holds no `:`, and no part holds `@`, `#` or a parenthesis, so a\n * subject set needs no parentheses: after the `@`, a `#` can only begin its\n * relation. {@link parseTuple} refuses a string where that would not hold,\n * rather than reading it two ways.\n */\nexport function formatEntity(entity: Entity): string {\n\treturn `${entity.type}:${entity.id}`;\n}\n\n/** One subject: `staff:u1`, or `team:t1#member`. */\nexport function formatSubject(subject: Subject): string {\n\treturn isSubjectSet(subject)\n\t\t? `${formatEntity(subject)}#${subject.relation}`\n\t\t: formatEntity(subject);\n}\n\n/** One relation tuple, in the notation above. */\nexport function formatTuple(tuple: RelationTuple): string {\n\treturn `${formatEntity(tuple.object)}#${tuple.relation}@${formatSubject(tuple.subject)}`;\n}\n\nconst TYPE = '([^:@#()]+)';\nconst ID = '([^@#()]+)';\nconst RELATION = '([^:@#()]+)';\n\nconst TUPLE = new RegExp(`^${TYPE}:${ID}#${RELATION}@(.+)$`);\nconst SUBJECT = new RegExp(`^${TYPE}:${ID}(?:#${RELATION})?$`);\n\n/**\n * Reads a tuple back. Refuses, with a `TypeError`, a string that is not one —\n * a permission question built from a malformed string is a question whose\n * answer means nothing, and no request is behind it: the string came from a\n * developer's own code.\n */\nexport function parseTuple(text: string): RelationTuple {\n\tconst match = TUPLE.exec(text);\n\n\tif (!match) {\n\t\tthrow new TypeError(\n\t\t\t`parseTuple: \"${text}\" is not a relation tuple; expected type:id#relation@subject`,\n\t\t);\n\t}\n\n\tconst [, type, id, relation, subject] = match as unknown as [\n\t\tstring,\n\t\tstring,\n\t\tstring,\n\t\tstring,\n\t\tstring,\n\t];\n\n\treturn { object: { type, id }, relation, subject: parseSubject(subject) };\n}\n\n/**\n * Reads one subject back: `staff:u1`, or `team:t1#member`. A set is answered\n * as `setOf()` makes it, so `can()` and `grant()` read it as the set it names\n * on a user type too.\n */\nexport function parseSubject(text: string): Entity | SetOf {\n\tconst match = SUBJECT.exec(text);\n\n\tif (!match) {\n\t\tthrow new TypeError(\n\t\t\t`parseSubject: \"${text}\" is not a subject; expected type:id, or type:id#relation for a subject set`,\n\t\t);\n\t}\n\n\tconst [, type, id, relation] = match as unknown as [\n\t\tstring,\n\t\tstring,\n\t\tstring,\n\t\tstring | undefined,\n\t];\n\n\treturn relation === undefined ? { type, id } : setOf({ type, id }, relation);\n}\n"
11
11
  ],
12
- "mappings": "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",
13
- "debugId": "4E81B0D2228C154C64756E2164756E21",
12
+ "mappings": "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",
13
+ "debugId": "2BB721119E78839E64756E2164756E21",
14
14
  "names": []
15
15
  }
@@ -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;AAiEzE,eAAO,MAAM,WAAW,EAAE,SAAS,eAAe,EA2FjD,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;AAkEzE,eAAO,MAAM,WAAW,EAAE,SAAS,eAAe,EAuGjD,CAAC"}
@@ -0,0 +1,8 @@
1
+ import type { ConformanceCase } from '../../types';
2
+ /**
3
+ * The optional `findUsers`: several users in one query. Skipped, with the
4
+ * reason, for a store that does not implement it — the core then reads with
5
+ * `findUser`.
6
+ */
7
+ export declare const userBatchCases: readonly ConformanceCase[];
8
+ //# sourceMappingURL=batch.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"batch.d.ts","sourceRoot":"","sources":["../../../../src/conformance/cases/users/batch.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAOnD;;;;GAIG;AACH,eAAO,MAAM,cAAc,EAAE,SAAS,eAAe,EAgDpD,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/conformance/cases/users/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAQnD,qEAAqE;AACrE,eAAO,MAAM,cAAc,EAAE,SAAS,eAAe,EAOpD,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/conformance/cases/users/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AASnD,qEAAqE;AACrE,eAAO,MAAM,cAAc,EAAE,SAAS,eAAe,EAQpD,CAAC"}
@@ -5,6 +5,7 @@ export declare const allCases: readonly ConformanceCase[];
5
5
  export declare const SKIP_REASONS: {
6
6
  readonly faults: "faults not provided: the outage invariant is not proven for this adapter";
7
7
  readonly deleteExpiredSessions: "stores.sessions does not implement the optional deleteExpiredSessions";
8
+ readonly findUsers: "stores.users does not implement the optional findUsers: findMany reads with findUser instead";
8
9
  };
9
10
  /**
10
11
  * Runs one case against one freshly opened set of stores, and closes them,
@@ -50,7 +51,7 @@ interface DescribedCase {
50
51
  readonly id: string;
51
52
  readonly group: string;
52
53
  readonly name: string;
53
- readonly needs?: string;
54
+ readonly needs?: string | readonly string[];
54
55
  }
55
56
  /**
56
57
  * Describes one suite's cases, grouped, under a runner. Shared by every suite
@@ -1 +1 @@
1
- {"version":3,"file":"describe.d.ts","sourceRoot":"","sources":["../../src/conformance/describe.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACX,eAAe,EACf,kBAAkB,EAClB,iBAAiB,EAEjB,MAAM,SAAS,CAAC;AAEjB,mDAAmD;AACnD,eAAO,MAAM,QAAQ,EAAE,SAAS,eAAe,EAK9C,CAAC;AAEF,uFAAuF;AACvF,eAAO,MAAM,YAAY;;;CAKf,CAAC;AAEX;;;;;;GAMG;AACH,wBAAsB,OAAO,CAC5B,eAAe,EAAE,eAAe,EAChC,OAAO,EAAE,kBAAkB,GACzB,OAAO,CAAC;IAAE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,QAAQ,CAAC,MAAM,EAAE,IAAI,CAAA;CAAE,CAAC,CAsBnE;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE;IAC5C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,kBAAkB,CAAC;IACrC,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,8EAA8E;IAC9E,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC;CAC1B,GAAG,IAAI,CASP;AAED,oEAAoE;AACpE,UAAU,aAAa;IACtB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;CACxB;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,CAAC,SAAS,aAAa,EAAE,OAAO,EAAE;IAC/D,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAC,EAAE,CAAC;IAC7B,QAAQ,CAAC,GAAG,EAAE,CACb,eAAe,EAAE,CAAC,KACd,OAAO,CAAC;QAAE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;KAAE,GAAG;QAAE,QAAQ,CAAC,MAAM,EAAE,IAAI,CAAA;KAAE,CAAC,CAAC;IACvE,QAAQ,CAAC,MAAM,EAAE,iBAAiB,CAAC;IACnC,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAChD,QAAQ,CAAC,MAAM,EAAE,OAAO,GAAG,SAAS,CAAC;CACrC,GAAG,IAAI,CA0CP;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,iBAAiB,CAgB5D"}
1
+ {"version":3,"file":"describe.d.ts","sourceRoot":"","sources":["../../src/conformance/describe.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAEX,eAAe,EACf,kBAAkB,EAClB,iBAAiB,EAEjB,MAAM,SAAS,CAAC;AAEjB,mDAAmD;AACnD,eAAO,MAAM,QAAQ,EAAE,SAAS,eAAe,EAK9C,CAAC;AAEF,uFAAuF;AACvF,eAAO,MAAM,YAAY;;;;CAOf,CAAC;AAEX;;;;;;GAMG;AACH,wBAAsB,OAAO,CAC5B,eAAe,EAAE,eAAe,EAChC,OAAO,EAAE,kBAAkB,GACzB,OAAO,CAAC;IAAE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,QAAQ,CAAC,MAAM,EAAE,IAAI,CAAA;CAAE,CAAC,CAiBnE;AAoBD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE;IAC5C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,kBAAkB,CAAC;IACrC,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,8EAA8E;IAC9E,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC;CAC1B,GAAG,IAAI,CASP;AAED,oEAAoE;AACpE,UAAU,aAAa;IACtB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,CAAC;CAC5C;AAQD;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,CAAC,SAAS,aAAa,EAAE,OAAO,EAAE;IAC/D,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAC,EAAE,CAAC;IAC7B,QAAQ,CAAC,GAAG,EAAE,CACb,eAAe,EAAE,CAAC,KACd,OAAO,CAAC;QAAE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;KAAE,GAAG;QAAE,QAAQ,CAAC,MAAM,EAAE,IAAI,CAAA;KAAE,CAAC,CAAC;IACvE,QAAQ,CAAC,MAAM,EAAE,iBAAiB,CAAC;IACnC,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAChD,QAAQ,CAAC,MAAM,EAAE,OAAO,GAAG,SAAS,CAAC;CACrC,GAAG,IAAI,CA6CP;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,iBAAiB,CAgB5D"}
@@ -29,5 +29,5 @@ export { userStoreCases } from './cases/users';
29
29
  export { allCases, describeJanusStores, runCase, SKIP_REASONS, } from './describe';
30
30
  export { referenceHarness } from './reference';
31
31
  export { allRelationCases, describeRelationStores, type OpenedRelations, type RelationCase, type RelationContext, type RelationFaults, type RelationHarness, type RelationMethod, referenceRelationHarness, relationOutageCases, relationStoreCases, runRelationCase, } from './relations';
32
- export type { CaseContext, ConformanceCase, ConformanceHarness, ConformanceRunner, OpenedStores, PortMethod, StoreFaults, } from './types';
32
+ export type { CaseContext, CaseNeed, ConformanceCase, ConformanceHarness, ConformanceRunner, OpenedStores, PortMethod, StoreFaults, } from './types';
33
33
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/conformance/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAC7C,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC/C,OAAO,EACN,QAAQ,EACR,mBAAmB,EACnB,OAAO,EACP,YAAY,GACZ,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,EACN,gBAAgB,EAChB,sBAAsB,EACtB,KAAK,eAAe,EACpB,KAAK,YAAY,EACjB,KAAK,eAAe,EACpB,KAAK,cAAc,EACnB,KAAK,eAAe,EACpB,KAAK,cAAc,EACnB,wBAAwB,EACxB,mBAAmB,EACnB,kBAAkB,EAClB,eAAe,GACf,MAAM,aAAa,CAAC;AACrB,YAAY,EACX,WAAW,EACX,eAAe,EACf,kBAAkB,EAClB,iBAAiB,EACjB,YAAY,EACZ,UAAU,EACV,WAAW,GACX,MAAM,SAAS,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/conformance/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAC7C,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC/C,OAAO,EACN,QAAQ,EACR,mBAAmB,EACnB,OAAO,EACP,YAAY,GACZ,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,EACN,gBAAgB,EAChB,sBAAsB,EACtB,KAAK,eAAe,EACpB,KAAK,YAAY,EACjB,KAAK,eAAe,EACpB,KAAK,cAAc,EACnB,KAAK,eAAe,EACpB,KAAK,cAAc,EACnB,wBAAwB,EACxB,mBAAmB,EACnB,kBAAkB,EAClB,eAAe,GACf,MAAM,aAAa,CAAC;AACrB,YAAY,EACX,WAAW,EACX,QAAQ,EACR,eAAe,EACf,kBAAkB,EAClB,iBAAiB,EACjB,YAAY,EACZ,UAAU,EACV,WAAW,GACX,MAAM,SAAS,CAAC"}