@happyvertical/smrt-users 0.55.22 → 0.55.24

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 (42) hide show
  1. package/AGENTS.md +8 -0
  2. package/README.md +129 -0
  3. package/agents/permissions.md +8 -0
  4. package/dist/chunks/{TerminalAuthService-BHqR0fQH.js → TerminalAuthService-B0icE2mR.js} +282 -116
  5. package/dist/chunks/TerminalAuthService-B0icE2mR.js.map +1 -0
  6. package/dist/collections/GroupMemberCollection.d.ts +6 -2
  7. package/dist/collections/GroupMemberCollection.d.ts.map +1 -1
  8. package/dist/collections/MembershipOverrideCollection.d.ts +9 -2
  9. package/dist/collections/MembershipOverrideCollection.d.ts.map +1 -1
  10. package/dist/collections/TenantPermissionOverrideCollection.d.ts +8 -2
  11. package/dist/collections/TenantPermissionOverrideCollection.d.ts.map +1 -1
  12. package/dist/index.d.ts +2 -1
  13. package/dist/index.d.ts.map +1 -1
  14. package/dist/index.js +84 -29
  15. package/dist/index.js.map +1 -1
  16. package/dist/manifest.json +75 -45
  17. package/dist/migrations/deduplicateAuthorityPairs.d.ts +27 -0
  18. package/dist/migrations/deduplicateAuthorityPairs.d.ts.map +1 -0
  19. package/dist/migrations/deduplicateRolePermissions.d.ts +3 -10
  20. package/dist/migrations/deduplicateRolePermissions.d.ts.map +1 -1
  21. package/dist/migrations/natural-key-dedup.d.ts +32 -0
  22. package/dist/migrations/natural-key-dedup.d.ts.map +1 -0
  23. package/dist/models/GroupMember.d.ts.map +1 -1
  24. package/dist/models/LoginAuditEvent.d.ts +5 -0
  25. package/dist/models/LoginAuditEvent.d.ts.map +1 -1
  26. package/dist/models/MembershipOverride.d.ts.map +1 -1
  27. package/dist/models/Session.d.ts +9 -0
  28. package/dist/models/Session.d.ts.map +1 -1
  29. package/dist/models/TenantPermissionOverride.d.ts.map +1 -1
  30. package/dist/services/LoginAttemptLimiter.d.ts +62 -11
  31. package/dist/services/LoginAttemptLimiter.d.ts.map +1 -1
  32. package/dist/services/PasswordCredentialService.d.ts +83 -1
  33. package/dist/services/PasswordCredentialService.d.ts.map +1 -1
  34. package/dist/services/index.d.ts +2 -2
  35. package/dist/services/index.d.ts.map +1 -1
  36. package/dist/smrt-knowledge.json +16 -9
  37. package/dist/sveltekit/password-handlers.d.ts +7 -0
  38. package/dist/sveltekit/password-handlers.d.ts.map +1 -1
  39. package/dist/sveltekit.js +13 -1
  40. package/dist/sveltekit.js.map +1 -1
  41. package/package.json +13 -13
  42. package/dist/chunks/TerminalAuthService-BHqR0fQH.js.map +0 -1
@@ -2,7 +2,7 @@
2
2
  "version": "1.0.0",
3
3
  "timestamp": 0,
4
4
  "packageName": "@happyvertical/smrt-users",
