@happyvertical/smrt-users 0.51.36 → 0.52.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.
@@ -1 +1 @@
1
- {"version":3,"file":"CliAuthApproveLimitCollection.d.ts","sourceRoot":"","sources":["../../src/collections/CliAuthApproveLimitCollection.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAC1D,OAAO,EAAE,wBAAwB,EAAE,MAAM,kCAAkC,CAAC;AAE5E,MAAM,MAAM,yBAAyB,GACjC;IAAE,OAAO,EAAE,IAAI,CAAC;IAAC,eAAe,EAAE,MAAM,CAAA;CAAE,GAC1C;IAAE,OAAO,EAAE,KAAK,CAAC;IAAC,iBAAiB,EAAE,MAAM,CAAA;CAAE,CAAC;AAElD,qBAAa,kCAAmC,SAAQ,cAAc,CAAC,wBAAwB,CAAC;IAC9F,MAAM,CAAC,QAAQ,CAAC,UAAU,kCAA4B;IAEtD;;;OAGG;IACG,cAAc,CAAC,KAAK,EAAE;QAC1B,WAAW,EAAE,MAAM,CAAC;QACpB,MAAM,EAAE,MAAM,CAAC;QACf,QAAQ,EAAE,MAAM,CAAC;KAClB,GAAG,OAAO,CAAC,yBAAyB,CAAC;IAgEtC,+EAA+E;IACzE,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAoB7E"}
1
+ {"version":3,"file":"CliAuthApproveLimitCollection.d.ts","sourceRoot":"","sources":["../../src/collections/CliAuthApproveLimitCollection.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAC1D,OAAO,EAAE,wBAAwB,EAAE,MAAM,kCAAkC,CAAC;AAE5E,MAAM,MAAM,yBAAyB,GACjC;IAAE,OAAO,EAAE,IAAI,CAAC;IAAC,eAAe,EAAE,MAAM,CAAA;CAAE,GAC1C;IAAE,OAAO,EAAE,KAAK,CAAC;IAAC,iBAAiB,EAAE,MAAM,CAAA;CAAE,CAAC;AAElD,qBAAa,kCAAmC,SAAQ,cAAc,CAAC,wBAAwB,CAAC;IAC9F,MAAM,CAAC,QAAQ,CAAC,UAAU,kCAA4B;IAEtD;;;OAGG;IACG,cAAc,CAAC,KAAK,EAAE;QAC1B,WAAW,EAAE,MAAM,CAAC;QACpB,MAAM,EAAE,MAAM,CAAC;QACf,QAAQ,EAAE,MAAM,CAAC;KAClB,GAAG,OAAO,CAAC,yBAAyB,CAAC;IAmEtC,+EAA+E;IACzE,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAoB7E"}
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { $ as deriveOperationPermissionSlug, A as DEFAULT_ANCESTOR_READ_MAX_DEPTH, B as TenantPermissionOverride, C as OidcLoginService, Ct as UsersCliAuthRequestCollection, D as resolveOidcProviderConfig, Dt as generateSessionId, E as getUsersOidcConfig, Et as Session, F as UserCollection, G as applyTenantHierarchyUpdates, H as Tenant, J as recordTenantHierarchyChanges, K as assertTenantTableName, L as UserEmailKeyBackfillError, M as isAncestorReadableSlug, N as normalizeAncestorReadPolicy, Ot as UsersCliAuthRequest, P as OidcProvisioningError, Q as deriveOperationPermissionCollectionName, R as backfillUserEmailKeys, S as OidcLoginError, St as normalizeEmail, T as encodeOidcTransaction, Tt as DEFAULT_SESSION_TTL, U as MAX_TENANT_HIERARCHY_DEPTH, V as TenantCollection, W as TenantHierarchyError, X as RolePermissionCollection, Y as DEFAULT_ROLE_PERMISSION_PATTERNS, Z as PermissionCatalogService, _ as readMobileBearerToken, _t as Group, a as TerminalAuthRateLimitError, at as Role, b as PermissionResolver, bt as User, c as assertOperationPermission, ct as MembershipOverrideCollection, d as getCurrentSessionPermissionContext, dt as Membership, et as normalizeOperationPermissionAction, f as getRequestScopedDatabase, ft as GroupRoleCollection, g as MobileAuthService, gt as GroupCollection, h as MobileAuthError, ht as GroupMember, i as TerminalAuthError, it as RoleCollection, j as getConfiguredAncestorReadPolicy, k as ANCESTOR_READ_ACTION, l as checkOperationPermission, lt as MembershipOverride, m as withSessionPermissionContext, mt as GroupMemberCollection, n as DEFAULT_CLI_AUTH_REQUEST_TTL_SECONDS, nt as syncPermissionCatalog, o as TerminalAuthService, ot as PermissionCollection, p as withPrincipalPermissionContext, pt as GroupRole, q as planTenantHierarchy, r as DEFAULT_CLI_SESSION_TTL_SECONDS, rt as RolePermission, s as OperationPermissionError, st as Permission, t as DEFAULT_CLI_AUTH_POLL_INTERVAL_SECONDS, tt as registerPermissionDefinitions, u as hasOperationPermission, ut as MembershipCollection, v as validateMobileRedirectUri, vt as UsersCliAuthApproveLimitCollection, w as decodeOidcTransaction, wt as SessionCollection, x as withoutListBounds, xt as isValidEmail, y as SessionService, yt as UsersCliAuthApproveLimit, z as TenantPermissionOverrideCollection } from "./chunks/TerminalAuthService-D9OXHSHy.js";
1
+ import { $ as deriveOperationPermissionSlug, A as DEFAULT_ANCESTOR_READ_MAX_DEPTH, B as TenantPermissionOverride, C as OidcLoginService, Ct as UsersCliAuthRequestCollection, D as resolveOidcProviderConfig, Dt as generateSessionId, E as getUsersOidcConfig, Et as Session, F as UserCollection, G as applyTenantHierarchyUpdates, H as Tenant, J as recordTenantHierarchyChanges, K as assertTenantTableName, L as UserEmailKeyBackfillError, M as isAncestorReadableSlug, N as normalizeAncestorReadPolicy, Ot as UsersCliAuthRequest, P as OidcProvisioningError, Q as deriveOperationPermissionCollectionName, R as backfillUserEmailKeys, S as OidcLoginError, St as normalizeEmail, T as encodeOidcTransaction, Tt as DEFAULT_SESSION_TTL, U as MAX_TENANT_HIERARCHY_DEPTH, V as TenantCollection, W as TenantHierarchyError, X as RolePermissionCollection, Y as DEFAULT_ROLE_PERMISSION_PATTERNS, Z as PermissionCatalogService, _ as readMobileBearerToken, _t as Group, a as TerminalAuthRateLimitError, at as Role, b as PermissionResolver, bt as User, c as assertOperationPermission, ct as MembershipOverrideCollection, d as getCurrentSessionPermissionContext, dt as Membership, et as normalizeOperationPermissionAction, f as getRequestScopedDatabase, ft as GroupRoleCollection, g as MobileAuthService, gt as GroupCollection, h as MobileAuthError, ht as GroupMember, i as TerminalAuthError, it as RoleCollection, j as getConfiguredAncestorReadPolicy, k as ANCESTOR_READ_ACTION, l as checkOperationPermission, lt as MembershipOverride, m as withSessionPermissionContext, mt as GroupMemberCollection, n as DEFAULT_CLI_AUTH_REQUEST_TTL_SECONDS, nt as syncPermissionCatalog, o as TerminalAuthService, ot as PermissionCollection, p as withPrincipalPermissionContext, pt as GroupRole, q as planTenantHierarchy, r as DEFAULT_CLI_SESSION_TTL_SECONDS, rt as RolePermission, s as OperationPermissionError, st as Permission, t as DEFAULT_CLI_AUTH_POLL_INTERVAL_SECONDS, tt as registerPermissionDefinitions, u as hasOperationPermission, ut as MembershipCollection, v as validateMobileRedirectUri, vt as UsersCliAuthApproveLimitCollection, w as decodeOidcTransaction, wt as SessionCollection, x as withoutListBounds, xt as isValidEmail, y as SessionService, yt as UsersCliAuthApproveLimit, z as TenantPermissionOverrideCollection } from "./chunks/TerminalAuthService-Br64vHtd.js";
2
2
  import { a as MembershipStatus, c as TenantPermissionEffect, i as DEFAULT_TENANT_POLICY, l as TenantStatus, n as DEFAULT_ROLES, o as OverrideEffect, r as DEFAULT_ROLE_SLUGS, s as SessionStatus, t as AccessRequestStatus, u as UserStatus } from "./chunks/types-DFqeph0R.js";
3
3
  import { ObjectRegistry, SmrtCollection, SmrtObject, field, findManifestEntryByQualifiedName, foreignKey, isUniqueViolationError, registerRetentionTask, smrt, unregisterRetentionTask } from "@happyvertical/smrt-core";
4
4
  import { PROFILE_EMAIL_KEY_BACKFILL_NAME, Person, ProfileCollection, ProfileTypeCollection, normalizeIdentityEmail } from "@happyvertical/smrt-profiles";
@@ -1194,7 +1194,7 @@ var MagicLinkService = class MagicLinkService {
1194
1194
  * The caller is responsible for emailing the token to the user.
1195
1195
  */
1196
1196
  async generate(email) {
1197
- const { SignJWT } = await import("./chunks/TerminalAuthService-D9OXHSHy.js").then((n) => n.O);
1197
+ const { SignJWT } = await import("./chunks/TerminalAuthService-Br64vHtd.js").then((n) => n.O);
1198
1198
  const key = await this.getSigningKey();
1199
1199
  const nonce = crypto.randomUUID();
1200
1200
  const normalizedEmail = normalizeEmail(email);
@@ -1223,7 +1223,7 @@ var MagicLinkService = class MagicLinkService {
1223
1223
  * @throws {MagicLinkError} If the token is invalid, expired, or already used
1224
1224
  */
1225
1225
  async verify(token) {
1226
- const { jwtVerify, errors } = await import("./chunks/TerminalAuthService-D9OXHSHy.js").then((n) => n.O);
1226
+ const { jwtVerify, errors } = await import("./chunks/TerminalAuthService-Br64vHtd.js").then((n) => n.O);
1227
1227
  const key = await this.getSigningKey();
1228
1228
  let payload;
1229
1229
  try {
@@ -2,7 +2,7 @@
2
2
  "version": "1.0.0",
3
3
  "timestamp": 0,
4
4
  "packageName": "@happyvertical/smrt-users",
5
- "packageVersion": "0.51.36",
5
+ "packageVersion": "0.52.0",
6
6
  "objects": {
7
7
  "@happyvertical/smrt-users:AccessRequestCollection": {
8
8
  "name": "accessrequestcollection",
@@ -509,12 +509,14 @@
509
509
  },
510
510
  "indexes": [
511
511
  {
512
- "name": "users_cli_auth_requests_slug_context_idx",
512
+ "name": "users_cli_auth_requests_tenant_id_slug_idx",
513
513
  "columns": [
514
+ "tenant_id",
514
515
  "slug",
515
516
  "context"
516
517
  ],
517
- "unique": true
518
+ "unique": true,
519
+ "nullsNotDistinct": true
518
520
  },
519
521
  {
520
522
  "name": "users_cli_auth_requests_expires_at_idx",
@@ -534,12 +536,6 @@
534
536
  "user_id"
535
537
  ]
536
538
  },
537
- {
538
- "name": "users_cli_auth_requests_tenant_id_idx",
539
- "columns": [
540
- "tenant_id"
541
- ]
542
- },
543
539
  {
544
540
  "name": "users_cli_auth_requests_session_id_idx",
545
541
  "columns": [
@@ -655,8 +651,9 @@
655
651
  },
656
652
  "indexes": [
657
653
  {
658
- "name": "groups_slug_context_idx",
654
+ "name": "groups_tenant_id_slug_idx",
659
655
  "columns": [
656
+ "tenant_id",
660
657
  "slug",
661
658
  "context"
662
659
  ],
@@ -667,12 +664,6 @@
667
664
  "columns": [
668
665
  "created_at"
669
666
  ]
670
- },
671
- {
672
- "name": "groups_tenant_id_idx",
673
- "columns": [
674
- "tenant_id"
675
- ]
676
667
  }
677
668
  ],
678
669
  "version": "1824c19b"
@@ -1444,8 +1435,9 @@
1444
1435
  },
1445
1436
  "indexes": [
1446
1437
  {
1447
- "name": "memberships_slug_context_idx",
1438
+ "name": "memberships_tenant_id_slug_idx",
1448
1439
  "columns": [
1440
+ "tenant_id",
1449
1441
  "slug",
1450
1442
  "context"
1451
1443
  ],
@@ -2254,24 +2246,20 @@
2254
2246
  },
2255
2247
  "indexes": [
2256
2248
  {
2257
- "name": "roles_slug_context_idx",
2249
+ "name": "roles_tenant_id_slug_idx",
2258
2250
  "columns": [
2251
+ "tenant_id",
2259
2252
  "slug",
2260
2253
  "context"
2261
2254
  ],
2262
- "unique": true
2255
+ "unique": true,
2256
+ "nullsNotDistinct": true
2263
2257
  },
2264
2258
  {
2265
2259
  "name": "roles_created_at_idx",
2266
2260
  "columns": [
2267
2261
  "created_at"
2268
2262
  ]
2269
- },
2270
- {
2271
- "name": "roles_tenant_id_idx",
2272
- "columns": [
2273
- "tenant_id"
2274
- ]
2275
2263
  }
2276
2264
  ],
2277
2265
  "version": "47369d9d"
@@ -2824,12 +2812,14 @@
2824
2812
  },
2825
2813
  "indexes": [
2826
2814
  {
2827
- "name": "sessions_slug_context_idx",
2815
+ "name": "sessions_tenant_id_slug_idx",
2828
2816
  "columns": [
2817
+ "tenant_id",
2829
2818
  "slug",
2830
2819
  "context"
2831
2820
  ],
2832
- "unique": true
2821
+ "unique": true,
2822
+ "nullsNotDistinct": true
2833
2823
  },
2834
2824
  {
2835
2825
  "name": "sessions_expires_at_idx",
@@ -2848,12 +2838,6 @@
2848
2838
  "columns": [
2849
2839
  "user_id"
2850
2840
  ]
2851
- },
2852
- {
2853
- "name": "sessions_tenant_id_idx",
2854
- "columns": [
2855
- "tenant_id"
2856
- ]
2857
2841
  }
2858
2842
  ],
2859
2843
  "version": "dc55d351"
@@ -3755,8 +3739,9 @@
3755
3739
  },
3756
3740
  "indexes": [
3757
3741
  {
3758
- "name": "tenant_permission_overrides_slug_context_idx",
3742
+ "name": "tenant_permission_overrides_tenant_id_slug_idx",
3759
3743
  "columns": [
3744
+ "tenant_id",
3760
3745
  "slug",
3761
3746
  "context"
3762
3747
  ],
@@ -3768,12 +3753,6 @@
3768
3753
  "created_at"
3769
3754
  ]
3770
3755
  },
3771
- {
3772
- "name": "tenant_permission_overrides_tenant_id_idx",
3773
- "columns": [
3774
- "tenant_id"
3775
- ]
3776
- },
3777
3756
  {
3778
3757
  "name": "tenant_permission_overrides_permission_id_idx",
3779
3758
  "columns": [
@@ -4518,7 +4497,12 @@
4518
4497
  },
4519
4498
  "mcp": {
4520
4499
  "include": []
4521
- }
4500
+ },
4501
+ "conflictColumns": [
4502
+ "tenant_id",
4503
+ "slug",
4504
+ "context"
4505
+ ]
4522
4506
  },
4523
4507
  "extends": "SmrtObject",
4524
4508
  "exportName": "UsersCliAuthRequest",
@@ -4628,12 +4612,14 @@
4628
4612
  },
4629
4613
  "indexes": [
4630
4614
  {
4631
- "name": "users_cli_auth_requests_slug_context_idx",
4615
+ "name": "users_cli_auth_requests_tenant_id_slug_idx",
4632
4616
  "columns": [
4617
+ "tenant_id",
4633
4618
  "slug",
4634
4619
  "context"
4635
4620
  ],
4636
- "unique": true
4621
+ "unique": true,
4622
+ "nullsNotDistinct": true
4637
4623
  },
4638
4624
  {
4639
4625
  "name": "users_cli_auth_requests_expires_at_idx",
@@ -4653,12 +4639,6 @@
4653
4639
  "user_id"
4654
4640
  ]
4655
4641
  },
4656
- {
4657
- "name": "users_cli_auth_requests_tenant_id_idx",
4658
- "columns": [
4659
- "tenant_id"
4660
- ]
4661
- },
4662
4642
  {
4663
4643
  "name": "users_cli_auth_requests_session_id_idx",
4664
4644
  "columns": [
@@ -4711,7 +4691,12 @@
4711
4691
  "get"
4712
4692
  ]
4713
4693
  },
4714
- "cli": true
4694
+ "cli": true,
4695
+ "conflictColumns": [
4696
+ "tenant_id",
4697
+ "slug",
4698
+ "context"
4699
+ ]
4715
4700
  },
4716
4701
  "extends": "SmrtObject",
4717
4702
  "exportName": "Group",
@@ -4779,8 +4764,9 @@
4779
4764
  },
4780
4765
  "indexes": [
4781
4766
  {
4782
- "name": "groups_slug_context_idx",
4767
+ "name": "groups_tenant_id_slug_idx",
4783
4768
  "columns": [
4769
+ "tenant_id",
4784
4770
  "slug",
4785
4771
  "context"
4786
4772
  ],
@@ -4791,12 +4777,6 @@
4791
4777
  "columns": [
4792
4778
  "created_at"
4793
4779
  ]
4794
- },
4795
- {
4796
- "name": "groups_tenant_id_idx",
4797
- "columns": [
4798
- "tenant_id"
4799
- ]
4800
4780
  }
4801
4781
  ],
4802
4782
  "version": "1824c19b"
@@ -5322,6 +5302,11 @@
5322
5302
  "userId"
5323
5303
  ]
5324
5304
  }
5305
+ ],
5306
+ "conflictColumns": [
5307
+ "tenant_id",
5308
+ "slug",
5309
+ "context"
5325
5310
  ]
