@happyvertical/smrt-users 0.54.0 → 0.55.2

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 (38) hide show
  1. package/AGENTS.md +16 -0
  2. package/README.md +167 -3
  3. package/agents/oidc-provisioning.md +6 -0
  4. package/dist/chunks/{TerminalAuthService-BfxG493c.js → TerminalAuthService-DdV-Rm4h.js} +969 -155
  5. package/dist/chunks/TerminalAuthService-DdV-Rm4h.js.map +1 -0
  6. package/dist/collections/PasswordCredentialCollection.d.ts +53 -0
  7. package/dist/collections/PasswordCredentialCollection.d.ts.map +1 -0
  8. package/dist/collections/SessionCollection.d.ts +7 -2
  9. package/dist/collections/SessionCollection.d.ts.map +1 -1
  10. package/dist/collections/index.d.ts +1 -0
  11. package/dist/collections/index.d.ts.map +1 -1
  12. package/dist/index.d.ts +3 -3
  13. package/dist/index.d.ts.map +1 -1
  14. package/dist/index.js +44 -4
  15. package/dist/index.js.map +1 -1
  16. package/dist/manifest.json +462 -7
  17. package/dist/models/PasswordCredential.d.ts +36 -0
  18. package/dist/models/PasswordCredential.d.ts.map +1 -0
  19. package/dist/models/index.d.ts +1 -0
  20. package/dist/models/index.d.ts.map +1 -1
  21. package/dist/services/DeviceCredentialService.d.ts.map +1 -1
  22. package/dist/services/PasswordCredentialService.d.ts +302 -0
  23. package/dist/services/PasswordCredentialService.d.ts.map +1 -0
  24. package/dist/services/SessionService.d.ts +3 -1
  25. package/dist/services/SessionService.d.ts.map +1 -1
  26. package/dist/services/credential-hash.d.ts +76 -0
  27. package/dist/services/credential-hash.d.ts.map +1 -0
  28. package/dist/services/index.d.ts +1 -0
  29. package/dist/services/index.d.ts.map +1 -1
  30. package/dist/smrt-knowledge.json +215 -10
  31. package/dist/sveltekit/index.d.ts +46 -0
  32. package/dist/sveltekit/index.d.ts.map +1 -1
  33. package/dist/sveltekit/password-handlers.d.ts +91 -0
  34. package/dist/sveltekit/password-handlers.d.ts.map +1 -0
  35. package/dist/sveltekit.js +250 -68
  36. package/dist/sveltekit.js.map +1 -1
  37. package/package.json +12 -12
  38. package/dist/chunks/TerminalAuthService-BfxG493c.js.map +0 -1
@@ -3,15 +3,15 @@
3
3
  "sensitiveFieldsExcluded": true,
4
4
  "generatedAt": "1970-01-01T00:00:00.000Z",
5
5
  "packageName": "@happyvertical/smrt-users",
6
- "packageVersion": "0.54.0",
6
+ "packageVersion": "0.55.2",
7
7
  "sourceManifestPath": "dist/manifest.json",
8
8
  "agentDocPath": "AGENTS.md",
9
9
  "sourceHashes": {
10
- "manifest": "240c2e24420c9e6df07c5c35ca18667c71ee4ee9955ce282c11a35fe17d37396",
11
- "packageJson": "7f47cda4f1c68140198bf399274fe77d9add2d5e928dc09e77649d1b156228af",
12
- "agents": "a0c6228ba98d46fc4bb2d39d6cc857c0a8a15571661169d2f8ffdbd9c1b0b966",
10
+ "manifest": "9d030b39ff492f4ec431ae26ed48570ac667f5ee9b550d532dabf83970dbe62a",
11
+ "packageJson": "af07a3e664950e4f2dd890f392191880b439336b5965f5141cecbf25d7e5da1d",
12
+ "agents": "fa1b9005064b329b1d2387cd56307b92a79f2cd4ea951776e687f9850a428335",
13
13
  "moduleDoc:agents/permissions.md": "5f6c0afab7e1fd0887b0d29b5a5b5ab2635694207bade70145d3cbfdb62ba78c",
14
- "moduleDoc:agents/oidc-provisioning.md": "5efa607ff23b9a693391e0c02670324a8cea4114d4968c9718f10a763da919c6",
14
+ "moduleDoc:agents/oidc-provisioning.md": "b73f3fdaf61136720132a614c7e14237b7bd35f7bf5d43eabb29f565485803b9",
15
15
  "moduleDoc:agents/mobile-auth.md": "25e85e83f43e3a46383a92fa809f3a003b4545c3026e78dbe1bccbbc35161e18",
16
16
  "moduleDoc:agents/terminal-auth-testing.md": "8a84c16a19e381427aed81d3b1882344c427fe22a70e87f5ac2db836b1a6822d",
17
17
  "moduleDoc:agents/retention.md": "073874bf16ce3fbbc503157679dc7fe69800fb39a59e40299bcc713f099bf3d8"
@@ -1715,6 +1715,145 @@
1715
1715
  "tags": [],
1716
1716
  "risks": []
1717
1717
  },
1718
+ {
1719
+ "name": "UsersPasswordCredentialCollection",
1720
+ "qualifiedName": "@happyvertical/smrt-users:UsersPasswordCredentialCollection",
1721
+ "collection": "userspasswordcredentials",
1722
+ "tableName": "users_password_credentials",
1723
+ "packageName": "@happyvertical/smrt-users",
1724
+ "extends": "SmrtCollection",
1725
+ "fields": [],
1726
+ "relationships": [],
1727
+ "methods": [
1728
+ "deleteByUserId",
1729
+ "deleteIfCurrent",
1730
+ "findByUserId",
1731
+ "insertIfAbsent",
1732
+ "replaceHashIfUnchanged",
1733
+ "replaceIfCurrent",
1734
+ "upsertForUser"
1735
+ ],
1736
+ "methodSignatures": [
1737
+ {
1738
+ "name": "deleteByUserId",
1739
+ "async": true,
1740
+ "params": [
1741
+ "userId: string"
1742
+ ],
1743
+ "returns": "Promise<boolean>"
1744
+ },
1745
+ {
1746
+ "name": "deleteIfCurrent",
1747
+ "async": true,
1748
+ "params": [
1749
+ "expected: UsersPasswordCredential"
1750
+ ],
1751
+ "returns": "Promise<boolean>"
1752
+ },
1753
+ {
1754
+ "name": "findByUserId",
1755
+ "async": true,
1756
+ "params": [
1757
+ "userId: string"
1758
+ ],
1759
+ "returns": "Promise<UsersPasswordCredential | null>"
1760
+ },
1761
+ {
1762
+ "name": "insertIfAbsent",
1763
+ "async": true,
1764
+ "params": [
1765
+ "userId: string",
1766
+ "write: PasswordCredentialWrite"
1767
+ ],
1768
+ "returns": "Promise<UsersPasswordCredential | null>"
1769
+ },
1770
+ {
1771
+ "name": "replaceHashIfUnchanged",
1772
+ "async": true,
1773
+ "params": [
1774
+ "userId: string",
1775
+ "expectedHash: string",
1776
+ "upgradedHash: string"
1777
+ ],
1778
+ "returns": "Promise<boolean>"
1779
+ },
1780
+ {
1781
+ "name": "replaceIfCurrent",
1782
+ "async": true,
1783
+ "params": [
1784
+ "expected: UsersPasswordCredential",
1785
+ "write: Omit<PasswordCredentialWrite, 'mustChange'>"
1786
+ ],
1787
+ "returns": "Promise<boolean>"
1788
+ },
1789
+ {
1790
+ "name": "upsertForUser",
1791
+ "async": true,
1792
+ "params": [
1793
+ "userId: string",
1794
+ "write: PasswordCredentialWrite"
1795
+ ],
1796
+ "returns": "Promise<UsersPasswordCredential>"
1797
+ }
1798
+ ],
1799
+ "surfaces": [],
1800
+ "withheldSurfaces": [
1801
+ {
1802
+ "kind": "api",
1803
+ "operation": "deleteByUserId",
1804
+ "code": "api-disabled",
1805
+ "reason": "api is disabled",
1806
+ "objectName": "@happyvertical/smrt-users:UsersPasswordCredentialCollection"
1807
+ },
1808
+ {
1809
+ "kind": "api",
1810
+ "operation": "deleteIfCurrent",
1811
+ "code": "api-disabled",
1812
+ "reason": "api is disabled",
1813
+ "objectName": "@happyvertical/smrt-users:UsersPasswordCredentialCollection"
1814
+ },
1815
+ {
1816
+ "kind": "api",
1817
+ "operation": "findByUserId",
1818
+ "code": "api-disabled",
1819
+ "reason": "api is disabled",
1820
+ "objectName": "@happyvertical/smrt-users:UsersPasswordCredentialCollection"
1821
+ },
1822
+ {
1823
+ "kind": "api",
1824
+ "operation": "insertIfAbsent",
1825
+ "code": "api-disabled",
1826
+ "reason": "api is disabled",
1827
+ "objectName": "@happyvertical/smrt-users:UsersPasswordCredentialCollection"
1828
+ },
1829
+ {
1830
+ "kind": "api",
1831
+ "operation": "replaceHashIfUnchanged",
1832
+ "code": "api-disabled",
1833
+ "reason": "api is disabled",
1834
+ "objectName": "@happyvertical/smrt-users:UsersPasswordCredentialCollection"
1835
+ },
1836
+ {
1837
+ "kind": "api",
1838
+ "operation": "replaceIfCurrent",
1839
+ "code": "api-disabled",
1840
+ "reason": "api is disabled",
1841
+ "objectName": "@happyvertical/smrt-users:UsersPasswordCredentialCollection"
1842
+ },
1843
+ {
1844
+ "kind": "api",
1845
+ "operation": "upsertForUser",
1846
+ "code": "api-disabled",
1847
+ "reason": "api is disabled",
1848
+ "objectName": "@happyvertical/smrt-users:UsersPasswordCredentialCollection"
1849
+ }
1850
+ ],
1851
+ "relationshipFeatures": [
1852
+ "uuidColumns"
1853
+ ],
1854
+ "tags": [],
1855
+ "risks": []
1856
+ },
1718
1857
  {
1719
1858
  "name": "PermissionCollection",
1720
1859
  "qualifiedName": "@happyvertical/smrt-users:PermissionCollection",
@@ -2596,7 +2735,8 @@
2596
2735
  "name": "revokeUserSessions",
2597
2736
  "async": true,
2598
2737
  "params": [
2599
- "userId: string"
2738
+ "userId: string",
2739
+ "options?: object"
2600
2740
  ],
2601
2741
  "returns": "Promise<number>"
2602
2742
  },