5
- "packageVersion": "0.55.22",
5
+ "packageVersion": "0.55.24",
6
6
  "objects": {
7
7
  "@happyvertical/smrt-users:AccessRequestCollection": {
8
8
  "name": "accessrequestcollection",
@@ -878,23 +878,24 @@
878
878
  },
879
879
  "indexes": [
880
880
  {
881
- "name": "group_members_slug_context_idx",
881
+ "name": "group_members_group_id_user_id_idx",
882
882
  "columns": [
883
- "slug",
884
- "context"
883
+ "group_id",
884
+ "user_id"
885
885
  ],
886
886
  "unique": true
887
887
  },
888
888
  {
889
- "name": "group_members_created_at_idx",
889
+ "name": "group_members_slug_context_idx",
890
890
  "columns": [
891
- "created_at"
891
+ "slug",
892
+ "context"
892
893
  ]
893
894
  },
894
895
  {
895
- "name": "group_members_group_id_idx",
896
+ "name": "group_members_created_at_idx",
896
897
  "columns": [
897
- "group_id"
898
+ "created_at"
898
899
  ]
899
900
  },
900
901
  {
@@ -2051,23 +2052,24 @@
2051
2052
  },
2052
2053
  "indexes": [
2053
2054
  {
2054
- "name": "membership_overrides_slug_context_idx",
2055
+ "name": "membership_overrides_membership_id_permission_id_idx",
2055
2056
  "columns": [
2056
- "slug",
2057
- "context"
2057
+ "membership_id",
2058
+ "permission_id"
2058
2059
  ],
2059
2060
  "unique": true
2060
2061
  },
2061
2062
  {
2062
- "name": "membership_overrides_created_at_idx",
2063
+ "name": "membership_overrides_slug_context_idx",
2063
2064
  "columns": [
2064
- "created_at"
2065
+ "slug",
2066
+ "context"
2065
2067
  ]
2066
2068
  },
2067
2069
  {
2068
- "name": "membership_overrides_membership_id_idx",
2070
+ "name": "membership_overrides_created_at_idx",
2069
2071
  "columns": [
2070
- "membership_id"
2072
+ "created_at"
2071
2073
  ]
2072
2074
  },
2073
2075
  {
@@ -5472,14 +5474,20 @@
5472
5474
  },
5473
5475
  "indexes": [
5474
5476
  {
5475
- "name": "tenant_permission_overrides_tenant_id_slug_idx",
5477
+ "name": "tenant_permission_overrides_tenant_id_permission_id_idx",
5476
5478
  "columns": [
5477
5479
  "tenant_id",
5478
- "slug",
5479
- "context"
5480
+ "permission_id"
5480
5481
  ],
5481
5482
  "unique": true
5482
5483
  },
5484
+ {
5485
+ "name": "tenant_permission_overrides_slug_context_idx",
5486
+ "columns": [
5487
+ "slug",
5488
+ "context"
5489
+ ]
5490
+ },
5483
5491
  {
5484
5492
  "name": "tenant_permission_overrides_created_at_idx",
5485
5493
  "columns": [
@@ -6543,7 +6551,8 @@
6543
6551
  "required": true,
6544
6552
  "related": "Group",
6545
6553
  "_meta": {
6546
- "required": true
6554
+ "required": true,
6555
+ "onDelete": "NO ACTION"
6547
6556
  }
6548
6557
  },
6549
6558
  "userId": {
@@ -6551,7 +6560,8 @@
6551
6560
  "required": true,
6552
6561
  "related": "User",
6553
6562
  "_meta": {
6554
- "required": true
6563
+ "required": true,
6564
+ "onDelete": "NO ACTION"
6555
6565
  }
6556
6566
  }
6557
6567
  },
@@ -6574,7 +6584,11 @@
6574
6584
  "list",
6575
6585
  "get"
6576
6586
  ]
6577
- }
6587
+ },
6588
+ "conflictColumns": [
6589
+ "group_id",
6590
+ "user_id"
6591
+ ]
6578
6592
  },
6579
6593
  "extends": "SmrtObject",
6580
6594
  "exportName": "GroupMember",
@@ -6647,23 +6661,24 @@
6647
6661
  },
6648
6662
  "indexes": [
6649
6663
  {
6650
- "name": "group_members_slug_context_idx",
6664
+ "name": "group_members_group_id_user_id_idx",
6651
6665
  "columns": [
6652
- "slug",
6653
- "context"
6666
+ "group_id",
6667
+ "user_id"
6654
6668
  ],
6655
6669
  "unique": true
6656
6670
  },
6657
6671
  {
6658
- "name": "group_members_created_at_idx",
6672
+ "name": "group_members_slug_context_idx",
6659
6673
  "columns": [
6660
- "created_at"
6674
+ "slug",
6675
+ "context"
6661
6676
  ]
6662
6677
  },
6663
6678
  {
6664
- "name": "group_members_group_id_idx",
6679
+ "name": "group_members_created_at_idx",
6665
6680
  "columns": [
6666
- "group_id"
6681
+ "created_at"
6667
6682
  ]
6668
6683
  },
6669
6684
  {
@@ -7075,6 +7090,7 @@
7075
7090
  "failed",
7076
7091
  "succeeded",
7077
7092
  "locked",
7093
+ "source-locked",
7078
7094
  "managed"
7079
7095
  ]
7080
7096
  },
@@ -7665,7 +7681,8 @@
7665
7681
  "required": true,
7666
7682
  "related": "Membership",
7667
7683
  "_meta": {
7668
- "required": true
7684
+ "required": true,
7685
+ "onDelete": "NO ACTION"
7669
7686
  }
7670
7687
  },
7671
7688
  "permissionId": {
@@ -7673,7 +7690,8 @@
7673
7690
  "required": true,
7674
7691
  "related": "Permission",
7675
7692
  "_meta": {
7676
- "required": true
7693
+ "required": true,
7694
+ "onDelete": "NO ACTION"
7677
7695
  }
7678
7696
  },
7679
7697
  "effect": {
@@ -7718,7 +7736,11 @@
7718
7736
  "list",
7719
7737
  "get"
7720
7738
  ]
7721
- }
7739
+ },
7740
+ "conflictColumns": [
7741
+ "membership_id",
7742
+ "permission_id"
7743
+ ]
7722
7744
  },