5326
5311
  },
5327
5312
  "extends": "SmrtObject",
@@ -5417,8 +5402,9 @@
5417
5402
  },
5418
5403
  "indexes": [
5419
5404
  {
5420
- "name": "memberships_slug_context_idx",
5405
+ "name": "memberships_tenant_id_slug_idx",
5421
5406
  "columns": [
5407
+ "tenant_id",
5422
5408
  "slug",
5423
5409
  "context"
5424
5410
  ],
@@ -6104,7 +6090,12 @@
6104
6090
  },
6105
6091
  "cli": {
6106
6092
  "skipApiCheck": true
6107
- }
6093
+ },
6094
+ "conflictColumns": [
6095
+ "tenant_id",
6096
+ "slug",
6097
+ "context"
6098
+ ]
6108
6099
  },
6109
6100
  "extends": "SmrtObject",
6110
6101
  "exportName": "Role",
@@ -6177,24 +6168,20 @@
6177
6168
  },
6178
6169
  "indexes": [
6179
6170
  {
6180
- "name": "roles_slug_context_idx",
6171
+ "name": "roles_tenant_id_slug_idx",
6181
6172
  "columns": [
6173
+ "tenant_id",
6182
6174
  "slug",
6183
6175
  "context"
6184
6176
  ],
6185
- "unique": true
6177
+ "unique": true,
6178
+ "nullsNotDistinct": true
6186
6179
  },
6187
6180
  {
6188
6181
  "name": "roles_created_at_idx",
6189
6182
  "columns": [
6190
6183
  "created_at"
6191
6184
  ]
6192
- },
6193
- {
6194
- "name": "roles_tenant_id_idx",
6195
- "columns": [
6196
- "tenant_id"
6197
- ]
6198
6185
  }
6199
6186
  ],
