@happyvertical/smrt-users 0.30.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (150) hide show
  1. package/AGENTS.md +85 -0
  2. package/CLAUDE.md +1 -0
  3. package/LICENSE +7 -0
  4. package/README.md +459 -0
  5. package/dist/__smrt-register__.d.ts +2 -0
  6. package/dist/__smrt-register__.d.ts.map +1 -0
  7. package/dist/chunks/TerminalAuthService-DoAMQ_yn.js +5118 -0
  8. package/dist/chunks/TerminalAuthService-DoAMQ_yn.js.map +1 -0
  9. package/dist/chunks/index-DkoYIvIu.js +169 -0
  10. package/dist/chunks/index-DkoYIvIu.js.map +1 -0
  11. package/dist/collections/CliAuthRequestCollection.d.ts +19 -0
  12. package/dist/collections/CliAuthRequestCollection.d.ts.map +1 -0
  13. package/dist/collections/GroupCollection.d.ts +17 -0
  14. package/dist/collections/GroupCollection.d.ts.map +1 -0
  15. package/dist/collections/GroupMemberCollection.d.ts +43 -0
  16. package/dist/collections/GroupMemberCollection.d.ts.map +1 -0
  17. package/dist/collections/GroupRoleCollection.d.ts +33 -0
  18. package/dist/collections/GroupRoleCollection.d.ts.map +1 -0
  19. package/dist/collections/MagicLinkTokenCollection.d.ts +26 -0
  20. package/dist/collections/MagicLinkTokenCollection.d.ts.map +1 -0
  21. package/dist/collections/MembershipCollection.d.ts +38 -0
  22. package/dist/collections/MembershipCollection.d.ts.map +1 -0
  23. package/dist/collections/MembershipOverrideCollection.d.ts +55 -0
  24. package/dist/collections/MembershipOverrideCollection.d.ts.map +1 -0
  25. package/dist/collections/PermissionCollection.d.ts +34 -0
  26. package/dist/collections/PermissionCollection.d.ts.map +1 -0
  27. package/dist/collections/RoleCollection.d.ts +29 -0
  28. package/dist/collections/RoleCollection.d.ts.map +1 -0
  29. package/dist/collections/RolePermissionCollection.d.ts +33 -0
  30. package/dist/collections/RolePermissionCollection.d.ts.map +1 -0
  31. package/dist/collections/SessionCollection.d.ts +82 -0
  32. package/dist/collections/SessionCollection.d.ts.map +1 -0
  33. package/dist/collections/TenantCollection.d.ts +119 -0
  34. package/dist/collections/TenantCollection.d.ts.map +1 -0
  35. package/dist/collections/TenantPermissionOverrideCollection.d.ts +111 -0
  36. package/dist/collections/TenantPermissionOverrideCollection.d.ts.map +1 -0
  37. package/dist/collections/UserCollection.d.ts +116 -0
  38. package/dist/collections/UserCollection.d.ts.map +1 -0
  39. package/dist/collections/index.d.ts +19 -0
  40. package/dist/collections/index.d.ts.map +1 -0
  41. package/dist/index.d.ts +5 -0
  42. package/dist/index.d.ts.map +1 -0
  43. package/dist/index.js +1482 -0
  44. package/dist/index.js.map +1 -0
  45. package/dist/manifest.json +5216 -0
  46. package/dist/models/CliAuthRequest.d.ts +25 -0
  47. package/dist/models/CliAuthRequest.d.ts.map +1 -0
  48. package/dist/models/Group.d.ts +34 -0
  49. package/dist/models/Group.d.ts.map +1 -0
  50. package/dist/models/GroupMember.d.ts +29 -0
  51. package/dist/models/GroupMember.d.ts.map +1 -0
  52. package/dist/models/GroupRole.d.ts +29 -0
  53. package/dist/models/GroupRole.d.ts.map +1 -0
  54. package/dist/models/MagicLinkToken.d.ts +22 -0
  55. package/dist/models/MagicLinkToken.d.ts.map +1 -0
  56. package/dist/models/Membership.d.ts +48 -0
  57. package/dist/models/Membership.d.ts.map +1 -0
  58. package/dist/models/MembershipOverride.d.ts +50 -0
  59. package/dist/models/MembershipOverride.d.ts.map +1 -0
  60. package/dist/models/Permission.d.ts +79 -0
  61. package/dist/models/Permission.d.ts.map +1 -0
  62. package/dist/models/Role.d.ts +67 -0
  63. package/dist/models/Role.d.ts.map +1 -0
  64. package/dist/models/RolePermission.d.ts +29 -0
  65. package/dist/models/RolePermission.d.ts.map +1 -0
  66. package/dist/models/Session.d.ts +105 -0
  67. package/dist/models/Session.d.ts.map +1 -0
  68. package/dist/models/Tenant.d.ts +138 -0
  69. package/dist/models/Tenant.d.ts.map +1 -0
  70. package/dist/models/TenantPermissionOverride.d.ts +74 -0
  71. package/dist/models/TenantPermissionOverride.d.ts.map +1 -0
  72. package/dist/models/User.d.ts +72 -0
  73. package/dist/models/User.d.ts.map +1 -0
  74. package/dist/models/index.d.ts +19 -0
  75. package/dist/models/index.d.ts.map +1 -0
  76. package/dist/playground.d.ts +2 -0
  77. package/dist/playground.d.ts.map +1 -0
  78. package/dist/playground.js +139 -0
  79. package/dist/playground.js.map +1 -0
  80. package/dist/services/MagicLinkService.d.ts +84 -0
  81. package/dist/services/MagicLinkService.d.ts.map +1 -0
  82. package/dist/services/OidcLoginService.d.ts +134 -0
  83. package/dist/services/OidcLoginService.d.ts.map +1 -0
  84. package/dist/services/PermissionCatalogService.d.ts +62 -0
  85. package/dist/services/PermissionCatalogService.d.ts.map +1 -0
  86. package/dist/services/PermissionResolver.d.ts +150 -0
  87. package/dist/services/PermissionResolver.d.ts.map +1 -0
  88. package/dist/services/PostgresPermissionPolicies.d.ts +29 -0
  89. package/dist/services/PostgresPermissionPolicies.d.ts.map +1 -0
  90. package/dist/services/SessionPermissionContext.d.ts +43 -0
  91. package/dist/services/SessionPermissionContext.d.ts.map +1 -0
  92. package/dist/services/SessionService.d.ts +139 -0
  93. package/dist/services/SessionService.d.ts.map +1 -0
  94. package/dist/services/TenantService.d.ts +135 -0
  95. package/dist/services/TenantService.d.ts.map +1 -0
  96. package/dist/services/TerminalAuthService.d.ts +189 -0
  97. package/dist/services/TerminalAuthService.d.ts.map +1 -0
  98. package/dist/services/index.d.ts +14 -0
  99. package/dist/services/index.d.ts.map +1 -0
  100. package/dist/smrt-knowledge.json +2744 -0
  101. package/dist/svelte/components/InviteUserModal.svelte +351 -0
  102. package/dist/svelte/components/InviteUserModal.svelte.d.ts +17 -0
  103. package/dist/svelte/components/InviteUserModal.svelte.d.ts.map +1 -0
  104. package/dist/svelte/components/UserAvatar.svelte +105 -0
  105. package/dist/svelte/components/UserAvatar.svelte.d.ts +10 -0
  106. package/dist/svelte/components/UserAvatar.svelte.d.ts.map +1 -0
  107. package/dist/svelte/components/UserCard.svelte +179 -0
  108. package/dist/svelte/components/UserCard.svelte.d.ts +18 -0
  109. package/dist/svelte/components/UserCard.svelte.d.ts.map +1 -0
  110. package/dist/svelte/components/UserForm.svelte +194 -0
  111. package/dist/svelte/components/UserForm.svelte.d.ts +18 -0
  112. package/dist/svelte/components/UserForm.svelte.d.ts.map +1 -0
  113. package/dist/svelte/components/UserList.svelte +107 -0
  114. package/dist/svelte/components/UserList.svelte.d.ts +20 -0
  115. package/dist/svelte/components/UserList.svelte.d.ts.map +1 -0
  116. package/dist/svelte/components/UserMenu.svelte +326 -0
  117. package/dist/svelte/components/UserMenu.svelte.d.ts +33 -0
  118. package/dist/svelte/components/UserMenu.svelte.d.ts.map +1 -0
  119. package/dist/svelte/components/__tests__/InviteUserModal.test.js +54 -0
  120. package/dist/svelte/components/__tests__/UserAvatar.test.js +31 -0
  121. package/dist/svelte/components/__tests__/UserCard.test.js +39 -0
  122. package/dist/svelte/components/__tests__/UserForm.test.js +50 -0
  123. package/dist/svelte/components/__tests__/UserList.test.js +48 -0
  124. package/dist/svelte/components/__tests__/UserMenu.test.js +38 -0
  125. package/dist/svelte/i18n.d.ts +15 -0
  126. package/dist/svelte/i18n.d.ts.map +1 -0
  127. package/dist/svelte/i18n.js +15 -0
  128. package/dist/svelte/index.d.ts +23 -0
  129. package/dist/svelte/index.d.ts.map +1 -0
  130. package/dist/svelte/index.js +27 -0
  131. package/dist/svelte/playground.d.ts +151 -0
  132. package/dist/svelte/playground.d.ts.map +1 -0
  133. package/dist/svelte/playground.js +134 -0
  134. package/dist/sveltekit/index.d.ts +379 -0
  135. package/dist/sveltekit/index.d.ts.map +1 -0
  136. package/dist/sveltekit/resource-list-handler.d.ts +127 -0
  137. package/dist/sveltekit/resource-list-handler.d.ts.map +1 -0
  138. package/dist/sveltekit/types.d.ts +31 -0
  139. package/dist/sveltekit/types.d.ts.map +1 -0
  140. package/dist/sveltekit.d.ts +2 -0
  141. package/dist/sveltekit.d.ts.map +1 -0
  142. package/dist/sveltekit.js +978 -0
  143. package/dist/sveltekit.js.map +1 -0
  144. package/dist/types/index.d.ts +61 -0
  145. package/dist/types/index.d.ts.map +1 -0
  146. package/dist/ui.d.ts +10 -0
  147. package/dist/ui.d.ts.map +1 -0
  148. package/dist/ui.js +75 -0
  149. package/dist/ui.js.map +1 -0
  150. package/package.json +97 -0