7723
7745
  "extends": "SmrtObject",
7724
7746
  "exportName": "MembershipOverride",
@@ -7796,23 +7818,24 @@
7796
7818
  },
7797
7819
  "indexes": [
7798
7820
  {
7799
- "name": "membership_overrides_slug_context_idx",
7821
+ "name": "membership_overrides_membership_id_permission_id_idx",
7800
7822
  "columns": [
7801
- "slug",
7802
- "context"
7823
+ "membership_id",
7824
+ "permission_id"
7803
7825
  ],
7804
7826
  "unique": true
7805
7827
  },
7806
7828
  {
7807
- "name": "membership_overrides_created_at_idx",
7829
+ "name": "membership_overrides_slug_context_idx",
7808
7830
  "columns": [
7809
- "created_at"
7831
+ "slug",
7832
+ "context"
7810
7833
  ]
7811
7834
  },
7812
7835
  {
7813
- "name": "membership_overrides_membership_id_idx",
7836
+ "name": "membership_overrides_created_at_idx",
7814
7837
  "columns": [
7815
- "membership_id"
7838
+ "created_at"
7816
7839
  ]
7817
7840
  },
7818
7841
  {
@@ -11182,7 +11205,8 @@
11182
11205
  "required": true,
11183
11206
  "related": "Tenant",
11184
11207
  "_meta": {
11185
- "required": true
11208
+ "required": true,
11209
+ "onDelete": "NO ACTION"
11186
11210
  }
11187
11211
  },
11188
11212
  "permissionId": {
@@ -11190,7 +11214,8 @@
11190
11214
  "required": true,
11191
11215
  "related": "Permission",
11192
11216
  "_meta": {
11193
- "required": true
11217
+ "required": true,
11218
+ "onDelete": "NO ACTION"
11194
11219
  }
11195
11220
  },
11196
11221
  "effect": {
@@ -11254,8 +11279,7 @@
11254
11279
  },
11255
11280
  "conflictColumns": [
11256
11281
  "tenant_id",
11257
- "slug",
11258
- "context"
11282
+ "permission_id"
11259
11283
  ]
11260
11284
  },
11261
11285
  "extends": "SmrtObject",
@@ -11334,14 +11358,20 @@
11334
11358
  },