6200
6187
  "version": "47369d9d"
@@ -6553,7 +6540,12 @@
6553
6540
  },
6554
6541
  "cli": {
6555
6542
  "skipApiCheck": true
6556
- }
6543
+ },
6544
+ "conflictColumns": [
6545
+ "tenant_id",
6546
+ "slug",
6547
+ "context"
6548
+ ]
6557
6549
  },
6558
6550
  "extends": "SmrtObject",
6559
6551
  "exportName": "Session",
@@ -6647,12 +6639,14 @@
6647
6639
  },
6648
6640
  "indexes": [
6649
6641
  {
6650
- "name": "sessions_slug_context_idx",
6642
+ "name": "sessions_tenant_id_slug_idx",
6651
6643
  "columns": [
6644
+ "tenant_id",
6652
6645
  "slug",
6653
6646
  "context"
6654
6647
  ],
6655
- "unique": true
6648
+ "unique": true,
6649
+ "nullsNotDistinct": true
6656
6650
  },
6657
6651
  {
6658
6652
  "name": "sessions_expires_at_idx",
@@ -6671,12 +6665,6 @@
6671
6665
  "columns": [
6672
6666
  "user_id"
6673
6667
  ]
6674
- },
6675
- {
6676
- "name": "sessions_tenant_id_idx",
6677
- "columns": [
6678
- "tenant_id"
6679
- ]
6680
6668
  }
6681
6669
  ],
