@happyvertical/smrt-users 0.37.1 → 0.37.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.
- package/AGENTS.md +2 -1
- package/README.md +63 -0
- package/dist/chunks/{TerminalAuthService-bY1oWeAh.js → TerminalAuthService-DcgimQYo.js} +243 -243
- package/dist/chunks/TerminalAuthService-DcgimQYo.js.map +1 -0
- package/dist/chunks/{index-DBpq-WMK.js → index-C3E55ikp.js} +3 -3
- package/dist/chunks/{index-DBpq-WMK.js.map → index-C3E55ikp.js.map} +1 -1
- package/dist/collections/AccessRequestCollection.d.ts +28 -0
- package/dist/collections/AccessRequestCollection.d.ts.map +1 -0
- package/dist/collections/index.d.ts +1 -0
- package/dist/collections/index.d.ts.map +1 -1
- package/dist/index.d.ts +4 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +748 -39
- package/dist/index.js.map +1 -1
- package/dist/manifest.json +421 -2
- package/dist/models/AccessRequest.d.ts +131 -0
- package/dist/models/AccessRequest.d.ts.map +1 -0
- package/dist/models/index.d.ts +1 -0
- package/dist/models/index.d.ts.map +1 -1
- package/dist/services/AccessRequestService.d.ts +326 -0
- package/dist/services/AccessRequestService.d.ts.map +1 -0
- package/dist/services/index.d.ts +1 -0
- package/dist/services/index.d.ts.map +1 -1
- package/dist/smrt-knowledge.json +121 -7
- package/dist/sveltekit.js +1 -1
- package/dist/types/index.d.ts +1 -1
- package/dist/types/index.d.ts.map +1 -1
- package/package.json +8 -8
- package/dist/chunks/TerminalAuthService-bY1oWeAh.js.map +0 -1
package/AGENTS.md
CHANGED
|
@@ -2,11 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
Multi-tenant user management with RBAC, hierarchical tenants, session handling, and SvelteKit integration.
|
|
4
4
|
|
|
5
|
-
## Models (
|
|
5
|
+
## Models (14)
|
|
6
6
|
|
|
7
7
|
| Model | Key Pattern |
|
|
8
8
|
|-------|-------------|
|
|
9
9
|
| User | Auth identity. `profileId` is plain string (not FK) to smrt-profiles. Email auto-lowercased. |
|
|
10
|
+
| AccessRequest | "Request access / waitlist" record captured before a `User` exists. CLOSED generated surface (`api`/`mcp`/`cli` = `[]`) — all access via `AccessRequestService`. Email normalized + indexed; JSON `requestContext` (NOT `context` — reserved for slug scoping). |
|
|
10
11
|
| Tenant | **STI** + hierarchical parent-child. `hierarchyPath` (materialized path), `hierarchyLevel`. Max depth 10. |
|
|
11
12
|
| Session | Server-side. Secure UUID. TTL in **seconds** (not ms). Status auto-updates to EXPIRED on access. |
|
|
12
13
|
| MagicLinkToken | Single-use email login token. Backed by `MagicLinkService`. |
|
package/README.md
CHANGED
|
@@ -228,6 +228,64 @@ Optional-tenancy and global tables are skipped and returned in
|
|
|
228
228
|
`result.skipped` instead of generating unsafe policies. Custom permissions can
|
|
229
229
|
participate in RLS by adding explicit Postgres bindings as shown above.
|
|
230
230
|
|
|
231
|
+
### Access requests (request access / waitlist)
|
|
232
|
+
|
|
233
|
+
Capture a prospective user from a public form *before* they are a real `User`,
|
|
234
|
+
let an operator triage, and **graduate** an approved request into a `User`
|
|
235
|
+
(optionally attached to a tenant). `createAccessRequest` is **public-safe** (no
|
|
236
|
+
auth) — expose it from your own rate-limited endpoint. Operator methods are gated
|
|
237
|
+
by an optional `authorize` hook (capabilities `access-requests:read` /
|
|
238
|
+
`access-requests:manage`). Lifecycle events let apps send invites/notifications;
|
|
239
|
+
this package never owns email delivery.
|
|
240
|
+
|
|
241
|
+
```typescript
|
|
242
|
+
import { AccessRequestService } from '@happyvertical/smrt-users';
|
|
243
|
+
|
|
244
|
+
const accessRequests = await AccessRequestService.create({
|
|
245
|
+
db: { type: 'postgres', url: process.env.DATABASE_URL },
|
|
246
|
+
|
|
247
|
+
// Optional: gate operator methods against your permission system.
|
|
248
|
+
// (createAccessRequest is always public-safe and never calls this.)
|
|
249
|
+
authorize: async ({ capability, by }) => {
|
|
250
|
+
if (!by || !(await isPlatformOperator(by, capability))) {
|
|
251
|
+
throw new Error(`Missing capability: ${capability}`);
|
|
252
|
+
}
|
|
253
|
+
},
|
|
254
|
+
|
|
255
|
+
// Optional: react to lifecycle changes (send a magic link on graduate, etc.).
|
|
256
|
+
onEvent: async (event) => {
|
|
257
|
+
if (event.type === 'access-request.graduated' && event.user) {
|
|
258
|
+
await sendWelcomeEmail(event.user.email);
|
|
259
|
+
}
|
|
260
|
+
},
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
// 1) Public form handler (app adds rate-limiting) — no auth required.
|
|
264
|
+
const request = await accessRequests.createAccessRequest({
|
|
265
|
+
email: 'jane@example.com',
|
|
266
|
+
name: 'Jane Doe',
|
|
267
|
+
source: 'www',
|
|
268
|
+
context: { company: 'Acme', intendedUse: 'evaluation' },
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
// 2) Operator triages the queue.
|
|
272
|
+
const open = await accessRequests.listAccessRequests({
|
|
273
|
+
status: AccessRequestStatus.REQUESTED,
|
|
274
|
+
by: operatorId,
|
|
275
|
+
});
|
|
276
|
+
await accessRequests.approveAccessRequest(request.id, { by: operatorId });
|
|
277
|
+
|
|
278
|
+
// 3) Graduate into a User — operator picks new-vs-existing tenant per request:
|
|
279
|
+
// a) brand-new tenant, requester as owner
|
|
280
|
+
const { user, tenant, membership } = await accessRequests.graduateAccessRequest(
|
|
281
|
+
request.id,
|
|
282
|
+
{ by: operatorId, tenant: { create: { name: 'Acme Inc' } } },
|
|
283
|
+
);
|
|
284
|
+
// b) existing tenant: { tenant: { tenantId, role: 'member' } }
|
|
285
|
+
// c) user only: { tenant: 'none' }
|
|
286
|
+
// Graduation is idempotent and reuses the existing User/Membership paths.
|
|
287
|
+
```
|
|
288
|
+
|
|
231
289
|
### SvelteKit hooks
|
|
232
290
|
|
|
233
291
|
```typescript
|
|
@@ -399,6 +457,7 @@ TenantService supports three modes: `flexible` (no auto-create), `personal` (aut
|
|
|
399
457
|
| `MembershipOverride` | Per-user permission grant/deny on a membership. |
|
|
400
458
|
| `TenantPermissionOverride` | Tenant-level permission override (INHERIT/GRANT/DENY). |
|
|
401
459
|
| `GroupMember`, `GroupRole`, `RolePermission` | Junction tables for groups and role-permission assignments. |
|
|
460
|
+
| `AccessRequest` | "Request access / waitlist" record captured before a `User` exists. Closed generated surface — all access via `AccessRequestService`. |
|
|
402
461
|
|
|
403
462
|
### Collections
|
|
404
463
|
|
|
@@ -409,6 +468,7 @@ TenantService supports three modes: `flexible` (no auto-create), `personal` (aut
|
|
|
409
468
|
| `MembershipCollection` | Membership CRUD, `findByUserAndTenant()` |
|
|
410
469
|
| `MembershipOverrideCollection`, `TenantPermissionOverrideCollection` | Override management at membership and tenant levels |
|
|
411
470
|
| `GroupCollection`, `GroupMemberCollection`, `GroupRoleCollection`, `RolePermissionCollection` | Group and role-permission junction management |
|
|
471
|
+
| `AccessRequestCollection` | AccessRequest queries: `findByEmail()`, `findOpenByEmail()`, `findByStatus()`, `findOpen()` |
|
|
412
472
|
|
|
413
473
|
### Services
|
|
414
474
|
|
|
@@ -423,6 +483,7 @@ TenantService supports three modes: `flexible` (no auto-create), `personal` (aut
|
|
|
423
483
|
| `withSessionPermissionContext()` | Loads a session, optionally enters tenancy context, and exposes a request-scoped database/permission context. |
|
|
424
484
|
| `getCurrentSessionPermissionContext()`, `getRequestScopedDatabase()` | Read the active request/session context inside app code. |
|
|
425
485
|
| `TenantService` | Policy-driven tenant lifecycle. `ensureTenantForUser()`, `createTenantWithOwnership()`. |
|
|
486
|
+
| `AccessRequestService` | Request-access/waitlist lifecycle + graduation. `createAccessRequest()` (public-safe), `list`/`get`/`approve`/`decline`/`cancel`, `graduateAccessRequest()` (new/existing/no tenant). Capability + event hooks. |
|
|
426
487
|
|
|
427
488
|
### SvelteKit (`@happyvertical/smrt-users/sveltekit`)
|
|
428
489
|
|
|
@@ -441,7 +502,9 @@ TenantService supports three modes: `flexible` (no auto-create), `personal` (aut
|
|
|
441
502
|
| Export | Description |
|
|
442
503
|
|--------|-------------|
|
|
443
504
|
| `UserStatus`, `TenantStatus`, `SessionStatus`, `MembershipStatus` | Status enums |
|
|
505
|
+
| `AccessRequestStatus` | Access-request lifecycle enum (`REQUESTED`/`APPROVED`/`DECLINED`/`GRADUATED`/`CANCELED`) |
|
|
444
506
|
| `OverrideEffect`, `TenantPermissionEffect` | Override effect enums |
|
|
507
|
+
| `ACCESS_REQUEST_CAPABILITIES`, `AccessRequestError` | Operator capability slugs; typed domain error (`error.code`) |
|
|
445
508
|
| `DEFAULT_ROLE_SLUGS`, `DEFAULT_ROLES`, `DEFAULT_TENANT_POLICY` | System role slugs, role configs, default tenant policy |
|
|
446
509
|
| `DEFAULT_SESSION_TTL`, `MAX_TENANT_HIERARCHY_DEPTH` | 604800 (7 days in seconds), 10 |
|
|
447
510
|
| `TenantHierarchyError` | Thrown when hierarchy depth limit is exceeded |
|