@@ -0,0 +1,138 @@
1
+ import { SmrtObject } from '@happyvertical/smrt-core';
2
+ import { Tenant as TenantContract } from '@happyvertical/smrt-types';
3
+ import { TenantStatus } from '../types/index.js';
4
+ /**
5
+ * Maximum allowed depth for tenant hierarchy.
6
+ * Prevents excessively deep trees that could cause performance issues.
7
+ */
8
+ export declare const MAX_TENANT_HIERARCHY_DEPTH = 10;
9
+ /**
10
+ * Tenant represents an organizational boundary in the multi-tenant system.
11
+ *
12
+ * Supports hierarchical organization with parent-child relationships.
13
+ * Users can belong to multiple tenants through Memberships.
14
+ * Each tenant can have custom roles in addition to system defaults.
15
+ *
16
+ * ## Hierarchical Tenants
17
+ *
18
+ * Tenants can be organized in a tree structure where child tenants
19
+ * can optionally inherit permissions from their parent tenants.
20
+ *
21
+ * ### Cascade Control
22
+ *
23
+ * Two flags control permission inheritance:
24
+ * - `cascadePermissions`: If true, this tenant pushes its permissions to children
25
+ * - `inheritPermissions`: If true, this tenant accepts permissions from parent
26
+ *
27
+ * Both must be true for inheritance to flow from parent to child.
28
+ *
29
+ * @example
30
+ * ```typescript
31
+ * // Create root tenant
32
+ * const corp = await tenants.create({
33
+ * name: 'Acme Corporation',
34
+ * slug: 'acme-corp',
35
+ * cascadePermissions: true, // Push permissions to children
36
+ * });
37
+ * await corp.save();
38
+ *
39
+ * // Create child tenant that inherits
40
+ * const division = await tenants.create({
41
+ * name: 'Acme West Division',
42
+ * slug: 'acme-west',
43
+ * parentTenantId: corp.id,
44
+ * inheritPermissions: true, // Accept parent permissions
45
+ * });
46
+ * await division.save();
47
+ *
48
+ * // Create independent child (breaks inheritance chain)
49
+ * const independent = await tenants.create({
50
+ * name: 'Acme Labs',
51
+ * slug: 'acme-labs',
52
+ * parentTenantId: corp.id,
53
+ * inheritPermissions: false, // Does NOT inherit from parent
54
+ * });
55
+ * await independent.save();
56
+ * ```
57
+ */
58
+ export declare class Tenant extends SmrtObject implements TenantContract {
59
+ /**
60
+ * Display name for the tenant
61
+ */
62
+ name: string;
63
+ /**
64
+ * Tenant status
65
+ */
66
+ status: TenantStatus;
67
+ /**
68
+ * Optional description
69
+ */
70
+ description: string;
71
+ /**
72
+ * Parent tenant ID for hierarchical organization.
73
+ * Null for root-level tenants.
74
+ */
75
+ parentTenantId?: string | null;
76
+ /**
77
+ * Depth in the hierarchy tree (0 = root, 1 = first level child, etc.)
78
+ * Automatically managed by TenantCollection methods.
79
+ */
80
+ hierarchyLevel: number;
81
+ /**
82
+ * Materialized path for efficient tree traversal.
83
+ * Format: "ancestor-id/parent-id" (path to parent; does not include this tenant's id)
84
+ * Empty string for root tenants.
85
+ * Automatically managed by TenantCollection methods.
86
+ */
87
+ hierarchyPath: string;
88
+ /**
89
+ * If true, this tenant's permissions cascade DOWN to child tenants.
90
+ * Children can still opt-out by setting inheritPermissions: false.
91
+ * Default: true
92
+ */
93
+ cascadePermissions: boolean;
94
+ /**
95
+ * If true, this tenant ACCEPTS permissions from its parent tenant.
96
+ * Parent must also have cascadePermissions: true for inheritance to work.
97
+ * Default: true
98
+ */
99
+ inheritPermissions: boolean;
100
+ constructor(options?: any);
101
+ /**
102
+ * Check if tenant is active
103
+ */
104
+ isActive(): boolean;
105
+ /**
106
+ * Check if tenant is suspended
107
+ */
108
+ isSuspended(): boolean;
109
+ /**
110
+ * Check if this is a root-level tenant (no parent)
111
+ */
112
+ isRoot(): boolean;
113
+ /**
114
+ * Check if this tenant is configured to cascade permissions to children.
115
+ *
116
+ * Note: This does NOT indicate whether any child tenants actually exist.
117
+ * Use TenantCollection.findChildren() for accurate child lookup.
118
+ */
119
+ canCascadeToChildren(): boolean;
120
+ /**
121
+ * Check if permission inheritance is active for this tenant.
122
+ * Inheritance is active if:
123
+ * - This tenant has a parent AND
124
+ * - This tenant has inheritPermissions: true
125
+ *
126
+ * Note: The parent must also have cascadePermissions: true
127
+ * for actual inheritance to occur. Use PermissionResolver
128
+ * for accurate permission calculation.
129
+ */
130
+ acceptsInheritance(): boolean;
131
+ /**
132
+ * Get ancestor IDs from the hierarchy path.
133
+ * Returns an array of tenant IDs from root to immediate parent.
134
+ * Empty array for root tenants.
135
+ */
136
+ getAncestorIds(): string[];
137
+ }
138
+ //# sourceMappingURL=Tenant.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Tenant.d.ts","sourceRoot":"","sources":["../../src/models/Tenant.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAqB,UAAU,EAAQ,MAAM,0BAA0B,CAAC;AAC/E,OAAO,KAAK,EAAE,MAAM,IAAI,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAC1E,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEjD;;;GAGG;AACH,eAAO,MAAM,0BAA0B,KAAK,CAAC;AAE7C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgDG;AACH,qBASa,MAAO,SAAQ,UAAW,YAAW,cAAc;IAC9D;;OAEG;IACH,IAAI,EAAE,MAAM,CAAM;IAElB;;OAEG;IAEH,MAAM,EAAE,YAAY,CAAuB;IAE3C;;OAEG;IACH,WAAW,EAAE,MAAM,CAAM;IAIzB;;;OAGG;IAEH,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAE/B;;;OAGG;IACH,cAAc,EAAE,MAAM,CAAK;IAE3B;;;;;OAKG;IACH,aAAa,EAAE,MAAM,CAAM;IAI3B;;;;OAIG;IACH,kBAAkB,EAAE,OAAO,CAAQ;IAEnC;;;;OAIG;IACH,kBAAkB,EAAE,OAAO,CAAQ;gBAEvB,OAAO,GAAE,GAAQ;IAkB7B;;OAEG;IACH,QAAQ,IAAI,OAAO;IAInB;;OAEG;IACH,WAAW,IAAI,OAAO;IAItB;;OAEG;IACH,MAAM,IAAI,OAAO;IAIjB;;;;;OAKG;IACH,oBAAoB,IAAI,OAAO;IAI/B;;;;;;;;;OASG;IACH,kBAAkB,IAAI,OAAO;IAI7B;;;;OAIG;IACH,cAAc,IAAI,MAAM,EAAE;CAI3B"}
@@ -0,0 +1,74 @@
1
+ import { SmrtObject } from '@happyvertical/smrt-core';
2
+ import { TenantPermissionEffect } from '../types/index.js';
3
+ /**
4
+ * TenantPermissionOverride allows setting explicit permission values at the tenant level.
5
+ *
6
+ * This is used in hierarchical tenant structures to control permission inheritance.
7
+ * Each override specifies whether a permission is:
8
+ * - INHERIT: Use the parent tenant's value (default behavior)
9
+ * - GRANT: Explicitly grant at this tenant level
10
+ * - DENY: Explicitly deny at this tenant level (blocks inheritance)
11
+ *
12
+ * ## Resolution Order
13
+ *
14
+ * When resolving effective tenant permissions:
15
+ * 1. Walk down the tenant hierarchy from root to target, accumulating permissions
16
+ * 2. Apply each tenant's overrides (DENY blocks, GRANT adds)
17
+ * 3. INHERIT means "use whatever the parent resolved to"
18
+ *
19
+ * @example
20
+ * ```typescript
21
+ * // Explicitly grant a permission at this tenant level
22
+ * const override = await tenantPermissionOverrides.create({
23
+ * tenantId: tenant.id,
24
+ * permissionId: specialPermission.id,
25
+ * effect: TenantPermissionEffect.GRANT
26
+ * });
27
+ *
28
+ * // Block a permission from being inherited (even if parent grants it)
29
+ * const block = await tenantPermissionOverrides.create({
30
+ * tenantId: tenant.id,
31
+ * permissionId: dangerousPermission.id,
32
+ * effect: TenantPermissionEffect.DENY
33
+ * });
34
+ *
35
+ * // Explicitly inherit (same as not having an override, but documents intent)
36
+ * const inherit = await tenantPermissionOverrides.create({
37
+ * tenantId: tenant.id,
38
+ * permissionId: standardPermission.id,
39
+ * effect: TenantPermissionEffect.INHERIT
40
+ * });
41
+ * ```
42
+ */
43
+ export declare class TenantPermissionOverride extends SmrtObject {
44
+ /**
45
+ * Foreign key to Tenant
46
+ */
47
+ tenantId?: string;
48
+ /**
49
+ * Foreign key to Permission
50
+ */
51
+ permissionId?: string;
52
+ /**
53
+ * Effect of the override: inherit, grant, or deny
54
+ */
55
+ effect: TenantPermissionEffect;
56
+ constructor(options?: any);
57
+ /**
58
+ * Check if this override inherits from parent
59
+ */
60
+ isInherit(): boolean;
61
+ /**
62
+ * Check if this override grants the permission
63
+ */
64
+ isGrant(): boolean;
65
+ /**
66
+ * Check if this override denies the permission
67
+ */
68
+ isDeny(): boolean;
69
+ /**
70
+ * Check if this override has an explicit effect (not inherit)
71
+ */
72
+ hasExplicitEffect(): boolean;
73
+ }
74
+ //# sourceMappingURL=TenantPermissionOverride.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TenantPermissionOverride.d.ts","sourceRoot":"","sources":["../../src/models/TenantPermissionOverride.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAqB,UAAU,EAAQ,MAAM,0BAA0B,CAAC;AAC/E,OAAO,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AAE3D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AACH,qBAQa,wBAAyB,SAAQ,UAAU;IACtD;;OAEG;IAEH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB;;OAEG;IAEH,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB;;OAEG;IAEH,MAAM,EAAE,sBAAsB,CAAkC;gBAEpD,OAAO,GAAE,GAAQ;IAQ7B;;OAEG;IACH,SAAS,IAAI,OAAO;IAIpB;;OAEG;IACH,OAAO,IAAI,OAAO;IAIlB;;OAEG;IACH,MAAM,IAAI,OAAO;IAIjB;;OAEG;IACH,iBAAiB,IAAI,OAAO;CAG7B"}
@@ -0,0 +1,72 @@
1
+ import { SmrtObject } from '@happyvertical/smrt-core';
2
+ import { User as UserContract } from '@happyvertical/smrt-types';
3
+ import { UserStatus } from '../types/index.js';
4
+ /**
5
+ * Validate email format.
6
+ * @param email - Email address to validate
7
+ * @returns true if email format is valid
8
+ */
9
+ export declare function isValidEmail(email: string): boolean;
10
+ /**
11
+ * Normalize email address (lowercase and trim).
12
+ * @param email - Email address to normalize
13
+ * @returns Normalized email
14
+ */
15
+ export declare function normalizeEmail(email: string): string;
16
+ /**
17
+ * User represents an authenticated identity in the system.
18
+ *
19
+ * Users are linked to Profiles from smrt-profiles via profileId.
20
+ * A User can have multiple Memberships across different Tenants.
21
+ *
22
+ * @example
23
+ * ```typescript
24
+ * const user = await users.create({
25
+ * profileId: 'profile-uuid',
26
+ * email: 'user@example.com',
27
+ * status: UserStatus.ACTIVE
28
+ * });
29
+ * await user.save();
30
+ * ```
31
+ */
32
+ export declare class User extends SmrtObject implements UserContract {
33
+ /**
34
+ * Foreign key to smrt-profiles Profile (cross-package)
35
+ */
36
+ profileId: string;
37
+ /**
38
+ * User's email address (unique, used for lookup)
39
+ */
40
+ email: string;
41
+ /**
42
+ * User account status
43
+ */
44
+ status: UserStatus;
45
+ /**
46
+ * Last login timestamp
47
+ */
48
+ lastLoginAt: Date | null;
49
+ constructor(options?: any);
50
+ /**
51
+ * Validate the user's email format.
52
+ * @returns true if email is valid
53
+ */
54
+ hasValidEmail(): boolean;
55
+ /**
56
+ * Check if user is active
57
+ */
58
+ isActive(): boolean;
59
+ /**
60
+ * Check if user is suspended
61
+ */
62
+ isSuspended(): boolean;
63
+ /**
64
+ * Check if user is pending verification
65
+ */
66
+ isPending(): boolean;
67
+ /**
68
+ * Record a login event
69
+ */
70
+ recordLogin(): void;
71
+ }
72
+ //# sourceMappingURL=User.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"User.d.ts","sourceRoot":"","sources":["../../src/models/User.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAGL,UAAU,EAEX,MAAM,0BAA0B,CAAC;AAClC,OAAO,KAAK,EAAE,IAAI,IAAI,YAAY,EAAE,MAAM,2BAA2B,CAAC;AACtE,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAQ/C;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAGnD;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAGpD;AAED;;;;;;;;;;;;;;;GAeG;AACH,qBAOa,IAAK,SAAQ,UAAW,YAAW,YAAY;IAC1D;;OAEG;IAEH,SAAS,EAAE,MAAM,CAAM;IAEvB;;OAEG;IACH,KAAK,EAAE,MAAM,CAAM;IAEnB;;OAEG;IAEH,MAAM,EAAE,UAAU,CAAqB;IAEvC;;OAEG;IACH,WAAW,EAAE,IAAI,GAAG,IAAI,CAAQ;gBAEpB,OAAO,GAAE,GAAQ;IAS7B;;;OAGG;IACH,aAAa,IAAI,OAAO;IAIxB;;OAEG;IACH,QAAQ,IAAI,OAAO;IAInB;;OAEG;IACH,WAAW,IAAI,OAAO;IAItB;;OAEG;IACH,SAAS,IAAI,OAAO;IAIpB;;OAEG;IACH,WAAW,IAAI,IAAI;CAGpB"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Model exports for smrt-users
3
+ * @packageDocumentation
4
+ */
5
+ export { CliAuthRequest, type CliAuthRequestStatus, UsersCliAuthRequest, } from './CliAuthRequest.js';
6
+ export { Group } from './Group.js';
7
+ export { GroupMember } from './GroupMember.js';
8
+ export { GroupRole } from './GroupRole.js';
9
+ export { DEFAULT_TOKEN_EXPIRY_SECONDS, MagicLinkToken, UsersMagicLinkToken, } from './MagicLinkToken.js';
10
+ export { Membership } from './Membership.js';
11
+ export { MembershipOverride } from './MembershipOverride.js';
12
+ export { isValidPermissionSlug, type ParsedPermissionSlug, Permission, parsePermissionSlug, } from './Permission.js';
13
+ export { Role } from './Role.js';
14
+ export { RolePermission } from './RolePermission.js';
15
+ export { DEFAULT_SESSION_TTL, generateSessionId, Session, } from './Session.js';
16
+ export { MAX_TENANT_HIERARCHY_DEPTH, Tenant } from './Tenant.js';
17
+ export { TenantPermissionOverride } from './TenantPermissionOverride.js';
18
+ export { isValidEmail, normalizeEmail, User } from './User.js';
19
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/models/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EACL,cAAc,EACd,KAAK,oBAAoB,EACzB,mBAAmB,GACpB,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAE3C,OAAO,EACL,4BAA4B,EAC5B,cAAc,EACd,mBAAmB,GACpB,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAC7D,OAAO,EACL,qBAAqB,EACrB,KAAK,oBAAoB,EACzB,UAAU,EACV,mBAAmB,GACpB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAErD,OAAO,EACL,mBAAmB,EACnB,iBAAiB,EACjB,OAAO,GACR,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,0BAA0B,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACjE,OAAO,EAAE,wBAAwB,EAAE,MAAM,+BAA+B,CAAC;AAEzE,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC"}
@@ -0,0 +1,2 @@
1
+ export { default } from './svelte/playground.js';
2
+ //# sourceMappingURL=playground.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"playground.d.ts","sourceRoot":"","sources":["../src/playground.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC"}
@@ -0,0 +1,139 @@
1
+ import { USERS_MODULE_META } from "./ui.js";
2
+ const noop = () => {
3
+ };
4
+ const sampleTenant = {
5
+ id: "tenant-riverstone",
6
+ name: "Riverstone Newsroom",
7
+ slug: "riverstone-newsroom",
8
+ status: "active"
9
+ };
10
+ const sampleRoles = [
11
+ {
12
+ id: "role-member",
13
+ slug: "member",
14
+ name: "Member",
15
+ description: "Can collaborate on editorial work."
16
+ },
17
+ {
18
+ id: "role-editor",
19
+ slug: "editor",
20
+ name: "Editor",
21
+ description: "Can approve and publish content."
22
+ }
23
+ ];
24
+ const sampleUsers = [
25
+ {
26
+ user: {
27
+ id: "user-taylor",
28
+ email: "taylor@example.com",
29
+ status: "active"
30
+ },
31
+ profile: {
32
+ id: "profile-taylor",
33
+ name: "Taylor Rowan",
34
+ email: "taylor@example.com"
35
+ },
36
+ role: "Editor"
37
+ },
38
+ {
39
+ user: {
40
+ id: "user-jordan",
41
+ email: "jordan@example.com",
42
+ status: "pending"
43
+ },
44
+ profile: {
45
+ id: "profile-jordan",
46
+ name: "Jordan Lee",
47
+ email: "jordan@example.com"
48
+ },
49
+ role: "Contributor"
50
+ }
51
+ ];
52
+ const loadInviteUserModal = () => import("./svelte/components/InviteUserModal.svelte");
53
+ const loadUserForm = () => import("./svelte/components/UserForm.svelte");
54
+ const loadUserList = () => import("./svelte/components/UserList.svelte");
55
+ const loadUserMenu = () => import("./svelte/components/UserMenu.svelte");
56
+ const playground = {
57
+ packageName: "@happyvertical/smrt-users",
58
+ displayName: USERS_MODULE_META.displayName,
59
+ description: USERS_MODULE_META.description,
60
+ moduleMeta: USERS_MODULE_META,
61
+ entries: [
62
+ {
63
+ id: "user-list",
64
+ title: "User List",
65
+ description: "Role-aware list of users with selection and profile display.",
66
+ loadComponent: loadUserList,
67
+ order: 1,
68
+ props: {
69
+ users: sampleUsers,
70
+ selectedId: "user-taylor",
71
+ onselect: noop
72
+ },
73
+ modes: {
74
+ mock: {
75
+ label: "Mock"
76
+ }
77
+ }
78
+ },
79
+ {
80
+ id: "user-form",
81
+ title: "User Form",
82
+ description: "Create and edit form for user records and account status.",
83
+ loadComponent: loadUserForm,
84
+ order: 2,
85
+ props: {
86
+ user: sampleUsers[0].user,
87
+ profile: sampleUsers[0].profile,
88
+ onsubmit: noop,
89
+ oncancel: noop
90
+ },
91
+ modes: {
92
+ mock: {
93
+ label: "Mock"
94
+ }
95
+ }
96
+ },
97
+ {
98
+ id: "invite-user-modal",
99
+ title: "Invite User Modal",
100
+ description: "Invitation flow for adding a tenant member with a role assignment.",
101
+ loadComponent: loadInviteUserModal,
102
+ order: 3,
103
+ props: {
104
+ open: false,
105
+ tenant: sampleTenant,
106
+ roles: sampleRoles,
107
+ onsubmit: noop,
108
+ onclose: noop
109
+ },
110
+ modes: {
111
+ mock: {
112
+ label: "Mock"
113
+ }
114
+ }
115
+ },
116
+ {
117
+ id: "user-menu",
118
+ title: "User Menu",
119
+ description: "Authenticated account menu for profile, settings, and sign-out actions.",
120
+ loadComponent: loadUserMenu,
121
+ order: 4,
122
+ props: {
123
+ profile: sampleUsers[0].profile,
124
+ profileUrl: "/settings/profile",
125
+ settingsUrl: "/settings",
126
+ signoutUrl: "/auth/signout"
127
+ },
128
+ modes: {
129
+ mock: {
130
+ label: "Mock"
131
+ }
132
+ }
133
+ }
134
+ ]
135
+ };
136
+ export {
137
+ playground as default
138
+ };
139
+ //# sourceMappingURL=playground.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"playground.js","sources":["../src/svelte/playground.ts"],"sourcesContent":["import { USERS_MODULE_META } from '../ui.js';\n\nconst noop = () => {};\n\nconst sampleTenant = {\n id: 'tenant-riverstone',\n name: 'Riverstone Newsroom',\n slug: 'riverstone-newsroom',\n status: 'active',\n};\n\nconst sampleRoles = [\n {\n id: 'role-member',\n slug: 'member',\n name: 'Member',\n description: 'Can collaborate on editorial work.',\n },\n {\n id: 'role-editor',\n slug: 'editor',\n name: 'Editor',\n description: 'Can approve and publish content.',\n },\n];\n\nconst sampleUsers = [\n {\n user: {\n id: 'user-taylor',\n email: 'taylor@example.com',\n status: 'active',\n },\n profile: {\n id: 'profile-taylor',\n name: 'Taylor Rowan',\n email: 'taylor@example.com',\n },\n role: 'Editor',\n },\n {\n user: {\n id: 'user-jordan',\n email: 'jordan@example.com',\n status: 'pending',\n },\n profile: {\n id: 'profile-jordan',\n name: 'Jordan Lee',\n email: 'jordan@example.com',\n },\n role: 'Contributor',\n },\n];\n\nconst loadInviteUserModal = () => import('./components/InviteUserModal.svelte');\nconst loadUserForm = () => import('./components/UserForm.svelte');\nconst loadUserList = () => import('./components/UserList.svelte');\nconst loadUserMenu = () => import('./components/UserMenu.svelte');\n\nexport default {\n packageName: '@happyvertical/smrt-users',\n displayName: USERS_MODULE_META.displayName,\n description: USERS_MODULE_META.description,\n moduleMeta: USERS_MODULE_META,\n entries: [\n {\n id: 'user-list',\n title: 'User List',\n description:\n 'Role-aware list of users with selection and profile display.',\n loadComponent: loadUserList,\n order: 1,\n props: {\n users: sampleUsers,\n selectedId: 'user-taylor',\n onselect: noop,\n },\n modes: {\n mock: {\n label: 'Mock',\n },\n },\n },\n {\n id: 'user-form',\n title: 'User Form',\n description: 'Create and edit form for user records and account status.',\n loadComponent: loadUserForm,\n order: 2,\n props: {\n user: sampleUsers[0].user,\n profile: sampleUsers[0].profile,\n onsubmit: noop,\n oncancel: noop,\n },\n modes: {\n mock: {\n label: 'Mock',\n },\n },\n },\n {\n id: 'invite-user-modal',\n title: 'Invite User Modal',\n description:\n 'Invitation flow for adding a tenant member with a role assignment.',\n loadComponent: loadInviteUserModal,\n order: 3,\n props: {\n open: false,\n tenant: sampleTenant,\n roles: sampleRoles,\n onsubmit: noop,\n onclose: noop,\n },\n modes: {\n mock: {\n label: 'Mock',\n },\n },\n },\n {\n id: 'user-menu',\n title: 'User Menu',\n description:\n 'Authenticated account menu for profile, settings, and sign-out actions.',\n loadComponent: loadUserMenu,\n order: 4,\n props: {\n profile: sampleUsers[0].profile,\n profileUrl: '/settings/profile',\n settingsUrl: '/settings',\n signoutUrl: '/auth/signout',\n },\n modes: {\n mock: {\n label: 'Mock',\n },\n },\n },\n ],\n};\n"],"names":[],"mappings":";AAEA,MAAM,OAAO,MAAM;AAAC;AAEpB,MAAM,eAAe;AAAA,EACnB,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,MAAM;AAAA,EACN,QAAQ;AACV;AAEA,MAAM,cAAc;AAAA,EAClB;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,MAAM;AAAA,IACN,aAAa;AAAA,EAAA;AAAA,EAEf;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,MAAM;AAAA,IACN,aAAa;AAAA,EAAA;AAEjB;AAEA,MAAM,cAAc;AAAA,EAClB;AAAA,IACE,MAAM;AAAA,MACJ,IAAI;AAAA,MACJ,OAAO;AAAA,MACP,QAAQ;AAAA,IAAA;AAAA,IAEV,SAAS;AAAA,MACP,IAAI;AAAA,MACJ,MAAM;AAAA,MACN,OAAO;AAAA,IAAA;AAAA,IAET,MAAM;AAAA,EAAA;AAAA,EAER;AAAA,IACE,MAAM;AAAA,MACJ,IAAI;AAAA,MACJ,OAAO;AAAA,MACP,QAAQ;AAAA,IAAA;AAAA,IAEV,SAAS;AAAA,MACP,IAAI;AAAA,MACJ,MAAM;AAAA,MACN,OAAO;AAAA,IAAA;AAAA,IAET,MAAM;AAAA,EAAA;AAEV;AAEA,MAAM,sBAAsB,MAAM,OAAO,4CAAqC;AAC9E,MAAM,eAAe,MAAM,OAAO,qCAA8B;AAChE,MAAM,eAAe,MAAM,OAAO,qCAA8B;AAChE,MAAM,eAAe,MAAM,OAAO,qCAA8B;AAEhE,MAAA,aAAe;AAAA,EACb,aAAa;AAAA,EACb,aAAa,kBAAkB;AAAA,EAC/B,aAAa,kBAAkB;AAAA,EAC/B,YAAY;AAAA,EACZ,SAAS;AAAA,IACP;AAAA,MACE,IAAI;AAAA,MACJ,OAAO;AAAA,MACP,aACE;AAAA,MACF,eAAe;AAAA,MACf,OAAO;AAAA,MACP,OAAO;AAAA,QACL,OAAO;AAAA,QACP,YAAY;AAAA,QACZ,UAAU;AAAA,MAAA;AAAA,MAEZ,OAAO;AAAA,QACL,MAAM;AAAA,UACJ,OAAO;AAAA,QAAA;AAAA,MACT;AAAA,IACF;AAAA,IAEF;AAAA,MACE,IAAI;AAAA,MACJ,OAAO;AAAA,MACP,aAAa;AAAA,MACb,eAAe;AAAA,MACf,OAAO;AAAA,MACP,OAAO;AAAA,QACL,MAAM,YAAY,CAAC,EAAE;AAAA,QACrB,SAAS,YAAY,CAAC,EAAE;AAAA,QACxB,UAAU;AAAA,QACV,UAAU;AAAA,MAAA;AAAA,MAEZ,OAAO;AAAA,QACL,MAAM;AAAA,UACJ,OAAO;AAAA,QAAA;AAAA,MACT;AAAA,IACF;AAAA,IAEF;AAAA,MACE,IAAI;AAAA,MACJ,OAAO;AAAA,MACP,aACE;AAAA,MACF,eAAe;AAAA,MACf,OAAO;AAAA,MACP,OAAO;AAAA,QACL,MAAM;AAAA,QACN,QAAQ;AAAA,QACR,OAAO;AAAA,QACP,UAAU;AAAA,QACV,SAAS;AAAA,MAAA;AAAA,MAEX,OAAO;AAAA,QACL,MAAM;AAAA,UACJ,OAAO;AAAA,QAAA;AAAA,MACT;AAAA,IACF;AAAA,IAEF;AAAA,MACE,IAAI;AAAA,MACJ,OAAO;AAAA,MACP,aACE;AAAA,MACF,eAAe;AAAA,MACf,OAAO;AAAA,MACP,OAAO;AAAA,QACL,SAAS,YAAY,CAAC,EAAE;AAAA,QACxB,YAAY;AAAA,QACZ,aAAa;AAAA,QACb,YAAY;AAAA,MAAA;AAAA,MAEd,OAAO;AAAA,QACL,MAAM;AAAA,UACJ,OAAO;AAAA,QAAA;AAAA,MACT;AAAA,IACF;AAAA,EACF;AAEJ;"}
@@ -0,0 +1,84 @@
1
+ import { SmrtClassOptions } from '@happyvertical/smrt-core';
2
+ /**
3
+ * Options for MagicLinkService
4
+ */
5
+ export interface MagicLinkServiceOptions extends SmrtClassOptions {
6
+ /** Secret used to derive the HMAC signing key (required) */
7
+ secret: string;
8
+ /** Token expiry in seconds (default: 10 minutes) */
9
+ tokenExpiry?: number;
10
+ /** JWT issuer claim (default: 'smrt:magiclink') */
11
+ issuer?: string;
12
+ }
13
+ /**
14
+ * Result of generating a magic link token
15
+ */
16
+ export interface MagicLinkResult {
17
+ /** The signed JWT token */
18
+ token: string;
19
+ /** When the token expires */
20
+ expiresAt: Date;
21
+ }
22
+ /**
23
+ * Result of verifying a magic link token
24
+ */
25
+ export interface MagicLinkVerifyResult {
26
+ /** The email address from the token */
27
+ email: string;
28
+ /** The nonce (for correlation/logging) */
29
+ nonce: string;
30
+ }
31
+ /**
32
+ * Error class for magic link authentication failures
33
+ */
34
+ export declare class MagicLinkError extends Error {
35
+ constructor(message: string);
36
+ }
37
+ /**
38
+ * MagicLinkService provides passwordless authentication via email magic links.
39
+ *
40
+ * Tokens are HMAC-signed JWTs with embedded nonces for replay protection.
41
+ * The service is framework-agnostic — it does not send emails or set cookies.
42
+ */
43
+ export declare class MagicLinkService {
44
+ private tokenCollection;
45
+ private signingKey;
46
+ private readonly secret;
47
+ private readonly tokenExpiry;
48
+ private readonly issuer;
49
+ private readonly options;
50
+ constructor(options: MagicLinkServiceOptions);
51
+ /**
52
+ * Initialize collections
53
+ */
54
+ initialize(): Promise<void>;
55
+ /**
56
+ * Derive the HMAC signing key from the secret
57
+ */
58
+ private getSigningKey;
59
+ /**
60
+ * Generate a magic link token for the given email.
61
+ *
62
+ * Stores a nonce in the database for replay protection.
63
+ * The caller is responsible for emailing the token to the user.
64
+ */
65
+ generate(email: string): Promise<MagicLinkResult>;
66
+ /**
67
+ * Verify a magic link token.
68
+ *
69
+ * Checks JWT signature, expiry, and that the nonce hasn't been used.
70
+ * Marks the nonce as used on success (single-use enforcement).
71
+ *
72
+ * @throws {MagicLinkError} If the token is invalid, expired, or already used
73
+ */
74
+ verify(token: string): Promise<MagicLinkVerifyResult>;
75
+ /**
76
+ * Clean up expired tokens (run periodically)
77
+ */
78
+ cleanupExpiredTokens(): Promise<number>;
79
+ /**
80
+ * Static factory method
81
+ */
82
+ static create(options: MagicLinkServiceOptions): Promise<MagicLinkService>;
83
+ }
84
+ //# sourceMappingURL=MagicLinkService.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MagicLinkService.d.ts","sourceRoot":"","sources":["../../src/services/MagicLinkService.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAKjE;;GAEG;AACH,MAAM,WAAW,uBAAwB,SAAQ,gBAAgB;IAC/D,4DAA4D;IAC5D,MAAM,EAAE,MAAM,CAAC;IACf,oDAAoD;IACpD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,mDAAmD;IACnD,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,2BAA2B;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,6BAA6B;IAC7B,SAAS,EAAE,IAAI,CAAC;CACjB;AAED;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC,uCAAuC;IACvC,KAAK,EAAE,MAAM,CAAC;IACd,0CAA0C;IAC1C,KAAK,EAAE,MAAM,CAAC;CACf;AAED;;GAEG;AACH,qBAAa,cAAe,SAAQ,KAAK;gBAC3B,OAAO,EAAE,MAAM;CAI5B;AAED;;;;;GAKG;AACH,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,eAAe,CAAiC;IACxD,OAAO,CAAC,UAAU,CAA2B;IAC7C,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IACrC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA0B;gBAEtC,OAAO,EAAE,uBAAuB;IAU5C;;OAEG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAMjC;;OAEG;YACW,aAAa;IAW3B;;;;;OAKG;IACG,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC;IAoCvD;;;;;;;OAOG;IACG,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,qBAAqB,CAAC;IAuC3D;;OAEG;IACG,oBAAoB,IAAI,OAAO,CAAC,MAAM,CAAC;IAI7C;;OAEG;WACU,MAAM,CACjB,OAAO,EAAE,uBAAuB,GAC/B,OAAO,CAAC,gBAAgB,CAAC;CAK7B"}