6682
6670
  "version": "dc55d351"
@@ -7331,7 +7319,12 @@
7331
7319
  },
7332
7320
  "cli": {
7333
7321
  "skipApiCheck": true
7334
- }
7322
+ },
7323
+ "conflictColumns": [
7324
+ "tenant_id",
7325
+ "slug",
7326
+ "context"
7327
+ ]
7335
7328
  },
7336
7329
  "extends": "SmrtObject",
7337
7330
  "exportName": "TenantPermissionOverride",
@@ -7409,8 +7402,9 @@
7409
7402
  },
7410
7403
  "indexes": [
7411
7404
  {
7412
- "name": "tenant_permission_overrides_slug_context_idx",
7405
+ "name": "tenant_permission_overrides_tenant_id_slug_idx",
7413
7406
  "columns": [
7407
+ "tenant_id",
7414
7408
  "slug",
7415
7409
  "context"
7416
7410
  ],
@@ -7422,12 +7416,6 @@
7422
7416
  "created_at"
7423
7417
  ]
7424
7418
  },
7425
- {
7426
- "name": "tenant_permission_overrides_tenant_id_idx",
7427
- "columns": [
7428
- "tenant_id"
7429
- ]
7430
- },
7431
7419
  {
7432
7420
  "name": "tenant_permission_overrides_permission_id_idx",
7433
7421
  "columns": [
@@ -3,16 +3,17 @@
3
3
  "sensitiveFieldsExcluded": true,
4
4
  "generatedAt": "1970-01-01T00:00:00.000Z",
5
5
  "packageName": "@happyvertical/smrt-users",
6
- "packageVersion": "0.51.36",
6
+ "packageVersion": "0.52.0",
7
7
  "sourceManifestPath": "dist/manifest.json",
8
8
  "agentDocPath": "AGENTS.md",
9
9
  "sourceHashes": {
10
- "manifest": "52a438a6c33ee54de951ada763fb531b980f8e5c92b5d64625b92e27fd0d4e46",
11
- "packageJson": "d4ddbd3fb50c44235eee096f63f1d17c4469408da18cd091778860d4030c8d5f",
12
- "agents": "d7f1bb57f7bbbc1b750ab87c33592a53622236d17f49f8c04b15c4745b5c2ab2",
10
+ "manifest": "bf43eb6941f3d30ddd5106bf17478d7b05ecda56fa632bdc32e34c46d5285b1c",
11
+ "packageJson": "56710fe63eb927dc3f6632196acaaf149389a1efcce248bff1bd2b583ee4973d",
12
+ "agents": "c1bd1dcae5f1662f31d01d0cff19cb3f774715eb71ecfd249eb429e5f64a3eb7",
13
13
  "moduleDoc:agents/permissions.md": "b5be3f5b84b409cb6e62080e2d7a75b67e0763266c11054045c5c401b84f8dd6",
14
14
  "moduleDoc:agents/oidc-provisioning.md": "5efa607ff23b9a693391e0c02670324a8cea4114d4968c9718f10a763da919c6",
15
15
  "moduleDoc:agents/mobile-auth.md": "25e85e83f43e3a46383a92fa809f3a003b4545c3026e78dbe1bccbbc35161e18",
16
+ "moduleDoc:agents/terminal-auth-testing.md": "8a84c16a19e381427aed81d3b1882344c427fe22a70e87f5ac2db836b1a6822d",
16
17
  "moduleDoc:agents/retention.md": "425c0a34ed33969badfef699751bfa670bdf618eda65e079e00815620aabed68"
17
18
  },
18
19
  "exports": [
@@ -40,7 +41,7 @@
40
41
  "@sveltejs/vite-plugin-svelte": "^7.3.0",
41
42
  "@types/node": "24.13.6",
42
43
  "fast-glob": "^3.3.3",
43
- "svelte": "^5.57.1",
44
+ "svelte": "^5.57.0",
44
45
  "svelte-check": "^4.7.6",
45
46
  "typescript": "6.0.3",
46
47
  "vite": "8.1.4",
@@ -4312,6 +4313,11 @@
4312
4313
  }
4313
4314
  ],
4314
4315
  "methods": [],
4316
+ "conflictColumns": [
4317
+ "tenant_id",
4318
+ "slug",
4319
+ "context"
4320
+ ],
4315
4321
  "surfaces": [],
4316
4322
  "relationshipFeatures": [
4317
4323
  "foreignKey",
@@ -4360,6 +4366,11 @@
4360
4366
  }
4361
4367
  ],