11335
11359
  "indexes": [
11336
11360
  {
11337
- "name": "tenant_permission_overrides_tenant_id_slug_idx",
11361
+ "name": "tenant_permission_overrides_tenant_id_permission_id_idx",
11338
11362
  "columns": [
11339
11363
  "tenant_id",
11340
- "slug",
11341
- "context"
11364
+ "permission_id"
11342
11365
  ],
11343
11366
  "unique": true
11344
11367
  },
11368
+ {
11369
+ "name": "tenant_permission_overrides_slug_context_idx",
11370
+ "columns": [
11371
+ "slug",
11372
+ "context"
11373
+ ]
11374
+ },
11345
11375
  {
11346
11376
  "name": "tenant_permission_overrides_created_at_idx",
11347
11377
  "columns": [
@@ -0,0 +1,27 @@
1
+ import type { DatabaseInterface } from '@happyvertical/sql';
2
+ import { type NaturalKeyDedupOptions, type NaturalKeyDedupResult } from './natural-key-dedup.js';
3
+ /** Options for the explicit, maintenance-window authority-pair migration. */
4
+ export type DeduplicateAuthorityPairsOptions = NaturalKeyDedupOptions;
5
+ /** Per-table result of {@link deduplicateAuthorityPairs}. */
6
+ export interface DeduplicateAuthorityPairsResult {
7
+ membershipOverrides: NaturalKeyDedupResult;
8
+ tenantPermissionOverrides: NaturalKeyDedupResult;
9
+ groupMembers: NaturalKeyDedupResult;
10
+ }
11
+ /**
12
+ * Collapse duplicate `MembershipOverride`, `TenantPermissionOverride` and
13
+ * `GroupMember` rows to one per natural-key pair and install the unique
14
+ * indexes their models now declare (#3375). Run BEFORE ordinary schema
15
+ * migration, with every writer stopped: adding the indexes directly fails
16
+ * while duplicates exist, and older application versions do not write
17
+ * against them safely.
18
+ *
19
+ * Override pairs keep the row whose effect the resolver already applies
20
+ * (DENY, then GRANT, then INHERIT), so the effective authority of every pair
21
+ * is unchanged; ties, and group memberships, keep the earliest `created_at`
22
+ * (lowest `id` breaks ties; null timestamps sort last). Survivors are
23
+ * unchanged. All three tables commit together; failure leaves them intact.
24
+ * Re-running is safe.
25
+ */
26
+ export declare function deduplicateAuthorityPairs(db: DatabaseInterface, options?: DeduplicateAuthorityPairsOptions): Promise<DeduplicateAuthorityPairsResult>;
27
+ //# sourceMappingURL=deduplicateAuthorityPairs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deduplicateAuthorityPairs.d.ts","sourceRoot":"","sources":["../../src/migrations/deduplicateAuthorityPairs.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAC5D,OAAO,EAEL,KAAK,sBAAsB,EAC3B,KAAK,qBAAqB,EAE3B,MAAM,wBAAwB,CAAC;AAEhC,6EAA6E;AAC7E,MAAM,MAAM,gCAAgC,GAAG,sBAAsB,CAAC;AAEtE,6DAA6D;AAC7D,MAAM,WAAW,+BAA+B;IAC9C,mBAAmB,EAAE,qBAAqB,CAAC;IAC3C,yBAAyB,EAAE,qBAAqB,CAAC;IACjD,YAAY,EAAE,qBAAqB,CAAC;CACrC;AAgCD;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,yBAAyB,CAC7C,EAAE,EAAE,iBAAiB,EACrB,OAAO,GAAE,gCAAqC,GAC7C,OAAO,CAAC,+BAA+B,CAAC,CAS1C"}
@@ -1,16 +1,9 @@
1
1
  import type { DatabaseInterface } from '@happyvertical/sql';
2
+ import { type NaturalKeyDedupOptions, type NaturalKeyDedupResult } from './natural-key-dedup.js';
2
3
  /** Options for the explicit, maintenance-window grant migration. */
3
- export interface DeduplicateRolePermissionsOptions {
4
- /** Inspect the duplicate count without changing rows or indexes. */
5
- dryRun?: boolean;
6
- /** Confirm all application writers and seeders are stopped. */
7
- maintenanceConfirmed?: boolean;
8
- }
4
+ export type DeduplicateRolePermissionsOptions = NaturalKeyDedupOptions;
9
5
  /** Result of the grant migration; removed is zero for a dry run. */
10
- export interface DeduplicateRolePermissionsResult {
11
- duplicates: number;
12
- removed: number;
13
- }
6
+ export type DeduplicateRolePermissionsResult = NaturalKeyDedupResult;
14
7
  /**
15
8
  * Keep the oldest grant for each role/permission pair and install its unique
16
9
  * index. Run BEFORE ordinary schema migration, with every writer stopped;
@@ -1 +1 @@
1
- {"version":3,"file":"deduplicateRolePermissions.d.ts","sourceRoot":"","sources":["../../src/migrations/deduplicateRolePermissions.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAE5D,oEAAoE;AACpE,MAAM,WAAW,iCAAiC;IAChD,oEAAoE;IACpE,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,+DAA+D;IAC/D,oBAAoB,CAAC,EAAE,OAAO,CAAC;CAChC;AAED,oEAAoE;AACpE,MAAM,WAAW,gCAAgC;IAC/C,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;CACjB;AASD;;;;;;;GAOG;AACH,wBAAsB,0BAA0B,CAC9C,EAAE,EAAE,iBAAiB,EACrB,OAAO,GAAE,iCAAsC,GAC9C,OAAO,CAAC,gCAAgC,CAAC,CA0C3C"}
1
+ {"version":3,"file":"deduplicateRolePermissions.d.ts","sourceRoot":"","sources":["../../src/migrations/deduplicateRolePermissions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAC5D,OAAO,EAEL,KAAK,sBAAsB,EAC3B,KAAK,qBAAqB,EAC3B,MAAM,wBAAwB,CAAC;AAEhC,oEAAoE;AACpE,MAAM,MAAM,iCAAiC,GAAG,sBAAsB,CAAC;AAEvE,oEAAoE;AACpE,MAAM,MAAM,gCAAgC,GAAG,qBAAqB,CAAC;AAErE;;;;;;;GAOG;AACH,wBAAsB,0BAA0B,CAC9C,EAAE,EAAE,iBAAiB,EACrB,OAAO,GAAE,iCAAsC,GAC9C,OAAO,CAAC,gCAAgC,CAAC,CAc3C"}
@@ -0,0 +1,32 @@
1
+ import type { DatabaseInterface } from '@happyvertical/sql';
2
+ /** Options shared by the maintenance-window natural-key migrations. */
3
+ export interface NaturalKeyDedupOptions {
4
+ /** Inspect the duplicate count without changing rows or indexes. */
5
+ dryRun?: boolean;
6
+ /** Confirm all application writers and seeders are stopped. */
7
+ maintenanceConfirmed?: boolean;
8
+ }
9
+ /** Per-table result; removed is zero for a dry run. */
10
+ export interface NaturalKeyDedupResult {
11
+ duplicates: number;
12
+ removed: number;
13
+ }
14
+ /** One table whose rows must be unique on a column pair. */
15
+ export interface NaturalKeyDedupTarget {
16
+ table: string;
17
+ columns: readonly [string, string];
18
+ /** Unique index the generated schema declares for the pair. */
19
+ index: string;
20
+ /**
21
+ * Leading ORDER BY terms that choose the survivor before the oldest-row
22
+ * rule, e.g. the effect the resolver already applies for the pair.
23
+ */
24
+ survivorOrder?: string;
25
+ }
26
+ /**
27
+ * Remove natural-key duplicates and install each target's unique index in one
28
+ * transaction, so failure leaves every table as it was. Run BEFORE ordinary
29
+ * schema migration with every writer stopped. Re-running is safe.
30
+ */
31
+ export declare function deduplicateNaturalKeys(db: DatabaseInterface, targets: readonly NaturalKeyDedupTarget[], options: NaturalKeyDedupOptions, label: string): Promise<NaturalKeyDedupResult[]>;
32
+ //# sourceMappingURL=natural-key-dedup.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"natural-key-dedup.d.ts","sourceRoot":"","sources":["../../src/migrations/natural-key-dedup.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAE5D,uEAAuE;AACvE,MAAM,WAAW,sBAAsB;IACrC,oEAAoE;IACpE,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,+DAA+D;IAC/D,oBAAoB,CAAC,EAAE,OAAO,CAAC;CAChC;AAED,uDAAuD;AACvD,MAAM,WAAW,qBAAqB;IACpC,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,4DAA4D;AAC5D,MAAM,WAAW,qBAAqB;IACpC,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACnC,+DAA+D;IAC/D,KAAK,EAAE,MAAM,CAAC;IACd;;;OAGG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAcD;;;;GAIG;AACH,wBAAsB,sBAAsB,CAC1C,EAAE,EAAE,iBAAiB,EACrB,OAAO,EAAE,SAAS,qBAAqB,EAAE,EACzC,OAAO,EAAE,sBAAsB,EAC/B,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,qBAAqB,EAAE,CAAC,CAyDlC"}
@@ -1 +1 @@
1
- {"version":3,"file":"GroupMember.d.ts","sourceRoot":"","sources":["../../src/models/GroupMember.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAEL,UAAU,EACV,KAAK,iBAAiB,EAEvB,MAAM,0BAA0B,CAAC;AAElC;;GAEG;AACH,MAAM,WAAW,kBAAmB,SAAQ,iBAAiB;IAC3D,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;;;;;;;;;;GAeG;AACH,qBASa,WAAY,SAAQ,UAAU;IACzC;;OAEG;IAEH,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB;;OAEG;IAEH,MAAM,CAAC,EAAE,MAAM,CAAC;gBAEJ,OAAO,GAAE,kBAAuB;CAK7C"}
1
+ {"version":3,"file":"GroupMember.d.ts","sourceRoot":"","sources":["../../src/models/GroupMember.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAEL,UAAU,EACV,KAAK,iBAAiB,EAEvB,MAAM,0BAA0B,CAAC;AAElC;;GAEG;AACH,MAAM,WAAW,kBAAmB,SAAQ,iBAAiB;IAC3D,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;;;;;;;;;;GAeG;AACH,qBAaa,WAAY,SAAQ,UAAU;IACzC;;OAEG;IAEH,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB;;OAEG;IAEH,MAAM,CAAC,EAAE,MAAM,CAAC;gBAEJ,OAAO,GAAE,kBAAuB;CAK7C"}
@@ -19,6 +19,11 @@ export type LoginAuditOutcome =
19
19
  | 'succeeded'
20
20
  /** A failure exhausted the budget and the key is now locked out. */
21
21
  | 'locked'
22
+ /**
23
+ * A failure started a SOURCE lockout (#3531). Carries the source hash only,
24
+ * never a subject; rate limited per source.
25
+ */
26
+ | 'source-locked'
22
27
  /** A credential was set, reset, or cleared (administrative). */
23
28
  | 'managed';
24
29
  export declare class UsersLoginAuditEvent extends SmrtObject {
@@ -1 +1 @@
1
- {"version":3,"file":"LoginAuditEvent.d.ts","sourceRoot":"","sources":["../../src/models/LoginAuditEvent.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAS,UAAU,EAAQ,MAAM,0BAA0B,CAAC;AAEnE,0CAA0C;AAC1C,MAAM,MAAM,iBAAiB;AAC3B,0EAA0E;AACxE,QAAQ;AACV,wDAAwD;GACtD,QAAQ;AACV,yCAAyC;GACvC,WAAW;AACb,oEAAoE;GAClE,QAAQ;AACV,gEAAgE;GAC9D,SAAS,CAAC;AAEd,qBASa,oBAAqB,SAAQ,UAAU;IAClD,2EAA2E;IAE3E,IAAI,SAAM;IAGV,OAAO,EAAE,iBAAiB,CAAY;IAEtC,mEAAmE;IAEnE,cAAc,EAAE,MAAM,GAAG,IAAI,CAAQ;IAErC,gFAAgF;IAEhF,aAAa,EAAE,MAAM,GAAG,IAAI,CAAQ;IAEpC,sEAAsE;IAEtE,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAQ;IAExC;;;;OAIG;IAEH,UAAU,OAAc;IAExB;;;;OAIG;IAEH,QAAQ,SAAQ;IAEhB,WAAW,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAWtC,WAAW,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;CAGlD"}
1
+ {"version":3,"file":"LoginAuditEvent.d.ts","sourceRoot":"","sources":["../../src/models/LoginAuditEvent.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAS,UAAU,EAAQ,MAAM,0BAA0B,CAAC;AAEnE,0CAA0C;AAC1C,MAAM,MAAM,iBAAiB;AAC3B,0EAA0E;AACxE,QAAQ;AACV,wDAAwD;GACtD,QAAQ;AACV,yCAAyC;GACvC,WAAW;AACb,oEAAoE;GAClE,QAAQ;AACV;;;GAGG;GACD,eAAe;AACjB,gEAAgE;GAC9D,SAAS,CAAC;AAEd,qBASa,oBAAqB,SAAQ,UAAU;IAClD,2EAA2E;IAE3E,IAAI,SAAM;IAGV,OAAO,EAAE,iBAAiB,CAAY;IAEtC,mEAAmE;IAEnE,cAAc,EAAE,MAAM,GAAG,IAAI,CAAQ;IAErC,gFAAgF;IAEhF,aAAa,EAAE,MAAM,GAAG,IAAI,CAAQ;IAEpC,sEAAsE;IAEtE,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAQ;IAExC;;;;OAIG;IAEH,UAAU,OAAc;IAExB;;;;OAIG;IAEH,QAAQ,SAAQ;IAEhB,WAAW,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAWtC,WAAW,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;CAGlD"}
@@ -1 +1 @@
1
- {"version":3,"file":"MembershipOverride.d.ts","sourceRoot":"","sources":["../../src/models/MembershipOverride.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAGL,UAAU,EACV,KAAK,iBAAiB,EAEvB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAEnD;;GAEG;AACH,MAAM,WAAW,yBAA0B,SAAQ,iBAAiB;IAClE,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,CAAC,EAAE,cAAc,CAAC;CACzB;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,qBASa,kBAAmB,SAAQ,UAAU;IAChD;;OAEG;IAEH,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB;;OAEG;IAEH,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB;;OAEG;IAEH,MAAM,EAAE,cAAc,CAAwB;gBAElC,OAAO,GAAE,yBAA8B;IASnD;;OAEG;IACH,OAAO,IAAI,OAAO;IAIlB;;OAEG;IACH,MAAM,IAAI,OAAO;CAGlB"}
1
+ {"version":3,"file":"MembershipOverride.d.ts","sourceRoot":"","sources":["../../src/models/MembershipOverride.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAGL,UAAU,EACV,KAAK,iBAAiB,EAEvB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAEnD;;GAEG;AACH,MAAM,WAAW,yBAA0B,SAAQ,iBAAiB;IAClE,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,CAAC,EAAE,cAAc,CAAC;CACzB;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,qBAaa,kBAAmB,SAAQ,UAAU;IAChD;;OAEG;IAEH,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB;;OAEG;IAEH,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB;;OAEG;IAEH,MAAM,EAAE,cAAc,CAAwB;gBAElC,OAAO,GAAE,yBAA8B;IASnD;;OAEG;IACH,OAAO,IAAI,OAAO;IAIlB;;OAEG;IACH,MAAM,IAAI,OAAO;CAGlB"}
@@ -43,6 +43,15 @@ export declare const SESSION_DATA_KEYS: {
43
43
  readonly absoluteExpiresAt: "absoluteExpiresAt";
44
44
  /** Sliding idle timeout in seconds, applied on every recorded activity. */
45
45
  readonly idleSeconds: "idleSeconds";
46
+ /**
47
+ * ISO timestamp of the out-of-band proof (a recovery link, an operator-
48
+ * issued code) a host verified before minting this session (#3905). Set
49
+ * only by the host's recovery flow at mint; it is what
50
+ * `PasswordCredentialService.replaceForgottenPassword` measures freshness
51
+ * from, and it survives tenant-switch rotation (unlike the row's
52
+ * `created_at`).
53
+ */
54
+ readonly outOfBandProofAt: "outOfBandProofAt";
46
55
  };
47
56
  /**
48
57
  * Expiry for a session minted or extended now: `ttlSeconds` ahead, bounded by
@@ -1 +1 @@
1
- {"version":3,"file":"Session.d.ts","sourceRoot":"","sources":["../../src/models/Session.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"Session.d.ts","sourceRoot":"","sources":["../../src/models/Session.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"TenantPermissionOverride.d.ts","sourceRoot":"","sources":["../../src/models/TenantPermissionOverride.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAGL,UAAU,EACV,KAAK,iBAAiB,EAEvB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AAE3D;;GAEG;AACH,MAAM,WAAW,+BAAgC,SAAQ,iBAAiB;IACxE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,CAAC,EAAE,sBAAsB,CAAC;CACjC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AACH,qBASa,wBAAyB,SAAQ,UAAU;IACtD;;OAEG;IAEH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB;;OAEG;IAEH,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB;;OAEG;IAEH,MAAM,EAAE,sBAAsB,CAAkC;gBAEpD,OAAO,GAAE,+BAAoC;IAQzD;;OAEG;IACH,SAAS,IAAI,OAAO;IAIpB;;OAEG;IACH,OAAO,IAAI,OAAO;IAIlB;;OAEG;IACH,MAAM,IAAI,OAAO;IAIjB;;OAEG;IACH,iBAAiB,IAAI,OAAO;CAG7B"}
1
+ {"version":3,"file":"TenantPermissionOverride.d.ts","sourceRoot":"","sources":["../../src/models/TenantPermissionOverride.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAGL,UAAU,EACV,KAAK,iBAAiB,EAEvB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AAE3D;;GAEG;AACH,MAAM,WAAW,+BAAgC,SAAQ,iBAAiB;IACxE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,CAAC,EAAE,sBAAsB,CAAC;CACjC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AACH,qBAaa,wBAAyB,SAAQ,UAAU;IACtD;;OAEG;IAEH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB;;OAEG;IAEH,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB;;OAEG;IAEH,MAAM,EAAE,sBAAsB,CAAkC;gBAEpD,OAAO,GAAE,+BAAoC;IAQzD;;OAEG;IACH,SAAS,IAAI,OAAO;IAIpB;;OAEG;IACH,OAAO,IAAI,OAAO;IAIlB;;OAEG;IACH,MAAM,IAAI,OAAO;IAIjB;;OAEG;IACH,iBAAiB,IAAI,OAAO;CAG7B"}
@@ -21,7 +21,9 @@
21
21
  * the client submitted — an email key or user id, never a resolved account)
22
22
  * and the **source** (client IP, or the device/station the attempt came
23
23
  * from). Either one being exhausted refuses the attempt. Both are stored as
24
- * hashes.
24
+ * hashes. Each budget can be sized on its own (`subject`, `source`), and the
25
+ * source budget can be turned off (`source: false`) where no trustworthy
26
+ * client address exists (#3531).
25
27
  *
26
28
  * ## Non-enumeration
27
29
  *
@@ -49,7 +51,10 @@
49
51
  *
50
52
  * Every decision is reported to a {@link LoginAuditSink}. The default sink
51
53
  * persists {@link UsersLoginAuditEvent} rows; pass `audit: false` to disable
52
- * or supply a sink that forwards to the host's own log.
54
+ * or supply a sink that forwards to the host's own log. When a failure starts
55
+ * a SOURCE lockout the limiter also reports one `source-locked` entry that
56
+ * carries the source hash but no subject (so it never names the accounts that
57
+ * were tried), at most once per source per `sourceLockoutAuditSeconds`.
53
58
  *
54
59
  * @packageDocumentation
55
60
  */
@@ -66,6 +71,8 @@ export declare const DEFAULT_LOGIN_LOCKOUT_BASE_SECONDS = 60;
66
71
  export declare const DEFAULT_LOGIN_LOCKOUT_FACTOR = 2;
67
72
  /** Default lockout ceiling (1 hour). */
68
73
  export declare const DEFAULT_LOGIN_LOCKOUT_MAX_SECONDS: number;
74
+ /** Default minimum spacing of `source-locked` audit entries per source (5 minutes). */
75
+ export declare const DEFAULT_SOURCE_LOCKOUT_AUDIT_SECONDS: number;
69
76
  export interface LoginLockoutOptions {
70
77
  baseSeconds?: number;
71
78
  factor?: number;
@@ -81,6 +88,18 @@ export interface LoginAuditEntry {
81
88
  occurredAt: Date;
82
89
  metadata?: Record<string, unknown>;
83
90
  }
91
+ /**
92
+ * One budget's sizing (#3531). Every field falls back to the limiter's
93
+ * top-level option of the same meaning.
94
+ */
95
+ export interface LoginBudgetOptions {
96
+ /** Failed attempts allowed per window (top-level `maxAttempts`). */
97
+ maxFailures?: number;
98
+ /** Sliding window in seconds (top-level `windowSeconds`). */
99
+ windowSeconds?: number;
100
+ /** Lockout once the budget is exhausted; `false` keeps only the window. */
101
+ lockout?: LoginLockoutOptions | false;
102
+ }
84
103
  /** Where sign-in decisions are reported. Must not throw into the sign-in path. */
85
104
  export interface LoginAuditSink {
86
105
  record(entry: LoginAuditEntry): Promise<void>;
@@ -96,9 +115,30 @@ export interface LoginAttemptLimiterOptions extends SmrtClassOptions {
96
115
  * terminal-approve behaviour).
97
116
  */
98
117
  lockout?: LoginLockoutOptions | false;
118
+ /**
119
+ * Per-account budget (#3531). Omitted fields use the top-level options.
120
+ */
121
+ subject?: LoginBudgetOptions;
122
+ /**
123
+ * Per-address (or per-device) budget (#3531). Omitted fields use the
124
+ * top-level options. `false` ignores the source key entirely — for a
125
+ * deployment that cannot see a trustworthy client address, where every
126
+ * browser would otherwise share one budget and a handful of failures from
127
+ * anyone would lock everyone out. A reservation then needs a subject.
128
+ * This applies to every credential kind using this instance, so a host
129
+ * whose PIN sign-ins share it should prefer a larger source budget (or a
130
+ * separate limiter for passwords) over disabling it.
131
+ */
132
+ source?: LoginBudgetOptions | false;
133
+ /**
134
+ * Minimum spacing, per source, of the `source-locked` audit entry reported
135
+ * when a failure starts a source lockout. Defaults to
136
+ * {@link DEFAULT_SOURCE_LOCKOUT_AUDIT_SECONDS}. Tracked per instance.
137
+ */
138
+ sourceLockoutAuditSeconds?: number;
99
139
  /**
100
140
  * Time since a key's last failure after which its streak is forgiven. Defaults to
101
- * twice the larger of the window and the lockout ceiling.
141
+ * twice the larger of the budget's window and lockout ceiling.
102
142
  */
103
143
  streakResetSeconds?: number;
104
144
  /**
@@ -188,22 +228,26 @@ export declare class DurableLoginAuditSink implements LoginAuditSink {
188
228
  }
189
229
  export declare class LoginAttemptLimiter {
190
230
  private readonly options;
191
- private readonly maxAttempts;
192
- private readonly windowMs;
193
- private readonly lockout;
194
- private readonly streakResetMs;
231
+ private readonly budgets;
195
232
  private readonly sourceStreakDecayMs;
233
+ private readonly sourceLockoutAuditMs;
234
+ /** Source hash → earliest time its next `source-locked` entry may be reported. */
235
+ private readonly sourceLockoutAudited;
196
236
  private attempts;
197
237
  private audit;
198
238
  constructor(options: LoginAttemptLimiterOptions);
239
+ /** False when this limiter was configured with `source: false`. */
240
+ get limitsSource(): boolean;
199
241
  static create(options: LoginAttemptLimiterOptions): Promise<LoginAttemptLimiter>;
200
242
  initialize(): Promise<void>;
201
- /** How long a row this limiter writes must outlive the retention sweep. */
202
- private get retainMs();
203
243
  /** Stable, peppered hash for a key. Exposed so hosts can correlate audit rows. */
204
244
  hashKey(scope: LoginAttemptScope, raw: string): string;
205
- /** Lockout length for the n-th consecutive exhausted budget (0-based). */
206
- lockoutMsFor(exhaustedBudgets: number): number;
245
+ /**
246
+ * Lockout length for the n-th consecutive exhausted budget (0-based) of the
247
+ * given scope's budget (the subject's by default).
248
+ */
249
+ lockoutMsFor(exhaustedBudgets: number, scope?: LoginAttemptScope): number;
250
+ private budgetFor;
207
251
  /**
208
252
  * Reserve one attempt against every key supplied. Subject is reserved
209
253
  * first; if the source then refuses, the subject reservation is handed
@@ -222,6 +266,13 @@ export declare class LoginAttemptLimiter {
222
266
  dryRun?: boolean;
223
267
  }): Promise<number>;
224
268
  private releaseAll;
269
+ /**
270
+ * Report that a source lockout started, without the subject or the caller's
271
+ * metadata, so the entry attributes the outage to the address or device but
272
+ * never names an attempted account. Rate limited per source, in memory, so
273
+ * a sustained attack yields a bounded number of entries per instance.
274
+ */
275
+ private reportSourceLockout;
225
276
  private report;
226
277
  }
227
278
  //# sourceMappingURL=LoginAttemptLimiter.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"LoginAttemptLimiter.d.ts","sourceRoot":"","sources":["../../src/services/LoginAttemptLimiter.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"LoginAttemptLimiter.d.ts","sourceRoot":"","sources":["../../src/services/LoginAttemptLimiter.ts"],"names":[],"mappings":"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"}