authvital-sdk 0.1.1-dev.3.cefb119.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.
@@ -0,0 +1,2656 @@
1
+ import { y as AuthVitalEventHandler, f as SubjectCreatedEvent, g as SubjectUpdatedEvent, h as SubjectDeletedEvent, i as SubjectDeactivatedEvent, M as MemberJoinedEvent, j as MemberLeftEvent, k as MemberRoleChangedEvent, A as AppAccessGrantedEvent, n as AppAccessRevokedEvent, p as AppAccessRoleChangedEvent } from './webhook-router-DdfXLtHa.js';
2
+ export { o as AppAccessDeactivatedEvent, D as AppAccessEventHandler, K as IAppAccessEventHandler, F as IAuthVitalEventHandler, G as IInviteEventHandler, N as ILicenseEventHandler, J as IMemberEventHandler, H as ISubjectEventHandler, b as InviteAcceptedEvent, I as InviteCreatedEvent, c as InviteDeletedEvent, z as InviteEventHandler, d as InviteExpiredEvent, L as LicenseAssignedEvent, r as LicenseChangedEvent, E as LicenseEventHandler, q as LicenseRevokedEvent, m as MemberActivatedEvent, C as MemberEventHandler, l as MemberSuspendedEvent, x as SYNC_EVENT_TYPES, e as SubjectData, B as SubjectEventHandler, S as SyncEvent, a as SyncEventType, W as WebhookRouter, O as WebhookRouterOptions, P as WebhookVerifier, Q as WebhookVerifierOptions, v as isAppAccessEvent, s as isInviteEvent, w as isLicenseEvent, u as isMemberEvent, t as isSubjectEvent } from './webhook-router-DdfXLtHa.js';
3
+
4
+ /**
5
+ * @authvital/sdk - JWT Validator
6
+ *
7
+ * Validates JWTs issued by AuthVital using JWKS (JSON Web Key Set).
8
+ * Automatically fetches keys from the IDP's well-known endpoint,
9
+ * handles caching, and supports key rotation.
10
+ *
11
+ * @example
12
+ * ```ts
13
+ * import { createJwtValidator } from '@authvital/sdk/server';
14
+ *
15
+ * const validator = createJwtValidator({
16
+ * authVitalHost: process.env.AV_HOST,
17
+ * });
18
+ *
19
+ * // Validate a token
20
+ * const payload = await validator.validateToken(token);
21
+ *
22
+ * // Get public keys for manual verification
23
+ * const keys = await validator.getPublicKeys();
24
+ * ```
25
+ */
26
+ interface JwtValidatorConfig {
27
+ /** AuthVital IDP URL (e.g., "https://auth.example.com") */
28
+ authVitalHost: string;
29
+ /** Cache TTL in seconds (default: 3600 = 1 hour) */
30
+ cacheTtl?: number;
31
+ /** Expected audience (client_id) - optional but recommended */
32
+ audience?: string;
33
+ /** Expected issuer - defaults to authVitalHost */
34
+ issuer?: string;
35
+ }
36
+ interface JwksKey {
37
+ kty: string;
38
+ kid: string;
39
+ use?: string;
40
+ alg?: string;
41
+ n?: string;
42
+ e?: string;
43
+ x5c?: string[];
44
+ }
45
+ interface Jwks {
46
+ keys: JwksKey[];
47
+ }
48
+ interface JwtHeader {
49
+ alg: string;
50
+ typ?: string;
51
+ kid?: string;
52
+ }
53
+ interface JwtPayload {
54
+ iss?: string;
55
+ sub?: string;
56
+ aud?: string | string[];
57
+ exp?: number;
58
+ nbf?: number;
59
+ iat?: number;
60
+ jti?: string;
61
+ [key: string]: unknown;
62
+ }
63
+ interface ValidateTokenResult {
64
+ valid: boolean;
65
+ payload?: JwtPayload;
66
+ error?: string;
67
+ }
68
+ /**
69
+ * JWT Validator for AuthVital tokens
70
+ *
71
+ * Fetches JWKS from the IDP, caches keys, and validates tokens.
72
+ * Handles key rotation automatically by refetching JWKS when a key is not found.
73
+ */
74
+ declare class JwtValidator {
75
+ private config;
76
+ private jwksCache;
77
+ private jwksCacheTime;
78
+ private fetchPromise;
79
+ constructor(config: JwtValidatorConfig);
80
+ /**
81
+ * Get the JWKS URL for this IDP
82
+ */
83
+ getJwksUrl(): string;
84
+ /**
85
+ * Get the OpenID Configuration URL
86
+ */
87
+ getOpenIdConfigUrl(): string;
88
+ /**
89
+ * Fetch public keys from the JWKS endpoint
90
+ * Results are cached according to cacheTtl
91
+ */
92
+ getPublicKeys(forceRefresh?: boolean): Promise<Jwks>;
93
+ /**
94
+ * Fetch JWKS from the IDP
95
+ */
96
+ private fetchJwks;
97
+ /**
98
+ * Find a key by its ID (kid)
99
+ */
100
+ private findKey;
101
+ /**
102
+ * Decode a JWT without verification (to get header/payload)
103
+ */
104
+ decodeToken(token: string): {
105
+ header: JwtHeader;
106
+ payload: JwtPayload;
107
+ } | null;
108
+ /**
109
+ * Validate a JWT token
110
+ *
111
+ * @param token - The JWT to validate
112
+ * @returns Validation result with payload if valid
113
+ */
114
+ validateToken(token: string): Promise<ValidateTokenResult>;
115
+ /**
116
+ * Verify RS256 signature using Web Crypto API
117
+ */
118
+ private verifySignature;
119
+ /**
120
+ * Base64URL decode to string
121
+ */
122
+ private base64UrlDecode;
123
+ /**
124
+ * Base64URL decode to Uint8Array
125
+ */
126
+ private base64UrlDecodeToBuffer;
127
+ /**
128
+ * Clear the JWKS cache (useful for testing or forced refresh)
129
+ */
130
+ clearCache(): void;
131
+ /**
132
+ * Check if the JWT payload has a specific tenant permission
133
+ *
134
+ * @param payload - Decoded JWT payload
135
+ * @param permission - Permission to check (e.g., 'licenses:manage')
136
+ * @returns true if user has the permission (wildcards supported)
137
+ *
138
+ * @example
139
+ * ```ts
140
+ * const { user } = await validator.getCurrentUser(authHeader);
141
+ * if (validator.hasTenantPermission(user, 'licenses:manage')) {
142
+ * // User can manage licenses
143
+ * }
144
+ * ```
145
+ */
146
+ hasTenantPermission(payload: JwtPayload, permission: string): boolean;
147
+ /**
148
+ * Check if the JWT payload has a specific app permission
149
+ *
150
+ * @param payload - Decoded JWT payload
151
+ * @param permission - Permission to check (e.g., 'projects:create')
152
+ * @returns true if user has the permission (wildcards supported)
153
+ *
154
+ * @example
155
+ * ```ts
156
+ * const { user } = await validator.getCurrentUser(authHeader);
157
+ * if (validator.hasAppPermission(user, 'projects:create')) {
158
+ * // User can create projects
159
+ * }
160
+ * ```
161
+ */
162
+ hasAppPermission(payload: JwtPayload, permission: string): boolean;
163
+ /**
164
+ * Check if the JWT payload has a specific feature enabled
165
+ *
166
+ * This reads from the `license.features` array in the JWT.
167
+ * No API call needed - feature information is embedded in the token!
168
+ *
169
+ * @param payload - Decoded JWT payload
170
+ * @param featureKey - Feature to check (e.g., 'sso', 'audit_logs')
171
+ * @returns true if feature is enabled
172
+ *
173
+ * @example
174
+ * ```ts
175
+ * const { user } = await validator.getCurrentUser(authHeader);
176
+ * if (validator.hasFeature(user, 'sso')) {
177
+ * // User's tenant has SSO enabled
178
+ * }
179
+ * ```
180
+ */
181
+ hasFeature(payload: JwtPayload, featureKey: string): boolean;
182
+ /**
183
+ * Get the license type from JWT payload
184
+ *
185
+ * @param payload - Decoded JWT payload
186
+ * @returns License type slug (e.g., 'pro', 'enterprise') or null
187
+ *
188
+ * @example
189
+ * ```ts
190
+ * const { user } = await validator.getCurrentUser(authHeader);
191
+ * const licenseType = validator.getLicenseType(user);
192
+ * if (licenseType === 'enterprise') {
193
+ * // Show enterprise features
194
+ * }
195
+ * ```
196
+ */
197
+ getLicenseType(payload: JwtPayload): string | null;
198
+ /**
199
+ * Check if wildcard pattern matches permission
200
+ *
201
+ * @example
202
+ * - '*' matches everything
203
+ * - 'licenses:*' matches 'licenses:manage', 'licenses:view', etc.
204
+ * - 'licenses:manage' only matches 'licenses:manage'
205
+ */
206
+ private matchesWildcard;
207
+ /**
208
+ * Get the current user from an Authorization header.
209
+ * This is the helper for implementing `/api/auth/me` endpoints.
210
+ *
211
+ * - Does NOT call the IDP
212
+ * - Validates JWT signature using cached JWKS
213
+ * - Returns the decoded JWT payload
214
+ *
215
+ * @example
216
+ * ```ts
217
+ * const validator = createJwtValidator({ authVitalHost: process.env.AV_HOST });
218
+ *
219
+ * // GET /api/auth/me
220
+ * app.get('/api/auth/me', async (req, res) => {
221
+ * const result = await validator.getCurrentUser(req.headers.authorization);
222
+ *
223
+ * if (!result.authenticated) {
224
+ * return res.status(401).json({ error: result.error });
225
+ * }
226
+ *
227
+ * res.json(result.user);
228
+ * });
229
+ * ```
230
+ */
231
+ getCurrentUser(authorizationHeader: string | null | undefined): Promise<GetCurrentUserResult$1>;
232
+ }
233
+ /**
234
+ * Create a JWT validator instance
235
+ *
236
+ * @example
237
+ * ```ts
238
+ * const validator = createJwtValidator({
239
+ * authVitalHost: 'https://auth.example.com',
240
+ * audience: 'my-client-id', // optional but recommended
241
+ * });
242
+ *
243
+ * const result = await validator.validateToken(token);
244
+ * if (result.valid) {
245
+ * console.log('User:', result.payload.sub);
246
+ * }
247
+ * ```
248
+ */
249
+ declare function createJwtValidator(config: JwtValidatorConfig): JwtValidator;
250
+ interface GetCurrentUserResult$1 {
251
+ /** Whether the request is authenticated with a valid token */
252
+ authenticated: boolean;
253
+ /** The decoded JWT payload (user data) if authenticated */
254
+ user: JwtPayload | null;
255
+ /** Error message if authentication failed */
256
+ error?: string;
257
+ }
258
+ /**
259
+ * Extract and validate the current user from an Authorization header.
260
+ * This is the helper for implementing `/api/auth/me` endpoints.
261
+ *
262
+ * - Does NOT call the IDP
263
+ * - Validates JWT signature using cached JWKS (fetches if not cached)
264
+ * - Returns the decoded JWT payload
265
+ *
266
+ * @example
267
+ * ```ts
268
+ * import { getCurrentUser, createJwtValidator } from '@authvital/sdk/server';
269
+ *
270
+ * // Create a validator (typically once at startup)
271
+ * const validator = createJwtValidator({
272
+ * authVitalHost: process.env.AV_HOST,
273
+ * });
274
+ *
275
+ * // GET /api/auth/me
276
+ * app.get('/api/auth/me', async (req, res) => {
277
+ * const result = await getCurrentUser(req.headers.authorization, validator);
278
+ *
279
+ * if (!result.authenticated) {
280
+ * return res.status(401).json({ error: result.error });
281
+ * }
282
+ *
283
+ * // Return the decoded JWT claims (no IDP call!)
284
+ * res.json(result.user);
285
+ * });
286
+ * ```
287
+ *
288
+ * @example Next.js API Route
289
+ * ```ts
290
+ * import { getCurrentUser, createJwtValidator } from '@authvital/sdk/server';
291
+ *
292
+ * const validator = createJwtValidator({ authVitalHost: process.env.AV_HOST });
293
+ *
294
+ * export async function GET(request: Request) {
295
+ * const result = await getCurrentUser(
296
+ * request.headers.get('authorization'),
297
+ * validator
298
+ * );
299
+ *
300
+ * if (!result.authenticated) {
301
+ * return Response.json({ error: result.error }, { status: 401 });
302
+ * }
303
+ *
304
+ * return Response.json(result.user);
305
+ * }
306
+ * ```
307
+ */
308
+ declare function getCurrentUser(authorizationHeader: string | null | undefined, validator: JwtValidator): Promise<GetCurrentUserResult$1>;
309
+ /**
310
+ * Convenience function that creates a validator and gets the current user in one call.
311
+ * Use this for simple cases; for better performance, create the validator once and reuse it.
312
+ *
313
+ * @example
314
+ * ```ts
315
+ * import { getCurrentUserFromConfig } from '@authvital/sdk/server';
316
+ *
317
+ * // GET /api/auth/me (simple one-liner)
318
+ * app.get('/api/auth/me', async (req, res) => {
319
+ * const result = await getCurrentUserFromConfig(
320
+ * req.headers.authorization,
321
+ * { authVitalHost: process.env.AV_HOST }
322
+ * );
323
+ *
324
+ * if (!result.authenticated) {
325
+ * return res.status(401).json({ error: result.error });
326
+ * }
327
+ *
328
+ * res.json(result.user);
329
+ * });
330
+ * ```
331
+ */
332
+ declare function getCurrentUserFromConfig(authorizationHeader: string | null | undefined, config: JwtValidatorConfig): Promise<GetCurrentUserResult$1>;
333
+ /**
334
+ * Express/Connect middleware factory for JWT validation
335
+ *
336
+ * @example
337
+ * ```ts
338
+ * import { createJwtMiddleware } from '@authvital/sdk/server';
339
+ *
340
+ * const requireAuth = createJwtMiddleware({
341
+ * authVitalHost: process.env.AV_HOST,
342
+ * });
343
+ *
344
+ * app.get('/api/protected', requireAuth, (req, res) => {
345
+ * console.log('User:', req.user);
346
+ * res.json({ message: 'Hello!' });
347
+ * });
348
+ * ```
349
+ */
350
+ declare function createJwtMiddleware(config: JwtValidatorConfig): (req: any, res: any, next: any) => Promise<any>;
351
+ /**
352
+ * Create options for passport-jwt Strategy
353
+ *
354
+ * @example
355
+ * ```ts
356
+ * import { Strategy as JwtStrategy } from 'passport-jwt';
357
+ * import { createPassportJwtOptions } from '@authvital/sdk/server';
358
+ *
359
+ * const options = await createPassportJwtOptions({
360
+ * authVitalHost: process.env.AV_HOST,
361
+ * });
362
+ *
363
+ * passport.use(new JwtStrategy(options, (payload, done) => {
364
+ * // payload is the decoded JWT
365
+ * done(null, payload);
366
+ * }));
367
+ * ```
368
+ */
369
+ declare function createPassportJwtOptions(config: JwtValidatorConfig): Promise<{
370
+ jwtFromRequest: (req: any) => string | null;
371
+ secretOrKeyProvider: (req: any, rawJwt: any, done: any) => void;
372
+ issuer: string;
373
+ audience?: string;
374
+ algorithms: string[];
375
+ }>;
376
+
377
+ /**
378
+ * @authvital/sdk - Base Client
379
+ *
380
+ * Shared HTTP utilities, token management, and JWT validation for the AuthVital SDK.
381
+ * All namespaces extend from this base to access authenticated API calls.
382
+ */
383
+
384
+ interface AuthVitalConfig {
385
+ /** AuthVital IDP URL (e.g., "https://auth.example.com") */
386
+ authVitalHost: string;
387
+ /** OAuth client_id for your application */
388
+ clientId: string;
389
+ /** OAuth client_secret for your application */
390
+ clientSecret: string;
391
+ /** JWKS cache TTL in seconds (default: 3600 = 1 hour) */
392
+ jwksCacheTtl?: number;
393
+ /** Expected audience for JWT validation (defaults to clientId) */
394
+ audience?: string;
395
+ }
396
+ interface GetCurrentUserResult {
397
+ /** Whether the request is authenticated with a valid token */
398
+ authenticated: boolean;
399
+ /** The decoded JWT payload (user data) if authenticated */
400
+ user: JwtPayload | null;
401
+ /** Error message if authentication failed */
402
+ error?: string;
403
+ }
404
+ interface ValidatedClaims {
405
+ /** User ID (sub claim) */
406
+ sub: string;
407
+ /** Tenant ID (tenant_id claim) - only present if token is tenant-scoped */
408
+ tenantId: string;
409
+ /** Tenant subdomain/slug (tenant_subdomain claim) */
410
+ tenantSubdomain?: string;
411
+ /** User's email (if email scope was requested) */
412
+ email?: string;
413
+ /** User's tenant roles (tenant_roles claim) */
414
+ tenant_roles?: string[];
415
+ /** Full JWT payload */
416
+ payload: JwtPayload;
417
+ }
418
+ type RequestLike = Request | {
419
+ headers: {
420
+ authorization?: string;
421
+ Authorization?: string;
422
+ };
423
+ } | {
424
+ headers: Headers;
425
+ } | {
426
+ headers: {
427
+ get: (name: string) => string | null;
428
+ };
429
+ };
430
+ /**
431
+ * Extract Authorization header from various request types
432
+ */
433
+ declare function extractAuthorizationHeader(request: RequestLike): string | null;
434
+ /**
435
+ * Append client_id query parameter to a URI
436
+ * Handles URIs that already have query params
437
+ */
438
+ declare function appendClientIdToUri(uri: string | null, clientId: string): string | null;
439
+ /**
440
+ * Base client with shared HTTP utilities and token management.
441
+ *
442
+ * Provides:
443
+ * - M2M token management (client_credentials flow)
444
+ * - Authenticated requests (forwarding user JWTs)
445
+ * - JWT validation and claims extraction
446
+ */
447
+ declare class BaseClient {
448
+ readonly config: AuthVitalConfig;
449
+ readonly jwtValidator: JwtValidator;
450
+ private accessToken;
451
+ private tokenExpiresAt;
452
+ constructor(config: AuthVitalConfig);
453
+ /**
454
+ * Validate JWT from an incoming request and return the decoded user.
455
+ *
456
+ * - Extracts Authorization header from the request
457
+ * - Validates JWT signature using cached JWKS (public endpoint, no auth needed)
458
+ * - Returns decoded JWT payload
459
+ * - Does NOT call the IDP
460
+ *
461
+ * @example
462
+ * ```ts
463
+ * // Express
464
+ * app.get('/api/auth/me', async (req, res) => {
465
+ * const { authenticated, user, error } = await authvital.getCurrentUser(req);
466
+ * if (!authenticated) return res.status(401).json({ error });
467
+ * res.json(user);
468
+ * });
469
+ * ```
470
+ */
471
+ getCurrentUser(request: RequestLike): Promise<GetCurrentUserResult>;
472
+ /**
473
+ * Validate the JWT from an incoming request and extract key claims.
474
+ *
475
+ * This is the recommended way to get user/tenant context for API calls.
476
+ * Throws an error if the token is invalid or missing required claims.
477
+ *
478
+ * @param request - The incoming HTTP request (Express, Next.js, Fetch API, etc.)
479
+ * @returns Validated claims including sub (userId) and tenantId
480
+ * @throws Error if token is invalid or missing tenant_id claim
481
+ *
482
+ * @example
483
+ * ```ts
484
+ * // Express
485
+ * app.get('/api/members', async (req, res) => {
486
+ * const claims = await authvital.validateRequest(req);
487
+ * const members = await authvital.memberships.listForApplication(claims);
488
+ * res.json(members);
489
+ * });
490
+ * ```
491
+ */
492
+ validateRequest(request: RequestLike): Promise<ValidatedClaims>;
493
+ /**
494
+ * Get M2M access token (client_credentials flow)
495
+ *
496
+ * Returns cached token if still valid, otherwise fetches a new one.
497
+ */
498
+ getAccessToken(): Promise<string>;
499
+ /**
500
+ * Make an M2M authenticated request
501
+ *
502
+ * Uses client_credentials token for machine-to-machine calls.
503
+ */
504
+ request<T>(method: 'GET' | 'POST' | 'PUT' | 'DELETE', path: string, body?: unknown, isRetry?: boolean): Promise<T>;
505
+ /**
506
+ * Make an authenticated request using the JWT from the original request
507
+ *
508
+ * This version forwards the user's JWT token instead of using the
509
+ * M2M (client_credentials) token. Used for endpoints that require
510
+ * user context and validate tenant permissions.
511
+ *
512
+ * @param originalRequest - The incoming request with JWT
513
+ * @param method - HTTP method
514
+ * @param path - API path
515
+ * @param body - Request body (for POST/PUT)
516
+ * @returns Parsed response
517
+ * @throws Error if request fails or JWT is required
518
+ */
519
+ authenticatedRequest<T>(originalRequest: RequestLike, method: 'GET' | 'POST' | 'PUT' | 'DELETE', path: string, body?: unknown): Promise<T>;
520
+ }
521
+
522
+ /**
523
+ * @authvital/sdk - Sessions Namespace (Token Ghosting)
524
+ *
525
+ * Manage user sessions: list, revoke specific sessions, or logout everywhere.
526
+ */
527
+
528
+ interface SessionInfo {
529
+ id: string;
530
+ createdAt: string;
531
+ expiresAt: string;
532
+ userAgent: string | null;
533
+ ipAddress: string | null;
534
+ tenant: string | null;
535
+ }
536
+ interface SessionsListResponse {
537
+ sessions: SessionInfo[];
538
+ count: number;
539
+ }
540
+ interface SessionRevokeResponse {
541
+ success: boolean;
542
+ message: string;
543
+ }
544
+ interface LogoutAllResponse {
545
+ success: boolean;
546
+ message: string;
547
+ count: number;
548
+ }
549
+ /**
550
+ * Creates the sessions namespace with all session management methods.
551
+ *
552
+ * @param client - The base client instance for making authenticated requests
553
+ * @returns Object containing all session methods
554
+ */
555
+ declare function createSessionsNamespace(client: BaseClient): {
556
+ /**
557
+ * Get all active sessions for the authenticated user
558
+ *
559
+ * Returns a list of active sessions with metadata (device info, location, etc.).
560
+ * Useful for building "manage sessions" UI.
561
+ *
562
+ * @example
563
+ * ```ts
564
+ * app.get('/api/sessions', async (req, res) => {
565
+ * const { sessions, count } = await authvital.sessions.list(req);
566
+ * res.json(sessions);
567
+ * });
568
+ * ```
569
+ */
570
+ list: (request: RequestLike, options?: {
571
+ applicationId?: string;
572
+ }) => Promise<SessionsListResponse>;
573
+ /**
574
+ * Revoke a specific session by ID
575
+ *
576
+ * Call this from "manage sessions" UI to logout a specific device.
577
+ * User can only revoke their own sessions.
578
+ *
579
+ * @example
580
+ * ```ts
581
+ * app.post('/api/sessions/:id/revoke', async (req, res) => {
582
+ * const result = await authvital.sessions.revoke(req, req.params.id);
583
+ * res.json(result);
584
+ * });
585
+ * ```
586
+ */
587
+ revoke: (request: RequestLike, sessionId: string) => Promise<SessionRevokeResponse>;
588
+ /**
589
+ * Revoke ALL sessions for the authenticated user
590
+ *
591
+ * Call this when user clicks "logout everywhere".
592
+ * Revokes all active sessions, forcing re-authentication on all devices.
593
+ *
594
+ * @example
595
+ * ```ts
596
+ * app.post('/api/logout-all', async (req, res) => {
597
+ * const result = await authvital.sessions.revokeAll(req);
598
+ * res.json({ message: `Logged out of ${result.count} devices` });
599
+ * });
600
+ * ```
601
+ */
602
+ revokeAll: (request: RequestLike, options?: {
603
+ applicationId?: string;
604
+ }) => Promise<LogoutAllResponse>;
605
+ /**
606
+ * Logout current session
607
+ *
608
+ * Revokes the session associated with the current refresh token.
609
+ * Call this for normal logout.
610
+ *
611
+ * Note: For browser apps, prefer redirecting to /oauth/logout which
612
+ * handles cookie clearing automatically.
613
+ *
614
+ * @example
615
+ * ```ts
616
+ * app.post('/api/logout', async (req, res) => {
617
+ * // Get refresh token from cookie or body
618
+ * const refreshToken = req.cookies.refresh_token || req.body.refresh_token;
619
+ * const result = await authvital.sessions.logout(refreshToken);
620
+ * res.clearCookie('refresh_token');
621
+ * res.json(result);
622
+ * });
623
+ * ```
624
+ */
625
+ logout: (refreshToken: string) => Promise<SessionRevokeResponse>;
626
+ };
627
+ type SessionsNamespace = ReturnType<typeof createSessionsNamespace>;
628
+
629
+ /**
630
+ * @authvital/sdk - Server-Side Types
631
+ *
632
+ * Clean, well-organized type definitions for the AuthVital server SDK.
633
+ *
634
+ * ╔════════════════════════════════════════════════════════════════════════════╗
635
+ * ║ IMPORTANT: CANONICAL TYPE SYNCHRONIZATION ║
636
+ * ╠════════════════════════════════════════════════════════════════════════════╣
637
+ * ║ The following types are COPIES of canonical definitions: ║
638
+ * ║ ║
639
+ * ║ - SubscriptionSummary ║
640
+ * ║ - SubscriptionStatusType ║
641
+ * ║ - MemberWithLicenses ║
642
+ * ║ - MembershipStatusType ║
643
+ * ║ - AvailableLicenseType ║
644
+ * ║ - TenantLicenseOverview ║
645
+ * ║ ║
646
+ * ║ SOURCE OF TRUTH: backend/src/common/types/licensing.types.ts ║
647
+ * ║ ║
648
+ * ║ When updating these types, ALWAYS update the canonical source first, ║
649
+ * ║ then sync changes here to maintain consistency. ║
650
+ * ╚════════════════════════════════════════════════════════════════════════════╝
651
+ */
652
+ /**
653
+ * Subscription status values.
654
+ * @sync backend/src/common/types/licensing.types.ts
655
+ */
656
+ type SubscriptionStatusType = 'ACTIVE' | 'TRIALING' | 'PAST_DUE' | 'CANCELED' | 'EXPIRED';
657
+ /**
658
+ * Membership status values.
659
+ * @sync backend/src/common/types/licensing.types.ts
660
+ */
661
+ type MembershipStatusType = 'ACTIVE' | 'INVITED' | 'SUSPENDED';
662
+ /**
663
+ * Summary of a tenant's subscription (license inventory).
664
+ * @sync backend/src/common/types/licensing.types.ts
665
+ */
666
+ interface SubscriptionSummary {
667
+ id: string;
668
+ applicationId: string;
669
+ applicationName: string;
670
+ licenseTypeId: string;
671
+ licenseTypeName: string;
672
+ licenseTypeSlug: string;
673
+ quantityPurchased: number;
674
+ quantityAssigned: number;
675
+ quantityAvailable: number;
676
+ status: SubscriptionStatusType;
677
+ currentPeriodEnd: string;
678
+ features: Record<string, boolean>;
679
+ }
680
+ /**
681
+ * A tenant member with their license assignments.
682
+ * @sync backend/src/common/types/licensing.types.ts
683
+ */
684
+ interface MemberWithLicenses {
685
+ user: {
686
+ id: string;
687
+ email: string | null;
688
+ givenName: string | null;
689
+ familyName: string | null;
690
+ };
691
+ membership: {
692
+ id: string;
693
+ status: MembershipStatusType;
694
+ };
695
+ licenses: Array<{
696
+ id: string;
697
+ applicationId: string;
698
+ applicationName: string;
699
+ licenseTypeId: string;
700
+ licenseTypeName: string;
701
+ licenseTypeSlug: string;
702
+ assignedAt: string;
703
+ }>;
704
+ }
705
+ /**
706
+ * A license type available for provisioning.
707
+ * @sync backend/src/common/types/licensing.types.ts
708
+ */
709
+ interface AvailableLicenseType {
710
+ id: string;
711
+ name: string;
712
+ slug: string;
713
+ description: string | null;
714
+ applicationId: string;
715
+ applicationName: string;
716
+ features: Record<string, boolean>;
717
+ displayOrder: number;
718
+ hasSubscription: boolean;
719
+ existingSubscription?: {
720
+ id: string;
721
+ quantityPurchased: number;
722
+ quantityAssigned: number;
723
+ };
724
+ }
725
+ /**
726
+ * Full license overview for a tenant.
727
+ * @sync backend/src/common/types/licensing.types.ts
728
+ */
729
+ interface TenantLicenseOverview {
730
+ tenantId: string;
731
+ subscriptions: SubscriptionSummary[];
732
+ totalSeatsOwned: number;
733
+ totalSeatsAssigned: number;
734
+ }
735
+ interface AuthVitalClientConfig {
736
+ /** AuthVital server URL (e.g., https://auth.yourapp.com) */
737
+ authVitalHost: string;
738
+ /** OAuth client_id for your application */
739
+ clientId: string;
740
+ /** OAuth client_secret for your application */
741
+ clientSecret: string;
742
+ /** Optional: Scopes to request (default: 'system:admin') */
743
+ scope?: string;
744
+ }
745
+ interface OAuthFlowConfig {
746
+ /** AuthVital server URL */
747
+ authVitalHost: string;
748
+ /** OAuth client_id */
749
+ clientId: string;
750
+ /** OAuth client_secret (optional for public clients) */
751
+ clientSecret?: string;
752
+ /** OAuth redirect URI */
753
+ redirectUri: string;
754
+ /** OAuth scopes */
755
+ scope?: string;
756
+ }
757
+ interface TokenResponse {
758
+ access_token: string;
759
+ token_type: string;
760
+ expires_in: number;
761
+ refresh_token?: string;
762
+ id_token?: string;
763
+ scope?: string;
764
+ }
765
+ /**
766
+ * License information included in JWT
767
+ */
768
+ interface JwtLicenseInfo {
769
+ /** License type slug (e.g., "pro", "enterprise") */
770
+ type: string;
771
+ /** License type display name */
772
+ name: string;
773
+ /** Enabled feature keys */
774
+ features: string[];
775
+ }
776
+ /**
777
+ * Enhanced JWT payload with OIDC standard claims
778
+ *
779
+ * This represents the decoded JWT token contents from AuthVital.
780
+ * Claims are included based on requested OAuth scopes.
781
+ */
782
+ interface EnhancedJwtPayload {
783
+ /** Subject (user ID) */
784
+ sub: string;
785
+ /** Audience (client ID) */
786
+ aud: string | string[];
787
+ /** Issuer (AuthVital URL) */
788
+ iss: string;
789
+ /** Issued at (unix timestamp) */
790
+ iat: number;
791
+ /** Expiration (unix timestamp) */
792
+ exp: number;
793
+ /** Unique handle - OIDC: preferred_username */
794
+ preferred_username?: string;
795
+ /** Full display name - OIDC: name */
796
+ name?: string;
797
+ /** First name - OIDC: given_name */
798
+ given_name?: string;
799
+ /** Last name - OIDC: family_name */
800
+ family_name?: string;
801
+ /** Middle name(s) - OIDC: middle_name */
802
+ middle_name?: string;
803
+ /** Casual name - OIDC: nickname */
804
+ nickname?: string;
805
+ /** Profile picture URL - OIDC: picture */
806
+ picture?: string;
807
+ /** Personal URL - OIDC: website */
808
+ website?: string;
809
+ /** Gender identity - OIDC: gender */
810
+ gender?: string;
811
+ /** Birth date (YYYY-MM-DD) - OIDC: birthdate */
812
+ birthdate?: string;
813
+ /** IANA timezone - OIDC: zoneinfo */
814
+ zoneinfo?: string;
815
+ /** Language/region - OIDC: locale */
816
+ locale?: string;
817
+ /** Last profile update (unix timestamp) - OIDC: updated_at */
818
+ updated_at?: number;
819
+ /** Email address - OIDC: email */
820
+ email?: string;
821
+ /** Whether email is verified - OIDC: email_verified */
822
+ email_verified?: boolean;
823
+ /** Phone number (E.164) - OIDC: phone_number */
824
+ phone_number?: string;
825
+ /** Whether phone is verified - OIDC: phone_number_verified */
826
+ phone_number_verified?: boolean;
827
+ /** Current tenant ID (when token is tenant-scoped) */
828
+ tenant_id?: string;
829
+ /** Tenant subdomain */
830
+ tenant_subdomain?: string;
831
+ /** Tenant-level roles (from TenantRole) */
832
+ tenant_roles?: string[];
833
+ /** Tenant-level permissions */
834
+ tenant_permissions?: string[];
835
+ /** Application-specific roles (from Role) */
836
+ app_roles?: string[];
837
+ /** Application-specific permissions */
838
+ app_permissions?: string[];
839
+ /** Groups the user belongs to in the current tenant */
840
+ groups?: string[];
841
+ /** License info for current app */
842
+ license?: JwtLicenseInfo;
843
+ /** Granted scopes */
844
+ scope?: string;
845
+ [key: string]: unknown;
846
+ }
847
+ interface InvitationResponse {
848
+ /** The user's ID (sub claim in JWT) */
849
+ sub: string;
850
+ /** When the invitation expires */
851
+ expiresAt: string;
852
+ }
853
+ interface PendingInvitation {
854
+ id: string;
855
+ email: string;
856
+ role: string;
857
+ expiresAt: string;
858
+ createdAt: string;
859
+ invitedBy: {
860
+ id: string;
861
+ email: string | null;
862
+ givenName: string | null;
863
+ familyName: string | null;
864
+ } | null;
865
+ }
866
+ interface PendingInvitationsResponse {
867
+ tenantId: string;
868
+ tenantName: string;
869
+ invitations: PendingInvitation[];
870
+ totalCount: number;
871
+ }
872
+ interface SendInvitationParams {
873
+ email: string;
874
+ /** User's first name (used if creating new user) */
875
+ givenName?: string;
876
+ /** User's last name (used if creating new user) */
877
+ familyName?: string;
878
+ /**
879
+ * Tenant role ID to assign when invitation is accepted.
880
+ * Required. Get available role IDs from `authvital.memberships.getTenantRoles()`.
881
+ */
882
+ roleId: string;
883
+ expiresInDays?: number;
884
+ /** Application clientId - determines redirect URL after acceptance */
885
+ clientId?: string;
886
+ }
887
+ interface ResendInvitationParams {
888
+ invitationId: string;
889
+ expiresInDays?: number;
890
+ }
891
+ interface RevokeInvitationResponse {
892
+ success: boolean;
893
+ message: string;
894
+ }
895
+ interface MembershipUser {
896
+ id: string;
897
+ email: string | null;
898
+ givenName: string | null;
899
+ familyName: string | null;
900
+ }
901
+ interface MembershipRole {
902
+ id: string;
903
+ name: string;
904
+ slug: string;
905
+ applicationId: string;
906
+ applicationName: string;
907
+ }
908
+ interface TenantMembership {
909
+ id: string;
910
+ status: string;
911
+ joinedAt: string | null;
912
+ createdAt: string;
913
+ user: MembershipUser;
914
+ roles: MembershipRole[];
915
+ }
916
+ interface TenantMembershipsResponse {
917
+ tenantId: string;
918
+ tenantName: string;
919
+ tenantSlug: string;
920
+ initiateLoginUri: string | null;
921
+ memberships: TenantMembership[];
922
+ totalCount: number;
923
+ }
924
+ interface ApplicationMembership {
925
+ id: string;
926
+ status: string;
927
+ joinedAt: string | null;
928
+ createdAt: string;
929
+ user: MembershipUser;
930
+ tenant: {
931
+ id: string;
932
+ name: string;
933
+ slug: string;
934
+ initiateLoginUri: string | null;
935
+ };
936
+ roles: MembershipRole[];
937
+ }
938
+ interface ApplicationMembershipsResponse {
939
+ applicationId: string;
940
+ applicationName: string;
941
+ clientId: string;
942
+ memberships: ApplicationMembership[];
943
+ totalCount: number;
944
+ }
945
+ interface ValidateMembershipResponse {
946
+ isMember: boolean;
947
+ membership: {
948
+ id: string;
949
+ status: string;
950
+ joinedAt: string | null;
951
+ } | null;
952
+ }
953
+ interface UserTenantMembership {
954
+ id: string;
955
+ status: string;
956
+ joinedAt: string | null;
957
+ createdAt: string;
958
+ tenant: {
959
+ id: string;
960
+ name: string;
961
+ slug: string;
962
+ initiateLoginUri: string | null;
963
+ };
964
+ roles: MembershipRole[];
965
+ }
966
+ interface UserTenantsResponse {
967
+ userId: string;
968
+ memberships: UserTenantMembership[];
969
+ totalCount: number;
970
+ }
971
+ interface TenantRoleDefinition {
972
+ id: string;
973
+ name: string;
974
+ slug: string;
975
+ description: string | null;
976
+ isSystem: boolean;
977
+ permissions: string[];
978
+ }
979
+ interface TenantRolesResponse {
980
+ roles: TenantRoleDefinition[];
981
+ }
982
+ interface ApplicationRoleDefinition {
983
+ id: string;
984
+ name: string;
985
+ slug: string;
986
+ description: string | null;
987
+ isSystem: boolean;
988
+ permissions: string[];
989
+ }
990
+ interface ApplicationRolesResponse {
991
+ applicationId: string;
992
+ applicationName: string;
993
+ clientId: string;
994
+ roles: ApplicationRoleDefinition[];
995
+ }
996
+ interface SetMemberRoleResponse {
997
+ success: boolean;
998
+ message: string;
999
+ role: {
1000
+ id: string;
1001
+ name: string;
1002
+ slug: string;
1003
+ };
1004
+ }
1005
+ interface CheckPermissionParams {
1006
+ userId: string;
1007
+ tenantId: string;
1008
+ permission: string;
1009
+ }
1010
+ interface CheckPermissionResult {
1011
+ allowed: boolean;
1012
+ reason?: string;
1013
+ }
1014
+ interface CheckPermissionsParams {
1015
+ userId: string;
1016
+ tenantId: string;
1017
+ permissions: string[];
1018
+ }
1019
+ interface CheckPermissionsResult {
1020
+ results: Record<string, boolean>;
1021
+ allAllowed: boolean;
1022
+ }
1023
+ interface UserPermissions {
1024
+ permissions: string[];
1025
+ roles: Array<{
1026
+ id: string;
1027
+ name: string;
1028
+ slug: string;
1029
+ }>;
1030
+ }
1031
+ /**
1032
+ * Result of checking a quota
1033
+ */
1034
+ interface QuotaCheckResult {
1035
+ /** Whether the action is allowed */
1036
+ allowed: boolean;
1037
+ /** Current usage count */
1038
+ currentUsage?: number;
1039
+ /** The limit */
1040
+ limit?: number;
1041
+ /** Reason if not allowed */
1042
+ reason?: string;
1043
+ /** Whether this would trigger overage billing */
1044
+ wouldTriggerOverage?: boolean;
1045
+ /** The overage price ID if applicable */
1046
+ overagePriceId?: string | null;
1047
+ }
1048
+ /**
1049
+ * Result of checking a feature flag
1050
+ */
1051
+ interface FeatureCheckResult {
1052
+ /** Whether the feature is enabled */
1053
+ hasAccess: boolean;
1054
+ /** The license type slug */
1055
+ licenseType: string | null;
1056
+ /** Reason if not enabled */
1057
+ reason?: string;
1058
+ }
1059
+ /**
1060
+ * User's license assignment info
1061
+ */
1062
+ interface UserLicenseAssignment {
1063
+ id: string;
1064
+ userId: string;
1065
+ applicationId: string;
1066
+ applicationName: string;
1067
+ licenseTypeId: string;
1068
+ licenseTypeName: string;
1069
+ licenseTypeSlug: string;
1070
+ features: Record<string, boolean>;
1071
+ assignedAt: string;
1072
+ assignedById?: string;
1073
+ }
1074
+ /**
1075
+ * Parameters for granting a license (M2M)
1076
+ */
1077
+ interface GrantLicenseParams {
1078
+ tenantId: string;
1079
+ userId: string;
1080
+ applicationId: string;
1081
+ licenseTypeId: string;
1082
+ }
1083
+ /**
1084
+ * Parameters for revoking a license (M2M)
1085
+ */
1086
+ interface RevokeLicenseParams {
1087
+ tenantId: string;
1088
+ userId: string;
1089
+ applicationId: string;
1090
+ }
1091
+ /**
1092
+ * Parameters for changing license type (M2M)
1093
+ */
1094
+ interface ChangeLicenseTypeParams {
1095
+ tenantId: string;
1096
+ userId: string;
1097
+ applicationId: string;
1098
+ newLicenseTypeId: string;
1099
+ }
1100
+ /**
1101
+ * Bulk grant license result
1102
+ */
1103
+ interface BulkGrantLicenseResult {
1104
+ userId: string;
1105
+ applicationId: string;
1106
+ success: boolean;
1107
+ error?: string;
1108
+ }
1109
+ /**
1110
+ * Bulk revoke license result
1111
+ */
1112
+ interface BulkRevokeLicenseResult {
1113
+ revokedCount: number;
1114
+ failures: Array<{
1115
+ userId: string;
1116
+ applicationId: string;
1117
+ error: string;
1118
+ }>;
1119
+ }
1120
+
1121
+ /**
1122
+ * Main AuthVital SDK client.
1123
+ *
1124
+ * Extends BaseClient with namespaced APIs for:
1125
+ * - Invitations (send, list, resend, revoke)
1126
+ * - Memberships (list, validate, roles)
1127
+ * - Permissions (check, list)
1128
+ * - Entitlements (quotas, features)
1129
+ * - Licenses (grant, revoke, check)
1130
+ * - Sessions (list, revoke, logout)
1131
+ */
1132
+ declare class AuthVital extends BaseClient {
1133
+ readonly invitations: {
1134
+ send: (request: RequestLike, params: Omit<SendInvitationParams, "tenantId">) => Promise<InvitationResponse>;
1135
+ listPending: (request: RequestLike) => Promise<PendingInvitationsResponse>;
1136
+ resend: (request: RequestLike, params: ResendInvitationParams) => Promise<{
1137
+ expiresAt: string;
1138
+ }>;
1139
+ revoke: (request: RequestLike, invitationId: string) => Promise<RevokeInvitationResponse>;
1140
+ };
1141
+ readonly memberships: {
1142
+ listForTenant: (request: RequestLike, options?: {
1143
+ status?: "ACTIVE" | "INVITED" | "SUSPENDED";
1144
+ includeRoles?: boolean;
1145
+ appendClientId?: boolean;
1146
+ }) => Promise<TenantMembershipsResponse>;
1147
+ listForApplication: (request: RequestLike, options?: {
1148
+ status?: "ACTIVE" | "INVITED" | "SUSPENDED";
1149
+ appendClientId?: boolean;
1150
+ }) => Promise<ApplicationMembershipsResponse>;
1151
+ validate: (request: RequestLike) => Promise<ValidateMembershipResponse>;
1152
+ listTenantsForUser: (request: RequestLike, options?: {
1153
+ status?: "ACTIVE" | "INVITED" | "SUSPENDED";
1154
+ includeRoles?: boolean;
1155
+ appendClientId?: boolean;
1156
+ }) => Promise<UserTenantsResponse>;
1157
+ getTenantRoles: () => Promise<TenantRolesResponse>;
1158
+ getApplicationRoles: () => Promise<ApplicationRolesResponse>;
1159
+ setMemberRole: (request: RequestLike, membershipId: string, roleSlug: string) => Promise<SetMemberRoleResponse>;
1160
+ };
1161
+ readonly permissions: {
1162
+ check: (request: RequestLike, permission: string) => Promise<CheckPermissionResult>;
1163
+ checkMany: (request: RequestLike, permissions: string[]) => Promise<CheckPermissionsResult>;
1164
+ list: (request: RequestLike) => Promise<UserPermissions>;
1165
+ };
1166
+ readonly entitlements: {
1167
+ canPerform: (request: RequestLike, featureKey: string, _options?: {
1168
+ appScope?: string;
1169
+ incrementCount?: number;
1170
+ }) => Promise<QuotaCheckResult>;
1171
+ decrementUsage: (request: RequestLike, featureKey: string, options?: {
1172
+ appScope?: string;
1173
+ by?: number;
1174
+ }) => Promise<{
1175
+ newUsage: number;
1176
+ }>;
1177
+ };
1178
+ readonly licenses: {
1179
+ getTenantOverview: (tenantId: string) => Promise<TenantLicenseOverview>;
1180
+ getUserLicenses: (tenantId: string, userId: string) => Promise<UserLicenseAssignment[]>;
1181
+ getTenantSubscriptions: (tenantId: string) => Promise<SubscriptionSummary[]>;
1182
+ getMembersWithLicenses: (tenantId: string) => Promise<MemberWithLicenses[]>;
1183
+ getAvailableLicenseTypes: (tenantId: string) => Promise<AvailableLicenseType[]>;
1184
+ grantToUser: (params: GrantLicenseParams) => Promise<UserLicenseAssignment>;
1185
+ revokeFromUser: (params: RevokeLicenseParams) => Promise<void>;
1186
+ changeUserType: (params: ChangeLicenseTypeParams) => Promise<UserLicenseAssignment>;
1187
+ grantBulk: (assignments: GrantLicenseParams[]) => Promise<BulkGrantLicenseResult[]>;
1188
+ revokeBulk: (revocations: RevokeLicenseParams[]) => Promise<BulkRevokeLicenseResult>;
1189
+ grant: (request: RequestLike, options: {
1190
+ userId?: string;
1191
+ applicationId: string;
1192
+ licenseTypeId: string;
1193
+ }) => Promise<LicenseGrantResponse>;
1194
+ revoke: (request: RequestLike, options: {
1195
+ userId?: string;
1196
+ applicationId: string;
1197
+ }) => Promise<LicenseRevokeResponse>;
1198
+ changeType: (request: RequestLike, options: {
1199
+ userId?: string;
1200
+ applicationId: string;
1201
+ newLicenseTypeId: string;
1202
+ }) => Promise<LicenseRevokeResponse>;
1203
+ listForUser: (request: RequestLike, userId?: string) => Promise<UserLicenseListItem[]>;
1204
+ check: (request: RequestLike, userId: string | undefined, applicationId: string) => Promise<LicenseCheckResponse>;
1205
+ hasFeature: (request: RequestLike, userId: string | undefined, applicationId: string, featureKey: string) => Promise<LicenseFeatureResponse>;
1206
+ getAppLicensedUsers: (request: RequestLike, applicationId: string) => Promise<LicensedUser[]>;
1207
+ countLicensedUsers: (request: RequestLike, applicationId: string) => Promise<{
1208
+ count: number;
1209
+ }>;
1210
+ getUserLicenseType: (request: RequestLike, userId: string | undefined, applicationId: string) => Promise<string | null>;
1211
+ getHolders: (request: RequestLike, applicationId: string) => Promise<LicenseHolder[]>;
1212
+ getAuditLog: (request: RequestLike, options?: {
1213
+ userId?: string;
1214
+ applicationId?: string;
1215
+ limit?: number;
1216
+ offset?: number;
1217
+ }) => Promise<LicenseAuditLogResponse>;
1218
+ getUsageOverview: (request: RequestLike) => Promise<UsageOverviewResponse>;
1219
+ getUsageTrends: (request: RequestLike, days?: number) => Promise<UsageTrendEntry[]>;
1220
+ };
1221
+ readonly sessions: {
1222
+ list: (request: RequestLike, options?: {
1223
+ applicationId?: string;
1224
+ }) => Promise<SessionsListResponse>;
1225
+ revoke: (request: RequestLike, sessionId: string) => Promise<SessionRevokeResponse>;
1226
+ revokeAll: (request: RequestLike, options?: {
1227
+ applicationId?: string;
1228
+ }) => Promise<LogoutAllResponse>;
1229
+ logout: (refreshToken: string) => Promise<SessionRevokeResponse>;
1230
+ };
1231
+ /**
1232
+ * Check tenant permission from JWT (no API call)
1233
+ * Returns true if user has the specified tenant permission.
1234
+ *
1235
+ * Reads from the `tenant_permissions` claim in the JWT.
1236
+ * Wildcards are supported (e.g., `licenses:*` matches `licenses:manage`).
1237
+ *
1238
+ * @example
1239
+ * ```ts
1240
+ * if (await authvital.hasTenantPermission(req, 'licenses:manage')) {
1241
+ * // User can manage licenses - show admin UI
1242
+ * }
1243
+ * ```
1244
+ */
1245
+ hasTenantPermission(request: RequestLike, permission: string): Promise<boolean>;
1246
+ /**
1247
+ * Check app permission from JWT (no API call)
1248
+ * Returns true if user has the specified app permission.
1249
+ *
1250
+ * Reads from the `app_permissions` claim in the JWT.
1251
+ *
1252
+ * @example
1253
+ * ```ts
1254
+ * if (await authvital.hasAppPermission(req, 'projects:create')) {
1255
+ * // User can create projects
1256
+ * }
1257
+ * ```
1258
+ */
1259
+ hasAppPermission(request: RequestLike, permission: string): Promise<boolean>;
1260
+ /**
1261
+ * Check feature from JWT license claim (no API call)
1262
+ * Returns true if the feature is enabled in the user's license.
1263
+ *
1264
+ * Reads from the `license.features` array in the JWT.
1265
+ *
1266
+ * @example
1267
+ * ```ts
1268
+ * if (await authvital.hasFeatureFromJwt(req, 'sso')) {
1269
+ * // User's tenant has SSO enabled
1270
+ * }
1271
+ * ```
1272
+ */
1273
+ hasFeatureFromJwt(request: RequestLike, featureKey: string): Promise<boolean>;
1274
+ /**
1275
+ * Get license type from JWT (no API call)
1276
+ * Returns the license type slug (e.g., 'pro', 'enterprise') or null.
1277
+ *
1278
+ * Reads from the `license.type` claim in the JWT.
1279
+ *
1280
+ * @example
1281
+ * ```ts
1282
+ * const licenseType = await authvital.getLicenseTypeFromJwt(req);
1283
+ * if (licenseType === 'enterprise') {
1284
+ * // Show enterprise features
1285
+ * }
1286
+ * ```
1287
+ */
1288
+ getLicenseTypeFromJwt(request: RequestLike): Promise<string | null>;
1289
+ /**
1290
+ * Get all tenant permissions from JWT (no API call)
1291
+ * Returns the array of tenant permissions granted to the user.
1292
+ *
1293
+ * @example
1294
+ * ```ts
1295
+ * const permissions = await authvital.getTenantPermissions(req);
1296
+ * console.log(permissions); // ['licenses:view', 'members:invite', ...]
1297
+ * ```
1298
+ */
1299
+ getTenantPermissions(request: RequestLike): Promise<string[]>;
1300
+ /**
1301
+ * Get all app permissions from JWT (no API call)
1302
+ * Returns the array of app permissions granted to the user.
1303
+ *
1304
+ * @example
1305
+ * ```ts
1306
+ * const permissions = await authvital.getAppPermissions(req);
1307
+ * console.log(permissions); // ['projects:create', 'datasets:read', ...]
1308
+ * ```
1309
+ */
1310
+ getAppPermissions(request: RequestLike): Promise<string[]>;
1311
+ /**
1312
+ * Get all tenant roles from JWT (no API call)
1313
+ * Returns the array of tenant role slugs for the user.
1314
+ *
1315
+ * @example
1316
+ * ```ts
1317
+ * const roles = await authvital.getTenantRoles(req);
1318
+ * console.log(roles); // ['owner', 'admin']
1319
+ * ```
1320
+ */
1321
+ getTenantRoles(request: RequestLike): Promise<string[]>;
1322
+ /**
1323
+ * Get all app roles from JWT (no API call)
1324
+ * Returns the array of app role slugs for the user.
1325
+ *
1326
+ * @example
1327
+ * ```ts
1328
+ * const roles = await authvital.getAppRoles(req);
1329
+ * console.log(roles); // ['editor', 'viewer']
1330
+ * ```
1331
+ */
1332
+ getAppRoles(request: RequestLike): Promise<string[]>;
1333
+ /**
1334
+ * Get URL for tenant members management page
1335
+ * Extracts tenantId from the request JWT
1336
+ */
1337
+ getMembersUrl(req: RequestLike): Promise<string>;
1338
+ /**
1339
+ * Get URL for tenant applications management page
1340
+ * Extracts tenantId from the request JWT
1341
+ */
1342
+ getApplicationsUrl(req: RequestLike): Promise<string>;
1343
+ /**
1344
+ * Get URL for tenant settings page
1345
+ * Extracts tenantId from the request JWT
1346
+ */
1347
+ getSettingsUrl(req: RequestLike): Promise<string>;
1348
+ /**
1349
+ * Get URL for tenant overview page
1350
+ * Extracts tenantId from the request JWT
1351
+ */
1352
+ getOverviewUrl(req: RequestLike): Promise<string>;
1353
+ /**
1354
+ * Get URL for user account settings page
1355
+ * (Does not require tenantId)
1356
+ */
1357
+ getAccountSettingsUrl(): string;
1358
+ /**
1359
+ * Get all management URLs at once
1360
+ * Extracts tenantId from the request JWT
1361
+ *
1362
+ * @example
1363
+ * ```typescript
1364
+ * const urls = await authvital.getManagementUrls(req);
1365
+ * res.json({ urls });
1366
+ * // {
1367
+ * // overview: 'https://auth.example.com/tenant/abc/overview',
1368
+ * // members: 'https://auth.example.com/tenant/abc/members',
1369
+ * // applications: 'https://auth.example.com/tenant/abc/applications',
1370
+ * // settings: 'https://auth.example.com/tenant/abc/settings',
1371
+ * // accountSettings: 'https://auth.example.com/account/settings',
1372
+ * // }
1373
+ * ```
1374
+ */
1375
+ getManagementUrls(req: RequestLike): Promise<{
1376
+ overview: string;
1377
+ members: string;
1378
+ applications: string;
1379
+ settings: string;
1380
+ accountSettings: string;
1381
+ }>;
1382
+ }
1383
+ /**
1384
+ * Create an AuthVital client instance.
1385
+ *
1386
+ * Configure once at startup, use everywhere.
1387
+ *
1388
+ * @example
1389
+ * ```ts
1390
+ * // lib/authvital.ts
1391
+ * import { createAuthVital } from '@authvital/sdk/server';
1392
+ *
1393
+ * export const authvital = createAuthVital({
1394
+ * authVitalHost: process.env.AV_HOST!,
1395
+ * clientId: process.env.AV_CLIENT_ID!,
1396
+ * clientSecret: process.env.AV_CLIENT_SECRET!,
1397
+ * });
1398
+ *
1399
+ * // Then use it anywhere:
1400
+ * import { authvital } from '@/lib/authvital';
1401
+ *
1402
+ * // Validate JWT from request (uses cached JWKS, no IDP auth needed)
1403
+ * const { user } = await authvital.getCurrentUser(request);
1404
+ *
1405
+ * // M2M calls (uses client_credentials automatically)
1406
+ * const members = await authvital.memberships.listForTenant('tenant-123');
1407
+ * ```
1408
+ */
1409
+ declare function createAuthVital(config: AuthVitalConfig): AuthVital;
1410
+
1411
+ /**
1412
+ * @authvital/sdk - Invitations Namespace
1413
+ *
1414
+ * Manage tenant invitations: send, list pending, resend, and revoke.
1415
+ */
1416
+
1417
+ /**
1418
+ * Creates the invitations namespace with all invitation-related methods.
1419
+ *
1420
+ * @param client - The base client instance for making authenticated requests
1421
+ * @returns Object containing all invitation methods
1422
+ */
1423
+ declare function createInvitationsNamespace(client: BaseClient): {
1424
+ /**
1425
+ * Send an invitation to join a tenant
1426
+ *
1427
+ * Automatically validates JWT and uses tenantId from it.
1428
+ * If a user with this email already exists, uses that user.
1429
+ * If not, creates a new user with the provided details.
1430
+ * Returns only the user's sub (ID) and invitation expiry for security.
1431
+ *
1432
+ * @example
1433
+ * ```ts
1434
+ * // First, get the role ID from available roles
1435
+ * const { roles } = await authvital.memberships.getTenantRoles();
1436
+ * const adminRole = roles.find(r => r.slug === 'admin');
1437
+ *
1438
+ * const { sub, expiresAt } = await authvital.invitations.send(request, {
1439
+ * email: 'newuser@example.com',
1440
+ * givenName: 'John',
1441
+ * familyName: 'Doe',
1442
+ * roleId: adminRole?.id, // Use role ID, not slug
1443
+ * });
1444
+ * // sub = user's ID (can be used in your app's database)
1445
+ * // expiresAt = when the invitation expires
1446
+ * ```
1447
+ */
1448
+ send: (request: RequestLike, params: Omit<SendInvitationParams, "tenantId">) => Promise<InvitationResponse>;
1449
+ /**
1450
+ * Get all pending invitations for a tenant
1451
+ *
1452
+ * Automatically validates JWT and uses tenantId from it.
1453
+ *
1454
+ * @example
1455
+ * ```ts
1456
+ * const { invitations, totalCount } = await authvital.invitations.listPending(request);
1457
+ * ```
1458
+ */
1459
+ listPending: (request: RequestLike) => Promise<PendingInvitationsResponse>;
1460
+ /**
1461
+ * Resend an invitation (generates new token, extends expiry)
1462
+ *
1463
+ * Automatically validates JWT and uses tenantId from it.
1464
+ * Returns the new expiration date
1465
+ *
1466
+ * @example
1467
+ * ```ts
1468
+ * const { expiresAt } = await authvital.invitations.resend(request, {
1469
+ * invitationId: 'inv-123',
1470
+ * expiresInDays: 7,
1471
+ * });
1472
+ * ```
1473
+ */
1474
+ resend: (request: RequestLike, params: ResendInvitationParams) => Promise<{
1475
+ expiresAt: string;
1476
+ }>;
1477
+ /**
1478
+ * Revoke an invitation
1479
+ *
1480
+ * @example
1481
+ * ```ts
1482
+ * await authvital.invitations.revoke(request, 'inv-123');
1483
+ * ```
1484
+ */
1485
+ revoke: (request: RequestLike, invitationId: string) => Promise<RevokeInvitationResponse>;
1486
+ };
1487
+ type InvitationsNamespace = ReturnType<typeof createInvitationsNamespace>;
1488
+
1489
+ /**
1490
+ * @authvital/sdk - Memberships Namespace
1491
+ *
1492
+ * Manage tenant and application memberships, roles, and user access.
1493
+ */
1494
+
1495
+ /**
1496
+ * Creates the memberships namespace with all membership-related methods.
1497
+ *
1498
+ * @param client - The base client instance for making authenticated requests
1499
+ * @returns Object containing all membership methods
1500
+ */
1501
+ declare function createMembershipsNamespace(client: BaseClient): {
1502
+ /**
1503
+ * Get all memberships for the authenticated user's tenant
1504
+ *
1505
+ * Automatically validates JWT and uses tenantId from it.
1506
+ *
1507
+ * @param request - The incoming HTTP request
1508
+ * @param options - Optional filters and configuration
1509
+ *
1510
+ * @example
1511
+ * ```ts
1512
+ * app.get('/api/team', async (req, res) => {
1513
+ * const members = await authvital.memberships.listForTenant(req, {
1514
+ * status: 'ACTIVE',
1515
+ * });
1516
+ * res.json(members);
1517
+ * });
1518
+ * ```
1519
+ */
1520
+ listForTenant: (request: RequestLike, options?: {
1521
+ status?: "ACTIVE" | "INVITED" | "SUSPENDED";
1522
+ includeRoles?: boolean;
1523
+ /** Append client_id to initiateLoginUri using SDK's configured clientId */
1524
+ appendClientId?: boolean;
1525
+ }) => Promise<TenantMembershipsResponse>;
1526
+ /**
1527
+ * Get all memberships for your application in the authenticated user's tenant
1528
+ *
1529
+ * Automatically uses clientId from SDK config and tenantId from the validated JWT.
1530
+ *
1531
+ * @param request - The incoming HTTP request
1532
+ * @param options - Optional filters and configuration
1533
+ *
1534
+ * @example
1535
+ * ```ts
1536
+ * app.get('/api/members', async (req, res) => {
1537
+ * const { memberships } = await authvital.memberships.listForApplication(req);
1538
+ * res.json(memberships);
1539
+ * });
1540
+ * ```
1541
+ */
1542
+ listForApplication: (request: RequestLike, options?: {
1543
+ status?: "ACTIVE" | "INVITED" | "SUSPENDED";
1544
+ /** Append client_id to each tenant's initiateLoginUri using SDK's configured clientId */
1545
+ appendClientId?: boolean;
1546
+ }) => Promise<ApplicationMembershipsResponse>;
1547
+ /**
1548
+ * Validate that the authenticated user is a member of their tenant
1549
+ *
1550
+ * @param request - The incoming HTTP request
1551
+ */
1552
+ validate: (request: RequestLike) => Promise<ValidateMembershipResponse>;
1553
+ /**
1554
+ * Get all tenants for the authenticated user
1555
+ *
1556
+ * Returns all tenants the user is a member of, with optional role information.
1557
+ *
1558
+ * @param request - The incoming HTTP request
1559
+ * @param options - Optional filters and configuration
1560
+ *
1561
+ * @example
1562
+ * ```ts
1563
+ * app.get('/api/my-tenants', async (req, res) => {
1564
+ * const result = await authvital.memberships.listTenantsForUser(req, {
1565
+ * status: 'ACTIVE',
1566
+ * appendClientId: true,
1567
+ * });
1568
+ * res.json(result.memberships);
1569
+ * });
1570
+ * ```
1571
+ */
1572
+ listTenantsForUser: (request: RequestLike, options?: {
1573
+ status?: "ACTIVE" | "INVITED" | "SUSPENDED";
1574
+ includeRoles?: boolean;
1575
+ /** Append client_id to each tenant's initiateLoginUri using SDK's configured clientId */
1576
+ appendClientId?: boolean;
1577
+ }) => Promise<UserTenantsResponse>;
1578
+ /**
1579
+ * Get all available tenant roles (IDP-level)
1580
+ *
1581
+ * Returns the role definitions (owner, admin, member, etc.) that can be
1582
+ * assigned to memberships. These are instance-wide, not tenant-specific.
1583
+ * Use this to populate a role picker dropdown.
1584
+ *
1585
+ * @example
1586
+ * ```ts
1587
+ * app.get('/api/roles', async (req, res) => {
1588
+ * const { roles } = await authvital.memberships.getTenantRoles();
1589
+ * res.json(roles);
1590
+ * // [{ slug: 'owner', name: 'Owner', ... }, { slug: 'admin', ... }, ...]
1591
+ * });
1592
+ * ```
1593
+ */
1594
+ getTenantRoles: () => Promise<TenantRolesResponse>;
1595
+ /**
1596
+ * Get all roles for your application
1597
+ *
1598
+ * Returns the role definitions (admin, editor, viewer, etc.) specific to
1599
+ * your application. Uses the clientId from SDK config automatically.
1600
+ * Use this to populate a role picker for invite flows or role assignment.
1601
+ *
1602
+ * NOTE: These are APPLICATION-specific roles, different from tenant roles
1603
+ * (owner/admin/member). Application roles are used for fine-grained
1604
+ * permissions within your app.
1605
+ *
1606
+ * @example
1607
+ * ```ts
1608
+ * app.get('/api/app-roles', async (req, res) => {
1609
+ * const { roles } = await authvital.memberships.getApplicationRoles();
1610
+ * res.json(roles);
1611
+ * // [{ slug: 'admin', name: 'Admin', permissions: [...] }, ...]
1612
+ * });
1613
+ *
1614
+ * // Use in invite flow:
1615
+ * const { roles } = await authvital.memberships.getApplicationRoles();
1616
+ * const editorRole = roles.find(r => r.slug === 'editor');
1617
+ * await authvital.invitations.send(request, {
1618
+ * email: 'user@example.com',
1619
+ * roleId: editorRole?.id,
1620
+ * });
1621
+ * ```
1622
+ */
1623
+ getApplicationRoles: () => Promise<ApplicationRolesResponse>;
1624
+ /**
1625
+ * Set a member's tenant role (replaces any existing roles)
1626
+ *
1627
+ * Performs a pre-flight check using the caller's JWT to catch obvious
1628
+ * permission violations before calling the IDP. The IDP then does the
1629
+ * full authoritative check (e.g., admin can't demote an owner).
1630
+ *
1631
+ * Role hierarchy: owner > admin > member
1632
+ * - Owners can change anyone's role
1633
+ * - Admins can change admins and members, but cannot touch owners or promote to owner
1634
+ * - Members cannot change roles
1635
+ *
1636
+ * @param request - The incoming HTTP request (used to read caller's JWT)
1637
+ * @param membershipId - The membership to update
1638
+ * @param roleSlug - The role slug to set (e.g., 'admin', 'member', 'owner')
1639
+ *
1640
+ * @example
1641
+ * ```ts
1642
+ * app.put('/api/team/:membershipId/role', async (req, res) => {
1643
+ * const result = await authvital.memberships.setMemberRole(
1644
+ * req,
1645
+ * req.params.membershipId,
1646
+ * req.body.role, // e.g., 'admin'
1647
+ * );
1648
+ * res.json(result.role); // { id, name, slug }
1649
+ * });
1650
+ * ```
1651
+ */
1652
+ setMemberRole: (request: RequestLike, membershipId: string, roleSlug: string) => Promise<SetMemberRoleResponse>;
1653
+ };
1654
+ type MembershipsNamespace = ReturnType<typeof createMembershipsNamespace>;
1655
+
1656
+ /**
1657
+ * @authvital/sdk - Permissions Namespace
1658
+ *
1659
+ * Check and list user permissions for tenant-scoped operations.
1660
+ */
1661
+
1662
+ /**
1663
+ * Creates the permissions namespace with all permission-related methods.
1664
+ *
1665
+ * @param client - The base client instance for making authenticated requests
1666
+ * @returns Object containing all permission methods
1667
+ */
1668
+ declare function createPermissionsNamespace(client: BaseClient): {
1669
+ /**
1670
+ * Check if the authenticated user has a specific permission
1671
+ *
1672
+ * @param request - The incoming HTTP request
1673
+ * @param permission - The permission to check (e.g., 'users:write')
1674
+ *
1675
+ * @example
1676
+ * ```ts
1677
+ * app.post('/api/users', async (req, res) => {
1678
+ * const { allowed } = await authvital.permissions.check(req, 'users:write');
1679
+ * if (!allowed) return res.status(403).json({ error: 'Forbidden' });
1680
+ * // ... create user
1681
+ * });
1682
+ * ```
1683
+ */
1684
+ check: (request: RequestLike, permission: string) => Promise<CheckPermissionResult>;
1685
+ /**
1686
+ * Check multiple permissions at once for the authenticated user
1687
+ *
1688
+ * @param request - The incoming HTTP request
1689
+ * @param permissions - Array of permissions to check
1690
+ *
1691
+ * @example
1692
+ * ```ts
1693
+ * const { results } = await authvital.permissions.checkMany(req, ['users:read', 'users:write']);
1694
+ * // results = { 'users:read': true, 'users:write': false }
1695
+ * ```
1696
+ */
1697
+ checkMany: (request: RequestLike, permissions: string[]) => Promise<CheckPermissionsResult>;
1698
+ /**
1699
+ * Get all permissions for the authenticated user
1700
+ *
1701
+ * @param request - The incoming HTTP request
1702
+ *
1703
+ * @example
1704
+ * ```ts
1705
+ * app.get('/api/my-permissions', async (req, res) => {
1706
+ * const perms = await authvital.permissions.list(req);
1707
+ * res.json(perms);
1708
+ * });
1709
+ * ```
1710
+ */
1711
+ list: (request: RequestLike) => Promise<UserPermissions>;
1712
+ };
1713
+ type PermissionsNamespace = ReturnType<typeof createPermissionsNamespace>;
1714
+
1715
+ /**
1716
+ * @authvital/sdk - Entitlements Namespace (The Gatekeeper 🛡️)
1717
+ *
1718
+ * Check quotas, features, and entitlements for tenant-scoped operations.
1719
+ */
1720
+
1721
+ /**
1722
+ * Creates the entitlements namespace with all entitlement-related methods.
1723
+ *
1724
+ * @param client - The base client instance for making authenticated requests
1725
+ * @returns Object containing all entitlement methods
1726
+ */
1727
+ declare function createEntitlementsNamespace(client: BaseClient): {
1728
+ /**
1729
+ * Check if a quota-based action is allowed
1730
+ *
1731
+ * This is the main "gatekeeper" function. Use it before any quota-consuming action.
1732
+ *
1733
+ * @param request - The incoming HTTP request
1734
+ * @param featureKey - The quota to check (e.g., 'seats', 'projects')
1735
+ * @param options - Optional: appScope and incrementCount
1736
+ *
1737
+ * @example
1738
+ * ```ts
1739
+ * // Before adding a team member
1740
+ * const check = await authvital.entitlements.canPerform(req, 'seats');
1741
+ * if (!check.allowed) {
1742
+ * return res.status(403).json({ error: check.reason });
1743
+ * }
1744
+ * // Add the member...
1745
+ * await authvital.entitlements.incrementUsage(req, 'seats');
1746
+ * ```
1747
+ */
1748
+ canPerform: (request: RequestLike, featureKey: string, _options?: {
1749
+ appScope?: string;
1750
+ incrementCount?: number;
1751
+ }) => Promise<QuotaCheckResult>;
1752
+ /**
1753
+ * Decrement usage for a quota (call after removing resource)
1754
+ *
1755
+ * @param request - The incoming HTTP request
1756
+ * @param featureKey - The quota to decrement (e.g., 'seats')
1757
+ * @param options - Optional: appScope and amount to decrement by
1758
+ *
1759
+ * @example
1760
+ * ```ts
1761
+ * // After removing a team member
1762
+ * await authvital.entitlements.decrementUsage(req, 'seats');
1763
+ * ```
1764
+ */
1765
+ decrementUsage: (request: RequestLike, featureKey: string, options?: {
1766
+ appScope?: string;
1767
+ by?: number;
1768
+ }) => Promise<{
1769
+ newUsage: number;
1770
+ }>;
1771
+ };
1772
+ type EntitlementsNamespace = ReturnType<typeof createEntitlementsNamespace>;
1773
+
1774
+ /**
1775
+ * @authvital/sdk - License Types
1776
+ *
1777
+ * Shared types for the licenses namespace.
1778
+ */
1779
+ interface LicenseGrantResponse {
1780
+ assignmentId: string;
1781
+ message: string;
1782
+ }
1783
+ interface LicenseRevokeResponse {
1784
+ message: string;
1785
+ }
1786
+ interface LicenseCheckResponse {
1787
+ hasLicense: boolean;
1788
+ licenseType: string | null;
1789
+ features?: string[];
1790
+ }
1791
+ interface LicenseFeatureResponse {
1792
+ hasFeature: boolean;
1793
+ }
1794
+ interface LicensedUser {
1795
+ id: string;
1796
+ userId: string;
1797
+ email: string;
1798
+ licenseType: string;
1799
+ }
1800
+ interface LicenseHolder {
1801
+ userId: string;
1802
+ userEmail: string;
1803
+ userName?: string;
1804
+ licenseTypeId: string;
1805
+ licenseTypeName: string;
1806
+ assignedAt: string;
1807
+ }
1808
+ interface LicenseAuditLogEntry {
1809
+ id: string;
1810
+ userId: string;
1811
+ userEmail: string;
1812
+ userName?: string;
1813
+ applicationId: string;
1814
+ applicationName: string;
1815
+ licenseTypeId: string;
1816
+ licenseTypeName: string;
1817
+ action: 'GRANTED' | 'REVOKED' | 'CHANGED';
1818
+ previousLicenseTypeName?: string;
1819
+ performedBy: string;
1820
+ performedAt?: string;
1821
+ reason?: string;
1822
+ }
1823
+ interface LicenseAuditLogResponse {
1824
+ entries: LicenseAuditLogEntry[];
1825
+ total: number;
1826
+ limit: number;
1827
+ offset: number;
1828
+ }
1829
+ interface UsageOverviewResponse {
1830
+ tenantId: string;
1831
+ applications: Array<{
1832
+ applicationId: string;
1833
+ applicationName: string;
1834
+ licenseTypeName: string;
1835
+ totalSeats: number;
1836
+ seatsAssigned: number;
1837
+ seatsAvailable: number;
1838
+ utilizationPercentage: number;
1839
+ }>;
1840
+ totalSeatsAcrossAllApps: number;
1841
+ totalSeatsAssigned: number;
1842
+ overallUtilization: number;
1843
+ hasOverage: boolean;
1844
+ overageApplications: string[];
1845
+ }
1846
+ interface UsageTrendEntry {
1847
+ date: string;
1848
+ seatsAssigned: number;
1849
+ seatsAvailable: number;
1850
+ utilizationPercentage: number;
1851
+ }
1852
+ interface UserLicenseListItem {
1853
+ id: string;
1854
+ licenseTypeId: string;
1855
+ licenseTypeName: string;
1856
+ licenseTypeSlug: string;
1857
+ applicationId: string;
1858
+ applicationName: string;
1859
+ assignedAt: string;
1860
+ }
1861
+
1862
+ /**
1863
+ * Creates the licenses namespace with all license-related methods.
1864
+ *
1865
+ * Combines:
1866
+ * - User-scoped operations (JWT auth): grant, revoke, check, etc.
1867
+ * - Admin operations (M2M): tenant overview, bulk operations, etc.
1868
+ *
1869
+ * @param client - The base client instance for making authenticated requests
1870
+ * @returns Object containing all license methods
1871
+ */
1872
+ declare function createLicensesNamespace(client: BaseClient): {
1873
+ getTenantOverview: (tenantId: string) => Promise<TenantLicenseOverview>;
1874
+ getUserLicenses: (tenantId: string, userId: string) => Promise<UserLicenseAssignment[]>;
1875
+ getTenantSubscriptions: (tenantId: string) => Promise<SubscriptionSummary[]>;
1876
+ getMembersWithLicenses: (tenantId: string) => Promise<MemberWithLicenses[]>;
1877
+ getAvailableLicenseTypes: (tenantId: string) => Promise<AvailableLicenseType[]>;
1878
+ grantToUser: (params: GrantLicenseParams) => Promise<UserLicenseAssignment>;
1879
+ revokeFromUser: (params: RevokeLicenseParams) => Promise<void>;
1880
+ changeUserType: (params: ChangeLicenseTypeParams) => Promise<UserLicenseAssignment>;
1881
+ grantBulk: (assignments: GrantLicenseParams[]) => Promise<BulkGrantLicenseResult[]>;
1882
+ revokeBulk: (revocations: RevokeLicenseParams[]) => Promise<BulkRevokeLicenseResult>;
1883
+ grant: (request: RequestLike, options: {
1884
+ userId?: string;
1885
+ applicationId: string;
1886
+ licenseTypeId: string;
1887
+ }) => Promise<LicenseGrantResponse>;
1888
+ revoke: (request: RequestLike, options: {
1889
+ userId?: string;
1890
+ applicationId: string;
1891
+ }) => Promise<LicenseRevokeResponse>;
1892
+ changeType: (request: RequestLike, options: {
1893
+ userId?: string;
1894
+ applicationId: string;
1895
+ newLicenseTypeId: string;
1896
+ }) => Promise<LicenseRevokeResponse>;
1897
+ listForUser: (request: RequestLike, userId?: string) => Promise<UserLicenseListItem[]>;
1898
+ check: (request: RequestLike, userId: string | undefined, applicationId: string) => Promise<LicenseCheckResponse>;
1899
+ hasFeature: (request: RequestLike, userId: string | undefined, applicationId: string, featureKey: string) => Promise<LicenseFeatureResponse>;
1900
+ getAppLicensedUsers: (request: RequestLike, applicationId: string) => Promise<LicensedUser[]>;
1901
+ countLicensedUsers: (request: RequestLike, applicationId: string) => Promise<{
1902
+ count: number;
1903
+ }>;
1904
+ getUserLicenseType: (request: RequestLike, userId: string | undefined, applicationId: string) => Promise<string | null>;
1905
+ getHolders: (request: RequestLike, applicationId: string) => Promise<LicenseHolder[]>;
1906
+ getAuditLog: (request: RequestLike, options?: {
1907
+ userId?: string;
1908
+ applicationId?: string;
1909
+ limit?: number;
1910
+ offset?: number;
1911
+ }) => Promise<LicenseAuditLogResponse>;
1912
+ getUsageOverview: (request: RequestLike) => Promise<UsageOverviewResponse>;
1913
+ getUsageTrends: (request: RequestLike, days?: number) => Promise<UsageTrendEntry[]>;
1914
+ };
1915
+ type LicensesNamespace = ReturnType<typeof createLicensesNamespace>;
1916
+
1917
+ /**
1918
+ * @authvital/sdk - Server-Side OAuth Flow
1919
+ *
1920
+ * Utilities for implementing OAuth 2.0 Authorization Code Flow with PKCE
1921
+ * on your backend. Use this when you need to handle OAuth callbacks server-side.
1922
+ *
1923
+ * @example
1924
+ * ```ts
1925
+ * import { OAuthFlow } from '@authvital/sdk/server';
1926
+ *
1927
+ * const oauth = new OAuthFlow({
1928
+ * authVitalHost: process.env.AV_HOST,
1929
+ * clientId: process.env.AV_CLIENT_ID,
1930
+ * clientSecret: process.env.AV_CLIENT_SECRET,
1931
+ * redirectUri: 'https://myapp.com/api/auth/callback',
1932
+ * });
1933
+ *
1934
+ * // GET /api/auth/login
1935
+ * app.get('/api/auth/login', (req, res) => {
1936
+ * const { authorizeUrl, state, codeVerifier } = oauth.startFlow();
1937
+ * req.session.oauthState = state;
1938
+ * req.session.codeVerifier = codeVerifier;
1939
+ * res.redirect(authorizeUrl);
1940
+ * });
1941
+ *
1942
+ * // GET /api/auth/callback
1943
+ * app.get('/api/auth/callback', async (req, res) => {
1944
+ * const tokens = await oauth.handleCallback(
1945
+ * req.query.code,
1946
+ * req.query.state,
1947
+ * req.session.oauthState,
1948
+ * req.session.codeVerifier
1949
+ * );
1950
+ * req.session.accessToken = tokens.access_token;
1951
+ * res.redirect('/dashboard');
1952
+ * });
1953
+ * ```
1954
+ */
1955
+
1956
+ /**
1957
+ * Generate a cryptographically secure code verifier
1958
+ */
1959
+ declare function generateCodeVerifier(): string;
1960
+ /**
1961
+ * Generate code challenge from verifier (S256 method)
1962
+ */
1963
+ declare function generateCodeChallenge(verifier: string): string;
1964
+ /**
1965
+ * Generate both PKCE values at once
1966
+ */
1967
+ declare function generatePKCE(): {
1968
+ codeVerifier: string;
1969
+ codeChallenge: string;
1970
+ };
1971
+ /**
1972
+ * Payload structure for OAuth state parameter
1973
+ * Contains CSRF nonce and optional app-specific state
1974
+ */
1975
+ interface StatePayload {
1976
+ csrf: string;
1977
+ appState?: string;
1978
+ }
1979
+ /**
1980
+ * Generate a secure random state for CSRF protection
1981
+ */
1982
+ declare function generateState(): string;
1983
+ /**
1984
+ * Encode state payload as base64url JSON
1985
+ * Used to pass both CSRF nonce and app-specific state through OAuth flow
1986
+ *
1987
+ * @param csrf - CSRF nonce for security
1988
+ * @param appState - Optional app-specific state (e.g., return URL)
1989
+ */
1990
+ declare function encodeState(csrf: string, appState?: string): string;
1991
+ /**
1992
+ * Decode state payload from base64url JSON
1993
+ * Returns null if decoding fails (invalid format)
1994
+ *
1995
+ * @param state - The encoded state string from OAuth callback
1996
+ */
1997
+ declare function decodeState(state: string): StatePayload | null;
1998
+ /**
1999
+ * Encode state with embedded verifier (for stateless mode)
2000
+ * Format: {csrf}:{base64url_verifier}
2001
+ *
2002
+ * Use this if you don't want to store state server-side.
2003
+ */
2004
+ declare function encodeStateWithVerifier(csrf: string, codeVerifier: string): string;
2005
+ /**
2006
+ * Decode state to extract CSRF and verifier
2007
+ */
2008
+ declare function decodeStateWithVerifier(state: string): {
2009
+ csrf: string;
2010
+ codeVerifier: string;
2011
+ } | null;
2012
+ interface AuthorizeUrlParams {
2013
+ authVitalHost: string;
2014
+ clientId: string;
2015
+ redirectUri: string;
2016
+ state: string;
2017
+ codeChallenge: string;
2018
+ scope?: string;
2019
+ nonce?: string;
2020
+ }
2021
+ /**
2022
+ * Build the OAuth authorize URL
2023
+ */
2024
+ declare function buildAuthorizeUrl(params: AuthorizeUrlParams): string;
2025
+ interface TokenExchangeParams {
2026
+ authVitalHost: string;
2027
+ clientId: string;
2028
+ clientSecret?: string;
2029
+ code: string;
2030
+ codeVerifier: string;
2031
+ redirectUri: string;
2032
+ }
2033
+ /**
2034
+ * Exchange authorization code for tokens (SERVER-TO-SERVER)
2035
+ */
2036
+ declare function exchangeCodeForTokens(params: TokenExchangeParams): Promise<TokenResponse>;
2037
+ interface RefreshTokenParams {
2038
+ authVitalHost: string;
2039
+ clientId: string;
2040
+ clientSecret?: string;
2041
+ refreshToken: string;
2042
+ }
2043
+ /**
2044
+ * Refresh access token using refresh token (SERVER-TO-SERVER)
2045
+ */
2046
+ declare function refreshAccessToken(params: RefreshTokenParams): Promise<TokenResponse>;
2047
+ /**
2048
+ * Decode JWT payload (without verification - for extracting claims only)
2049
+ */
2050
+ declare function decodeJwt<T = Record<string, unknown>>(token: string): T | null;
2051
+ /**
2052
+ * Helper class for managing the OAuth flow server-side
2053
+ */
2054
+ declare class OAuthFlow {
2055
+ private config;
2056
+ constructor(config: OAuthFlowConfig);
2057
+ /**
2058
+ * Start the OAuth flow - generates PKCE, state, and authorize URL
2059
+ *
2060
+ * @param options.appState - Optional app-specific state to pass through OAuth (e.g., return URL)
2061
+ */
2062
+ startFlow(options?: {
2063
+ appState?: string;
2064
+ }): {
2065
+ authorizeUrl: string;
2066
+ state: string;
2067
+ codeVerifier: string;
2068
+ codeChallenge: string;
2069
+ };
2070
+ /**
2071
+ * Handle the OAuth callback - verify state and exchange code for tokens
2072
+ *
2073
+ * @param code - Authorization code from callback
2074
+ * @param receivedState - State parameter from callback URL
2075
+ * @param expectedState - State that was stored when starting the flow
2076
+ * @param codeVerifier - PKCE code verifier that was stored when starting the flow
2077
+ * @returns Token response with optional appState that was passed through
2078
+ * @throws Error if state doesn't match (CSRF) or token exchange fails
2079
+ */
2080
+ handleCallback(code: string, receivedState: string, expectedState: string, codeVerifier: string): Promise<TokenResponse & {
2081
+ appState?: string;
2082
+ }>;
2083
+ /**
2084
+ * Refresh tokens using refresh token
2085
+ */
2086
+ refreshTokens(refreshToken: string): Promise<TokenResponse>;
2087
+ }
2088
+
2089
+ /**
2090
+ * @authvital/sdk - Server-Side URL Builders
2091
+ *
2092
+ * Simple URL builders for landing pages, emails, and other non-OAuth contexts.
2093
+ * Use these when you just need a link to the AuthVital login/signup page
2094
+ * WITHOUT the full PKCE ceremony.
2095
+ *
2096
+ * For full OAuth flows with PKCE, use OAuthFlow from './oauth-flow' instead.
2097
+ *
2098
+ * @example
2099
+ * ```ts
2100
+ * import { getSignupUrl, getLoginUrl } from '@authvital/sdk/server';
2101
+ *
2102
+ * // For a "Get Started" button on your landing page
2103
+ * const signupLink = getSignupUrl({
2104
+ * authVitalHost: 'https://auth.myapp.com',
2105
+ * clientId: 'my-app',
2106
+ * redirectUri: 'https://app.myapp.com/dashboard',
2107
+ * });
2108
+ *
2109
+ * // For an email CTA
2110
+ * const loginLink = getLoginUrl({
2111
+ * authVitalHost: 'https://auth.myapp.com',
2112
+ * clientId: 'my-app',
2113
+ * });
2114
+ * ```
2115
+ */
2116
+ interface AuthUrlOptions {
2117
+ /** AuthVital server URL (e.g., https://auth.myapp.com) */
2118
+ authVitalHost: string;
2119
+ /** OAuth client_id for your application */
2120
+ clientId: string;
2121
+ /** Optional: Where to redirect after auth completes */
2122
+ redirectUri?: string;
2123
+ }
2124
+ interface SignupUrlOptions extends AuthUrlOptions {
2125
+ /** Optional: Pre-fill the email field */
2126
+ email?: string;
2127
+ /** Optional: Invitation token (for accepting team invites) */
2128
+ inviteToken?: string;
2129
+ }
2130
+ interface LoginUrlOptions extends AuthUrlOptions {
2131
+ /** Optional: Pre-fill the email field */
2132
+ email?: string;
2133
+ /** Optional: Hint for which tenant to log into */
2134
+ tenantHint?: string;
2135
+ }
2136
+ /**
2137
+ * Build a signup URL for landing pages, emails, etc.
2138
+ *
2139
+ * This is a simple redirect - NOT a full OAuth flow.
2140
+ * AuthVital will handle the OAuth redirect internally after signup.
2141
+ *
2142
+ * @example
2143
+ * ```ts
2144
+ * // Basic signup link
2145
+ * const url = getSignupUrl({
2146
+ * authVitalHost: 'https://auth.myapp.com',
2147
+ * clientId: 'my-app',
2148
+ * });
2149
+ *
2150
+ * // With redirect after signup
2151
+ * const url = getSignupUrl({
2152
+ * authVitalHost: 'https://auth.myapp.com',
2153
+ * clientId: 'my-app',
2154
+ * redirectUri: 'https://app.myapp.com/onboarding',
2155
+ * });
2156
+ *
2157
+ * // With pre-filled email (e.g., from waitlist)
2158
+ * const url = getSignupUrl({
2159
+ * authVitalHost: 'https://auth.myapp.com',
2160
+ * clientId: 'my-app',
2161
+ * email: 'user@example.com',
2162
+ * });
2163
+ *
2164
+ * // For team invite acceptance
2165
+ * const url = getSignupUrl({
2166
+ * authVitalHost: 'https://auth.myapp.com',
2167
+ * clientId: 'my-app',
2168
+ * inviteToken: 'abc123',
2169
+ * });
2170
+ * ```
2171
+ */
2172
+ declare function getSignupUrl(options: SignupUrlOptions): string;
2173
+ /**
2174
+ * Build a login URL for landing pages, emails, etc.
2175
+ *
2176
+ * This is a simple redirect - NOT a full OAuth flow.
2177
+ * AuthVital will handle the OAuth redirect internally after login.
2178
+ *
2179
+ * @example
2180
+ * ```ts
2181
+ * // Basic login link
2182
+ * const url = getLoginUrl({
2183
+ * authVitalHost: 'https://auth.myapp.com',
2184
+ * clientId: 'my-app',
2185
+ * });
2186
+ *
2187
+ * // With redirect after login
2188
+ * const url = getLoginUrl({
2189
+ * authVitalHost: 'https://auth.myapp.com',
2190
+ * clientId: 'my-app',
2191
+ * redirectUri: 'https://app.myapp.com/dashboard',
2192
+ * });
2193
+ *
2194
+ * // With tenant hint (for multi-tenant apps)
2195
+ * const url = getLoginUrl({
2196
+ * authVitalHost: 'https://auth.myapp.com',
2197
+ * clientId: 'my-app',
2198
+ * tenantHint: 'acme-corp',
2199
+ * });
2200
+ * ```
2201
+ */
2202
+ declare function getLoginUrl(options: LoginUrlOptions): string;
2203
+ /**
2204
+ * Build a password reset URL.
2205
+ *
2206
+ * @example
2207
+ * ```ts
2208
+ * const url = getPasswordResetUrl({
2209
+ * authVitalHost: 'https://auth.myapp.com',
2210
+ * clientId: 'my-app',
2211
+ * email: 'user@example.com',
2212
+ * });
2213
+ * ```
2214
+ */
2215
+ declare function getPasswordResetUrl(options: AuthUrlOptions & {
2216
+ email?: string;
2217
+ }): string;
2218
+ /**
2219
+ * Build an invite acceptance URL.
2220
+ *
2221
+ * Use this when sending team invitation emails.
2222
+ *
2223
+ * @example
2224
+ * ```ts
2225
+ * const url = getInviteAcceptUrl({
2226
+ * authVitalHost: 'https://auth.myapp.com',
2227
+ * clientId: 'my-app',
2228
+ * inviteToken: 'abc123xyz',
2229
+ * });
2230
+ * ```
2231
+ */
2232
+ declare function getInviteAcceptUrl(options: AuthUrlOptions & {
2233
+ inviteToken: string;
2234
+ }): string;
2235
+ interface LogoutUrlOptions {
2236
+ /** AuthVital server URL (e.g., https://auth.myapp.com) */
2237
+ authVitalHost: string;
2238
+ /** Optional: Where to redirect after logout completes. If not provided, shows IDP's logged-out page. */
2239
+ postLogoutRedirectUri?: string;
2240
+ }
2241
+ /**
2242
+ * Build a logout URL that clears the IDP session.
2243
+ *
2244
+ * Use this when logging out users - it will clear both your app's
2245
+ * cookies AND the IDP session.
2246
+ *
2247
+ * @example
2248
+ * ```ts
2249
+ * // In your logout endpoint - show IDP's logged out page:
2250
+ * const logoutUrl = getLogoutUrl({
2251
+ * authVitalHost: 'https://auth.myapp.com',
2252
+ * });
2253
+ * res.redirect(logoutUrl);
2254
+ *
2255
+ * // Or redirect back to your app after logout:
2256
+ * const logoutUrl = getLogoutUrl({
2257
+ * authVitalHost: 'https://auth.myapp.com',
2258
+ * postLogoutRedirectUri: 'https://myapp.com/',
2259
+ * });
2260
+ * ```
2261
+ */
2262
+ declare function getLogoutUrl(options: LogoutUrlOptions): string;
2263
+ /**
2264
+ * Get URL for user account settings page (standalone version)
2265
+ *
2266
+ * RECOMMENDED: Use authvital.getAccountSettingsUrl() instead for consistency.
2267
+ * This standalone function is for cases where you don't have an AuthVital client.
2268
+ *
2269
+ * @example
2270
+ * ```typescript
2271
+ * const url = getAccountSettingsUrl(authVitalHost);
2272
+ * // Returns: https://auth.example.com/account/settings
2273
+ * ```
2274
+ */
2275
+ declare function getAccountSettingsUrl(authVitalHost: string): string;
2276
+
2277
+ /**
2278
+ * @authvital/sdk - Prisma Schema Snippets
2279
+ *
2280
+ * Copy these model definitions into your schema.prisma file.
2281
+ * The sync handler expects these exact field names.
2282
+ */
2283
+ declare const IDENTITY_SCHEMA = "\n// =============================================================================\n// AUTHVITAL IDENTITY (synced from IDP)\n// =============================================================================\n// Copy this into your schema.prisma and customize as needed.\n// The sync handler only touches these base fields.\n\nmodel Identity {\n // \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n // CORE IDENTITY (synced from AuthVital - OIDC Standard Claims)\n // \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n id String @id // AuthVital subject ID (sub claim)\n username String? @unique // Unique handle (@janesmith)\n displayName String? @map(\"display_name\") // Full name (OIDC: name)\n givenName String? @map(\"given_name\") // First name\n familyName String? @map(\"family_name\") // Last name\n middleName String? @map(\"middle_name\") // Middle name(s)\n nickname String? // Casual name\n pictureUrl String? @map(\"picture_url\") // Profile picture URL\n website String? // Personal URL\n gender String? // Gender identity\n birthdate String? // YYYY-MM-DD\n zoneinfo String? // IANA timezone\n locale String? // Language (e.g., en-US)\n \n // \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n // EMAIL SCOPE (OIDC Standard)\n // \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n email String? @unique\n emailVerified Boolean @default(false) @map(\"email_verified\")\n \n // \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n // PHONE SCOPE (OIDC Standard)\n // \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n phone String? @unique\n phoneVerified Boolean @default(false) @map(\"phone_verified\")\n \n // \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n // TENANT CONTEXT (for multi-tenant apps)\n // \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n tenantId String? @map(\"tenant_id\") // Current tenant ID\n appRole String? @map(\"app_role\") // Role slug (e.g., \"admin\")\n groups String[] @default([]) // Group slugs in tenant\n \n // \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n // STATUS\n // \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n isActive Boolean @default(true) @map(\"is_active\") // IDP-level: can user log in at all?\n hasAppAccess Boolean @default(true) @map(\"has_app_access\") // App-level: does user have access to THIS app?\n \n // \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n // SYNC METADATA\n // \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n syncedAt DateTime @default(now()) @map(\"synced_at\")\n createdAt DateTime @default(now()) @map(\"created_at\")\n updatedAt DateTime @updatedAt @map(\"updated_at\")\n \n // \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n // RELATIONS\n // \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n sessions IdentitySession[]\n \n // \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n // ADD YOUR APP-SPECIFIC RELATIONS BELOW\n // \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n // profile UserProfile?\n // posts Post[]\n \n @@index([tenantId])\n @@index([email])\n @@index([username])\n @@map(\"av_identities\")\n}\n";
2284
+ declare const IDENTITY_SESSION_SCHEMA = "\n// =============================================================================\n// AUTHVITAL IDENTITY SESSION (optional - for session management)\n// =============================================================================\n\nmodel IdentitySession {\n id String @id @default(cuid())\n identityId String @map(\"identity_id\")\n identity Identity @relation(fields: [identityId], references: [id], onDelete: Cascade)\n \n authSessionId String? @map(\"auth_session_id\") // AuthVital session ID\n deviceInfo String? @map(\"device_info\") // Parsed device info\n ipAddress String? @map(\"ip_address\")\n userAgent String? @map(\"user_agent\")\n \n createdAt DateTime @default(now()) @map(\"created_at\")\n lastActiveAt DateTime @default(now()) @map(\"last_active_at\")\n expiresAt DateTime @map(\"expires_at\")\n revokedAt DateTime? @map(\"revoked_at\")\n \n @@index([identityId])\n @@index([authSessionId])\n @@map(\"av_identity_sessions\")\n}\n";
2285
+ /**
2286
+ * Combined schema snippet - both models together
2287
+ */
2288
+ declare const FULL_SCHEMA = "\n// =============================================================================\n// AUTHVITAL IDENTITY (synced from IDP)\n// =============================================================================\n// Copy this into your schema.prisma and customize as needed.\n// The sync handler only touches these base fields.\n\nmodel Identity {\n // \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n // CORE IDENTITY (synced from AuthVital - OIDC Standard Claims)\n // \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n id String @id // AuthVital subject ID (sub claim)\n username String? @unique // Unique handle (@janesmith)\n displayName String? @map(\"display_name\") // Full name (OIDC: name)\n givenName String? @map(\"given_name\") // First name\n familyName String? @map(\"family_name\") // Last name\n middleName String? @map(\"middle_name\") // Middle name(s)\n nickname String? // Casual name\n pictureUrl String? @map(\"picture_url\") // Profile picture URL\n website String? // Personal URL\n gender String? // Gender identity\n birthdate String? // YYYY-MM-DD\n zoneinfo String? // IANA timezone\n locale String? // Language (e.g., en-US)\n \n // \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n // EMAIL SCOPE (OIDC Standard)\n // \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n email String? @unique\n emailVerified Boolean @default(false) @map(\"email_verified\")\n \n // \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n // PHONE SCOPE (OIDC Standard)\n // \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n phone String? @unique\n phoneVerified Boolean @default(false) @map(\"phone_verified\")\n \n // \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n // TENANT CONTEXT (for multi-tenant apps)\n // \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n tenantId String? @map(\"tenant_id\") // Current tenant ID\n appRole String? @map(\"app_role\") // Role slug (e.g., \"admin\")\n groups String[] @default([]) // Group slugs in tenant\n \n // \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n // STATUS\n // \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n isActive Boolean @default(true) @map(\"is_active\") // IDP-level: can user log in at all?\n hasAppAccess Boolean @default(true) @map(\"has_app_access\") // App-level: does user have access to THIS app?\n \n // \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n // SYNC METADATA\n // \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n syncedAt DateTime @default(now()) @map(\"synced_at\")\n createdAt DateTime @default(now()) @map(\"created_at\")\n updatedAt DateTime @updatedAt @map(\"updated_at\")\n \n // \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n // RELATIONS\n // \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n sessions IdentitySession[]\n \n // \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n // ADD YOUR APP-SPECIFIC RELATIONS BELOW\n // \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n // profile UserProfile?\n // posts Post[]\n \n @@index([tenantId])\n @@index([email])\n @@index([username])\n @@map(\"av_identities\")\n}\n\n\n\n// =============================================================================\n// AUTHVITAL IDENTITY SESSION (optional - for session management)\n// =============================================================================\n\nmodel IdentitySession {\n id String @id @default(cuid())\n identityId String @map(\"identity_id\")\n identity Identity @relation(fields: [identityId], references: [id], onDelete: Cascade)\n \n authSessionId String? @map(\"auth_session_id\") // AuthVital session ID\n deviceInfo String? @map(\"device_info\") // Parsed device info\n ipAddress String? @map(\"ip_address\")\n userAgent String? @map(\"user_agent\")\n \n createdAt DateTime @default(now()) @map(\"created_at\")\n lastActiveAt DateTime @default(now()) @map(\"last_active_at\")\n expiresAt DateTime @map(\"expires_at\")\n revokedAt DateTime? @map(\"revoked_at\")\n \n @@index([identityId])\n @@index([authSessionId])\n @@map(\"av_identity_sessions\")\n}\n";
2289
+ /**
2290
+ * Print the schema to console (for easy copy-paste)
2291
+ */
2292
+ declare function printSchema(): void;
2293
+
2294
+ /**
2295
+ * @authvital/sdk - Identity Sync Types
2296
+ *
2297
+ * TypeScript types matching the Prisma schema snippets.
2298
+ * Use these for type-safe operations with synced identities.
2299
+ *
2300
+ * Follows OIDC Standard Claims:
2301
+ * - Profile Scope: name, given_name, family_name, etc.
2302
+ * - Email Scope: email, email_verified
2303
+ * - Phone Scope: phone_number, phone_number_verified
2304
+ */
2305
+ /**
2306
+ * Base identity fields synced from AuthVital (OIDC-compliant)
2307
+ */
2308
+ interface IdentityBase {
2309
+ /** AuthVital subject ID (sub claim in JWT) */
2310
+ id: string;
2311
+ /** Unique handle (e.g., @janesmith) - OIDC: preferred_username */
2312
+ username: string | null;
2313
+ /** Full display name - OIDC: name */
2314
+ displayName: string | null;
2315
+ /** First name - OIDC: given_name */
2316
+ givenName: string | null;
2317
+ /** Last name - OIDC: family_name */
2318
+ familyName: string | null;
2319
+ /** Middle name(s) - OIDC: middle_name */
2320
+ middleName: string | null;
2321
+ /** Casual name - OIDC: nickname */
2322
+ nickname: string | null;
2323
+ /** Profile picture URL - OIDC: picture */
2324
+ pictureUrl: string | null;
2325
+ /** Personal/professional URL - OIDC: website */
2326
+ website: string | null;
2327
+ /** Gender identity - OIDC: gender */
2328
+ gender: string | null;
2329
+ /** Birth date in YYYY-MM-DD format - OIDC: birthdate */
2330
+ birthdate: string | null;
2331
+ /** IANA timezone (e.g., America/New_York) - OIDC: zoneinfo */
2332
+ zoneinfo: string | null;
2333
+ /** Language/region (e.g., en-US) - OIDC: locale */
2334
+ locale: string | null;
2335
+ /** Identity's email address - OIDC: email */
2336
+ email: string | null;
2337
+ /** Whether email is verified - OIDC: email_verified */
2338
+ emailVerified: boolean;
2339
+ /** Phone number in E.164 format - OIDC: phone_number */
2340
+ phone: string | null;
2341
+ /** Whether phone is verified - OIDC: phone_number_verified */
2342
+ phoneVerified: boolean;
2343
+ /** Current tenant ID (for multi-tenant apps) */
2344
+ tenantId: string | null;
2345
+ /** Role slug from app_roles claim */
2346
+ appRole: string | null;
2347
+ /** Group slugs in current tenant */
2348
+ groups: string[];
2349
+ /**
2350
+ * Whether the identity is active at the IDP level.
2351
+ * When false, user cannot log into ANY app - all sessions invalidated.
2352
+ * Set via subject.deactivated event.
2353
+ */
2354
+ isActive: boolean;
2355
+ /**
2356
+ * Whether the identity has access to THIS specific app.
2357
+ * When false, user can still log into other apps, just not this one.
2358
+ * Set via app_access.granted/revoked events.
2359
+ */
2360
+ hasAppAccess: boolean;
2361
+ /** Last sync timestamp */
2362
+ syncedAt: Date;
2363
+ /** When the identity was first synced */
2364
+ createdAt: Date;
2365
+ /** Last update timestamp - OIDC: updated_at (as unix timestamp in JWT) */
2366
+ updatedAt: Date;
2367
+ }
2368
+ /**
2369
+ * Identity for creation (id required, others optional)
2370
+ */
2371
+ interface IdentityCreate {
2372
+ id: string;
2373
+ username?: string | null;
2374
+ displayName?: string | null;
2375
+ givenName?: string | null;
2376
+ familyName?: string | null;
2377
+ middleName?: string | null;
2378
+ nickname?: string | null;
2379
+ pictureUrl?: string | null;
2380
+ website?: string | null;
2381
+ gender?: string | null;
2382
+ birthdate?: string | null;
2383
+ zoneinfo?: string | null;
2384
+ locale?: string | null;
2385
+ email?: string | null;
2386
+ emailVerified?: boolean;
2387
+ phone?: string | null;
2388
+ phoneVerified?: boolean;
2389
+ tenantId?: string | null;
2390
+ appRole?: string | null;
2391
+ groups?: string[];
2392
+ isActive?: boolean;
2393
+ hasAppAccess?: boolean;
2394
+ }
2395
+ /**
2396
+ * Identity for updates (all fields optional)
2397
+ */
2398
+ interface IdentityUpdate {
2399
+ username?: string | null;
2400
+ displayName?: string | null;
2401
+ givenName?: string | null;
2402
+ familyName?: string | null;
2403
+ middleName?: string | null;
2404
+ nickname?: string | null;
2405
+ pictureUrl?: string | null;
2406
+ website?: string | null;
2407
+ gender?: string | null;
2408
+ birthdate?: string | null;
2409
+ zoneinfo?: string | null;
2410
+ locale?: string | null;
2411
+ email?: string | null;
2412
+ emailVerified?: boolean;
2413
+ phone?: string | null;
2414
+ phoneVerified?: boolean;
2415
+ tenantId?: string | null;
2416
+ appRole?: string | null;
2417
+ groups?: string[];
2418
+ isActive?: boolean;
2419
+ hasAppAccess?: boolean;
2420
+ syncedAt?: Date;
2421
+ }
2422
+ /**
2423
+ * Identity session fields
2424
+ */
2425
+ interface IdentitySessionBase {
2426
+ id: string;
2427
+ identityId: string;
2428
+ /** AuthVital's session ID (for linking) */
2429
+ authSessionId: string | null;
2430
+ /** Parsed device info (e.g., "Chrome on macOS") */
2431
+ deviceInfo: string | null;
2432
+ /** Client IP address */
2433
+ ipAddress: string | null;
2434
+ /** Raw user agent string */
2435
+ userAgent: string | null;
2436
+ /** When the session was created */
2437
+ createdAt: Date;
2438
+ /** Last activity timestamp */
2439
+ lastActiveAt: Date;
2440
+ /** When the session expires */
2441
+ expiresAt: Date;
2442
+ /** When the session was revoked (null if active) */
2443
+ revokedAt: Date | null;
2444
+ }
2445
+ /**
2446
+ * Session for creation
2447
+ */
2448
+ interface IdentitySessionCreate {
2449
+ identityId: string;
2450
+ authSessionId?: string | null;
2451
+ deviceInfo?: string | null;
2452
+ ipAddress?: string | null;
2453
+ userAgent?: string | null;
2454
+ expiresAt: Date;
2455
+ }
2456
+ /**
2457
+ * Session for updates
2458
+ */
2459
+ interface IdentitySessionUpdate {
2460
+ lastActiveAt?: Date;
2461
+ revokedAt?: Date | null;
2462
+ deviceInfo?: string | null;
2463
+ }
2464
+ /**
2465
+ * Options for session cleanup
2466
+ */
2467
+ interface SessionCleanupOptions {
2468
+ /** Delete sessions expired more than X days ago (default: 30) */
2469
+ expiredOlderThanDays?: number;
2470
+ /** Also delete revoked sessions (default: false - keeps for audit) */
2471
+ deleteRevoked?: boolean;
2472
+ /** Dry run - log what would be deleted without deleting (default: false) */
2473
+ dryRun?: boolean;
2474
+ }
2475
+ /**
2476
+ * Result of cleanup operation
2477
+ */
2478
+ interface SessionCleanupResult {
2479
+ /** Number of sessions deleted (or would be deleted in dry run) */
2480
+ deletedCount: number;
2481
+ /** Whether this was a dry run */
2482
+ dryRun: boolean;
2483
+ }
2484
+ /**
2485
+ * Minimal Prisma client interface for the sync handler
2486
+ *
2487
+ * This allows the sync handler to work with any Prisma client
2488
+ * that has the expected identity and identitySession models.
2489
+ */
2490
+ interface PrismaClientLike {
2491
+ identity: {
2492
+ upsert: (args: {
2493
+ where: {
2494
+ id: string;
2495
+ };
2496
+ create: IdentityCreate;
2497
+ update: IdentityUpdate;
2498
+ }) => Promise<unknown>;
2499
+ update: (args: {
2500
+ where: {
2501
+ id: string;
2502
+ };
2503
+ data: IdentityUpdate;
2504
+ }) => Promise<unknown>;
2505
+ delete: (args: {
2506
+ where: {
2507
+ id: string;
2508
+ };
2509
+ }) => Promise<unknown>;
2510
+ };
2511
+ identitySession: {
2512
+ deleteMany: (args: {
2513
+ where: {
2514
+ OR?: Array<Record<string, unknown>>;
2515
+ expiresAt?: {
2516
+ lt: Date;
2517
+ };
2518
+ revokedAt?: {
2519
+ not: null;
2520
+ } | {
2521
+ lt: Date;
2522
+ };
2523
+ };
2524
+ }) => Promise<{
2525
+ count: number;
2526
+ }>;
2527
+ };
2528
+ }
2529
+ /**
2530
+ * Function that resolves a Prisma client for a given tenant
2531
+ * Used for tenant-isolated database architectures
2532
+ */
2533
+ type PrismaClientResolver = (tenantId: string) => PrismaClientLike | Promise<PrismaClientLike>;
2534
+ /**
2535
+ * Either a direct Prisma client (shared DB) or a resolver function (tenant-isolated DBs)
2536
+ */
2537
+ type PrismaClientOrResolver = PrismaClientLike | PrismaClientResolver;
2538
+
2539
+ /**
2540
+ * @authvital/sdk - Identity Sync Handler
2541
+ *
2542
+ * Pre-built webhook handler that syncs AuthVital identities to your local database.
2543
+ * Supports all OIDC standard claims.
2544
+ *
2545
+ * @example Single database (shared or single-tenant)
2546
+ * ```typescript
2547
+ * import { IdentitySyncHandler, WebhookRouter } from '@authvital/sdk/server';
2548
+ * import { prisma } from './prisma';
2549
+ *
2550
+ * const handler = new IdentitySyncHandler(prisma);
2551
+ * const router = new WebhookRouter({ handler });
2552
+ * ```
2553
+ *
2554
+ * @example Tenant-isolated databases
2555
+ * ```typescript
2556
+ * import { IdentitySyncHandler, WebhookRouter } from '@authvital/sdk/server';
2557
+ * import { getTenantPrisma } from './db';
2558
+ *
2559
+ * // Pass a resolver function that returns the correct client per tenant
2560
+ * const handler = new IdentitySyncHandler((tenantId) => getTenantPrisma(tenantId));
2561
+ * const router = new WebhookRouter({ handler });
2562
+ * ```
2563
+ */
2564
+
2565
+ /**
2566
+ * Pre-built webhook handler for syncing identities from AuthVital
2567
+ *
2568
+ * Supports two modes:
2569
+ * 1. **Shared DB**: Pass a single Prisma client
2570
+ * 2. **Tenant-isolated DBs**: Pass a resolver function that returns the client per tenant
2571
+ *
2572
+ * Handles:
2573
+ * - subject.created → Creates identity in local DB
2574
+ * - subject.updated → Updates identity in local DB
2575
+ * - subject.deleted → Deletes identity from local DB
2576
+ * - subject.deactivated → Marks identity as inactive
2577
+ * - member.joined → Updates identity's tenant context
2578
+ * - member.left → Clears identity's tenant context
2579
+ * - member.role_changed → Updates identity's tenant role
2580
+ * - app_access.granted → Updates identity's app role
2581
+ * - app_access.revoked → Clears identity's app role
2582
+ * - app_access.role_changed → Updates identity's app role
2583
+ */
2584
+ declare class IdentitySyncHandler extends AuthVitalEventHandler {
2585
+ private readonly prismaOrResolver;
2586
+ private readonly isResolver;
2587
+ /**
2588
+ * Create a new identity sync handler
2589
+ *
2590
+ * @param prismaOrResolver - Either a Prisma client (shared DB) or a resolver function (tenant-isolated DBs)
2591
+ *
2592
+ * @example Shared database
2593
+ * ```typescript
2594
+ * new IdentitySyncHandler(prisma)
2595
+ * ```
2596
+ *
2597
+ * @example Tenant-isolated databases
2598
+ * ```typescript
2599
+ * new IdentitySyncHandler((tenantId) => getTenantPrisma(tenantId))
2600
+ * ```
2601
+ */
2602
+ constructor(prismaOrResolver: PrismaClientOrResolver);
2603
+ /**
2604
+ * Get the Prisma client for the given tenant
2605
+ * - Shared DB mode: Returns the single client (tenantId ignored)
2606
+ * - Tenant-isolated mode: Calls resolver with tenantId
2607
+ */
2608
+ private getClient;
2609
+ onSubjectCreated(event: SubjectCreatedEvent): Promise<void>;
2610
+ onSubjectUpdated(event: SubjectUpdatedEvent): Promise<void>;
2611
+ onSubjectDeleted(event: SubjectDeletedEvent): Promise<void>;
2612
+ onSubjectDeactivated(event: SubjectDeactivatedEvent): Promise<void>;
2613
+ onMemberJoined(event: MemberJoinedEvent): Promise<void>;
2614
+ onMemberLeft(event: MemberLeftEvent): Promise<void>;
2615
+ onMemberRoleChanged(event: MemberRoleChangedEvent): Promise<void>;
2616
+ onAppAccessGranted(event: AppAccessGrantedEvent): Promise<void>;
2617
+ onAppAccessRevoked(event: AppAccessRevokedEvent): Promise<void>;
2618
+ onAppAccessRoleChanged(event: AppAccessRoleChangedEvent): Promise<void>;
2619
+ }
2620
+
2621
+ /**
2622
+ * @authvital/sdk - Session Cleanup Utility
2623
+ *
2624
+ * Optional utility for cleaning up expired/revoked sessions.
2625
+ * Call this on a schedule (cron job) or manually.
2626
+ *
2627
+ * @example
2628
+ * ```typescript
2629
+ * import { cleanupSessions } from '@authvital/sdk/server';
2630
+ * import { prisma } from './prisma';
2631
+ *
2632
+ * // Run daily via cron
2633
+ * await cleanupSessions(prisma, {
2634
+ * expiredOlderThanDays: 30,
2635
+ * deleteRevoked: false, // Keep revoked for audit trail
2636
+ * });
2637
+ * ```
2638
+ */
2639
+
2640
+ /**
2641
+ * Clean up expired and optionally revoked sessions
2642
+ *
2643
+ * @param prisma - Prisma client instance
2644
+ * @param options - Cleanup configuration
2645
+ * @returns Result with count of deleted sessions
2646
+ */
2647
+ declare function cleanupSessions(prisma: PrismaClientLike, options?: SessionCleanupOptions): Promise<SessionCleanupResult>;
2648
+ /**
2649
+ * Get raw SQL for session cleanup (for use with pg_cron or similar)
2650
+ *
2651
+ * @param options - Cleanup configuration
2652
+ * @returns SQL statement string
2653
+ */
2654
+ declare function getCleanupSQL(options?: SessionCleanupOptions): string;
2655
+
2656
+ export { AppAccessGrantedEvent, AppAccessRevokedEvent, AppAccessRoleChangedEvent, type ApplicationMembership, type ApplicationMembershipsResponse, type ApplicationRoleDefinition, type ApplicationRolesResponse, type AuthUrlOptions, AuthVital, type AuthVitalClientConfig, type AuthVitalConfig, AuthVitalEventHandler, type AuthorizeUrlParams, type AvailableLicenseType, BaseClient, type CheckPermissionParams, type CheckPermissionResult, type CheckPermissionsParams, type CheckPermissionsResult, type EnhancedJwtPayload, type EntitlementsNamespace, FULL_SCHEMA, type FeatureCheckResult, type GetCurrentUserResult, IDENTITY_SCHEMA, IDENTITY_SESSION_SCHEMA, type IdentityBase, type IdentityCreate, type IdentitySessionBase, type IdentitySessionCreate, type IdentitySessionUpdate, IdentitySyncHandler, type IdentityUpdate, type InvitationResponse, type InvitationsNamespace, type Jwks, type JwksKey, type JwtHeader, type JwtLicenseInfo, type JwtPayload, JwtValidator, type JwtValidatorConfig, type LicenseAuditLogEntry, type LicenseAuditLogResponse, type LicenseCheckResponse, type LicenseFeatureResponse, type LicenseGrantResponse, type LicenseHolder, type LicenseRevokeResponse, type LicensedUser, type LicensesNamespace, type LoginUrlOptions, type LogoutUrlOptions, MemberJoinedEvent, MemberLeftEvent, MemberRoleChangedEvent, type MemberWithLicenses, type MembershipRole, type MembershipStatusType, type MembershipUser, type MembershipsNamespace, OAuthFlow, type OAuthFlowConfig, type PendingInvitation, type PendingInvitationsResponse, type PermissionsNamespace, type PrismaClientLike, type PrismaClientOrResolver, type PrismaClientResolver, type RefreshTokenParams, type RequestLike, type ResendInvitationParams, type RevokeInvitationResponse, type SendInvitationParams, type SessionCleanupOptions, type SessionCleanupResult, type SessionsNamespace, type SetMemberRoleResponse, type SignupUrlOptions, type StatePayload, SubjectCreatedEvent, SubjectDeactivatedEvent, SubjectDeletedEvent, SubjectUpdatedEvent, type SubscriptionStatusType, type SubscriptionSummary, type TenantLicenseOverview, type TenantMembership, type TenantMembershipsResponse, type TenantRoleDefinition, type TenantRolesResponse, type TokenExchangeParams, type TokenResponse, type UsageOverviewResponse, type UsageTrendEntry, type UserLicenseListItem, type UserPermissions, type UserTenantMembership, type UserTenantsResponse, type ValidateMembershipResponse, type ValidateTokenResult, type ValidatedClaims, appendClientIdToUri, buildAuthorizeUrl, cleanupSessions, createAuthVital, createEntitlementsNamespace, createInvitationsNamespace, createJwtMiddleware, createJwtValidator, createLicensesNamespace, createMembershipsNamespace, createPassportJwtOptions, createPermissionsNamespace, createSessionsNamespace, decodeJwt, decodeState, decodeStateWithVerifier, encodeState, encodeStateWithVerifier, exchangeCodeForTokens, extractAuthorizationHeader, generateCodeChallenge, generateCodeVerifier, generatePKCE, generateState, getAccountSettingsUrl, getCleanupSQL, getCurrentUser, getCurrentUserFromConfig, getInviteAcceptUrl, getLoginUrl, getLogoutUrl, getPasswordResetUrl, getSignupUrl, printSchema, refreshAccessToken };