4362
4368
  "methods": [],
4369
+ "conflictColumns": [
4370
+ "tenant_id",
4371
+ "slug",
4372
+ "context"
4373
+ ],
4363
4374
  "surfaces": [
4364
4375
  {
4365
4376
  "kind": "api",
@@ -4831,6 +4842,11 @@
4831
4842
  "returns": "boolean"
4832
4843
  }
4833
4844
  ],
4845
+ "conflictColumns": [
4846
+ "tenant_id",
4847
+ "slug",
4848
+ "context"
4849
+ ],
4834
4850
  "surfaces": [
4835
4851
  {
4836
4852
  "kind": "api",
@@ -5496,6 +5512,11 @@
5496
5512
  "returns": "boolean"
5497
5513
  }
5498
5514
  ],
5515
+ "conflictColumns": [
5516
+ "tenant_id",
5517
+ "slug",
5518
+ "context"
5519
+ ],
5499
5520
  "surfaces": [
5500
5521
  {
5501
5522
  "kind": "api",
@@ -5869,6 +5890,11 @@
5869
5890
  "returns": "void"
5870
5891
  }
5871
5892
  ],
5893
+ "conflictColumns": [
5894
+ "tenant_id",
5895
+ "slug",
5896
+ "context"
5897
+ ],
5872
5898
  "surfaces": [
5873
5899
  {
5874
5900
  "kind": "api",
@@ -6711,6 +6737,11 @@
6711
6737
  "returns": "boolean"
6712
6738
  }
6713
6739
  ],