@@ -4288,6 +4428,7 @@
4288
4428
  {
4289
4429
  "name": "AccessRequest",
4290
4430
  "qualifiedName": "@happyvertical/smrt-users:AccessRequest",
4431
+ "displayLabelField": "name",
4291
4432
  "collection": "accessrequests",
4292
4433
  "tableName": "access_requests",
4293
4434
  "packageName": "@happyvertical/smrt-users",
@@ -4617,6 +4758,7 @@
4617
4758
  {
4618
4759
  "name": "Group",
4619
4760
  "qualifiedName": "@happyvertical/smrt-users:Group",
4761
+ "displayLabelField": "name",
4620
4762
  "collection": "groups",
4621
4763
  "tableName": "groups",
4622
4764
  "packageName": "@happyvertical/smrt-users",
@@ -5544,9 +5686,70 @@
5544
5686
  "tags": [],
5545
5687
  "risks": []
5546
5688
  },
5689
+ {
5690
+ "name": "UsersPasswordCredential",
5691
+ "qualifiedName": "@happyvertical/smrt-users:UsersPasswordCredential",
5692
+ "collection": "userspasswordcredentials",
5693
+ "tableName": "users_password_credentials",
5694
+ "packageName": "@happyvertical/smrt-users",
5695
+ "extends": "SmrtObject",
5696
+ "fields": [
5697
+ {
5698
+ "name": "userId",
5699
+ "type": "foreignKey",
5700
+ "required": true,
5701
+ "related": "User",
5702
+ "columnType": "UUID"
5703
+ },
5704
+ {
5705
+ "name": "version",
5706
+ "type": "integer",
5707
+ "required": true,
5708
+ "columnType": "INTEGER",
5709
+ "default": 1
5710
+ },
5711
+ {
5712
+ "name": "mustChange",
5713
+ "type": "boolean",
5714
+ "required": true,
5715
+ "columnType": "BOOLEAN",
5716
+ "default": false
5717
+ },
5718
+ {
5719
+ "name": "rotatedAt",
5720
+ "type": "datetime",
5721
+ "required": false,
5722
+ "columnType": "TIMESTAMP"
5723
+ },
5724
+ {
5725
+ "name": "rotatedBy",
5726
+ "type": "text",
5727
+ "required": false,
5728
+ "columnType": "TEXT"
5729
+ }
5730
+ ],
5731
+ "relationships": [
5732
+ {
5733
+ "name": "userId",
5734
+ "type": "foreignKey",
5735
+ "required": true,
5736
+ "related": "User",
5737
+ "columnType": "UUID"
5738
+ }
5739
+ ],
5740
+ "methods": [],
5741
+ "surfaces": [],
5742
+ "relationshipFeatures": [
5743
+ "foreignKey",
5744
+ "uuidColumns"
5745
+ ],
5746
+ "tags": [],
5747
+ "risks": []
5748
+ },
5547
5749
  {
5548
5750
  "name": "Permission",
5549
5751
  "qualifiedName": "@happyvertical/smrt-users:Permission",
5752
+ "displayLabelField": "name",
5550
5753
  "collection": "permissions",
5551
5754
  "tableName": "permissions",
5552
5755
  "packageName": "@happyvertical/smrt-users",
@@ -5945,6 +6148,7 @@
5945
6148
  {
5946
6149
  "name": "Role",
5947
6150
  "qualifiedName": "@happyvertical/smrt-users:Role",
6151
+ "displayLabelField": "name",
5948
6152
  "collection": "roles",
5949
6153
  "tableName": "roles",
5950
6154
  "packageName": "@happyvertical/smrt-users",
@@ -6688,6 +6892,7 @@
6688
6892
  {
6689
6893
  "name": "Tenant",
6690
6894
  "qualifiedName": "@happyvertical/smrt-users:Tenant",
6895
+ "displayLabelField": "name",
6691
6896
  "collection": "tenants",
6692
6897
  "tableName": "tenants",
6693
6898
  "packageName": "@happyvertical/smrt-users",
@@ -11253,14 +11458,14 @@
11253
11458
  ],
11254
11459
  "prompts": [],
11255
11460
  "relationshipsV2": {
11256
- "foreignKeyFields": 26,
11461
+ "foreignKeyFields": 27,
11257
11462
  "crossPackageRefFields": 1,
11258
11463
  "junctionCollections": 0,
11259
11464
  "hierarchicalObjects": 0,
11260
11465
  "polymorphicAssociations": 0,
11261
- "uuidColumns": 100
11466
+ "uuidColumns": 104
11262
11467
  },
11263
- "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/services/LoginAttemptLimiter.ts`, `src/collections/LoginAttemptCollection.ts` | terminal approval concurrency, shared login budget and lockout (#3273), retry-safe database fixtures | [agents/terminal-auth-testing.md](agents/terminal-auth-testing.md) |\n| `src/services/DeviceCredentialService.ts` | per-person PIN layered on a device session (#3276), verifier seam for other credential kinds | this file, \"Security boundaries\" |\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- `Session.authMethod` is server-set at mint time and never read from the\n client; every mint site in this package sets it. A session with\n `parentSessionId` is valid only while its parent validates\n (`loadSessionContext` enforces this; there is no FK cascade by design), may\n not switch to a tenant other than the parent's, and is revoked with its\n parent by `destroySession`.\n- Credential sign-ins reserve through `LoginAttemptLimiter` BEFORE credential\n work and key the subject on the submitted identifier, never a resolved user,\n so unknown and wrong take the same path. Reservations are fail-closed: keep\n them on failure, release on success or abort, never skip the reserve.\n Limiter writes are raw SQL and bypass the change feed; the audit sink is the\n observability seam, and it must never throw into the sign-in path.\n- `DeviceCredentialService` accepts a person credential only from a\n first-class session whose `authMethod` is a device-enrollment method\n (`terminal` by default) and that the host's `assertEnrolledDevice` confirms.\n A layered or PIN session can never administer PINs regardless of\n permissions. PIN hashes carry a per-row salt and the configured pepper;\n treat an unset pepper as a production misconfiguration.\n- A person session carries the PERSON's authority (resolved from their own\n membership on every load), never the device account's. `Session.data` keys\n in `SESSION_DATA_KEYS` are server-set controls enforced by the model:\n `permissionCeiling` only ever intersects (malformed fails closed to none)\n and suppresses `superAdminBypass`/`systemContext`; `absoluteExpiresAt`\n bounds `extend()` and `isValid()`; `idleSeconds` overrides the resolving\n service's TTL policy. Never write them from client input. The ceiling is a\n sign-in snapshot; `singleOccupant` revokes other children only AFTER a\n successful mint. A `mustReset` sign-in mints with an empty ceiling and\n `setPin` ends that session; do not grant it authority another way.\n- A layered session whose tenant differs from its parent's never loads (null\n is allowed: narrower). Limiter rows carry `retain_until`; retention must\n not fall back to a process-wide horizon.\n- `Session.parentSessionId` is the parent's bearer: sensitive, never a\n `list()` filter (raw-SQL id reads, which also keep revocation sweeps free of\n caller list bounds), never serialized to clients. `users.pin.manage` reaches\n only people whose every active membership is in the actor's tenant (the PIN\n is global per person). A sign-in re-checks the verified\n credential generation AFTER the mint (`stillValid`); keep that ordering.\n Operation guards deny outside a session's ceiling; `loadPersonSession`\n re-checks device enrollment.\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, and layered sessions never rotate (a replacement would escape\n the revocation sweeps they depend on). Layers do not nest. `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",
11468
+ "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/services/LoginAttemptLimiter.ts`, `src/collections/LoginAttemptCollection.ts` | terminal approval concurrency, shared login budget and lockout (#3273), retry-safe database fixtures | [agents/terminal-auth-testing.md](agents/terminal-auth-testing.md) |\n| `src/services/DeviceCredentialService.ts` | per-person PIN layered on a device session (#3276), verifier seam for other credential kinds | this file, \"Security boundaries\" |\n| `src/services/PasswordCredentialService.ts`, `src/sveltekit/password-handlers.ts` | email + password sign-in and password lifecycle (#3274); shared scrypt in `credential-hash.ts` | this file, \"Security boundaries\"; README \"Password sign-in\" |\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- `Session.authMethod` is server-set at mint time and never read from the\n client; every mint site in this package sets it. A session with\n `parentSessionId` is valid only while its parent validates\n (`loadSessionContext` enforces this; there is no FK cascade by design), may\n not switch to a tenant other than the parent's, and is revoked with its\n parent by `destroySession`.\n- Credential sign-ins reserve through `LoginAttemptLimiter` BEFORE credential\n work and key the subject on the submitted identifier, never a resolved user,\n so unknown and wrong take the same path. Reservations are fail-closed: keep\n them on failure, release on success or abort, never skip the reserve.\n Limiter writes are raw SQL and bypass the change feed; the audit sink is the\n observability seam, and it must never throw into the sign-in path.\n- `DeviceCredentialService` accepts a person credential only from a\n first-class session whose `authMethod` is a device-enrollment method\n (`terminal` by default) and that the host's `assertEnrolledDevice` confirms.\n A layered or PIN session can never administer PINs regardless of\n permissions. PIN hashes carry a per-row salt and the configured pepper;\n treat an unset pepper as a production misconfiguration.\n- A person session carries the PERSON's authority (resolved from their own\n membership on every load), never the device account's. `Session.data` keys\n in `SESSION_DATA_KEYS` are server-set controls enforced by the model:\n `permissionCeiling` only ever intersects (malformed fails closed to none)\n and suppresses `superAdminBypass`/`systemContext`; `absoluteExpiresAt`\n bounds `extend()` and `isValid()`; `idleSeconds` overrides the resolving\n service's TTL policy. Never write them from client input. The ceiling is a\n sign-in snapshot; `singleOccupant` revokes other children only AFTER a\n successful mint. A `mustReset` sign-in mints with an empty ceiling and\n `setPin` ends that session; do not grant it authority another way.\n- `UsersPasswordCredential` is one row per person, sensitive, with no\n generated surface; `PasswordCredentialService` and its handlers are its only\n read/write paths. Sign-in normalizes the email like `emailKey`, reserves\n before work, always runs one scrypt verify (dummy hash when absent), never\n creates a user, and maps every non-rate-limit refusal to one\n `PasswordCredentialError`. It re-checks the credential after the mint (a\n rehash that keeps row and version is confirmed by re-verifying); the\n parameter-upgrade write is a guarded UPDATE that must never replace a\n rotated password, and verification against a weaker stored hash is padded\n to the policy's scrypt cost. Self-service writes are guarded on the proven\n credential (first set insert-only); session sweeps run before and after\n each write. Self-service needs the current password except for a first\n set; `users.password.manage` follows the PIN's single-tenant target\n rule and never resets the actor's own. Layered sessions never manage\n passwords; a `mustChange` sign-in mints an empty ceiling.\n- A layered session whose tenant differs from its parent's never loads (null\n is allowed: narrower). Limiter rows carry `retain_until`; retention must\n not fall back to a process-wide horizon.\n- `Session.parentSessionId` is the parent's bearer: sensitive, never a\n `list()` filter (raw-SQL id reads, which also keep revocation sweeps free of\n caller list bounds), never serialized to clients. `users.pin.manage` reaches\n only people whose every active membership is in the actor's tenant (the PIN\n is global per person). A sign-in re-checks the verified\n credential generation AFTER the mint (`stillValid`); keep that ordering.\n Operation guards deny outside a session's ceiling; `loadPersonSession`\n re-checks device enrollment.\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, and layered sessions never rotate (a replacement would escape\n the revocation sweeps they depend on). Layers do not nest. `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",
11264
11469
  "moduleDocs": [
11265
11470
  {
11266
11471
  "path": "agents/permissions.md",
@@ -11270,7 +11475,7 @@
11270
11475
  {
11271
11476
  "path": "agents/oidc-provisioning.md",
11272
11477
  "module": "oidc-provisioning",
11273
- "content": "# OIDC provisioning\n\nRead for changes to `src/collections/UserCollection.ts`, `src/services/OidcLoginService.ts`,\nOIDC handlers, or identity migrations. The canonical scenario matrix is\n`packages/profiles/src/testing/oidcProvisioningDecisionMatrix.ts`.\n\n- **OIDC `email_verified` is enforced.** `UserCollection.getOrCreateFromOidc`\n refuses to provision a user when the IdP explicitly returns\n `email_verified: false` (opt out with `{ allowUnverifiedEmail: true }`). An\n absent claim makes no assertion and is not enforced.\n- **RFC 9207 response issuer is exact.** OIDC callbacks validate a supplied\n `iss` against discovered metadata with exact string comparison before trusting\n a code or error. If metadata advertises issuer-response support, `iss` is\n required.\n- **Verified-email Profile reuse is fail-closed.** The typed canonical scenarios\n live in\n `packages/profiles/src/testing/oidcProvisioningDecisionMatrix.ts`; both\n package suites execute that matrix and public docs reference it rather than\n maintaining another behavioral table. Default provisioning reuses only one\n unowned, global `Person`. Tenant-scoped, non-Person, duplicate-email,\n and already-owned matches fail before User/session creation. An existing\n issuer/subject link without a User must still be the unique global Person for\n the current verified claim email; once owned, the stable issuer/subject link\n reuses its canonical Person and owner.\n Issuer and subject are opaque, case-sensitive identifiers; preserve their\n exact value and use trim only to reject blank claims.\n- **`resolveProfile` is the application reconciliation boundary.** The\n SvelteKit handlers, `OidcLoginService`, and `getOrCreateFromOidc` accept the\n same hook inside the provisioning transaction. The service/handler path\n supplies protocol-validated claims; direct collection callers must validate\n and trust their claim source before calling `getOrCreateFromOidc`.\n Token/userinfo merging keeps `email` and `email_verified` paired to the same\n claim source; verification is never borrowed across sources.\n Resolver reads/writes use the supplied `db`, and the hook must be idempotent\n because a concurrent unique-key conflict can retry it. `undefined` chooses\n the secure default and `null` rejects, including exact issuer/subject reuse.\n For a new identity, a supplied Profile is still validated as the unique,\n unowned global Person for the verified email. For an exact existing identity,\n it must be the already-linked Profile and cannot rebind identity authority;\n stable-link owner and canonical-Person checks still apply. The hook receives a\n separate frozen claims snapshot; internal retry and persistence state is not\n exposed for mutation.\n- **Owned first binding requires `authorizeProfileOwner`.** An invitation or\n approval workflow may explicitly return both its pre-provisioned canonical\n global `Person` and existing approved `User` from this transaction-bound\n hook. `undefined` keeps the secure `profile_owned` default and `null`\n rejects. SMRT treats only the selected IDs as input, reloads them in the\n provisioning transaction, and requires `email_verified === true`, the unique\n canonical global Person for the normalized claim email, exactly one owner,\n that owner as the selected User, and the same normalized User email. The\n hook runs before identity/User/session creation and may be retried, so use\n only its supplied `db` and `users` handles and keep application authorization\n idempotent. Never authorize from email matching alone. Existing exact\n identities cannot be rebound; when `resolveProfile` is also present both\n hooks must select the same Profile.\n- **OIDC first login is atomic.** The Profile, `OidcIdentity`, and User are one\n transaction. The database arbiters are `OidcIdentity.identityKey`,\n private `oidc_profile_email_reservations.email_key`, `User.emailKey`, and the\n unique `User.profileId`; local callbacks acquire exact issuer/subject and normalized\n email locks in deterministic order so changed email claims also serialize.\n SQLite and DuckDB callbacks additionally serialize every root-handle statement\n the coordinator owns per database URL — `_smrt_backfills` initialization, the\n transaction, and the post-commit rebind — because one adapter multiplexes a\n single native connection and cannot safely overlap unrelated root\n transactions. Never overlap two statements on one such handle, inside a\n transaction or not: rebind and owner/email candidate reads are sequential,\n never `Promise.all`. Owner-authorized DuckDB callbacks use that same\n root-handle serialization;\n PostgreSQL deadlock and serialization errors use a bounded transaction retry.\n Newly provisioned Profiles use non-semantic per-profile slugs so equal IdP\n display names cannot trigger a natural-key upsert;\n run\n `smrt db:status`, `smrt db:migrate`, then `smrt db:status` before deployment.\n Stop or upgrade old writers first. Before migration, group\n non-null `users.profile_id` values, then reconcile duplicates. After\n migration, run public `backfillProfileEmailKeys(db)`,\n `backfillUserEmailKeys(db)`, then `backfillLegacyUserProfiles(db)` from one\n deploy process. The first two use the shared\n TypeScript `normalizeIdentityEmail()` implementation transactionally and are\n idempotent; the User backfill fails before writes if normalized duplicates\n remain. The legacy Profile backfill transactionally creates canonical global\n Persons for null/blank User links without creating OIDC identities or\n inferring ownership; reconcile any same-email Profile or reservation before\n retrying. Its marker records a completed pass but never skips newly imported\n legacy Users on a later run. Every OIDC path requires the Profile email-key\n readiness marker; creating a User or checking User email uniqueness\n additionally requires the User marker. A stable issuer/subject with an\n existing owning User skips only the User email-key lookup and marker. Full\n scans remain in the explicit deploy step; guarded runtime paths use indexed\n keys and validate only returned candidates. Multiple null links remain valid.\n Legacy race keys backfill only after canonical validation. Pass a root\n database on adapters such as DuckDB that cannot create nested savepoints.\n Root adapters must expose `beginTransaction`; transaction-only handles are\n ambiguous and fail closed before provisioning writes. Caller-owned\n transactions never run `_smrt_backfills` DDL and require that table to\n already exist; use the root database when initialization or recovery is\n needed.\n"
11478
+ "content": "# OIDC provisioning\n\nRead for changes to `src/collections/UserCollection.ts`, `src/services/OidcLoginService.ts`,\nOIDC handlers, or identity migrations. The canonical scenario matrix is\n`packages/profiles/src/testing/oidcProvisioningDecisionMatrix.ts`.\n\n- **OIDC `email_verified` is enforced.** `UserCollection.getOrCreateFromOidc`\n refuses to provision a user when the IdP explicitly returns\n `email_verified: false` (opt out with `{ allowUnverifiedEmail: true }`). An\n absent claim makes no assertion and is not enforced.\n- **RFC 9207 response issuer is exact.** OIDC callbacks validate a supplied\n `iss` against discovered metadata with exact string comparison before trusting\n a code or error. If metadata advertises issuer-response support, `iss` is\n required.\n- **The login start route is the IdP landing URL (#3569).** Kanidm drops a\n pending authorization after any detour through its `/ui/login` and strands the\n user in its apps panel; the client landing URL is the only way back.\n `getOidcClientRegistration()` derives it from `loginPath` (default\n `/auth/<provider>/login`) alongside the callback URL; keep the login handler\n safe to enter with no query string.\n- **Verified-email Profile reuse is fail-closed.** The typed canonical scenarios\n live in\n `packages/profiles/src/testing/oidcProvisioningDecisionMatrix.ts`; both\n package suites execute that matrix and public docs reference it rather than\n maintaining another behavioral table. Default provisioning reuses only one\n unowned, global `Person`. Tenant-scoped, non-Person, duplicate-email,\n and already-owned matches fail before User/session creation. An existing\n issuer/subject link without a User must still be the unique global Person for\n the current verified claim email; once owned, the stable issuer/subject link\n reuses its canonical Person and owner.\n Issuer and subject are opaque, case-sensitive identifiers; preserve their\n exact value and use trim only to reject blank claims.\n- **`resolveProfile` is the application reconciliation boundary.** The\n SvelteKit handlers, `OidcLoginService`, and `getOrCreateFromOidc` accept the\n same hook inside the provisioning transaction. The service/handler path\n supplies protocol-validated claims; direct collection callers must validate\n and trust their claim source before calling `getOrCreateFromOidc`.\n Token/userinfo merging keeps `email` and `email_verified` paired to the same\n claim source; verification is never borrowed across sources.\n Resolver reads/writes use the supplied `db`, and the hook must be idempotent\n because a concurrent unique-key conflict can retry it. `undefined` chooses\n the secure default and `null` rejects, including exact issuer/subject reuse.\n For a new identity, a supplied Profile is still validated as the unique,\n unowned global Person for the verified email. For an exact existing identity,\n it must be the already-linked Profile and cannot rebind identity authority;\n stable-link owner and canonical-Person checks still apply. The hook receives a\n separate frozen claims snapshot; internal retry and persistence state is not\n exposed for mutation.\n- **Owned first binding requires `authorizeProfileOwner`.** An invitation or\n approval workflow may explicitly return both its pre-provisioned canonical\n global `Person` and existing approved `User` from this transaction-bound\n hook. `undefined` keeps the secure `profile_owned` default and `null`\n rejects. SMRT treats only the selected IDs as input, reloads them in the\n provisioning transaction, and requires `email_verified === true`, the unique\n canonical global Person for the normalized claim email, exactly one owner,\n that owner as the selected User, and the same normalized User email. The\n hook runs before identity/User/session creation and may be retried, so use\n only its supplied `db` and `users` handles and keep application authorization\n idempotent. Never authorize from email matching alone. Existing exact\n identities cannot be rebound; when `resolveProfile` is also present both\n hooks must select the same Profile.\n- **OIDC first login is atomic.** The Profile, `OidcIdentity`, and User are one\n transaction. The database arbiters are `OidcIdentity.identityKey`,\n private `oidc_profile_email_reservations.email_key`, `User.emailKey`, and the\n unique `User.profileId`; local callbacks acquire exact issuer/subject and normalized\n email locks in deterministic order so changed email claims also serialize.\n SQLite and DuckDB callbacks additionally serialize every root-handle statement\n the coordinator owns per database URL — `_smrt_backfills` initialization, the\n transaction, and the post-commit rebind — because one adapter multiplexes a\n single native connection and cannot safely overlap unrelated root\n transactions. Never overlap two statements on one such handle, inside a\n transaction or not: rebind and owner/email candidate reads are sequential,\n never `Promise.all`. Owner-authorized DuckDB callbacks use that same\n root-handle serialization;\n PostgreSQL deadlock and serialization errors use a bounded transaction retry.\n Newly provisioned Profiles use non-semantic per-profile slugs so equal IdP\n display names cannot trigger a natural-key upsert;\n run\n `smrt db:status`, `smrt db:migrate`, then `smrt db:status` before deployment.\n Stop or upgrade old writers first. Before migration, group\n non-null `users.profile_id` values, then reconcile duplicates. After\n migration, run public `backfillProfileEmailKeys(db)`,\n `backfillUserEmailKeys(db)`, then `backfillLegacyUserProfiles(db)` from one\n deploy process. The first two use the shared\n TypeScript `normalizeIdentityEmail()` implementation transactionally and are\n idempotent; the User backfill fails before writes if normalized duplicates\n remain. The legacy Profile backfill transactionally creates canonical global\n Persons for null/blank User links without creating OIDC identities or\n inferring ownership; reconcile any same-email Profile or reservation before\n retrying. Its marker records a completed pass but never skips newly imported\n legacy Users on a later run. Every OIDC path requires the Profile email-key\n readiness marker; creating a User or checking User email uniqueness\n additionally requires the User marker. A stable issuer/subject with an\n existing owning User skips only the User email-key lookup and marker. Full\n scans remain in the explicit deploy step; guarded runtime paths use indexed\n keys and validate only returned candidates. Multiple null links remain valid.\n Legacy race keys backfill only after canonical validation. Pass a root\n database on adapters such as DuckDB that cannot create nested savepoints.\n Root adapters must expose `beginTransaction`; transaction-only handles are\n ambiguous and fail closed before provisioning writes. Caller-owned\n transactions never run `_smrt_backfills` DDL and require that table to\n already exist; use the root database when initialization or recovery is\n needed.\n"
11274
11479
  },
11275
11480
  {
11276
11481
  "path": "agents/mobile-auth.md",
@@ -26,6 +26,7 @@ export type { NormalizedOidcClaims, OidcProfileOwnerAuthorization, OidcProfileOw
26
26
  export { MobileAuthError, type MobileAuthErrorCode, MobileAuthService, type MobileAuthServiceOptions, type MobileBootstrapContext, type MobileLoginContext, type MobileLogoutResult, type MobileRequestMeta, type MobileResolvedUser, type MobileTenantContext, readMobileBearerToken, validateMobileRedirectUri, } from '../services/MobileAuthService.js';
27
27
  export { createDeviceCredentialHandlers, type DeviceCredentialHandlers, } from './device-credential-handlers.js';
28
28
  export { type CreateMobileAuthHandlersOptions, createMobileAuthHandlers, type MobileAuthHandlers, type MobileRequestEvent, type MobileRequestHandler, resolveMobileUploadDedupKey, } from './mobile-handlers.js';
29
+ export { type CreatePasswordCredentialHandlersOptions, createPasswordCredentialHandlers, type PasswordCredentialHandlers, type PasswordRequestEvent, } from './password-handlers.js';
29
30
  export { type CliResource, type CommandDefinition, type CommandKind, type CommandPolicyContext, type CommandScope, type CreateResourceListHandlerOptions, createResourceListHandler, InvalidBearerError, type ResolvedSession, type ResourceListResponseBody, } from './resource-list-handler.js';
30
31
  export { defaultSessionLocals, type SessionLocals } from './types.js';
31
32
  /**
@@ -98,6 +99,12 @@ export interface OidcSvelteKitOptions extends SmrtClassOptions, OidcProviderReso
98
99
  provider?: OidcProviderResolver;
99
100
  /** Callback path used when provider.redirectUri is omitted. */
100
101
  callbackPath?: string | ((providerName: string) => string);
102
+ /**
103
+ * Path of the route that starts the login (the `createOidcLoginHandler`
104
+ * route). Defaults to `/auth/<provider>/login`. Only used to derive the
105
+ * IdP landing URL in {@link getOidcClientRegistration}.
106
+ */
107
+ loginPath?: string | ((providerName: string) => string);
101
108
  /** Query parameter used to preserve post-login redirects. */
102
109
  returnToParam?: string;
103
110
  /** Prefix for the temporary OIDC transaction cookie. */
@@ -141,6 +148,18 @@ export interface OidcSvelteKitOptions extends SmrtClassOptions, OidcProviderReso
141
148
  /** Redirect target after failed callback. If omitted, failures return 401. */
142
149
  failureRedirect?: string | ((error: unknown, event: SvelteKitRequestEvent) => string);
143
150
  }
151
+ /** URLs to register with the IdP for one SMRT OIDC client. */
152
+ export interface OidcClientRegistration {
153
+ providerName: string;
154
+ /** Callback URL: register as the client's allowed redirect URL. */
155
+ redirectUri: string;
156
+ /**
157
+ * Login start URL: register as the client's landing / initiate-login URL
158
+ * (Kanidm `set-landing-url`). The IdP links its app tile here, so a user
159
+ * whose pending authorization the IdP discarded can resume sign-in.
160
+ */
161
+ landingUrl: string;
162
+ }
144
163
  export interface BeginOidcLoginResult {
145
164
  providerName: string;
146
165
  transaction: OidcTransaction;
@@ -313,6 +332,30 @@ export declare function beginOidcLogin(event: SvelteKitRequestEvent, options: Oi
313
332
  * the session cookie.
314
333
  */
315
334
  export declare function completeOidcLogin(event: SvelteKitRequestEvent, options: OidcSvelteKitOptions): Promise<CompleteOidcLoginResult>;
335
+ /**
336
+ * Derive the URLs an IdP client registration must carry for this app, from the
337
+ * same options the login and callback handlers use.
338
+ *
339
+ * Register `redirectUri` as the allowed redirect URL and `landingUrl` as the
340
+ * client's landing URL. Kanidm discards a pending authorization whenever the
341
+ * user detours through its own login page (for example "Return to Login"
342
+ * after a mistyped password) and then lands the user in its apps panel; the
343
+ * landing URL is the only way back, so it must start the app's login rather
344
+ * than open its signed-out home page.
345
+ *
346
+ * @example
347
+ * ```typescript
348
+ * const { redirectUri, landingUrl } = getOidcClientRegistration(
349
+ * 'https://app.example.com',
350
+ * { provider: 'kanidm' },
351
+ * );
352
+ * // kanidm system oauth2 add-redirect-url <client> <redirectUri>
353
+ * // kanidm system oauth2 set-landing-url <client> <landingUrl>
354
+ * ```
355
+ */
356
+ export declare function getOidcClientRegistration(origin: string | URL, options?: Omit<OidcSvelteKitOptions, 'provider'> & {
357
+ provider?: string;
358
+ }): OidcClientRegistration;
316
359
  /**
317
360
  * Create a SvelteKit GET handler that redirects to an OIDC provider.
318
361
  *
@@ -325,6 +368,9 @@ export declare function completeOidcLogin(event: SvelteKitRequestEvent, options:
325
368
  * db: { type: 'postgres', url: process.env.DATABASE_URL! },
326
369
  * });
327
370
  * ```
371
+ *
372
+ * Register this route as the IdP client's landing URL; see
373
+ * {@link getOidcClientRegistration}.
328
374
  */
329
375
  export declare function createOidcLoginHandler(options: OidcSvelteKitOptions): (event: SvelteKitRequestEvent) => Promise<Response>;
330
376
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/sveltekit/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AASH,OAAO,yBAAyB,CAAC;AAGjC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AACjE,OAAO,KAAK,EACV,0BAA0B,EAC1B,mBAAmB,EACpB,MAAM,kCAAkC,CAAC;AAC1C,OAAO,EAEL,KAAK,iBAAiB,EACvB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAKL,KAAK,eAAe,EAGpB,KAAK,6BAA6B,EAClC,KAAK,eAAe,EAGrB,MAAM,iCAAiC,CAAC;AAGzC,OAAO,EAEL,iBAAiB,EACjB,0BAA0B,EAC1B,mBAAmB,EACnB,KAAK,0BAA0B,EAChC,MAAM,oCAAoC,CAAC;AAE5C,OAAO,EACL,KAAK,iBAAiB,EACtB,KAAK,iBAAiB,EACtB,KAAK,mBAAmB,EACxB,6BAA6B,EAC7B,kCAAkC,EAClC,KAAK,mBAAmB,EACxB,KAAK,0BAA0B,EAC/B,gCAAgC,EAChC,KAAK,4BAA4B,EACjC,KAAK,gBAAgB,EACrB,yBAAyB,EACzB,KAAK,SAAS,EACd,wBAAwB,EACxB,sBAAsB,EACtB,uBAAuB,EACvB,0CAA0C,EAC1C,iCAAiC,EACjC,kCAAkC,EAClC,4BAA4B,EAC5B,oCAAoC,GACrC,MAAM,oBAAoB,CAAC;AAC5B,YAAY,EACV,oBAAoB,EACpB,6BAA6B,EAC7B,0BAA0B,EAC1B,iCAAiC,EACjC,mBAAmB,EACnB,0BAA0B,GAC3B,MAAM,kCAAkC,CAAC;AAC1C,OAAO,EACL,eAAe,EACf,KAAK,mBAAmB,EACxB,iBAAiB,EACjB,KAAK,wBAAwB,EAC7B,KAAK,sBAAsB,EAC3B,KAAK,kBAAkB,EACvB,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,EACtB,KAAK,kBAAkB,EACvB,KAAK,mBAAmB,EACxB,qBAAqB,EACrB,yBAAyB,GAC1B,MAAM,kCAAkC,CAAC;AAC1C,OAAO,EACL,8BAA8B,EAC9B,KAAK,wBAAwB,GAC9B,MAAM,iCAAiC,CAAC;AACzC,OAAO,EACL,KAAK,+BAA+B,EACpC,wBAAwB,EACxB,KAAK,kBAAkB,EACvB,KAAK,kBAAkB,EACvB,KAAK,oBAAoB,EACzB,2BAA2B,GAC5B,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EACL,KAAK,WAAW,EAChB,KAAK,iBAAiB,EACtB,KAAK,WAAW,EAChB,KAAK,oBAAoB,EACzB,KAAK,YAAY,EACjB,KAAK,gCAAgC,EACrC,yBAAyB,EACzB,kBAAkB,EAClB,KAAK,eAAe,EACpB,KAAK,wBAAwB,GAC9B,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAAE,oBAAoB,EAAE,KAAK,aAAa,EAAE,MAAM,YAAY,CAAC;AAItE;;GAEG;AACH,MAAM,WAAW,qBAAsB,SAAQ,gBAAgB;IAC7D,mCAAmC;IACnC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,+CAA+C;IAC/C,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,0DAA0D;IAC1D,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB,uEAAuE;IACvE,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;;OAIG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,iCAAiC;IACjC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,+DAA+D;IAC/D,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,iDAAiD;IACjD,cAAc,CAAC,EAAE,QAAQ,GAAG,KAAK,GAAG,MAAM,CAAC;IAC3C,4EAA4E;IAC5E,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,sEAAsE;IACtE,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED;;GAEG;AACH,KAAK,WAAW,GAAG;IACjB,KAAK,EAAE;QACL,OAAO,EAAE;YACP,GAAG,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,CAAC;YAC1C,GAAG,EAAE,CACH,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,EACb,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAC9B,IAAI,CAAC;YACV,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;SACnE,CAAC;QACF,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAChC,GAAG,EAAE;YAAE,QAAQ,EAAE,MAAM,CAAC;YAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;SAAE,CAAC;QAC7C,OAAO,EAAE;YAAE,OAAO,EAAE,OAAO,CAAA;SAAE,CAAC;KAC/B,CAAC;IACF,OAAO,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;CAChD,CAAC;AAEF,KAAK,MAAM,GAAG,CAAC,KAAK,EAAE,WAAW,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;AAExD,KAAK,qBAAqB,GAAG;IAC3B,OAAO,EAAE,WAAW,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,CAAC;IACzC,gBAAgB,CAAC,EAAE,MAAM,MAAM,CAAC;IAChC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;IAC5C,OAAO,EAAE,OAAO,CAAC;IACjB,GAAG,EAAE,GAAG,CAAC;CACV,CAAC;AAEF,KAAK,oBAAoB,GACrB,MAAM,GACN,CAAC,CAAC,KAAK,EAAE,qBAAqB,KAAK,MAAM,GAAG,SAAS,CAAC,CAAC;AAE3D,KAAK,kBAAkB,CAAC,CAAC,IACrB,CAAC,GACD,CAAC,CAAC,MAAM,EAAE,eAAe,EAAE,KAAK,EAAE,qBAAqB,KAAK,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;AAEhF,MAAM,WAAW,oBACf,SAAQ,gBAAgB,EACtB,6BAA6B;IAC/B,4DAA4D;IAC5D,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;IACrB,0CAA0C;IAC1C,cAAc,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACjC,uEAAuE;IACvE,QAAQ,CAAC,EAAE,oBAAoB,CAAC;IAChC,+DAA+D;IAC/D,YAAY,CAAC,EAAE,MAAM,GAAG,CAAC,CAAC,YAAY,EAAE,MAAM,KAAK,MAAM,CAAC,CAAC;IAC3D,6DAA6D;IAC7D,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,wDAAwD;IACxD,uBAAuB,CAAC,EAAE,MAAM,CAAC;IACjC,wEAAwE;IACxE,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,sDAAsD;IACtD,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,6DAA6D;IAC7D,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAClC,gEAAgE;IAChE,yBAAyB,CAAC,EAAE,QAAQ,GAAG,KAAK,GAAG,MAAM,CAAC;IACtD,8EAA8E;IAC9E,uBAAuB,CAAC,EAAE,MAAM,CAAC;IACjC,4CAA4C;IAC5C,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,0CAA0C;IAC1C,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,qEAAqE;IACrE,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,6CAA6C;IAC7C,qBAAqB,CAAC,EAAE,QAAQ,GAAG,KAAK,GAAG,MAAM,CAAC;IAClD,uEAAuE;IACvE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,8CAA8C;IAC9C,QAAQ,CAAC,EAAE,kBAAkB,CAAC,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC,CAAC;IACzD;;;;OAIG;IACH,cAAc,CAAC,EAAE,mBAAmB,CAAC;IACrC;;;;OAIG;IACH,qBAAqB,CAAC,EAAE,0BAA0B,CAAC;IACnD,iDAAiD;IACjD,eAAe,CAAC,EAAE,kBAAkB,CAAC,MAAM,CAAC,CAAC;IAC7C,8EAA8E;IAC9E,eAAe,CAAC,EACZ,MAAM,GACN,CAAC,CAAC,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,qBAAqB,KAAK,MAAM,CAAC,CAAC;CAChE;AAED,MAAM,WAAW,oBAAoB;IACnC,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,eAAe,CAAC;IAC7B,GAAG,EAAE,GAAG,CAAC;CACV;AAED,MAAM,WAAW,uBAAwB,SAAQ,eAAe;IAC9D,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,qBAAqB,GAAG,MAAM,CA4E3E;AAED;;GAEG;AACH,MAAM,WAAW,0BAA0B;IACzC,+CAA+C;IAC/C,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,wBAAwB;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,wBAAwB;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,0BAA0B;IAC1B,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B;;;;OAIG;IACH,UAAU,CAAC,EAAE,iBAAiB,GAAG,IAAI,CAAC;IACtC,oDAAoD;IACpD,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACjC;AA0BD;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAsB,mBAAmB,CACvC,KAAK,EAAE,WAAW,CAAC,OAAO,CAAC,EAC3B,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,GAAG,SAAS,EAC5B,OAAO,EAAE,gBAAgB,GACvB,0BAA0B,GAAG;IAC3B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,cAAc,CAAC,EAAE,QAAQ,GAAG,KAAK,GAAG,MAAM,CAAC;CAC5C,GACF,OAAO,CAAC,MAAM,CAAC,CA6BjB;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAsB,oBAAoB,CACxC,KAAK,EAAE,WAAW,CAAC,OAAO,CAAC,EAC3B,OAAO,EAAE,gBAAgB,GAAG;IAC1B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,GAAG,CAAC,EAAE,MAAM,CAAC;CACd,GACA,OAAO,CAAC,IAAI,CAAC,CAsBf;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,wBAAsB,mBAAmB,CACvC,KAAK,EAAE,WAAW,CAAC,OAAO,CAAC,EAC3B,QAAQ,EAAE,MAAM,GAAG,IAAI,EACvB,OAAO,EAAE,gBAAgB,GAAG;IAC1B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,cAAc,CAAC,EAAE,QAAQ,GAAG,KAAK,GAAG,MAAM,CAAC;IAC3C,GAAG,CAAC,EAAE,MAAM,CAAC;CACd,GACA,OAAO,CAAC,OAAO,CAAC,CA0ClB;AAiQD;;;;;GAKG;AACH,wBAAsB,cAAc,CAClC,KAAK,EAAE,qBAAqB,EAC5B,OAAO,EAAE,oBAAoB,GAC5B,OAAO,CAAC,oBAAoB,CAAC,CAyB/B;AAED;;;GAGG;AACH,wBAAsB,iBAAiB,CACrC,KAAK,EAAE,qBAAqB,EAC5B,OAAO,EAAE,oBAAoB,GAC5B,OAAO,CAAC,uBAAuB,CAAC,CA2DlC;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,oBAAoB,IACpD,OAAO,qBAAqB,KAAG,OAAO,CAAC,QAAQ,CAAC,CAI/D;AAED;;GAEG;AACH,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,oBAAoB,IACvD,OAAO,qBAAqB,KAAG,OAAO,CAAC,QAAQ,CAAC,CAW/D;AAoCD;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,aAAa,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,GAAG,IAAI,CAG5E;AAED,mDAAmD;AACnD,MAAM,WAAW,qCACf,SAAQ,0BAA0B;IAClC;;;;OAIG;IACH,kBAAkB,CAAC,EAAE,MAAM,GAAG,CAAC,CAAC,KAAK,EAAE,qBAAqB,KAAK,MAAM,CAAC,CAAC;CAC1E;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,8BAA8B,CAC5C,OAAO,EAAE,qCAAqC,IAEhC,OAAO,qBAAqB,KAAG,OAAO,CAAC,QAAQ,CAAC,CAU/D;AAED;;;;GAIG;AACH,wBAAgB,8BAA8B,CAC5C,OAAO,EAAE,0BAA0B,IAErB,OAAO,qBAAqB,KAAG,OAAO,CAAC,QAAQ,CAAC,CAe/D;AAED;;;;GAIG;AACH,wBAAgB,gCAAgC,CAC9C,OAAO,EAAE,0BAA0B,IAErB,OAAO,qBAAqB,KAAG,OAAO,CAAC,QAAQ,CAAC,CAY/D;AAED;;;;GAIG;AACH,wBAAsB,wBAAwB,CAC5C,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,0BAA0B,wDAIpC;AAED,qDAAqD;AACrD,MAAM,WAAW,qBAAqB;IACpC,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;CAC9B;AAED,uDAAuD;AACvD,MAAM,WAAW,2BAA2B;IAC1C,QAAQ,EAAE,IAAI,CAAC;IACf,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,kEAAkE;AAClE,MAAM,WAAW,2BAA2B;IAC1C,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,MAAM,WAAW,6BACf,SAAQ,0BAA0B;IAClC,0DAA0D;IAC1D,WAAW,EAAE,CACX,KAAK,EAAE,qBAAqB,KACzB;QAAE,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,GAAG,IAAI,GAAG,SAAS,CAAC;IACtE,iDAAiD;IACjD,eAAe,EAAE,CAAC,KAAK,EAAE,qBAAqB,KAAK,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IAC7E,oEAAoE;IACpE,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,wBAAwB;IACvC,IAAI,EAAE,CAAC,KAAK,EAAE,qBAAqB,KAAK,OAAO,CAAC,qBAAqB,CAAC,CAAC;IACvE,OAAO,EAAE,CACP,KAAK,EAAE,qBAAqB,KACzB,OAAO,CACR,2BAA2B,GAC3B;QAAE,IAAI,EAAE,SAAS,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,2BAA2B,CAAA;KAAE,CACzE,CAAC;CACH;AAED,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,6BAA6B,GACrC,wBAAwB,CAuF1B;AAuBD,OAAO,EACL,iBAAiB,EACjB,0BAA0B,EAC1B,mBAAmB,EACnB,KAAK,0BAA0B,GAChC,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/sveltekit/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AASH,OAAO,yBAAyB,CAAC;AAGjC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AACjE,OAAO,KAAK,EACV,0BAA0B,EAC1B,mBAAmB,EACpB,MAAM,kCAAkC,CAAC;AAC1C,OAAO,EAEL,KAAK,iBAAiB,EACvB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAKL,KAAK,eAAe,EAGpB,KAAK,6BAA6B,EAClC,KAAK,eAAe,EAGrB,MAAM,iCAAiC,CAAC;AAGzC,OAAO,EAEL,iBAAiB,EACjB,0BAA0B,EAC1B,mBAAmB,EACnB,KAAK,0BAA0B,EAChC,MAAM,oCAAoC,CAAC;AAE5C,OAAO,EACL,KAAK,iBAAiB,EACtB,KAAK,iBAAiB,EACtB,KAAK,mBAAmB,EACxB,6BAA6B,EAC7B,kCAAkC,EAClC,KAAK,mBAAmB,EACxB,KAAK,0BAA0B,EAC/B,gCAAgC,EAChC,KAAK,4BAA4B,EACjC,KAAK,gBAAgB,EACrB,yBAAyB,EACzB,KAAK,SAAS,EACd,wBAAwB,EACxB,sBAAsB,EACtB,uBAAuB,EACvB,0CAA0C,EAC1C,iCAAiC,EACjC,kCAAkC,EAClC,4BAA4B,EAC5B,oCAAoC,GACrC,MAAM,oBAAoB,CAAC;AAC5B,YAAY,EACV,oBAAoB,EACpB,6BAA6B,EAC7B,0BAA0B,EAC1B,iCAAiC,EACjC,mBAAmB,EACnB,0BAA0B,GAC3B,MAAM,kCAAkC,CAAC;AAC1C,OAAO,EACL,eAAe,EACf,KAAK,mBAAmB,EACxB,iBAAiB,EACjB,KAAK,wBAAwB,EAC7B,KAAK,sBAAsB,EAC3B,KAAK,kBAAkB,EACvB,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,EACtB,KAAK,kBAAkB,EACvB,KAAK,mBAAmB,EACxB,qBAAqB,EACrB,yBAAyB,GAC1B,MAAM,kCAAkC,CAAC;AAC1C,OAAO,EACL,8BAA8B,EAC9B,KAAK,wBAAwB,GAC9B,MAAM,iCAAiC,CAAC;AACzC,OAAO,EACL,KAAK,+BAA+B,EACpC,wBAAwB,EACxB,KAAK,kBAAkB,EACvB,KAAK,kBAAkB,EACvB,KAAK,oBAAoB,EACzB,2BAA2B,GAC5B,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EACL,KAAK,uCAAuC,EAC5C,gCAAgC,EAChC,KAAK,0BAA0B,EAC/B,KAAK,oBAAoB,GAC1B,MAAM,wBAAwB,CAAC;AAChC,OAAO,EACL,KAAK,WAAW,EAChB,KAAK,iBAAiB,EACtB,KAAK,WAAW,EAChB,KAAK,oBAAoB,EACzB,KAAK,YAAY,EACjB,KAAK,gCAAgC,EACrC,yBAAyB,EACzB,kBAAkB,EAClB,KAAK,eAAe,EACpB,KAAK,wBAAwB,GAC9B,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAAE,oBAAoB,EAAE,KAAK,aAAa,EAAE,MAAM,YAAY,CAAC;AAItE;;GAEG;AACH,MAAM,WAAW,qBAAsB,SAAQ,gBAAgB;IAC7D,mCAAmC;IACnC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,+CAA+C;IAC/C,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,0DAA0D;IAC1D,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB,uEAAuE;IACvE,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;;OAIG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,iCAAiC;IACjC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,+DAA+D;IAC/D,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,iDAAiD;IACjD,cAAc,CAAC,EAAE,QAAQ,GAAG,KAAK,GAAG,MAAM,CAAC;IAC3C,4EAA4E;IAC5E,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,sEAAsE;IACtE,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED;;GAEG;AACH,KAAK,WAAW,GAAG;IACjB,KAAK,EAAE;QACL,OAAO,EAAE;YACP,GAAG,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,CAAC;YAC1C,GAAG,EAAE,CACH,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,EACb,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAC9B,IAAI,CAAC;YACV,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;SACnE,CAAC;QACF,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAChC,GAAG,EAAE;YAAE,QAAQ,EAAE,MAAM,CAAC;YAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;SAAE,CAAC;QAC7C,OAAO,EAAE;YAAE,OAAO,EAAE,OAAO,CAAA;SAAE,CAAC;KAC/B,CAAC;IACF,OAAO,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;CAChD,CAAC;AAEF,KAAK,MAAM,GAAG,CAAC,KAAK,EAAE,WAAW,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;AAExD,KAAK,qBAAqB,GAAG;IAC3B,OAAO,EAAE,WAAW,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,CAAC;IACzC,gBAAgB,CAAC,EAAE,MAAM,MAAM,CAAC;IAChC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;IAC5C,OAAO,EAAE,OAAO,CAAC;IACjB,GAAG,EAAE,GAAG,CAAC;CACV,CAAC;AAEF,KAAK,oBAAoB,GACrB,MAAM,GACN,CAAC,CAAC,KAAK,EAAE,qBAAqB,KAAK,MAAM,GAAG,SAAS,CAAC,CAAC;AAE3D,KAAK,kBAAkB,CAAC,CAAC,IACrB,CAAC,GACD,CAAC,CAAC,MAAM,EAAE,eAAe,EAAE,KAAK,EAAE,qBAAqB,KAAK,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;AAEhF,MAAM,WAAW,oBACf,SAAQ,gBAAgB,EACtB,6BAA6B;IAC/B,4DAA4D;IAC5D,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;IACrB,0CAA0C;IAC1C,cAAc,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACjC,uEAAuE;IACvE,QAAQ,CAAC,EAAE,oBAAoB,CAAC;IAChC,+DAA+D;IAC/D,YAAY,CAAC,EAAE,MAAM,GAAG,CAAC,CAAC,YAAY,EAAE,MAAM,KAAK,MAAM,CAAC,CAAC;IAC3D;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,GAAG,CAAC,CAAC,YAAY,EAAE,MAAM,KAAK,MAAM,CAAC,CAAC;IACxD,6DAA6D;IAC7D,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,wDAAwD;IACxD,uBAAuB,CAAC,EAAE,MAAM,CAAC;IACjC,wEAAwE;IACxE,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,sDAAsD;IACtD,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,6DAA6D;IAC7D,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAClC,gEAAgE;IAChE,yBAAyB,CAAC,EAAE,QAAQ,GAAG,KAAK,GAAG,MAAM,CAAC;IACtD,8EAA8E;IAC9E,uBAAuB,CAAC,EAAE,MAAM,CAAC;IACjC,4CAA4C;IAC5C,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,0CAA0C;IAC1C,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,qEAAqE;IACrE,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,6CAA6C;IAC7C,qBAAqB,CAAC,EAAE,QAAQ,GAAG,KAAK,GAAG,MAAM,CAAC;IAClD,uEAAuE;IACvE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,8CAA8C;IAC9C,QAAQ,CAAC,EAAE,kBAAkB,CAAC,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC,CAAC;IACzD;;;;OAIG;IACH,cAAc,CAAC,EAAE,mBAAmB,CAAC;IACrC;;;;OAIG;IACH,qBAAqB,CAAC,EAAE,0BAA0B,CAAC;IACnD,iDAAiD;IACjD,eAAe,CAAC,EAAE,kBAAkB,CAAC,MAAM,CAAC,CAAC;IAC7C,8EAA8E;IAC9E,eAAe,CAAC,EACZ,MAAM,GACN,CAAC,CAAC,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,qBAAqB,KAAK,MAAM,CAAC,CAAC;CAChE;AAED,8DAA8D;AAC9D,MAAM,WAAW,sBAAsB;IACrC,YAAY,EAAE,MAAM,CAAC;IACrB,mEAAmE;IACnE,WAAW,EAAE,MAAM,CAAC;IACpB;;;;OAIG;IACH,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,oBAAoB;IACnC,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,eAAe,CAAC;IAC7B,GAAG,EAAE,GAAG,CAAC;CACV;AAED,MAAM,WAAW,uBAAwB,SAAQ,eAAe;IAC9D,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,qBAAqB,GAAG,MAAM,CA4E3E;AAED;;GAEG;AACH,MAAM,WAAW,0BAA0B;IACzC,+CAA+C;IAC/C,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,wBAAwB;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,wBAAwB;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,0BAA0B;IAC1B,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B;;;;OAIG;IACH,UAAU,CAAC,EAAE,iBAAiB,GAAG,IAAI,CAAC;IACtC,oDAAoD;IACpD,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACjC;AA0BD;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAsB,mBAAmB,CACvC,KAAK,EAAE,WAAW,CAAC,OAAO,CAAC,EAC3B,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,GAAG,SAAS,EAC5B,OAAO,EAAE,gBAAgB,GACvB,0BAA0B,GAAG;IAC3B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,cAAc,CAAC,EAAE,QAAQ,GAAG,KAAK,GAAG,MAAM,CAAC;CAC5C,GACF,OAAO,CAAC,MAAM,CAAC,CA6BjB;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAsB,oBAAoB,CACxC,KAAK,EAAE,WAAW,CAAC,OAAO,CAAC,EAC3B,OAAO,EAAE,gBAAgB,GAAG;IAC1B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,GAAG,CAAC,EAAE,MAAM,CAAC;CACd,GACA,OAAO,CAAC,IAAI,CAAC,CAsBf;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,wBAAsB,mBAAmB,CACvC,KAAK,EAAE,WAAW,CAAC,OAAO,CAAC,EAC3B,QAAQ,EAAE,MAAM,GAAG,IAAI,EACvB,OAAO,EAAE,gBAAgB,GAAG;IAC1B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,cAAc,CAAC,EAAE,QAAQ,GAAG,KAAK,GAAG,MAAM,CAAC;IAC3C,GAAG,CAAC,EAAE,MAAM,CAAC;CACd,GACA,OAAO,CAAC,OAAO,CAAC,CA0ClB;AA4QD;;;;;GAKG;AACH,wBAAsB,cAAc,CAClC,KAAK,EAAE,qBAAqB,EAC5B,OAAO,EAAE,oBAAoB,GAC5B,OAAO,CAAC,oBAAoB,CAAC,CAyB/B;AAED;;;GAGG;AACH,wBAAsB,iBAAiB,CACrC,KAAK,EAAE,qBAAqB,EAC5B,OAAO,EAAE,oBAAoB,GAC5B,OAAO,CAAC,uBAAuB,CAAC,CA2DlC;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,yBAAyB,CACvC,MAAM,EAAE,MAAM,GAAG,GAAG,EACpB,OAAO,GAAE,IAAI,CAAC,oBAAoB,EAAE,UAAU,CAAC,GAAG;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAO,GAC3E,sBAAsB,CAiBxB;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,oBAAoB,IACpD,OAAO,qBAAqB,KAAG,OAAO,CAAC,QAAQ,CAAC,CAI/D;AAED;;GAEG;AACH,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,oBAAoB,IACvD,OAAO,qBAAqB,KAAG,OAAO,CAAC,QAAQ,CAAC,CAW/D;AAoCD;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,aAAa,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,GAAG,IAAI,CAG5E;AAED,mDAAmD;AACnD,MAAM,WAAW,qCACf,SAAQ,0BAA0B;IAClC;;;;OAIG;IACH,kBAAkB,CAAC,EAAE,MAAM,GAAG,CAAC,CAAC,KAAK,EAAE,qBAAqB,KAAK,MAAM,CAAC,CAAC;CAC1E;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,8BAA8B,CAC5C,OAAO,EAAE,qCAAqC,IAEhC,OAAO,qBAAqB,KAAG,OAAO,CAAC,QAAQ,CAAC,CAU/D;AAED;;;;GAIG;AACH,wBAAgB,8BAA8B,CAC5C,OAAO,EAAE,0BAA0B,IAErB,OAAO,qBAAqB,KAAG,OAAO,CAAC,QAAQ,CAAC,CAe/D;AAED;;;;GAIG;AACH,wBAAgB,gCAAgC,CAC9C,OAAO,EAAE,0BAA0B,IAErB,OAAO,qBAAqB,KAAG,OAAO,CAAC,QAAQ,CAAC,CAY/D;AAED;;;;GAIG;AACH,wBAAsB,wBAAwB,CAC5C,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,0BAA0B,wDAIpC;AAED,qDAAqD;AACrD,MAAM,WAAW,qBAAqB;IACpC,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;CAC9B;AAED,uDAAuD;AACvD,MAAM,WAAW,2BAA2B;IAC1C,QAAQ,EAAE,IAAI,CAAC;IACf,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,kEAAkE;AAClE,MAAM,WAAW,2BAA2B;IAC1C,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,MAAM,WAAW,6BACf,SAAQ,0BAA0B;IAClC,0DAA0D;IAC1D,WAAW,EAAE,CACX,KAAK,EAAE,qBAAqB,KACzB;QAAE,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,GAAG,IAAI,GAAG,SAAS,CAAC;IACtE,iDAAiD;IACjD,eAAe,EAAE,CAAC,KAAK,EAAE,qBAAqB,KAAK,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IAC7E,oEAAoE;IACpE,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,wBAAwB;IACvC,IAAI,EAAE,CAAC,KAAK,EAAE,qBAAqB,KAAK,OAAO,CAAC,qBAAqB,CAAC,CAAC;IACvE,OAAO,EAAE,CACP,KAAK,EAAE,qBAAqB,KACzB,OAAO,CACR,2BAA2B,GAC3B;QAAE,IAAI,EAAE,SAAS,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,2BAA2B,CAAA;KAAE,CACzE,CAAC;CACH;AAED,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,6BAA6B,GACrC,wBAAwB,CAuF1B;AAuBD,OAAO,EACL,iBAAiB,EACjB,0BAA0B,EAC1B,mBAAmB,EACnB,KAAK,0BAA0B,GAChC,CAAC"}
@@ -0,0 +1,91 @@
1
+ /**
2
+ * SvelteKit glue for {@link PasswordCredentialService} (#3274): browser
3
+ * email + password sign-in that sets the same session cookie
4
+ * `createSessionHandler` reads, and password management for the signed-in
5
+ * person and administrators.
6
+ *
7
+ * ```ts
8
+ * // src/lib/server/password-auth.ts
9
+ * import { createPasswordCredentialHandlers } from '@happyvertical/smrt-users/sveltekit';
10
+ *
11
+ * export const passwordAuth = createPasswordCredentialHandlers({
12
+ * db: { type: 'postgres', url: DATABASE_URL },
13
+ * tenantId: () => SHOP_TENANT_ID, // or (event) => …; omit for tenantless
14
+ * cookieName: 'sid', // must match createSessionHandler
15
+ * });
16
+ *
17
+ * // routes/auth/password/+server.ts → export const POST = passwordAuth.signIn;
18
+ * // routes/account/password/+server.ts → export const PUT = passwordAuth.changePassword;
19
+ * // export const POST = passwordAuth.setPassword;
20
+ * // export const DELETE = passwordAuth.clearPassword;
21
+ * // routes/admin/password-reset/+server.ts → export const POST = passwordAuth.resetPassword;
22
+ * ```
23
+ *
24
+ * Wire contract:
25
+ *
26
+ * - `signIn`: JSON or form body `{ email, password }` (`identifier` is accepted
27
+ * for `email`) → 200 `{ authenticated: true, userId, tenantId, expiresAt,
28
+ * mustChange }` and an httpOnly session cookie; any cookie session the
29
+ * browser held before is revoked. 401 `{ error, code: 'invalid_credentials' }`
30
+ * for every refusal that is not a rate limit (missing field, unknown email,
31
+ * no password, wrong password, inactive user, no membership); 429 +
32
+ * `Retry-After` `{ code: 'rate_limited' }` when the budget is exhausted. The
33
+ * session id is never in the body.
34
+ * - `setPassword` (`{ userId?, password }`), `changePassword`
35
+ * (`{ currentPassword, newPassword }`), `resetPassword`
36
+ * (`{ userId, password, mustChange? }`), `clearPassword`
37
+ * (`{ userId?, currentPassword? }`): act as the session the host's hook put
38
+ * in `event.locals` (which must include `authMethod` — `createSessionHandler`
39
+ * does). 200 `{ revokedSessions }` (`changePassword` adds
40
+ * `signedOut: true` and clears the cookie when it ended the current
41
+ * must-change session); 400 `password_policy` with a displayable message;
42
+ * 401 `invalid_credentials` for a wrong current password; 401
43
+ * `unauthenticated` without a session; 403 `forbidden`; 429 when the
44
+ * current-password check is rate limited.
45
+ *
46
+ * Sign out with `destroySessionCookie`.
47
+ *
48
+ * @packageDocumentation
49
+ */
50
+ import '../__smrt-register__.js';
51
+ import { PasswordCredentialService, type PasswordCredentialServiceOptions } from '../services/PasswordCredentialService.js';
52
+ type Cookies = {
53
+ get: (name: string) => string | undefined;
54
+ set: (name: string, value: string, options?: Record<string, unknown>) => void;
55
+ delete: (name: string, options?: Record<string, unknown>) => void;
56
+ };
57
+ /** The parts of a SvelteKit `RequestEvent` these handlers use. */
58
+ export type PasswordRequestEvent = {
59
+ cookies: Cookies;
60
+ getClientAddress?: () => string;
61
+ locals?: Record<string, unknown>;
62
+ request: Request;
63
+ url: URL;
64
+ };
65
+ export interface CreatePasswordCredentialHandlersOptions extends PasswordCredentialServiceOptions {
66
+ /**
67
+ * Tenant a sign-in enters; the person must hold an active membership in
68
+ * it. A value or a per-request resolver. Null/omitted signs in with no
69
+ * tenant context.
70
+ */
71
+ tenantId?: string | null | ((event: PasswordRequestEvent) => string | null | undefined | Promise<string | null | undefined>);
72
+ /** Session cookie name; must match `createSessionHandler`. Default `sid`. */
73
+ cookieName?: string;
74
+ cookiePath?: string;
75
+ cookieDomain?: string;
76
+ /** Default: secure when the request is https. */
77
+ cookieSecure?: boolean;
78
+ cookieSameSite?: 'strict' | 'lax' | 'none';
79
+ }
80
+ export interface PasswordCredentialHandlers {
81
+ signIn: (event: PasswordRequestEvent) => Promise<Response>;
82
+ setPassword: (event: PasswordRequestEvent) => Promise<Response>;
83
+ changePassword: (event: PasswordRequestEvent) => Promise<Response>;
84
+ resetPassword: (event: PasswordRequestEvent) => Promise<Response>;
85
+ clearPassword: (event: PasswordRequestEvent) => Promise<Response>;
86
+ /** The lazily created service, for form actions and admin screens. */
87
+ service: () => Promise<PasswordCredentialService>;
88
+ }
89
+ export declare function createPasswordCredentialHandlers(options: CreatePasswordCredentialHandlersOptions): PasswordCredentialHandlers;
90
+ export {};
91
+ //# sourceMappingURL=password-handlers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"password-handlers.d.ts","sourceRoot":"","sources":["../../src/sveltekit/password-handlers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgDG;AAGH,OAAO,yBAAyB,CAAC;AAIjC,OAAO,EAGL,yBAAyB,EACzB,KAAK,gCAAgC,EAEtC,MAAM,0CAA0C,CAAC;AAKlD,KAAK,OAAO,GAAG;IACb,GAAG,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,CAAC;IAC1C,GAAG,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;IAC9E,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;CACnE,CAAC;AAEF,kEAAkE;AAClE,MAAM,MAAM,oBAAoB,GAAG;IACjC,OAAO,EAAE,OAAO,CAAC;IACjB,gBAAgB,CAAC,EAAE,MAAM,MAAM,CAAC;IAChC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,OAAO,EAAE,OAAO,CAAC;IACjB,GAAG,EAAE,GAAG,CAAC;CACV,CAAC;AAEF,MAAM,WAAW,uCACf,SAAQ,gCAAgC;IACxC;;;;OAIG;IACH,QAAQ,CAAC,EACL,MAAM,GACN,IAAI,GACJ,CAAC,CACC,KAAK,EAAE,oBAAoB,KACxB,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC,CAAC,CAAC;IACzE,6EAA6E;IAC7E,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,iDAAiD;IACjD,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,cAAc,CAAC,EAAE,QAAQ,GAAG,KAAK,GAAG,MAAM,CAAC;CAC5C;AAED,MAAM,WAAW,0BAA0B;IACzC,MAAM,EAAE,CAAC,KAAK,EAAE,oBAAoB,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;IAC3D,WAAW,EAAE,CAAC,KAAK,EAAE,oBAAoB,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;IAChE,cAAc,EAAE,CAAC,KAAK,EAAE,oBAAoB,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;IACnE,aAAa,EAAE,CAAC,KAAK,EAAE,oBAAoB,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;IAClE,aAAa,EAAE,CAAC,KAAK,EAAE,oBAAoB,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;IAClE,sEAAsE;IACtE,OAAO,EAAE,MAAM,OAAO,CAAC,yBAAyB,CAAC,CAAC;CACnD;AAuHD,wBAAgB,gCAAgC,CAC9C,OAAO,EAAE,uCAAuC,GAC/C,0BAA0B,CAyI5B"}