@nxgt/janus 0.24.0 → 0.26.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.
- package/README.md +39 -12
- package/dist/auth/config/reserved.d.ts +1 -1
- package/dist/auth/config/reserved.d.ts.map +1 -1
- package/dist/auth/email-flows/any-type-change-email.d.ts +18 -0
- package/dist/auth/email-flows/any-type-change-email.d.ts.map +1 -0
- package/dist/auth/email-flows/change-email-token.d.ts +6 -1
- package/dist/auth/email-flows/change-email-token.d.ts.map +1 -1
- package/dist/auth/email-flows/change-email.d.ts +6 -0
- package/dist/auth/email-flows/change-email.d.ts.map +1 -1
- package/dist/auth/index.d.ts +1 -1
- package/dist/auth/index.d.ts.map +1 -1
- package/dist/auth/janus.d.ts.map +1 -1
- package/dist/auth/outage.d.ts +2 -2
- package/dist/auth/port/assert-stores.d.ts.map +1 -1
- package/dist/auth/port/memory/tokens.d.ts.map +1 -1
- package/dist/auth/port/types/stores.d.ts +2 -0
- package/dist/auth/port/types/stores.d.ts.map +1 -1
- package/dist/auth/port/types/tokens.d.ts +12 -0
- package/dist/auth/port/types/tokens.d.ts.map +1 -1
- package/dist/auth/sessions/collect-expired.d.ts +14 -0
- package/dist/auth/sessions/collect-expired.d.ts.map +1 -0
- package/dist/auth/sessions/shared-api.d.ts +1 -1
- package/dist/auth/sessions/shared-api.d.ts.map +1 -1
- package/dist/auth/types/change-email.d.ts +31 -0
- package/dist/auth/types/change-email.d.ts.map +1 -1
- package/dist/auth/types/index.d.ts +1 -1
- package/dist/auth/types/index.d.ts.map +1 -1
- package/dist/auth/types/janus.d.ts +13 -5
- package/dist/auth/types/janus.d.ts.map +1 -1
- package/dist/chunks/{index-6bjfv4xv.js → index-q3w3vr69.js} +13 -3
- package/dist/chunks/{index-6bjfv4xv.js.map → index-q3w3vr69.js.map} +3 -3
- package/dist/chunks/{index-cntabs9d.js → index-rpp0bw6e.js} +2 -2
- package/dist/chunks/{index-kppkcbn5.js → index-spwh8b9z.js} +2 -5
- package/dist/chunks/{index-kppkcbn5.js.map → index-spwh8b9z.js.map} +2 -2
- package/dist/chunks/{index-4khsm7mw.js → index-y9b327j8.js} +18 -18
- package/dist/chunks/{index-4khsm7mw.js.map → index-y9b327j8.js.map} +5 -5
- package/dist/conformance/cases/outage.d.ts.map +1 -1
- package/dist/conformance/cases/tokens/deletion.d.ts.map +1 -1
- package/dist/conformance/describe.d.ts +1 -0
- package/dist/conformance/describe.d.ts.map +1 -1
- package/dist/conformance/index.js +39 -5
- package/dist/conformance/index.js.map +5 -5
- package/dist/conformance/types.d.ts +1 -1
- package/dist/conformance/types.d.ts.map +1 -1
- package/dist/index.js +478 -453
- package/dist/index.js.map +21 -19
- package/dist/permissions/index.js +3 -3
- package/docs/guide/adapters.md +40 -3
- package/docs/guide/email-flows.md +16 -2
- package/docs/guide/errors.md +1 -1
- package/docs/guide/passwords.md +7 -10
- package/docs/guide/sessions.md +15 -4
- package/docs/guide/users.md +1 -1
- package/docs/roadmap.md +14 -20
- package/docs/troubleshooting.md +12 -10
- package/package.json +1 -1
- /package/dist/chunks/{index-cntabs9d.js.map → index-rpp0bw6e.js.map} +0 -0
package/README.md
CHANGED
|
@@ -410,7 +410,8 @@ else reaches the store and is asynchronous.
|
|
|
410
410
|
- **Shared**: `authenticate`, `signOut`, `signOutEverywhere(user, { except })`,
|
|
411
411
|
`findUser` and `getUser` across types, `cookie.serialize(token, session)` and
|
|
412
412
|
`cookie.clear()` — `HttpOnly; SameSite=Lax; Secure` unless you say otherwise
|
|
413
|
-
— and `collectExpired
|
|
413
|
+
— and `collectExpired`, which deletes lapsed sessions and lapsed one-time
|
|
414
|
+
tokens.
|
|
414
415
|
- **Password guessing is throttled**, on by default: past ten passwords
|
|
415
416
|
tried at one login in a 15-minute window, `signIn` refuses every one — the
|
|
416
417
|
right password included — with `CREDENTIALS_INVALID`, `reason:
|
|
@@ -797,6 +798,19 @@ there. Without janus-mail, send it with your own mailer.
|
|
|
797
798
|
- **Events**: `user.emailChanged`, carrying `formerEmail`, then
|
|
798
799
|
`user.emailVerified`. An `update` that moves the e-mail spends the
|
|
799
800
|
user's pending links, so a move back to the old address revives none.
|
|
801
|
+
- **With several user types**, `auth.admin.changeEmail.confirm(token)` answers
|
|
802
|
+
`TOKEN_UNKNOWN` for a token issued to a user of another type — and the token
|
|
803
|
+
is spent. A confirmation page that does not know the type calls the root's
|
|
804
|
+
instead, which reads the user the token was issued to, whatever their type,
|
|
805
|
+
and confirms exactly as their type does (`send` stays on each type):
|
|
806
|
+
|
|
807
|
+
```ts
|
|
808
|
+
await auth.admin.changeEmail.send(admin, newEmail);
|
|
809
|
+
const changed = await auth.changeEmail.confirm(token); // changed.type === 'admin'
|
|
810
|
+
```
|
|
811
|
+
|
|
812
|
+
It exists when at least one type has an e-mail, so a type cannot be named
|
|
813
|
+
`changeEmail`. Its type is `AnyTypeChangeEmailApi`.
|
|
800
814
|
|
|
801
815
|
[The e-mail flows guide](docs/guide/email-flows.md#changeemail) has a Hono
|
|
802
816
|
route for each step, with the notice to the former address.
|
|
@@ -1330,7 +1344,7 @@ describeJanusStores({
|
|
|
1330
1344
|
});
|
|
1331
1345
|
```
|
|
1332
1346
|
|
|
1333
|
-
There are
|
|
1347
|
+
There are 61 cases. They cover:
|
|
1334
1348
|
- round-trip, byte for byte — including every edge character the core lets
|
|
1335
1349
|
through (control characters, U+FFFF, a surrogate pair);
|
|
1336
1350
|
- uniqueness, as a constraint: of twenty concurrent inserts of one login,
|
|
@@ -1359,12 +1373,15 @@ There are 59 cases. They cover:
|
|
|
1359
1373
|
goes, with a replay answering `false` or `0` rather than failing;
|
|
1360
1374
|
- the optional `users.findUsers`: each stored user once, whatever its type, an
|
|
1361
1375
|
id nobody holds left out, and `[]` — never `null` — when nobody holds any;
|
|
1362
|
-
-
|
|
1376
|
+
- the optional `tokens.deleteExpiredTokens`: lapsed tokens deleted, spent or
|
|
1377
|
+
not, and a token one millisecond short of lapsing kept, still spent when it
|
|
1378
|
+
was;
|
|
1379
|
+
- **outages**, one case for each of the sixteen methods whose honest answer can
|
|
1363
1380
|
be "nothing".
|
|
1364
1381
|
|
|
1365
1382
|
**An optional method a store lacks skips its cases, with the reason** — a
|
|
1366
|
-
store without `sessions.deleteExpiredSessions
|
|
1367
|
-
suite. A case's `needs` names what it cannot run without, one `CaseNeed` or a list
|
|
1383
|
+
store without `sessions.deleteExpiredSessions`, `tokens.deleteExpiredTokens`
|
|
1384
|
+
or `users.findUsers` passes the suite. A case's `needs` names what it cannot run without, one `CaseNeed` or a list
|
|
1368
1385
|
(`outage.findUsers` needs `['faults', 'findUsers']`).
|
|
1369
1386
|
|
|
1370
1387
|
The suite imports no test framework and no assertion library. It runs under
|
|
@@ -1661,8 +1678,8 @@ test that tries more than ten wrong passwords at one login over a
|
|
|
1661
1678
|
`fixedClock` is throttled too: advance the clock past `retryAfter`, or wire
|
|
1662
1679
|
`signIn: { throttle: false }`. **Somebody who knows a login can keep its
|
|
1663
1680
|
password sign-in shut**, ten tries a window; a sign-in code or link, when you wire them, still opens it — the throttle counts passwords, never those.
|
|
1664
|
-
On
|
|
1665
|
-
row per window. One password tried against
|
|
1681
|
+
On a store with no TTL (PostgreSQL through `@nxgt/janus-drizzle`), schedule
|
|
1682
|
+
`collectExpired()`: every login tried adds a row per window, and it deletes them. One password tried against
|
|
1666
1683
|
many logins is not counted: rate-limit `signIn` per client address yourself
|
|
1667
1684
|
([passwords](docs/guide/passwords.md#what-you-still-limit-yourself)). The
|
|
1668
1685
|
counts live in the tokens store: a flushed or evicting Redis forgets them,
|
|
@@ -1693,11 +1710,21 @@ counted: add a per-IP ceiling with `@nxgt/redis` rate limits
|
|
|
1693
1710
|
[example](docs/guide/email-flows.md#requests-that-send-e-mail-are-throttled)). A test suite that requests more than five of
|
|
1694
1711
|
one flow for one address or user over a `fixedClock` is throttled: advance the
|
|
1695
1712
|
clock past `retryAfter`, or wire `mail: { throttle: false }`. The counts live
|
|
1696
|
-
in the tokens store, so on
|
|
1713
|
+
in the tokens store, so on a store with no TTL (PostgreSQL through `@nxgt/janus-drizzle`) schedule
|
|
1714
|
+
`collectExpired()`, which deletes them; a
|
|
1697
1715
|
flushed or evicting Redis forgets them, and a tokens store that cannot count
|
|
1698
1716
|
throws `STORE_FAILED` with nothing issued
|
|
1699
1717
|
([e-mail flows](docs/guide/email-flows.md#requests-that-send-e-mail-are-throttled)).
|
|
1700
1718
|
|
|
1719
|
+
**`collectExpired()` also collects lapsed one-time tokens, and a custom
|
|
1720
|
+
tokens store has to implement `deleteExpiredTokens` for it.** Without the
|
|
1721
|
+
method, only the sessions are collected — or `UNSUPPORTED`, when the sessions
|
|
1722
|
+
store has none either — and the throttles' counts pile up on a database with
|
|
1723
|
+
no TTL. Once a lapsed token is collected, its link answers `TOKEN_UNKNOWN`
|
|
1724
|
+
instead of `TOKEN_EXPIRED` or `TOKEN_SPENT`: a page that tells the two apart
|
|
1725
|
+
should treat the third as "this link is no longer valid"
|
|
1726
|
+
([sessions](docs/guide/sessions.md#collectexpired)).
|
|
1727
|
+
|
|
1701
1728
|
**A sign-in can move a user's `version`.** Rewriting a stale hash is a write. A
|
|
1702
1729
|
user object read before that sign-in, and then passed as `ifVersion`, gets
|
|
1703
1730
|
`VERSION_CONFLICT`. That is the conflict doing its job: read the user again.
|
|
@@ -1782,18 +1809,18 @@ that sends one, since it is awaited: queue the event and return.
|
|
|
1782
1809
|
|
|
1783
1810
|
## Type safety, counted
|
|
1784
1811
|
|
|
1785
|
-
**One hundred and eighty plausible mistakes, one hundred and eighty refused at compile time — and
|
|
1812
|
+
**One hundred and eighty-five plausible mistakes, one hundred and eighty-five refused at compile time — and
|
|
1786
1813
|
two gaps, named.**
|
|
1787
1814
|
|
|
1788
1815
|
The lists are typechecked and never run, with one `@ts-expect-error` per
|
|
1789
1816
|
mistake beside the shapes that must keep compiling. One is a single file:
|
|
1790
1817
|
`test/types/refusals.ts` (fifteen, on the shared vocabulary). The other three
|
|
1791
|
-
are folders with one file per behaviour: `test/types/port/` (twenty-
|
|
1818
|
+
are folders with one file per behaviour: `test/types/port/` (twenty-six, on
|
|
1792
1819
|
the identity stores' port, from the point of view of the person implementing
|
|
1793
|
-
it), `test/types/auth/` (
|
|
1820
|
+
it), `test/types/auth/` (ninety-two, on `janus()`, from the point of view of
|
|
1794
1821
|
the application — twelve of them on the second factor, three on sign-in codes,
|
|
1795
1822
|
five on user events, four on step-ups, six on the sign-in throttle, five on the mail throttle, four on
|
|
1796
|
-
sign-in links, six on devices, two on `findMany`, five on requests in two steps, three on signing in on the application's proof, three on finding a user by e-mail, three on proving an e-mail on the application's proof,
|
|
1823
|
+
sign-in links, six on devices, two on `findMany`, five on requests in two steps, three on signing in on the application's proof, three on finding a user by e-mail, three on proving an e-mail on the application's proof, six on changing an e-mail, four on `findOrCreate`) and `test/types/permissions/` (fifty-two, on the
|
|
1797
1824
|
permission model and the questions asked of it). The rule comes from
|
|
1798
1825
|
`nxgt-data`, and so does the reason to distrust the claim without the files:
|
|
1799
1826
|
when it was last measured on `@nxgt/mongo`, *seven of twelve plausible
|
|
@@ -10,5 +10,5 @@ export declare const SINGLE_TYPE = "user";
|
|
|
10
10
|
*/
|
|
11
11
|
export declare const RESERVED_FIELDS: readonly ["id", "type", "emailVerified", "active", "hasPassword", "hasSecondFactor", "version", "createdAt", "updatedAt", "password"];
|
|
12
12
|
/** Names on `janus()`'s answer, so a user type may not take one. */
|
|
13
|
-
export declare const RESERVED_TYPES: readonly ["authenticate", "signOut", "signOutEverywhere", "findUser", "getUser", "cookie", "collectExpired", "types"];
|
|
13
|
+
export declare const RESERVED_TYPES: readonly ["authenticate", "signOut", "signOutEverywhere", "findUser", "getUser", "cookie", "collectExpired", "types", "changeEmail"];
|
|
14
14
|
//# sourceMappingURL=reserved.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reserved.d.ts","sourceRoot":"","sources":["../../../src/auth/config/reserved.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,0DAA0D;AAC1D,eAAO,MAAM,WAAW,SAAS,CAAC;AAElC;;;GAGG;AACH,eAAO,MAAM,eAAe,uIAWlB,CAAC;AAEX,oEAAoE;AACpE,eAAO,MAAM,cAAc,
|
|
1
|
+
{"version":3,"file":"reserved.d.ts","sourceRoot":"","sources":["../../../src/auth/config/reserved.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,0DAA0D;AAC1D,eAAO,MAAM,WAAW,SAAS,CAAC;AAElC;;;GAGG;AACH,eAAO,MAAM,eAAe,uIAWlB,CAAC;AAEX,oEAAoE;AACpE,eAAO,MAAM,cAAc,sIAUjB,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The confirmation of a change of e-mail at the root of an instance with
|
|
3
|
+
* several user types: for the page that follows the link and does not know
|
|
4
|
+
* the user's type.
|
|
5
|
+
*/
|
|
6
|
+
import type { AnyUser, Context } from '../context';
|
|
7
|
+
/**
|
|
8
|
+
* `{ changeEmail: { confirm } }`. Built whatever the types, as each type's
|
|
9
|
+
* flows are; the types show it only when one has an e-mail, and a user of a
|
|
10
|
+
* type without one is `TOKEN_UNKNOWN`. `send` stays on each type: it needs the
|
|
11
|
+
* user's type to validate the address.
|
|
12
|
+
*/
|
|
13
|
+
export declare function anyTypeChangeEmail(context: Context): {
|
|
14
|
+
readonly changeEmail: {
|
|
15
|
+
confirm(token: string): Promise<AnyUser>;
|
|
16
|
+
};
|
|
17
|
+
};
|
|
18
|
+
//# sourceMappingURL=any-type-change-email.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"any-type-change-email.d.ts","sourceRoot":"","sources":["../../../src/auth/email-flows/any-type-change-email.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAGnD;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,OAAO,GAAG;IACrD,QAAQ,CAAC,WAAW,EAAE;QAAE,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;KAAE,CAAC;CACnE,CAOA"}
|
|
@@ -34,9 +34,14 @@ export declare function refuseMoved(type: ResolvedType, user: UserRecord, token:
|
|
|
34
34
|
* Spends a change's token and says why it cannot be used, when it cannot. A
|
|
35
35
|
* user gone since, or of another type, is as good as no token; a user who
|
|
36
36
|
* moved since the link was asked is stale.
|
|
37
|
+
*
|
|
38
|
+
* With `type` null the user's own type answers — whichever it is, provided it
|
|
39
|
+
* has an e-mail: a page that does not know the type confirms the link, and
|
|
40
|
+
* `type` in the answer is the one the user has.
|
|
37
41
|
*/
|
|
38
|
-
export declare function redeemChangeEmailToken(context: Context, type: ResolvedType, secret: string, where: string): Promise<{
|
|
42
|
+
export declare function redeemChangeEmailToken(context: Context, type: ResolvedType | null, secret: string, where: string): Promise<{
|
|
39
43
|
token: TokenRecord;
|
|
40
44
|
user: UserRecord;
|
|
45
|
+
type: ResolvedType;
|
|
41
46
|
}>;
|
|
42
47
|
//# sourceMappingURL=change-email-token.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"change-email-token.d.ts","sourceRoot":"","sources":["../../../src/auth/email-flows/change-email-token.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,EAAkB,KAAK,YAAY,EAAE,MAAM,WAAW,CAAC;AAC9D,OAAO,EAAE,KAAK,OAAO,EAAuC,MAAM,YAAY,CAAC;AAE/E,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAE7D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAE5C,qDAAqD;AACrD,eAAO,MAAM,UAAU,GAAI,QAAQ,MAAM,EAAE,QAAQ,MAAM,GAAG,IAAI,KAAG,MAGjE,CAAC;AAEH;;;;;GAKG;AACH,wBAAsB,YAAY,CACjC,IAAI,EAAE,YAAY,EAClB,IAAI,EAAE,UAAU,EAChB,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,GACX,OAAO,CAAC,MAAM,CAAC,CA0BjB;AAED;;;GAGG;AACH,wBAAsB,qBAAqB,CAC1C,OAAO,EAAE,OAAO,EAChB,IAAI,EAAE,YAAY,EAClB,IAAI,EAAE,UAAU,EAChB,OAAO,EAAE,MAAM,GACb,OAAO,CAAC,WAAW,CAAC,CAmBtB;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAC1B,IAAI,EAAE,YAAY,EAClB,IAAI,EAAE,UAAU,EAChB,KAAK,EAAE,WAAW,EAClB,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,GACX,IAAI,CAQN;AAED
|
|
1
|
+
{"version":3,"file":"change-email-token.d.ts","sourceRoot":"","sources":["../../../src/auth/email-flows/change-email-token.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,EAAkB,KAAK,YAAY,EAAE,MAAM,WAAW,CAAC;AAC9D,OAAO,EAAE,KAAK,OAAO,EAAuC,MAAM,YAAY,CAAC;AAE/E,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAE7D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAE5C,qDAAqD;AACrD,eAAO,MAAM,UAAU,GAAI,QAAQ,MAAM,EAAE,QAAQ,MAAM,GAAG,IAAI,KAAG,MAGjE,CAAC;AAEH;;;;;GAKG;AACH,wBAAsB,YAAY,CACjC,IAAI,EAAE,YAAY,EAClB,IAAI,EAAE,UAAU,EAChB,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,GACX,OAAO,CAAC,MAAM,CAAC,CA0BjB;AAED;;;GAGG;AACH,wBAAsB,qBAAqB,CAC1C,OAAO,EAAE,OAAO,EAChB,IAAI,EAAE,YAAY,EAClB,IAAI,EAAE,UAAU,EAChB,OAAO,EAAE,MAAM,GACb,OAAO,CAAC,WAAW,CAAC,CAmBtB;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAC1B,IAAI,EAAE,YAAY,EAClB,IAAI,EAAE,UAAU,EAChB,KAAK,EAAE,WAAW,EAClB,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,GACX,IAAI,CAQN;AAED;;;;;;;;GAQG;AACH,wBAAsB,sBAAsB,CAC3C,OAAO,EAAE,OAAO,EAChB,IAAI,EAAE,YAAY,GAAG,IAAI,EACzB,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,GACX,OAAO,CAAC;IAAE,KAAK,EAAE,WAAW,CAAC;IAAC,IAAI,EAAE,UAAU,CAAC;IAAC,IAAI,EAAE,YAAY,CAAA;CAAE,CAAC,CAmBvE"}
|
|
@@ -8,4 +8,10 @@ import { type AnyUser, type Context } from '../context';
|
|
|
8
8
|
import type { ChangeEmailApi } from '../types';
|
|
9
9
|
/** `changeEmail` of one user type: `send` to the new address, then `confirm`. */
|
|
10
10
|
export declare function changeEmailFlows(context: Context, type: ResolvedType, at: At): ChangeEmailApi<AnyUser>['changeEmail'];
|
|
11
|
+
/**
|
|
12
|
+
* Redeems a change's token: the write, then the events it earned. `asked` is
|
|
13
|
+
* the type whose `confirm` was called, or null for the root's, where the
|
|
14
|
+
* user's own type answers.
|
|
15
|
+
*/
|
|
16
|
+
export declare function confirmChange(context: Context, asked: ResolvedType | null, secret: string, where: string): Promise<AnyUser>;
|
|
11
17
|
//# sourceMappingURL=change-email.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"change-email.d.ts","sourceRoot":"","sources":["../../../src/auth/email-flows/change-email.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,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,EAMZ,MAAM,YAAY,CAAC;AAIpB,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAe/C,iFAAiF;AACjF,wBAAgB,gBAAgB,CAC/B,OAAO,EAAE,OAAO,EAChB,IAAI,EAAE,YAAY,EAClB,EAAE,EAAE,EAAE,GACJ,cAAc,CAAC,OAAO,CAAC,CAAC,aAAa,CAAC,CA4BxC"}
|
|
1
|
+
{"version":3,"file":"change-email.d.ts","sourceRoot":"","sources":["../../../src/auth/email-flows/change-email.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,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,EAMZ,MAAM,YAAY,CAAC;AAIpB,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAe/C,iFAAiF;AACjF,wBAAgB,gBAAgB,CAC/B,OAAO,EAAE,OAAO,EAChB,IAAI,EAAE,YAAY,EAClB,EAAE,EAAE,EAAE,GACJ,cAAc,CAAC,OAAO,CAAC,CAAC,aAAa,CAAC,CA4BxC;AAED;;;;GAIG;AACH,wBAAsB,aAAa,CAClC,OAAO,EAAE,OAAO,EAChB,KAAK,EAAE,YAAY,GAAG,IAAI,EAC1B,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,GACX,OAAO,CAAC,OAAO,CAAC,CAiDlB"}
|
package/dist/auth/index.d.ts
CHANGED
|
@@ -8,5 +8,5 @@ export type { JanusStores, Json, JsonObject, PasswordRecord, SecondFactorRecord,
|
|
|
8
8
|
export type { SealingKey } from './sealing';
|
|
9
9
|
export { assertFresh } from './sessions/fresh';
|
|
10
10
|
export type { StandardSchemaV1 } from './standard-schema';
|
|
11
|
-
export type { Authenticated, ChangeEmailApi, Checked, EmailOf, FindByEmailApi, FindOrCreateApi, FirstProof, HeaderRecord, IssuedCode, IssuedToken, Janus, LoginOf, MagicLinkApi, PasswordApi, PreparedCode, PreparedRequest, ProvenSignInApi, RecoveredSignIn, RecoveryCodesIssued, RequestLike, RequiredStringKeys, ResetPasswordApi, SecondFactorApi, SecondFactorEnrolment, SecondFactorRequired, Session, SharedApi, SignedIn, SignInCodeApi, SignInOptions, SignInResult, StepUpApi, StepUpByApp, StepUpByEmail, TypeApi, TypesOf, User, UserBase, UserOf, UserRef, UserTypeApi, VerifyEmailApi, WriteOptions, } from './types';
|
|
11
|
+
export type { AnyTypeChangeEmailApi, Authenticated, ChangeEmailApi, Checked, EmailOf, FindByEmailApi, FindOrCreateApi, FirstProof, HeaderRecord, IssuedCode, IssuedToken, Janus, LoginOf, MagicLinkApi, PasswordApi, PreparedCode, PreparedRequest, ProvenSignInApi, RecoveredSignIn, RecoveryCodesIssued, RequestLike, RequiredStringKeys, ResetPasswordApi, SecondFactorApi, SecondFactorEnrolment, SecondFactorRequired, Session, SharedApi, SignedIn, SignInCodeApi, SignInOptions, SignInResult, StepUpApi, StepUpByApp, StepUpByEmail, TypeApi, TypesOf, User, UserBase, UserOf, UserRef, UserTypeApi, VerifyEmailApi, WriteOptions, } from './types';
|
|
12
12
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/auth/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/auth/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACX,YAAY,EACZ,aAAa,EACb,UAAU,EACV,WAAW,EACX,UAAU,EACV,kBAAkB,EAClB,eAAe,EACf,SAAS,EACT,cAAc,EACd,cAAc,EACd,kBAAkB,EAClB,aAAa,EACb,YAAY,EACZ,oBAAoB,EACpB,gBAAgB,EAChB,UAAU,EACV,cAAc,GACd,MAAM,UAAU,CAAC;AAClB,YAAY,EACX,SAAS,EACT,iBAAiB,EACjB,aAAa,GACb,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AACpD,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAChC,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACpD,OAAO,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AACnD,YAAY,EACX,WAAW,EACX,IAAI,EACJ,UAAU,EACV,cAAc,EACd,kBAAkB,EAClB,SAAS,EACT,aAAa,EACb,YAAY,EACZ,iBAAiB,EACjB,SAAS,EACT,WAAW,EACX,UAAU,EACV,eAAe,EACf,SAAS,EACT,UAAU,EACV,SAAS,GACT,MAAM,cAAc,CAAC;AACtB,YAAY,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAC5C,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,YAAY,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAC1D,YAAY,EACX,aAAa,EACb,cAAc,EACd,OAAO,EACP,OAAO,EACP,cAAc,EACd,eAAe,EACf,UAAU,EACV,YAAY,EACZ,UAAU,EACV,WAAW,EACX,KAAK,EACL,OAAO,EACP,YAAY,EACZ,WAAW,EACX,YAAY,EACZ,eAAe,EACf,eAAe,EACf,eAAe,EACf,mBAAmB,EACnB,WAAW,EACX,kBAAkB,EAClB,gBAAgB,EAChB,eAAe,EACf,qBAAqB,EACrB,oBAAoB,EACpB,OAAO,EACP,SAAS,EACT,QAAQ,EACR,aAAa,EACb,aAAa,EACb,YAAY,EACZ,SAAS,EACT,WAAW,EACX,aAAa,EACb,OAAO,EACP,OAAO,EACP,IAAI,EACJ,QAAQ,EACR,MAAM,EACN,OAAO,EACP,WAAW,EACX,cAAc,EACd,YAAY,GACZ,MAAM,SAAS,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/auth/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACX,YAAY,EACZ,aAAa,EACb,UAAU,EACV,WAAW,EACX,UAAU,EACV,kBAAkB,EAClB,eAAe,EACf,SAAS,EACT,cAAc,EACd,cAAc,EACd,kBAAkB,EAClB,aAAa,EACb,YAAY,EACZ,oBAAoB,EACpB,gBAAgB,EAChB,UAAU,EACV,cAAc,GACd,MAAM,UAAU,CAAC;AAClB,YAAY,EACX,SAAS,EACT,iBAAiB,EACjB,aAAa,GACb,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AACpD,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAChC,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACpD,OAAO,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AACnD,YAAY,EACX,WAAW,EACX,IAAI,EACJ,UAAU,EACV,cAAc,EACd,kBAAkB,EAClB,SAAS,EACT,aAAa,EACb,YAAY,EACZ,iBAAiB,EACjB,SAAS,EACT,WAAW,EACX,UAAU,EACV,eAAe,EACf,SAAS,EACT,UAAU,EACV,SAAS,GACT,MAAM,cAAc,CAAC;AACtB,YAAY,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAC5C,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,YAAY,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAC1D,YAAY,EACX,qBAAqB,EACrB,aAAa,EACb,cAAc,EACd,OAAO,EACP,OAAO,EACP,cAAc,EACd,eAAe,EACf,UAAU,EACV,YAAY,EACZ,UAAU,EACV,WAAW,EACX,KAAK,EACL,OAAO,EACP,YAAY,EACZ,WAAW,EACX,YAAY,EACZ,eAAe,EACf,eAAe,EACf,eAAe,EACf,mBAAmB,EACnB,WAAW,EACX,kBAAkB,EAClB,gBAAgB,EAChB,eAAe,EACf,qBAAqB,EACrB,oBAAoB,EACpB,OAAO,EACP,SAAS,EACT,QAAQ,EACR,aAAa,EACb,aAAa,EACb,YAAY,EACZ,SAAS,EACT,WAAW,EACX,aAAa,EACb,OAAO,EACP,OAAO,EACP,IAAI,EACJ,QAAQ,EACR,MAAM,EACN,OAAO,EACP,WAAW,EACX,cAAc,EACd,YAAY,GACZ,MAAM,SAAS,CAAC"}
|
package/dist/auth/janus.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"janus.d.ts","sourceRoot":"","sources":["../../src/auth/janus.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,WAAW,EAAiB,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"janus.d.ts","sourceRoot":"","sources":["../../src/auth/janus.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,WAAW,EAAiB,MAAM,UAAU,CAAC;AAQ3D,OAAO,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAG9C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,wBAAgB,KAAK,CAAC,KAAK,CAAC,CAAC,SAAS,WAAW,EAChD,MAAM,EAAE,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,GACpB,KAAK,CAAC,CAAC,CAAC,CA+DV"}
|
package/dist/auth/outage.d.ts
CHANGED
|
@@ -29,8 +29,8 @@ import type { JanusStores } from './port/types';
|
|
|
29
29
|
* Rule 2 of the port, enforced at run time for the JavaScript adapter the
|
|
30
30
|
* compiler never saw.
|
|
31
31
|
*
|
|
32
|
-
* The optional `deleteExpiredSessions`
|
|
33
|
-
* when absent, so capability detection still reads the truth.
|
|
32
|
+
* The optional `deleteExpiredSessions` and `deleteExpiredTokens` are guarded
|
|
33
|
+
* when present and left absent when absent, so capability detection still reads the truth.
|
|
34
34
|
*/
|
|
35
35
|
export declare function guardStores(stores: JanusStores): JanusStores;
|
|
36
36
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"assert-stores.d.ts","sourceRoot":"","sources":["../../../src/auth/port/assert-stores.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAe,iBAAiB,EAAE,MAAM,SAAS,CAAC;AAoC9D;;;;;;;;;;;;GAYG;AACH,wBAAgB,YAAY,CAC3B,MAAM,EAAE,OAAO,EACf,KAAK,EAAE,MAAM,GACX,iBAAiB,
|
|
1
|
+
{"version":3,"file":"assert-stores.d.ts","sourceRoot":"","sources":["../../../src/auth/port/assert-stores.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAe,iBAAiB,EAAE,MAAM,SAAS,CAAC;AAoC9D;;;;;;;;;;;;GAYG;AACH,wBAAgB,YAAY,CAC3B,MAAM,EAAE,OAAO,EACf,KAAK,EAAE,MAAM,GACX,iBAAiB,CAqCnB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tokens.d.ts","sourceRoot":"","sources":["../../../../src/auth/port/memory/tokens.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAe,UAAU,EAAE,MAAM,UAAU,CAAC;AAGxD,gDAAgD;AAChD,wBAAgB,gBAAgB,IAAI,UAAU,
|
|
1
|
+
{"version":3,"file":"tokens.d.ts","sourceRoot":"","sources":["../../../../src/auth/port/memory/tokens.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAe,UAAU,EAAE,MAAM,UAAU,CAAC;AAGxD,gDAAgD;AAChD,wBAAgB,gBAAgB,IAAI,UAAU,CA+E7C"}
|
|
@@ -24,6 +24,8 @@ export interface JanusStores {
|
|
|
24
24
|
export interface StoreCapabilities {
|
|
25
25
|
/** Whether `sessions.deleteExpiredSessions` is implemented. */
|
|
26
26
|
readonly collectExpired: boolean;
|
|
27
|
+
/** Whether `tokens.deleteExpiredTokens` is implemented. */
|
|
28
|
+
readonly collectExpiredTokens: boolean;
|
|
27
29
|
/**
|
|
28
30
|
* Whether `users.findUsers` is implemented: `findMany` answers in one query
|
|
29
31
|
* when it is, and with `findUser`, a few ids at a time, when it is not.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stores.d.ts","sourceRoot":"","sources":["../../../../src/auth/port/types/stores.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC/C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAC3C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAEzC;;;;;;GAMG;AACH,MAAM,WAAW,WAAW;IAC3B,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAC;IAC1B,QAAQ,CAAC,QAAQ,EAAE,YAAY,CAAC;IAChC,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAC;CAC5B;AAED,6DAA6D;AAC7D,MAAM,WAAW,iBAAiB;IACjC,+DAA+D;IAC/D,QAAQ,CAAC,cAAc,EAAE,OAAO,CAAC;IACjC;;;OAGG;IACH,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;CAC5B"}
|
|
1
|
+
{"version":3,"file":"stores.d.ts","sourceRoot":"","sources":["../../../../src/auth/port/types/stores.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC/C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAC3C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAEzC;;;;;;GAMG;AACH,MAAM,WAAW,WAAW;IAC3B,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAC;IAC1B,QAAQ,CAAC,QAAQ,EAAE,YAAY,CAAC;IAChC,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAC;CAC5B;AAED,6DAA6D;AAC7D,MAAM,WAAW,iBAAiB;IACjC,+DAA+D;IAC/D,QAAQ,CAAC,cAAc,EAAE,OAAO,CAAC;IACjC,2DAA2D;IAC3D,QAAQ,CAAC,oBAAoB,EAAE,OAAO,CAAC;IACvC;;;OAGG;IACH,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;CAC5B"}
|
|
@@ -134,5 +134,17 @@ export interface TokenStore {
|
|
|
134
134
|
* must not outlive the user until its expiry.
|
|
135
135
|
*/
|
|
136
136
|
deleteUserTokens(userId: Id): Promise<number>;
|
|
137
|
+
/**
|
|
138
|
+
* **Optional capability.** Deletes every token — spent or not, of any kind
|
|
139
|
+
* and any user — whose `expiresAt` is at or before `before`, and answers how
|
|
140
|
+
* many. Never one whose `expiresAt` is later, spent or not: a spent token is
|
|
141
|
+
* kept until it lapses, or a count would start over.
|
|
142
|
+
*
|
|
143
|
+
* What collects the sign-in and mail throttles' counts, which are ordinary
|
|
144
|
+
* tokens under a keyed-hash user id that `deleteUserTokens` never reaches.
|
|
145
|
+
* A store with its own expiry — a TTL index, a key TTL — does not implement
|
|
146
|
+
* it; `collectExpired()` reads its presence.
|
|
147
|
+
*/
|
|
148
|
+
deleteExpiredTokens?(before: Date): Promise<number>;
|
|
137
149
|
}
|
|
138
150
|
//# sourceMappingURL=tokens.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tokens.d.ts","sourceRoot":"","sources":["../../../../src/auth/port/types/tokens.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,iBAAiB,CAAC;AAE1C;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,MAAM,SAAS,GAClB,aAAa,GACb,eAAe,GACf,cAAc,GACd,YAAY,GACZ,WAAW,GACX,QAAQ,GACR,aAAa,CAAC;AAEjB,yEAAyE;AACzE,MAAM,WAAW,WAAW;IAC3B,oEAAoE;IACpE,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IACzB,QAAQ,CAAC,MAAM,EAAE,EAAE,CAAC;IACpB;;;;OAIG;IACH,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB;;;;;;;OAOG;IACH,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC;;;;OAIG;IACH,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,SAAS,EAAE,IAAI,CAAC;IACzB,mDAAmD;IACnD,QAAQ,CAAC,OAAO,EAAE,IAAI,GAAG,IAAI,CAAC;IAC9B,QAAQ,CAAC,SAAS,EAAE,IAAI,CAAC;CACzB;AAED,kDAAkD;AAClD,MAAM,WAAW,UAAU;IAC1B;;;OAGG;IACH,WAAW,CAAC,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAEhD;;;;;;;;;;;;;;;;;;OAkBG;IACH,YAAY,CACX,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,SAAS,EACf,EAAE,EAAE,IAAI,GACN,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;IAE/B;;;;;;;;;;;;;;;;;;;OAmBG;IACH,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;IAE9E;;;;;;;;;;;;;;;;;OAiBG;IACH,eAAe,CACd,MAAM,EAAE,EAAE,EACV,IAAI,EAAE,SAAS,EACf,EAAE,EAAE,IAAI,EACR,MAAM,CAAC,EAAE,MAAM,GACb,OAAO,CAAC,MAAM,CAAC,CAAC;IAEnB;;;;OAIG;IACH,gBAAgB,CAAC,MAAM,EAAE,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"tokens.d.ts","sourceRoot":"","sources":["../../../../src/auth/port/types/tokens.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,iBAAiB,CAAC;AAE1C;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,MAAM,SAAS,GAClB,aAAa,GACb,eAAe,GACf,cAAc,GACd,YAAY,GACZ,WAAW,GACX,QAAQ,GACR,aAAa,CAAC;AAEjB,yEAAyE;AACzE,MAAM,WAAW,WAAW;IAC3B,oEAAoE;IACpE,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IACzB,QAAQ,CAAC,MAAM,EAAE,EAAE,CAAC;IACpB;;;;OAIG;IACH,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB;;;;;;;OAOG;IACH,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC;;;;OAIG;IACH,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,SAAS,EAAE,IAAI,CAAC;IACzB,mDAAmD;IACnD,QAAQ,CAAC,OAAO,EAAE,IAAI,GAAG,IAAI,CAAC;IAC9B,QAAQ,CAAC,SAAS,EAAE,IAAI,CAAC;CACzB;AAED,kDAAkD;AAClD,MAAM,WAAW,UAAU;IAC1B;;;OAGG;IACH,WAAW,CAAC,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAEhD;;;;;;;;;;;;;;;;;;OAkBG;IACH,YAAY,CACX,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,SAAS,EACf,EAAE,EAAE,IAAI,GACN,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;IAE/B;;;;;;;;;;;;;;;;;;;OAmBG;IACH,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;IAE9E;;;;;;;;;;;;;;;;;OAiBG;IACH,eAAe,CACd,MAAM,EAAE,EAAE,EACV,IAAI,EAAE,SAAS,EACf,EAAE,EAAE,IAAI,EACR,MAAM,CAAC,EAAE,MAAM,GACb,OAAO,CAAC,MAAM,CAAC,CAAC;IAEnB;;;;OAIG;IACH,gBAAgB,CAAC,MAAM,EAAE,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAE9C;;;;;;;;;;OAUG;IACH,mBAAmB,CAAC,CAAC,MAAM,EAAE,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;CACpD"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `collectExpired()`: the lapsed sessions and the lapsed one-time tokens, from
|
|
3
|
+
* whichever of the two stores implements its collector.
|
|
4
|
+
*/
|
|
5
|
+
import type { Context } from '../context';
|
|
6
|
+
/**
|
|
7
|
+
* Deletes what has lapsed at `clock.now()` and answers how many in all.
|
|
8
|
+
*
|
|
9
|
+
* Sessions first, then tokens, one after the other: both deletions are
|
|
10
|
+
* idempotent, so a token failure after the sessions went leaves a call that can
|
|
11
|
+
* simply be repeated. `UNSUPPORTED` only when neither store has a collector.
|
|
12
|
+
*/
|
|
13
|
+
export declare function collectExpired(context: Context): Promise<number>;
|
|
14
|
+
//# sourceMappingURL=collect-expired.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"collect-expired.d.ts","sourceRoot":"","sources":["../../../src/auth/sessions/collect-expired.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAE1C;;;;;;GAMG;AACH,wBAAsB,cAAc,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAmBtE"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* What `janus()` answers whatever its user types: authenticating a request,
|
|
3
3
|
* signing out, finding a user by id, the cookie, and collecting expired
|
|
4
|
-
* sessions.
|
|
4
|
+
* sessions and one-time tokens.
|
|
5
5
|
*/
|
|
6
6
|
import { type AnyUser, type Context } from '../context';
|
|
7
7
|
import type { Authenticated, RequestLike, SharedApi } from '../types';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shared-api.d.ts","sourceRoot":"","sources":["../../../src/auth/sessions/shared-api.ts"],"names":[],"mappings":"AAAA;;;;GAIG;
|
|
1
|
+
{"version":3,"file":"shared-api.d.ts","sourceRoot":"","sources":["../../../src/auth/sessions/shared-api.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EACN,KAAK,OAAO,EACZ,KAAK,OAAO,EAKZ,MAAM,YAAY,CAAC;AAEpB,OAAO,KAAK,EAAE,aAAa,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAMtE,6EAA6E;AAC7E,MAAM,MAAM,iBAAiB,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,EAAE,cAAc,CAAC,GAAG;IAC1E,YAAY,CACX,OAAO,EAAE,WAAW,EACpB,OAAO,CAAC,EAAE;QAAE,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,GAClC,OAAO,CAAC,aAAa,CAAC,OAAO,CAAC,GAAG,IAAI,CAAC,CAAC;CAC1C,CAAC;AAEF,4DAA4D;AAC5D,wBAAgB,SAAS,CAAC,OAAO,EAAE,OAAO,GAAG,iBAAiB,CA8C7D"}
|
|
@@ -44,6 +44,37 @@ export interface ChangeEmailApi<U> {
|
|
|
44
44
|
* holds is `LOGIN_TAKEN` — the token already spent; an inactive user
|
|
45
45
|
* is `USER_INACTIVE`. A user written in between is `VERSION_CONFLICT`,
|
|
46
46
|
* also after the token is spent.
|
|
47
|
+
*
|
|
48
|
+
* **With several user types**, a token issued to a user of another type
|
|
49
|
+
* is `TOKEN_UNKNOWN` here, and it is spent. A page that does not know
|
|
50
|
+
* the type — an anonymous confirmation page — calls the root's
|
|
51
|
+
* `janus.changeEmail.confirm` instead.
|
|
52
|
+
*/
|
|
53
|
+
confirm(token: string): Promise<U>;
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* What an instance with several user types answers at its root when at least
|
|
58
|
+
* one has an e-mail: the confirmation of a change, whatever the user's type.
|
|
59
|
+
*/
|
|
60
|
+
export interface AnyTypeChangeEmailApi<U> {
|
|
61
|
+
readonly changeEmail: {
|
|
62
|
+
/**
|
|
63
|
+
* Confirms a change of e-mail for a page that does not know the user's
|
|
64
|
+
* type: spends the link's token, reads the user it was issued to,
|
|
65
|
+
* whatever their type, and then does what that type's `confirm` does —
|
|
66
|
+
* the same move, events and refusals. The answer's `type` says which
|
|
67
|
+
* type it was.
|
|
68
|
+
*
|
|
69
|
+
* **Call it from a `POST`**, never from the `GET` of the link. An
|
|
70
|
+
* unknown, spent or lapsed token is `TOKEN_UNKNOWN`, `TOKEN_SPENT` or
|
|
71
|
+
* `TOKEN_EXPIRED`; a user gone since, or of a type with no e-mail, is
|
|
72
|
+
* `TOKEN_UNKNOWN`; a user whose e-mail is no longer the one the link
|
|
73
|
+
* was asked from is `TOKEN_STALE`; an address another user of the type
|
|
74
|
+
* holds is `LOGIN_TAKEN` — the token already spent; an inactive user
|
|
75
|
+
* is `USER_INACTIVE`. A user written in between is `VERSION_CONFLICT`.
|
|
76
|
+
*
|
|
77
|
+
* `send` stays on each type: `janus.admin.changeEmail.send(...)`.
|
|
47
78
|
*/
|
|
48
79
|
confirm(token: string): Promise<U>;
|
|
49
80
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"change-email.d.ts","sourceRoot":"","sources":["../../../src/auth/types/change-email.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AAEtC;;;GAGG;AACH,MAAM,WAAW,cAAc,CAAC,CAAC;IAChC,QAAQ,CAAC,WAAW,EAAE;QACrB;;;;;;;;;;;;;;;;;WAiBG;QACH,IAAI,CAAC,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;QACzD
|
|
1
|
+
{"version":3,"file":"change-email.d.ts","sourceRoot":"","sources":["../../../src/auth/types/change-email.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AAEtC;;;GAGG;AACH,MAAM,WAAW,cAAc,CAAC,CAAC;IAChC,QAAQ,CAAC,WAAW,EAAE;QACrB;;;;;;;;;;;;;;;;;WAiBG;QACH,IAAI,CAAC,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;QACzD;;;;;;;;;;;;;;;;;;WAkBG;QACH,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;KACnC,CAAC;CACF;AAED;;;GAGG;AACH,MAAM,WAAW,qBAAqB,CAAC,CAAC;IACvC,QAAQ,CAAC,WAAW,EAAE;QACrB;;;;;;;;;;;;;;;;WAgBG;QACH,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;KACnC,CAAC;CACF"}
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* keeps each schema's type travelling through every public method without
|
|
8
8
|
* dragging a type parameter through every internal function.
|
|
9
9
|
*/
|
|
10
|
-
export type { ChangeEmailApi } from './change-email';
|
|
10
|
+
export type { AnyTypeChangeEmailApi, ChangeEmailApi } from './change-email';
|
|
11
11
|
export type { Checked } from './checks';
|
|
12
12
|
export type { FirstProof, IssuedCode, IssuedToken, ResetPasswordApi, SignInCodeApi, VerifyEmailApi, } from './email-flows';
|
|
13
13
|
export type { FindByEmailApi } from './find-by-email';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/auth/types/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,YAAY,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/auth/types/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,YAAY,EAAE,qBAAqB,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAC5E,YAAY,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AACxC,YAAY,EACX,UAAU,EACV,UAAU,EACV,WAAW,EACX,gBAAgB,EAChB,aAAa,EACb,cAAc,GACd,MAAM,eAAe,CAAC;AACvB,YAAY,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACtD,YAAY,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AACxD,YAAY,EACX,OAAO,EACP,OAAO,EACP,kBAAkB,EAClB,OAAO,EACP,MAAM,GACN,MAAM,aAAa,CAAC;AACrB,YAAY,EAAE,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AACzD,YAAY,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AACjD,YAAY,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAC9C,YAAY,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAChE,YAAY,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AACxD,YAAY,EACX,eAAe,EACf,mBAAmB,EACnB,eAAe,EACf,qBAAqB,GACrB,MAAM,iBAAiB,CAAC;AACzB,YAAY,EACX,aAAa,EACb,YAAY,EACZ,WAAW,EACX,OAAO,GACP,MAAM,WAAW,CAAC;AACnB,YAAY,EACX,oBAAoB,EACpB,QAAQ,EACR,aAAa,EACb,YAAY,GACZ,MAAM,WAAW,CAAC;AACnB,YAAY,EAAE,SAAS,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AACvE,YAAY,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AACpE,YAAY,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC"}
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* Part of what `janus()` hands back; `./index` gathers it.
|
|
6
6
|
*/
|
|
7
7
|
import type { JanusConfig, MultiTypeConfig, SingleTypeConfig } from '../config';
|
|
8
|
-
import type { ChangeEmailApi } from './change-email';
|
|
8
|
+
import type { AnyTypeChangeEmailApi, ChangeEmailApi } from './change-email';
|
|
9
9
|
import type { ResetPasswordApi, SignInCodeApi, VerifyEmailApi } from './email-flows';
|
|
10
10
|
import type { FindByEmailApi } from './find-by-email';
|
|
11
11
|
import type { FindOrCreateApi } from './find-or-create';
|
|
@@ -68,9 +68,10 @@ export interface SharedApi<U extends {
|
|
|
68
68
|
clear(): string;
|
|
69
69
|
};
|
|
70
70
|
/**
|
|
71
|
-
* Deletes lapsed sessions
|
|
72
|
-
*
|
|
73
|
-
*
|
|
71
|
+
* Deletes lapsed sessions and lapsed one-time tokens — the throttles' counts
|
|
72
|
+
* included — from the stores that implement `deleteExpiredSessions` /
|
|
73
|
+
* `deleteExpiredTokens`, and answers how many in all. `UNSUPPORTED` when
|
|
74
|
+
* neither does — a store with its own TTL does not need to.
|
|
74
75
|
*/
|
|
75
76
|
collectExpired(): Promise<number>;
|
|
76
77
|
/** The user type names, in the order they were declared. */
|
|
@@ -82,9 +83,16 @@ export interface SharedApi<U extends {
|
|
|
82
83
|
* environment may be on at run time, and `signIn` must be typed for it.
|
|
83
84
|
*/
|
|
84
85
|
type TwoFactorOf<C> = 'secondFactor' extends keyof C ? true : false;
|
|
86
|
+
/**
|
|
87
|
+
* The users of the types that have an e-mail, which `changeEmail.confirm` at
|
|
88
|
+
* the root of several types answers; nothing when no type has one.
|
|
89
|
+
*/
|
|
90
|
+
type ChangeEmailUsers<C extends MultiTypeConfig> = {
|
|
91
|
+
[K in keyof C['users'] & string]: [EmailOf<C['users'][K]>] extends [never] ? never : UserOfType<K, C['users'][K]>;
|
|
92
|
+
}[keyof C['users'] & string];
|
|
85
93
|
/** What `janus(config)` answers. */
|
|
86
94
|
export type Janus<C extends JanusConfig> = SharedApi<UserOf<C>> & (C extends MultiTypeConfig ? {
|
|
87
95
|
readonly [K in keyof C['users'] & string]: TypeApi<K, C['users'][K], TwoFactorOf<C>>;
|
|
88
|
-
} : C extends SingleTypeConfig ? TypeApi<'user', SingleAsType<C>, TwoFactorOf<C>> : never);
|
|
96
|
+
} & ([ChangeEmailUsers<C>] extends [never] ? unknown : AnyTypeChangeEmailApi<ChangeEmailUsers<C>>) : C extends SingleTypeConfig ? TypeApi<'user', SingleAsType<C>, TwoFactorOf<C>> : never);
|
|
89
97
|
export {};
|
|
90
98
|
//# sourceMappingURL=janus.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"janus.d.ts","sourceRoot":"","sources":["../../../src/auth/types/janus.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAChF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"janus.d.ts","sourceRoot":"","sources":["../../../src/auth/types/janus.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
StoreConflict2,
|
|
3
3
|
NotFoundError2
|
|
4
|
-
} from "./index-
|
|
4
|
+
} from "./index-spwh8b9z.js";
|
|
5
5
|
|
|
6
6
|
// src/ids/id.ts
|
|
7
7
|
var HEX = Array.from({ length: 256 }, (_, i) => i.toString(16).padStart(2, "0"));
|
|
@@ -175,6 +175,16 @@ function memoryTokenStore() {
|
|
|
175
175
|
}
|
|
176
176
|
}
|
|
177
177
|
return deleted;
|
|
178
|
+
},
|
|
179
|
+
async deleteExpiredTokens(before) {
|
|
180
|
+
let deleted = 0;
|
|
181
|
+
for (const [tokenHash, stored] of byTokenHash) {
|
|
182
|
+
if (stored.expiresAt.getTime() <= before.getTime()) {
|
|
183
|
+
byTokenHash.delete(tokenHash);
|
|
184
|
+
deleted += 1;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
return deleted;
|
|
178
188
|
}
|
|
179
189
|
};
|
|
180
190
|
}
|
|
@@ -312,5 +322,5 @@ function createMemoryStores2() {
|
|
|
312
322
|
}
|
|
313
323
|
export { mintId2, isId2, mintedAt2, createMemoryStores2 };
|
|
314
324
|
|
|
315
|
-
//# debugId=
|
|
316
|
-
//# sourceMappingURL=index-
|
|
325
|
+
//# debugId=4BEC7DA3378A80BC64756E2164756E21
|
|
326
|
+
//# sourceMappingURL=index-q3w3vr69.js.map
|
|
@@ -5,13 +5,13 @@
|
|
|
5
5
|
"/**\n * An id — of a user, a session: a UUIDv7, lowercase, hyphenated.\n *\n * **The core mints it, not the store**, and that decision pays for itself three\n * times over:\n *\n * - A UUIDv7 leads with a 48-bit millisecond timestamp, so ids sort in\n * creation order as strings. The pagination cursor is therefore *the last\n * id* — one index on the id, and the ordering is already total. A\n * store-minted id would need a `createdAt` index plus the id as a tiebreak,\n * because a timestamp alone is not a total order, and an opaque cursor per\n * adapter.\n * - `insertUser` becomes **idempotent under retry**: the id is decided\n * before the call, so a retry after a timeout writes the same row rather\n * than a second user.\n * - Every adapter reports the same shape, so moving an application from one\n * adapter to another is a copy rather than a rewrite of every stored\n * reference.\n *\n * The price, stated plainly: an adapter cannot reuse an existing numeric primary\n * key. It gets a `uuid` column, or a 36-character string, and the monotonic\n * prefix gives it the index locality a UUIDv4 destroys.\n */\nexport type Id = string;\n\nconst HEX: readonly string[] = Array.from({ length: 256 }, (_, i) =>\n\ti.toString(16).padStart(2, '0'),\n);\n\nlet lastMs = -1;\nlet sequence = 0;\n\n/**\n * The 12-bit sequence UUIDv7 keeps for ordering inside one millisecond.\n *\n * RFC 9562 calls this the \"replace leftmost random bits with an increased clock\n * precision\" method. Without it, two ids minted in the same millisecond order\n * by their random tail — still a total order, which is all the port requires,\n * but not creation order, and \"newest first\" would then be wrong for anything\n * created in a burst. A signup storm is exactly such a burst.\n */\nconst SEQUENCE_MAX = 0xfff;\n\n/**\n * A fresh id.\n *\n * Strictly increasing: within one millisecond it uses the sequence, and if that\n * overflows — more than 4096 ids in a millisecond, which no real\n * application reaches — it borrows the next millisecond rather than repeating\n * one. Across processes the 62 random bits of the tail are what keep two machines\n * apart.\n */\nexport function mintId(now: number = Date.now()): Id {\n\tlet ms = now;\n\n\tif (ms === lastMs) {\n\t\tsequence += 1;\n\t\tif (sequence > SEQUENCE_MAX) {\n\t\t\t// Borrow from the next millisecond. This keeps ids strictly\n\t\t\t// increasing at the cost of a timestamp a hair ahead of the clock,\n\t\t\t// which is the right trade: a repeated id would break the cursor.\n\t\t\tms = lastMs + 1;\n\t\t\tsequence = 0;\n\t\t}\n\t} else if (ms > lastMs) {\n\t\tsequence = 0;\n\t} else {\n\t\t// The clock went backwards — an NTP step, or a container resumed. Hold\n\t\t// the last millisecond and keep counting, so ids stay ordered even\n\t\t// though they stop matching the wall clock for a moment.\n\t\tms = lastMs;\n\t\tsequence += 1;\n\t\tif (sequence > SEQUENCE_MAX) {\n\t\t\tms = lastMs + 1;\n\t\t\tsequence = 0;\n\t\t}\n\t}\n\n\tlastMs = ms;\n\n\tconst bytes = new Uint8Array(16);\n\tcrypto.getRandomValues(bytes.subarray(8));\n\n\tbytes[0] = (ms / 2 ** 40) & 0xff;\n\tbytes[1] = (ms / 2 ** 32) & 0xff;\n\tbytes[2] = (ms / 2 ** 24) & 0xff;\n\tbytes[3] = (ms / 2 ** 16) & 0xff;\n\tbytes[4] = (ms / 2 ** 8) & 0xff;\n\tbytes[5] = ms & 0xff;\n\t// Version 7 in the high nibble, the sequence's top 4 bits below it.\n\tbytes[6] = 0x70 | ((sequence >> 8) & 0x0f);\n\tbytes[7] = sequence & 0xff;\n\t// Variant 10 in the two high bits of byte 8; the rest of it stays random.\n\tbytes[8] = 0x80 | ((bytes[8] as number) & 0x3f);\n\n\treturn `${HEX[bytes[0] as number]}${HEX[bytes[1] as number]}${HEX[bytes[2] as number]}${HEX[bytes[3] as number]}-${HEX[bytes[4] as number]}${HEX[bytes[5] as number]}-${HEX[bytes[6] as number]}${HEX[bytes[7] as number]}-${HEX[bytes[8] as number]}${HEX[bytes[9] as number]}-${HEX[bytes[10] as number]}${HEX[bytes[11] as number]}${HEX[bytes[12] as number]}${HEX[bytes[13] as number]}${HEX[bytes[14] as number]}${HEX[bytes[15] as number]}`;\n}\n\nconst UUID_V7 =\n\t/^[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/;\n\n/**\n * Whether this string is an id this package could have minted.\n *\n * Used by an adapter to answer `null` for a malformed id **without reaching the\n * store**: an id arrives off a URL, and one of the wrong shape is \"no such\n * user\", not an outage and not a query. Rejecting it here also keeps a\n * hand-written id out of a store that would then hold something the cursor\n * cannot order.\n */\nexport function isId(value: string): boolean {\n\treturn UUID_V7.test(value);\n}\n\n/**\n * When this id was minted, from the id itself.\n *\n * Offered because the timestamp is *in* the id, so a `createdAt` column is a\n * convenience rather than the truth — and an adapter that loses one can still\n * answer. It is not a substitute for `createdAt`: the sequence may have borrowed\n * a millisecond, and a clock that stepped backwards is held rather than\n * followed, so this is accurate to the millisecond and no further.\n */\nexport function mintedAt(id: Id): Date {\n\tconst hex = id.replace(/-/g, '').slice(0, 12);\n\treturn new Date(Number.parseInt(hex, 16));\n}\n",
|
|
6
6
|
"/**\n * A deep copy: every record goes in and comes out through it, so a caller that\n * mutates what it passed or what it got back cannot reach the store.\n */\nexport const copy = <T>(value: T): T => structuredClone(value);\n",
|
|
7
7
|
"import type { SessionId, SessionRecord, SessionStore } from '../types';\nimport { copy } from './copy';\n\n/** What the in-memory session store holds: the records, and the index on their token hashes. */\ninterface SessionIndex {\n\treadonly byId: Map<SessionId, SessionRecord>;\n\treadonly byTokenHash: Map<string, SessionId>;\n}\n\n/** The session store in memory. */\nexport function memorySessionStore(): SessionStore {\n\tconst index: SessionIndex = {\n\t\tbyId: new Map<SessionId, SessionRecord>(),\n\t\tbyTokenHash: new Map<string, SessionId>(),\n\t};\n\tconst { byId, byTokenHash } = index;\n\n\treturn {\n\t\tasync insertSession(record) {\n\t\t\tif (byId.has(record.id)) return;\n\n\t\t\tconst written = copy(record);\n\t\t\tbyId.set(written.id, written);\n\t\t\tbyTokenHash.set(written.tokenHash, written.id);\n\t\t},\n\n\t\tasync findSessionByTokenHash(tokenHash) {\n\t\t\tconst id = byTokenHash.get(tokenHash);\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 extendSession(id, expiresAt) {\n\t\t\treturn standingWrite(index, id, { expiresAt: new Date(expiresAt) });\n\t\t},\n\n\t\tasync reauthenticateSession(id, at) {\n\t\t\treturn standingWrite(index, id, { authenticatedAt: new Date(at) });\n\t\t},\n\n\t\tasync revokeSession(id, at) {\n\t\t\tconst stored = byId.get(id);\n\t\t\tif (stored === undefined) return false;\n\n\t\t\tif (stored.revokedAt === null) revoke(index, id, stored, at);\n\t\t\treturn true;\n\t\t},\n\n\t\tasync revokeUserSessions(userId, at, except) {\n\t\t\tlet revoked = 0;\n\n\t\t\tfor (const [id, stored] of byId) {\n\t\t\t\tif (\n\t\t\t\t\tstored.userId === userId &&\n\t\t\t\t\tstored.revokedAt === null &&\n\t\t\t\t\tid !== except\n\t\t\t\t) {\n\t\t\t\t\trevoke(index, id, stored, at);\n\t\t\t\t\trevoked += 1;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn revoked;\n\t\t},\n\n\t\tasync deleteUserSessions(userId) {\n\t\t\treturn deleteWhere(index, (stored) => stored.userId === userId);\n\t\t},\n\n\t\tasync deleteExpiredSessions(before) {\n\t\t\treturn deleteWhere(\n\t\t\t\tindex,\n\t\t\t\t(stored) => stored.expiresAt.getTime() <= before.getTime(),\n\t\t\t);\n\t\t},\n\t};\n}\n\n/**\n * Writes `patch` on a session **only while it is not revoked**, and answers\n * it as written — or `null` for none, or a revoked one, never brought back.\n */\nfunction standingWrite(\n\t{ byId }: SessionIndex,\n\tid: SessionId,\n\tpatch: Pick<Partial<SessionRecord>, 'expiresAt' | 'authenticatedAt'>,\n): SessionRecord | null {\n\tconst stored = byId.get(id);\n\tif (stored === undefined || stored.revokedAt !== null) return null;\n\n\tconst written: SessionRecord = { ...stored, ...patch };\n\tbyId.set(id, written);\n\treturn copy(written);\n}\n\nfunction revoke(\n\t{ byId }: SessionIndex,\n\tid: SessionId,\n\tstored: SessionRecord,\n\tat: Date,\n): void {\n\tbyId.set(id, { ...stored, revokedAt: new Date(at) });\n}\n\n/** Deletes every session `matches` accepts, from both maps, and counts them. */\nfunction deleteWhere(\n\t{ byId, byTokenHash }: SessionIndex,\n\tmatches: (stored: SessionRecord) => boolean,\n): number {\n\tlet deleted = 0;\n\n\tfor (const [id, stored] of byId) {\n\t\tif (matches(stored)) {\n\t\t\tbyId.delete(id);\n\t\t\tbyTokenHash.delete(stored.tokenHash);\n\t\t\tdeleted += 1;\n\t\t}\n\t}\n\n\treturn deleted;\n}\n",
|
|
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",
|
|
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\n\t\tasync deleteExpiredTokens(before) {\n\t\t\tlet deleted = 0;\n\n\t\t\tfor (const [tokenHash, stored] of byTokenHash) {\n\t\t\t\tif (stored.expiresAt.getTime() <= before.getTime()) {\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
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": "
|
|
14
|
+
"mappings": ";;;;;;AAyBA,IAAM,MAAyB,MAAM,KAAK,EAAE,QAAQ,IAAI,GAAG,CAAC,GAAG,MAC9D,EAAE,SAAS,EAAE,EAAE,SAAS,GAAG,GAAG,CAC/B;AAEA,IAAI,SAAS;AACb,IAAI,WAAW;AAWf,IAAM,eAAe;AAWd,SAAS,OAAM,CAAC,MAAc,KAAK,IAAI,GAAO;AAAA,EACpD,IAAI,KAAK;AAAA,EAET,IAAI,OAAO,QAAQ;AAAA,IAClB,YAAY;AAAA,IACZ,IAAI,WAAW,cAAc;AAAA,MAI5B,KAAK,SAAS;AAAA,MACd,WAAW;AAAA,IACZ;AAAA,EACD,EAAO,SAAI,KAAK,QAAQ;AAAA,IACvB,WAAW;AAAA,EACZ,EAAO;AAAA,IAIN,KAAK;AAAA,IACL,YAAY;AAAA,IACZ,IAAI,WAAW,cAAc;AAAA,MAC5B,KAAK,SAAS;AAAA,MACd,WAAW;AAAA,IACZ;AAAA;AAAA,EAGD,SAAS;AAAA,EAET,MAAM,QAAQ,IAAI,WAAW,EAAE;AAAA,EAC/B,OAAO,gBAAgB,MAAM,SAAS,CAAC,CAAC;AAAA,EAExC,MAAM,KAAM,KAAK,KAAK,KAAM;AAAA,EAC5B,MAAM,KAAM,KAAK,KAAK,KAAM;AAAA,EAC5B,MAAM,KAAM,KAAK,KAAK,KAAM;AAAA,EAC5B,MAAM,KAAM,KAAK,KAAK,KAAM;AAAA,EAC5B,MAAM,KAAM,KAAK,KAAK,IAAK;AAAA,EAC3B,MAAM,KAAK,KAAK;AAAA,EAEhB,MAAM,KAAK,MAAS,YAAY,IAAK;AAAA,EACrC,MAAM,KAAK,WAAW;AAAA,EAEtB,MAAM,KAAK,MAAS,MAAM,KAAgB;AAAA,EAE1C,OAAO,GAAG,IAAI,MAAM,MAAgB,IAAI,MAAM,MAAgB,IAAI,MAAM,MAAgB,IAAI,MAAM,OAAiB,IAAI,MAAM,MAAgB,IAAI,MAAM,OAAiB,IAAI,MAAM,MAAgB,IAAI,MAAM,OAAiB,IAAI,MAAM,MAAgB,IAAI,MAAM,OAAiB,IAAI,MAAM,OAAiB,IAAI,MAAM,OAAiB,IAAI,MAAM,OAAiB,IAAI,MAAM,OAAiB,IAAI,MAAM,OAAiB,IAAI,MAAM;AAAA;AAGpa,IAAM,UACL;AAWM,SAAS,KAAI,CAAC,OAAwB;AAAA,EAC5C,OAAO,QAAQ,KAAK,KAAK;AAAA;AAYnB,SAAS,SAAQ,CAAC,IAAc;AAAA,EACtC,MAAM,MAAM,GAAG,QAAQ,MAAM,EAAE,EAAE,MAAM,GAAG,EAAE;AAAA,EAC5C,OAAO,IAAI,KAAK,OAAO,SAAS,KAAK,EAAE,CAAC;AAAA;;;ACzHlC,IAAM,OAAO,CAAI,UAAgB,gBAAgB,KAAK;;;ACMtD,SAAS,kBAAkB,GAAiB;AAAA,EAClD,MAAM,QAAsB;AAAA,IAC3B,MAAM,IAAI;AAAA,IACV,aAAa,IAAI;AAAA,EAClB;AAAA,EACA,QAAQ,MAAM,gBAAgB;AAAA,EAE9B,OAAO;AAAA,SACA,cAAa,CAAC,QAAQ;AAAA,MAC3B,IAAI,KAAK,IAAI,OAAO,EAAE;AAAA,QAAG;AAAA,MAEzB,MAAM,UAAU,KAAK,MAAM;AAAA,MAC3B,KAAK,IAAI,QAAQ,IAAI,OAAO;AAAA,MAC5B,YAAY,IAAI,QAAQ,WAAW,QAAQ,EAAE;AAAA;AAAA,SAGxC,uBAAsB,CAAC,WAAW;AAAA,MACvC,MAAM,KAAK,YAAY,IAAI,SAAS;AAAA,MACpC,MAAM,SAAS,OAAO,YAAY,YAAY,KAAK,IAAI,EAAE;AAAA,MACzD,OAAO,WAAW,YAAY,OAAO,KAAK,MAAM;AAAA;AAAA,SAG3C,cAAa,CAAC,IAAI,WAAW;AAAA,MAClC,OAAO,cAAc,OAAO,IAAI,EAAE,WAAW,IAAI,KAAK,SAAS,EAAE,CAAC;AAAA;AAAA,SAG7D,sBAAqB,CAAC,IAAI,IAAI;AAAA,MACnC,OAAO,cAAc,OAAO,IAAI,EAAE,iBAAiB,IAAI,KAAK,EAAE,EAAE,CAAC;AAAA;AAAA,SAG5D,cAAa,CAAC,IAAI,IAAI;AAAA,MAC3B,MAAM,SAAS,KAAK,IAAI,EAAE;AAAA,MAC1B,IAAI,WAAW;AAAA,QAAW,OAAO;AAAA,MAEjC,IAAI,OAAO,cAAc;AAAA,QAAM,OAAO,OAAO,IAAI,QAAQ,EAAE;AAAA,MAC3D,OAAO;AAAA;AAAA,SAGF,mBAAkB,CAAC,QAAQ,IAAI,QAAQ;AAAA,MAC5C,IAAI,UAAU;AAAA,MAEd,YAAY,IAAI,WAAW,MAAM;AAAA,QAChC,IACC,OAAO,WAAW,UAClB,OAAO,cAAc,QACrB,OAAO,QACN;AAAA,UACD,OAAO,OAAO,IAAI,QAAQ,EAAE;AAAA,UAC5B,WAAW;AAAA,QACZ;AAAA,MACD;AAAA,MAEA,OAAO;AAAA;AAAA,SAGF,mBAAkB,CAAC,QAAQ;AAAA,MAChC,OAAO,YAAY,OAAO,CAAC,WAAW,OAAO,WAAW,MAAM;AAAA;AAAA,SAGzD,sBAAqB,CAAC,QAAQ;AAAA,MACnC,OAAO,YACN,OACA,CAAC,WAAW,OAAO,UAAU,QAAQ,KAAK,OAAO,QAAQ,CAC1D;AAAA;AAAA,EAEF;AAAA;AAOD,SAAS,aAAa,GACnB,QACF,IACA,OACuB;AAAA,EACvB,MAAM,SAAS,KAAK,IAAI,EAAE;AAAA,EAC1B,IAAI,WAAW,aAAa,OAAO,cAAc;AAAA,IAAM,OAAO;AAAA,EAE9D,MAAM,UAAyB,KAAK,WAAW,MAAM;AAAA,EACrD,KAAK,IAAI,IAAI,OAAO;AAAA,EACpB,OAAO,KAAK,OAAO;AAAA;AAGpB,SAAS,MAAM,GACZ,QACF,IACA,QACA,IACO;AAAA,EACP,KAAK,IAAI,IAAI,KAAK,QAAQ,WAAW,IAAI,KAAK,EAAE,EAAE,CAAC;AAAA;AAIpD,SAAS,WAAW,GACjB,MAAM,eACR,SACS;AAAA,EACT,IAAI,UAAU;AAAA,EAEd,YAAY,IAAI,WAAW,MAAM;AAAA,IAChC,IAAI,QAAQ,MAAM,GAAG;AAAA,MACpB,KAAK,OAAO,EAAE;AAAA,MACd,YAAY,OAAO,OAAO,SAAS;AAAA,MACnC,WAAW;AAAA,IACZ;AAAA,EACD;AAAA,EAEA,OAAO;AAAA;;;ACnHD,SAAS,gBAAgB,GAAe;AAAA,EAC9C,MAAM,cAAc,IAAI;AAAA,EAExB,OAAO;AAAA,SACA,YAAW,CAAC,QAAQ;AAAA,MACzB,IAAI,YAAY,IAAI,OAAO,SAAS;AAAA,QAAG;AAAA,MACvC,YAAY,IAAI,OAAO,WAAW,KAAK,MAAM,CAAC;AAAA;AAAA,SAGzC,aAAY,CAAC,WAAW,MAAM,IAAI;AAAA,MAGvC,MAAM,SAAS,YAAY,IAAI,SAAS;AAAA,MACxC,IAAI,WAAW,aAAa,OAAO,SAAS;AAAA,QAAM,OAAO;AAAA,MAEzD,MAAM,SAAS,KAAK,MAAM;AAAA,MAC1B,IAAI,OAAO,YAAY,MAAM;AAAA,QAC5B,YAAY,IAAI,WAAW,KAAK,QAAQ,SAAS,IAAI,KAAK,EAAE,EAAE,CAAC;AAAA,MAChE;AAAA,MAEA,OAAO;AAAA;AAAA,SAGF,aAAY,CAAC,WAAW,MAAM;AAAA,MAGnC,MAAM,SAAS,YAAY,IAAI,SAAS;AAAA,MACxC,IAAI,WAAW,aAAa,OAAO,SAAS;AAAA,QAAM,OAAO;AAAA,MACzD,IAAI,OAAO,YAAY;AAAA,QAAM,OAAO,KAAK,MAAM;AAAA,MAE/C,MAAM,UAAU,KAAK,QAAQ,UAAU,OAAO,WAAW,EAAE;AAAA,MAC3D,YAAY,IAAI,WAAW,OAAO;AAAA,MAClC,OAAO,KAAK,OAAO;AAAA;AAAA,SAGd,gBAAe,CAAC,QAAQ,MAAM,IAAI,QAAQ;AAAA,MAC/C,IAAI,QAAQ;AAAA,MAEZ,YAAY,WAAW,WAAW,aAAa;AAAA,QAC9C,IACC,cAAc,UACd,OAAO,WAAW,UAClB,OAAO,SAAS,QAChB,OAAO,YAAY,MAClB;AAAA,UACD,YAAY,IAAI,WAAW,KAAK,QAAQ,SAAS,IAAI,KAAK,EAAE,EAAE,CAAC;AAAA,UAC/D,SAAS;AAAA,QACV;AAAA,MACD;AAAA,MAEA,OAAO;AAAA;AAAA,SAGF,iBAAgB,CAAC,QAAQ;AAAA,MAC9B,IAAI,UAAU;AAAA,MAEd,YAAY,WAAW,WAAW,aAAa;AAAA,QAC9C,IAAI,OAAO,WAAW,QAAQ;AAAA,UAC7B,YAAY,OAAO,SAAS;AAAA,UAC5B,WAAW;AAAA,QACZ;AAAA,MACD;AAAA,MAEA,OAAO;AAAA;AAAA,SAGF,oBAAmB,CAAC,QAAQ;AAAA,MACjC,IAAI,UAAU;AAAA,MAEd,YAAY,WAAW,WAAW,aAAa;AAAA,QAC9C,IAAI,OAAO,UAAU,QAAQ,KAAK,OAAO,QAAQ,GAAG;AAAA,UACnD,YAAY,OAAO,SAAS;AAAA,UAC5B,WAAW;AAAA,QACZ;AAAA,MACD;AAAA,MAEA,OAAO;AAAA;AAAA,EAET;AAAA;;;ACtEM,IAAM,QAAQ,CAAC,MAAc,UACnC,GAAG,WAAa;AAGV,IAAM,UAAU,GACpB,WACF,MACA,QACA,OAEA,OAAO,KAAK,CAAC,UAAU;AAAA,EACtB,MAAM,SAAS,QAAQ,IAAI,MAAM,MAAM,KAAK,CAAC;AAAA,EAC7C,OAAO,WAAW,aAAa,WAAW;AAAA,CAC1C;AAGK,IAAM,QAAQ,CAAC,WAAmB,MAAc,UACtD,IAAI,eACH,SACA,GAAG,4CAA4C,QAC/C,EAAE,OAAO,UAAU,MAAM,UAAU,CACpC;AAGM,SAAS,WAAW,GAAG,WAAsB,QAA0B;AAAA,EAC7E,WAAW,SAAS,OAAO,QAAQ;AAAA,IAClC,QAAQ,IAAI,MAAM,OAAO,MAAM,KAAK,GAAG,OAAO,EAAE;AAAA,EACjD;AAAA;AAIM,SAAS,UAAU,GAAG,WAAsB,QAA0B;AAAA,EAC5E,WAAW,SAAS,OAAO,QAAQ;AAAA,IAClC,QAAQ,OAAO,MAAM,OAAO,MAAM,KAAK,CAAC;AAAA,EACzC;AAAA;;;AC7BM,SAAS,YAAY,CAC3B,OACA,IACA,OACA,WACa;AAAA,EACb,MAAM,SAAS,MAAM,KAAK,IAAI,EAAE;AAAA,EAEhC,IAAI,WAAW,WAAW;AAAA,IACzB,MAAM,IAAI,eAAc,mCAAmC;AAAA,MAC1D,QAAQ;AAAA,MACR,WAAW;AAAA,IACZ,CAAC;AAAA,EACF;AAAA,EAEA,IAAI,OAAO,YAAY,WAAW;AAAA,IACjC,MAAM,IAAI,eACT,WACA,gCAAgC,oBAAoB,OAAO,WAC3D;AAAA,MACC,QAAQ;AAAA,MACR,iBAAiB;AAAA,MACjB,eAAe,OAAO;AAAA,MACtB,WAAW;AAAA,IACZ,CACD;AAAA,EACD;AAAA,EAEA,IAAI,MAAM,WAAW,WAAW;AAAA,IAC/B,MAAM,YAAY,QAAQ,OAAO,OAAO,MAAM,MAAM,QAAQ,EAAE;AAAA,IAC9D,IAAI,cAAc,WAAW;AAAA,MAC5B,MAAM,MAAM,cAAc,OAAO,MAAM,SAAS;AAAA,IACjD;AAAA,EACD;AAAA,EAEA,MAAM,UAAU,WAAW,QAAQ,KAAK,KAAK,CAAC;AAAA,EAE9C,MAAM,KAAK,IAAI,IAAI,OAAO;AAAA,EAC1B,IAAI,MAAM,WAAW,WAAW;AAAA,IAC/B,WAAW,OAAO,MAAM;AAAA,IACxB,YAAY,OAAO,OAAO;AAAA,EAC3B;AAAA,EAEA,OAAO,KAAK,OAAO;AAAA;AAYpB,SAAS,UAAU,CAAC,QAAoB,OAA8B;AAAA,EACrE,OAAO;AAAA,OACH;AAAA,IACH,eAAe,MAAM,iBAAiB,OAAO;AAAA,IAC7C,QAAQ,MAAM,UAAU,OAAO;AAAA,IAC/B,QAAQ,MAAM,UAAU,OAAO;AAAA,IAC/B,QAAQ,MAAM,UAAU,OAAO;AAAA,IAC/B,UAAU,MAAM,aAAa,YAAY,OAAO,WAAW,MAAM;AAAA,IACjE,cACC,MAAM,iBAAiB,YACpB,OAAO,eACP,MAAM;AAAA,IACV,iBACC,MAAM,oBAAoB,YACvB,OAAO,kBACP,MAAM;AAAA,IACV,SAAS,OAAO,UAAU;AAAA,IAC1B,WAAW,MAAM;AAAA,EAClB;AAAA;;;AC5EM,SAAS,eAAe,GAAc;AAAA,EAC5C,MAAM,QAAmB;AAAA,IACxB,MAAM,IAAI;AAAA,IACV,SAAS,IAAI;AAAA,EACd;AAAA,EACA,QAAQ,MAAM,YAAY;AAAA,EAE1B,OAAO;AAAA,SACA,WAAU,CAAC,QAAQ;AAAA,MACxB,MAAM,SAAS,KAAK,IAAI,OAAO,EAAE;AAAA,MACjC,IAAI,WAAW;AAAA,QAAW,OAAO,KAAK,MAAM;AAAA,MAE5C,MAAM,YAAY,QAAQ,OAAO,OAAO,MAAM,OAAO,QAAQ,OAAO,EAAE;AAAA,MACtE,IAAI,cAAc,WAAW;AAAA,QAC5B,MAAM,MAAM,cAAc,OAAO,MAAM,SAAS;AAAA,MACjD;AAAA,MAEA,MAAM,UAAU,KAAK,MAAM;AAAA,MAC3B,KAAK,IAAI,QAAQ,IAAI,OAAO;AAAA,MAC5B,YAAY,OAAO,OAAO;AAAA,MAE1B,OAAO,KAAK,OAAO;AAAA;AAAA,SAGd,SAAQ,CAAC,IAAI;AAAA,MAClB,MAAM,SAAS,KAAK,IAAI,EAAE;AAAA,MAC1B,OAAO,WAAW,YAAY,OAAO,KAAK,MAAM;AAAA;AAAA,SAG3C,UAAS,CAAC,KAAK;AAAA,MACpB,OAAO,CAAC,GAAG,IAAI,IAAI,GAAG,CAAC,EAAE,QAAQ,CAAC,OAAO;AAAA,QACxC,MAAM,SAAS,KAAK,IAAI,EAAE;AAAA,QAC1B,OAAO,WAAW,YAAY,CAAC,IAAI,CAAC,KAAK,MAAM,CAAC;AAAA,OAChD;AAAA;AAAA,SAGI,gBAAe,CAAC,MAAM,OAAO;AAAA,MAClC,MAAM,KAAK,QAAQ,IAAI,MAAM,MAAM,KAAK,CAAC;AAAA,MACzC,MAAM,SAAS,OAAO,YAAY,YAAY,KAAK,IAAI,EAAE;AAAA,MACzD,OAAO,WAAW,YAAY,OAAO,KAAK,MAAM;AAAA;AAAA,SAG3C,UAAS,GAAG,MAAM,OAAO,SAAS;AAAA,MAGvC,MAAM,MAAM,CAAC,GAAG,KAAK,OAAO,CAAC,EAC3B,OAAO,CAAC,SAAS,KAAK,SAAS,IAAI,EACnC,IAAI,CAAC,SAAS,KAAK,EAAE,EACrB,OAAO,CAAC,OAAO,UAAU,QAAQ,KAAK,KAAK,EAC3C,KAAK;AAAA,MACP,MAAM,UAAU,IAAI,MAAM,GAAG,KAAK;AAAA,MAClC,MAAM,OAAO,QAAQ,GAAG,EAAE;AAAA,MAE1B,OAAO;AAAA,QACN,OAAO,QAAQ,IAAI,CAAC,OAAO,KAAK,KAAK,IAAI,EAAE,CAAe,CAAC;AAAA,QAC3D,YAAY,IAAI,SAAS,SAAS,SAAS,YAAY,OAAO;AAAA,MAC/D;AAAA;AAAA,SAGK,WAAU,CAAC,IAAI,OAAO,WAAW;AAAA,MACtC,OAAO,aAAa,OAAO,IAAI,OAAO,SAAS;AAAA;AAAA,SAG1C,WAAU,CAAC,IAAI;AAAA,MACpB,MAAM,SAAS,KAAK,IAAI,EAAE;AAAA,MAC1B,IAAI,WAAW;AAAA,QAAW,OAAO;AAAA,MAEjC,KAAK,OAAO,EAAE;AAAA,MACd,WAAW,OAAO,MAAM;AAAA,MACxB,OAAO;AAAA;AAAA,EAET;AAAA;;;AC1DM,SAAS,mBAAkB,GAAgB;AAAA,EACjD,OAAO;AAAA,IACN,OAAO,gBAAgB;AAAA,IACvB,UAAU,mBAAmB;AAAA,IAC7B,QAAQ,iBAAiB;AAAA,EAC1B;AAAA;",
|
|
15
|
+
"debugId": "4BEC7DA3378A80BC64756E2164756E21",
|
|
16
16
|
"names": []
|
|
17
17
|
}
|