6740
+ "conflictColumns": [
6741
+ "tenant_id",
6742
+ "slug",
6743
+ "context"
6744
+ ],
6714
6745
  "surfaces": [
6715
6746
  {
6716
6747
  "kind": "api",
@@ -10555,7 +10586,7 @@
10555
10586
  "polymorphicAssociations": 0,
10556
10587
  "uuidColumns": 90
10557
10588
  },
10558
- "agentDoc": "# @happyvertical/smrt-users\n\nMulti-tenant identity, RBAC, hierarchical tenants, sessions, and SvelteKit auth.\n\n## Modules\n\nRead only the module relevant to the change; protocol and provisioning details\nare not prerequisites for unrelated user-package work.\n\n| Module | Scope | Module doc |\n|---|---|---|\n| `src/services/PermissionResolver.ts` | permission precedence, inherited memberships, guards, RLS, role seeding | [agents/permissions.md](agents/permissions.md) |\n| `src/services/OidcLoginService.ts`, collections and OIDC handlers | identity reconciliation, transaction boundaries, migration readiness | [agents/oidc-provisioning.md](agents/oidc-provisioning.md) |\n| `src/services/MobileAuthService.ts` | mobile handshake, bearer sessions, bootstrap extension boundary | [agents/mobile-auth.md](agents/mobile-auth.md) |\n| `src/retention.ts` | expired session/token/CLI-auth reaping and retention sweep wiring | [agents/retention.md](agents/retention.md) |\n\n## Models and authority\n\n- Users are global; tenant access comes through Membership (unique user/tenant).\n User email is normalized and globally unique through readonly nullable\n `emailKey`. `profileId` is a unique cross-package reference: at most one User\n owns each non-null Profile.\n- Tenant uses STI and a materialized hierarchy, maximum depth 10.\n `hierarchyPath`/`hierarchyLevel` are derived from `parentTenantId` by\n `Tenant.save()` on every save (any caller-supplied value is recomputed) and\n descendants are re-materialized when they change; never hand-maintain them.\n Legacy rows are backfilled with `smrt db:materialize-tenant-hierarchy`\n (`materializeTenantHierarchy()`). Tests that need a corrupt path must write it\n with raw SQL (#3036).\n- Role with `tenantId = null` is available to all tenants; `isSystem` prevents\n deletion. `inheritsToDescendants` is opt-in. Seed owner/admin/member/viewer\n through `RoleCollection.seedSystemRoles()` at application initialization.\n- Group roles apply only in their own tenant. Use `getGroupIdsForTenant()`,\n never cross-tenant `getGroupIds()`, for authorization.\n- Upward visibility is opt-in and read-only: `permissions.ancestorRead`\n ({ roles, collections, maxDepth? }) lets a DESCENDANT membership contribute\n declared `<collection>.read` at an ancestor, only when no membership resolved\n there, intersected with BOTH the role's own catalog grants and the\n principal's effective permissions in that descendant, and only for SYSTEM\n roles (a tenant-scoped role sharing a declared slug is ignored). Off by default, never\n write, never lateral, and never row visibility — sibling rows stay scoped by\n tenancy/RLS. Read the permissions module before changing it.\n- Membership DENY always wins. Direct inactive membership blocks inherited\n authority; a direct active membership pins resolution instead of unioning it\n with ancestors. Read the permissions module before changing these rules.\n- AccessRequest has no generated API/MCP/CLI operations; access it through\n `AccessRequestService`. Its JSON field is `requestContext`, not reserved\n slug-scoping `context`.\n\n## Security boundaries\n\n- Generated REST/MCP operations on identity/RBAC models are list/get only.\n Route authentication does not authorize authority mutations, and these models\n are not tenant-scoped. Use permission-gated services or explicitly checked\n consumer handlers. CLI remains a local-operator surface. Preserve the\n registry assertions in `security-audit-1400.test.ts`.\n- Resource guards take the resource tenant, not the session tenant. Omit a\n session membership when targeting a different tenant; mismatches fail closed.\n `loadSessionContext().tenantAuthorization` must be checked by required-tenant\n consumers: null membership can represent inherited authority.\n- Sessions use secure UUIDs; TTL is seconds (default seven days). Access marks\n expired sessions EXPIRED. Magic-link tokens are single use.\n- Tenant switching verifies active membership before writing and rotates the\n session ID for non-null targets, revoking the old session. Persist the returned\n `SwitchTenantResult.sessionId`; `switchSessionTenant()` updates the cookie and\n preserves its security settings. Failed switches mutate nothing; null clears\n do not rotate. `SessionCollection.setSessionTenant()` is unguarded and must\n never receive an untrusted tenant ID.\n- OIDC provisioning is atomic and fail-closed. Preserve exact issuer/subject\n identifiers, claim-source email verification, unique global Person ownership,\n and transaction-bound reconciliation. Read the OIDC module and canonical\n scenario matrix before changing any provisioning path.\n\n## Entry points and validation\n\n`src/sveltekit/` owns `createSessionHandler`, `createSessionCookie`,\n`destroySessionCookie`, and `switchSessionTenant`. Use README integration examples\nrather than copying application setup into these instructions.\n\nFrom the repository root:\n\n```bash\npnpm --filter @happyvertical/smrt-users test\npnpm --filter @happyvertical/smrt-users typecheck\npnpm --filter @happyvertical/smrt-users test:postgres\n```\n\nStart with the relevant test file via `test -- src/__tests__/<file>.test.ts`.\nRun `test:postgres` for RLS, principal context, OIDC, or terminal-auth database\nchanges. `typecheck` includes Svelte accessibility checks; plain `tsc` is\ninsufficient. Follow root knowledge freshness checks before shipping.\n",
10589
+ "agentDoc": "# @happyvertical/smrt-users\n\nMulti-tenant identity, RBAC, hierarchical tenants, sessions, and SvelteKit auth.\n\n## Modules\n\nRead only the module relevant to the change; protocol and provisioning details\nare not prerequisites for unrelated user-package work.\n\n| Module | Scope | Module doc |\n|---|---|---|\n| `src/services/PermissionResolver.ts` | permission precedence, inherited memberships, guards, RLS, role seeding | [agents/permissions.md](agents/permissions.md) |\n| `src/services/OidcLoginService.ts`, collections and OIDC handlers | identity reconciliation, transaction boundaries, migration readiness | [agents/oidc-provisioning.md](agents/oidc-provisioning.md) |\n| `src/services/MobileAuthService.ts` | mobile handshake, bearer sessions, bootstrap extension boundary | [agents/mobile-auth.md](agents/mobile-auth.md) |\n| `src/services/TerminalAuthService.ts`, `src/collections/CliAuthApproveLimitCollection.ts` | terminal approval concurrency, shared attempt budget, retry-safe database fixtures | [agents/terminal-auth-testing.md](agents/terminal-auth-testing.md) |\n| `src/retention.ts` | expired session/token/CLI-auth reaping and retention sweep wiring | [agents/retention.md](agents/retention.md) |\n\n## Models and authority\n\n- Users are global; tenant access comes through Membership (unique user/tenant).\n User email is normalized and globally unique through readonly nullable\n `emailKey`. `profileId` is a unique cross-package reference: at most one User\n owns each non-null Profile.\n- Tenant uses STI and a materialized hierarchy, maximum depth 10.\n `hierarchyPath`/`hierarchyLevel` are derived from `parentTenantId` by\n `Tenant.save()` on every save (any caller-supplied value is recomputed) and\n descendants are re-materialized when they change; never hand-maintain them.\n Legacy rows are backfilled with `smrt db:materialize-tenant-hierarchy`\n (`materializeTenantHierarchy()`). Tests that need a corrupt path must write it\n with raw SQL (#3036).\n- Role with `tenantId = null` is available to all tenants; `isSystem` prevents\n deletion. `inheritsToDescendants` is opt-in. Seed owner/admin/member/viewer\n through `RoleCollection.seedSystemRoles()` at application initialization.\n- Group roles apply only in their own tenant. Use `getGroupIdsForTenant()`,\n never cross-tenant `getGroupIds()`, for authorization.\n- Upward visibility is opt-in and read-only: `permissions.ancestorRead`\n ({ roles, collections, maxDepth? }) lets a DESCENDANT membership contribute\n declared `<collection>.read` at an ancestor, only when no membership resolved\n there, intersected with BOTH the role's own catalog grants and the\n principal's effective permissions in that descendant, and only for SYSTEM\n roles (a tenant-scoped role sharing a declared slug is ignored). Off by default, never\n write, never lateral, and never row visibility — sibling rows stay scoped by\n tenancy/RLS. Read the permissions module before changing it.\n- Membership DENY always wins. Direct inactive membership blocks inherited\n authority; a direct active membership pins resolution instead of unioning it\n with ancestors. Read the permissions module before changing these rules.\n- AccessRequest has no generated API/MCP/CLI operations; access it through\n `AccessRequestService`. Its JSON field is `requestContext`, not reserved\n slug-scoping `context`.\n\n## Security boundaries\n\n- Generated REST/MCP operations on identity/RBAC models are list/get only.\n Route authentication does not authorize authority mutations, and these models\n are not tenant-scoped. Use permission-gated services or explicitly checked\n consumer handlers. CLI remains a local-operator surface. Preserve the\n registry assertions in `security-audit-1400.test.ts`.\n- Resource guards take the resource tenant, not the session tenant. Omit a\n session membership when targeting a different tenant; mismatches fail closed.\n `loadSessionContext().tenantAuthorization` must be checked by required-tenant\n consumers: null membership can represent inherited authority.\n- Sessions use secure UUIDs; TTL is seconds (default seven days). Access marks\n expired sessions EXPIRED. Magic-link tokens are single use.\n- Tenant switching verifies active membership before writing and rotates the\n session ID for non-null targets, revoking the old session. Persist the returned\n `SwitchTenantResult.sessionId`; `switchSessionTenant()` updates the cookie and\n preserves its security settings. Failed switches mutate nothing; null clears\n do not rotate. `SessionCollection.setSessionTenant()` is unguarded and must\n never receive an untrusted tenant ID.\n- OIDC provisioning is atomic and fail-closed. Preserve exact issuer/subject\n identifiers, claim-source email verification, unique global Person ownership,\n and transaction-bound reconciliation. Read the OIDC module and canonical\n scenario matrix before changing any provisioning path.\n\n## Entry points and validation\n\n`src/sveltekit/` owns `createSessionHandler`, `createSessionCookie`,\n`destroySessionCookie`, and `switchSessionTenant`. Use README integration examples\nrather than copying application setup into these instructions.\n\nFrom the repository root:\n\n```bash\npnpm --filter @happyvertical/smrt-users test\npnpm --filter @happyvertical/smrt-users typecheck\npnpm --filter @happyvertical/smrt-users test:postgres\n```\n\nStart with the relevant test file via `test -- src/__tests__/<file>.test.ts`.\nRun `test:postgres` for RLS, principal context, OIDC, or terminal-auth database\nchanges. `typecheck` includes Svelte accessibility checks; plain `tsc` is\ninsufficient. Follow root knowledge freshness checks before shipping.\n",
10559
10590
  "moduleDocs": [
10560
10591
  {
10561
10592
  "path": "agents/permissions.md",
@@ -10572,6 +10603,11 @@
10572
10603
  "module": "mobile-auth",
10573
10604
  "content": "# Mobile authentication\n\nRead for `src/services/MobileAuthService.ts` and `/sveltekit` mobile handlers.\n\n`createMobileAuthHandlers(options)` (from `/sveltekit`) returns the mountable\nserver side of the KMP mobile contract: `authStart` (`POST auth/start`,\nserver-brokered PKCE via `OidcLoginService`), `authComplete`\n(`POST auth/complete`, code + echoed `state`/`codeVerifier` → bearer\nsession), `session.GET`/`session.DELETE` (bootstrap/logout), and\n`guard`/`withSession` — the bearer middleware for app-owned mobile routes.\nCore logic lives in `MobileAuthService` (framework-agnostic; exported from\nthe package root).\n\n- **Bearer = session id** (same convention as `TerminalAuthService`); 401\n bodies are `{ error, code }` and drive the mobile client's re-auth flow.\n- **Stateless handshake**: the OAuth `state` is an HMAC-signed token\n (secret: `stateSecret` ?? provider `clientSecret`) carrying\n nonce/provider/createdAt — full ID-token nonce verification with no\n server-side pending state. The `codeVerifier` never enters a URL: it is\n client-held per the frozen contract.\n- **Wire DTOs** come from `@happyvertical/smrt-mobile-contract`\n (`MobileAuthStartRequest` etc.) — one owning package for the Kotlin,\n Swift, and TypeScript shapes (compile-checked descriptors + parity test).\n- **Tenant options** honor `Role.inheritsToDescendants` (#1867): direct\n ACTIVE memberships plus descendants of flagged memberships (nearest\n flagged ancestor labels the option; any direct row pins; inactive direct\n rows exclude). Session binding defaults to the first DIRECT tenant —\n override with `resolveTenantId`.\n- **Hooks**: `resolveUser` (invite-gating; default provisions via\n `getOrCreateFromOidc`), `resolveTenantId`, `buildExtras` (bootstrap\n `extras`; model JSON must use `toPublicJSON({ permissions })` — #1822).\n `buildExtras` is the only app-domain bootstrap extension point. Never emit\n app fields such as `dashboard` at the response top level: they are outside\n `MobileSessionBootstrap` and the Kotlin decoder ignores them.\n- **Guard** wraps `withSessionPermissionContext`, so\n `assertOperationPermission`, tenancy context, and Postgres RLS all see the\n bearer caller; `OperationPermissionError` maps to 403 with a\n machine-readable `reason`.\n- **Uploads**: `resolveMobileUploadDedupKey` + the documented contract in\n `docs/content/architecture/mobile-upload-contract.md` (`clientCaptureId`\n field, `Idempotency-Key` header fallback); domain ingestion stays\n app-side. Framework-model writes ride `sync/apply`, not this path.\n- Configure `redirectUris` in production — RFC 8252 scheme rules always\n apply, but the allow list is the defense against redirecting authorization\n responses to attacker-controlled URIs.\n"
10574
10605
  },
10606
+ {
10607
+ "path": "agents/terminal-auth-testing.md",
10608
+ "module": "terminal-auth-testing",
10609
+ "content": "# Terminal approval storage and regression matrix — #3076\n\nThe failed-approval budget is shared storage, keyed by unique `user_id`.\nEach UPSERT candidate uses a unique private slug, so concurrent first inserts do\nnot also collide on the inherited `(slug, context)` index. Existing rows require\nno migration: their slug is not used for lookup or authorization. The guarded\nUPSERT continues to reserve at most the configured count across service instances\nand processes. Unknown database failures propagate; they are not authentication\nsuccesses or silently converted to a rate-limit response.\n\nRisk: high (terminal authentication and shared rate-limit authority). No public\nAPI, schema, session, tenant or approval contract changes.\n\n| Behavior / trigger | Positive | Negative / failure | Actor / executor | Runtime / edge | Validation |\n|---|---|---|---|---|---|\n| First reservation candidates | Distinct private insert slugs, one user budget | Third reservation denied at limit2; old code deterministically repeats slug | Same user, real SQL observed without replacing executor | SQLite; independent PostgreSQL service connections | users `test`, `test:postgres` |\n| Concurrent invalid approvals | Three attempts reach ordinary auth denial | Ten rejected, exactly seven typed rate limits; zero attacker sessions | One attacker/user+tenant, two instances, atomic UPSERT | SQLite and PostgreSQL18 | users `test`, `test:postgres` |\n| Concurrent approval/exchange | Eight approvals share one session, one of eight exchanges succeeds | Seven exchanges expired, consumed row clears session ID | UUID user/tenant, owning services | PostgreSQL; SQLite existing lifecycle coverage | users `test`, `test:postgres` |\n| Window/release | Successful attempts release their reservation | Old-window release cannot erase new-window failure; cleanup failure cannot reverse committed approval | Existing storage executor, no retry change | SQLite | users `test` |\n| Fixture retry/reseed | Two complete fixture cycles use the same emails | No duplicate email from prior committed fixture rows | Test-owned UUIDs, explicit cleanup through public database interface | PostgreSQL; intentionally independent connections outside rollback | users `test:postgres` |\n\nBefore the repair, the candidate regression fails (one slug instead of two),\nand the second PostgreSQL fixture cycle fails its fixed-email insert. Actual CI\nalso captured a PostgreSQL duplicate `(slug, context)` error during concurrent\nfirst reservations. The fixture cleans only its own IDs in FK order, then rolls\nback its isolated handle; it must not replace real connections with one shared\ntransaction, weaken count assertions, or disable retries.\n\nRun documented users build, typecheck (including Svelte), test, test:postgres and\nverify:pack gates. PostgreSQL runs use the canonical disposable-database wrapper.\nRoot knowledge checks follow all producers. No new dialect is introduced; the\nterminal auth regression suite declares SQLite and PostgreSQL coverage.\n"
10610
+ },
10575
10611
  {
10576
10612
  "path": "agents/retention.md",
10577
10613
  "module": "retention",
package/dist/sveltekit.js CHANGED
@@ -1,4 +1,4 @@
1
- import { C as OidcLoginService, D as resolveOidcProviderConfig, E as getUsersOidcConfig, S as OidcLoginError, T as encodeOidcTransaction, _ as readMobileBearerToken, a as TerminalAuthRateLimitError, g as MobileAuthService, h as MobileAuthError, i as TerminalAuthError, m as withSessionPermissionContext, o as TerminalAuthService, s as OperationPermissionError, v as validateMobileRedirectUri, w as decodeOidcTransaction, y as SessionService } from "./chunks/TerminalAuthService-D9OXHSHy.js";
1
+ import { C as OidcLoginService, D as resolveOidcProviderConfig, E as getUsersOidcConfig, S as OidcLoginError, T as encodeOidcTransaction, _ as readMobileBearerToken, a as TerminalAuthRateLimitError, g as MobileAuthService, h as MobileAuthError, i as TerminalAuthError, m as withSessionPermissionContext, o as TerminalAuthService, s as OperationPermissionError, v as validateMobileRedirectUri, w as decodeOidcTransaction, y as SessionService } from "./chunks/TerminalAuthService-Br64vHtd.js";
2
2
  import { DiscoveryArtifactValidationError, SMRT_APP_RESULT_CONTRACT, SMRT_APP_RESULT_SCHEMA, SMRT_APP_RESULT_VERSION, SMRT_DISCOVERY_CONFORMANCE_ARTIFACT_SCHEMA, SMRT_DISCOVERY_CONFORMANCE_SCHEMA, SMRT_DISCOVERY_CONFORMANCE_VERSION, SMRT_MCP_RESULT_METADATA_KEY, canonicalizeDiscoveryArtifact, createDiscoveryConformanceArtifact, deriveCommandRequirements, validateDiscoveryConformanceArtifact } from "./app-contract.js";
3
3
  import { ObjectRegistry, createClassNamePredicate, resolveCustomActionMetadata, resolveEffectiveActionMetadata } from "@happyvertical/smrt-core";
4
4
  import { createLogger } from "@happyvertical/logger";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@happyvertical/smrt-users",
3
- "version": "0.51.36",
3
+ "version": "0.52.0",
4
4
  "smrtJsdoc": "strict",
5
5
  "description": "Multi-tenant user management for the SMRT framework - users, tenants, roles, permissions, groups",
6
6
  "type": "module",
@@ -35,10 +35,11 @@
35
35
  "files": [
36
36
  "dist",
37
37
  "CLAUDE.md",
38
- "AGENTS.md"
38
+ "AGENTS.md",
39
+ "agents"
39
40
  ],
40
41
  "peerDependencies": {
41
- "svelte": "^5.57.1"
42
+ "svelte": "^5.57.0"
42
43
  },
43
44
  "peerDependenciesMeta": {
44
45
  "svelte": {
@@ -46,19 +47,19 @@
46
47
  }
47
48
  },
48
49
  "dependencies": {
49
- "@happyvertical/logger": "^0.96.0",
50
- "@happyvertical/smrt-config": "0.51.36",
51
- "@happyvertical/smrt-core": "0.51.36",
52
- "@happyvertical/smrt-mobile-contract": "0.51.36",
53
- "@happyvertical/smrt-profiles": "0.51.36",
54
- "@happyvertical/smrt-tenancy": "0.51.36",
55
- "@happyvertical/smrt-types": "0.51.36",
56
- "@happyvertical/smrt-ui": "0.51.36",
57
- "@happyvertical/sql": "^0.96.0",
50
+ "@happyvertical/logger": "^0.96.1",
51
+ "@happyvertical/smrt-config": "0.52.0",
52
+ "@happyvertical/smrt-core": "0.52.0",
53
+ "@happyvertical/smrt-mobile-contract": "0.52.0",
54
+ "@happyvertical/smrt-profiles": "0.52.0",
55
+ "@happyvertical/smrt-tenancy": "0.52.0",
56
+ "@happyvertical/smrt-types": "0.52.0",
57
+ "@happyvertical/smrt-ui": "0.52.0",
58
+ "@happyvertical/sql": "^0.96.1",
58
59
  "jose": "^6.2.12"
59
60
  },
60
61
  "devDependencies": {
61
- "@happyvertical/smrt-vitest": "0.51.36",
62
+ "@happyvertical/smrt-vitest": "0.52.0",
62
63
  "@sveltejs/package": "^2.5.8",
63
64
  "@sveltejs/vite-plugin-svelte": "^7.3.0",
64
65
  "@types/node": "24.13.6",