@spfn/auth 0.1.0-alpha.0 → 0.1.0-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +70 -12
  3. package/dist/api-BcQM4WKb.d.ts +45 -0
  4. package/dist/client.d.ts +2 -0
  5. package/dist/client.js +1 -0
  6. package/dist/client.js.map +1 -0
  7. package/dist/index.d.ts +57 -0
  8. package/dist/index.js +8966 -0
  9. package/dist/index.js.map +1 -0
  10. package/dist/lib/contracts/auth.d.ts +262 -0
  11. package/dist/lib/contracts/auth.js +2923 -0
  12. package/dist/lib/contracts/auth.js.map +1 -0
  13. package/dist/lib/contracts/index.d.ts +3 -0
  14. package/dist/lib/contracts/index.js +3162 -0
  15. package/dist/lib/contracts/index.js.map +1 -0
  16. package/dist/lib/contracts/invitation.d.ts +243 -0
  17. package/dist/lib/contracts/invitation.js +2883 -0
  18. package/dist/lib/contracts/invitation.js.map +1 -0
  19. package/dist/plugin.d.ts +12 -0
  20. package/dist/plugin.js +8949 -0
  21. package/dist/plugin.js.map +1 -0
  22. package/dist/server/entities/index.d.ts +10 -0
  23. package/dist/server/entities/index.js +399 -0
  24. package/dist/server/entities/index.js.map +1 -0
  25. package/dist/server/entities/invitations.d.ts +241 -0
  26. package/dist/server/entities/invitations.js +181 -0
  27. package/dist/server/entities/invitations.js.map +1 -0
  28. package/dist/server/entities/permissions.d.ts +196 -0
  29. package/dist/server/entities/permissions.js +44 -0
  30. package/dist/server/entities/permissions.js.map +1 -0
  31. package/dist/server/entities/role-permissions.d.ts +107 -0
  32. package/dist/server/entities/role-permissions.js +112 -0
  33. package/dist/server/entities/role-permissions.js.map +1 -0
  34. package/dist/server/entities/roles.d.ts +196 -0
  35. package/dist/server/entities/roles.js +45 -0
  36. package/dist/server/entities/roles.js.map +1 -0
  37. package/dist/server/entities/user-permissions.d.ts +163 -0
  38. package/dist/server/entities/user-permissions.js +191 -0
  39. package/dist/server/entities/user-permissions.js.map +1 -0
  40. package/dist/server/entities/user-public-keys.d.ts +227 -0
  41. package/dist/server/entities/user-public-keys.js +153 -0
  42. package/dist/server/entities/user-public-keys.js.map +1 -0
  43. package/dist/server/entities/user-social-accounts.d.ts +189 -0
  44. package/dist/server/entities/user-social-accounts.js +146 -0
  45. package/dist/server/entities/user-social-accounts.js.map +1 -0
  46. package/dist/server/entities/users.d.ts +235 -0
  47. package/dist/server/entities/users.js +113 -0
  48. package/dist/server/entities/users.js.map +1 -0
  49. package/dist/server/entities/verification-codes.d.ts +191 -0
  50. package/dist/server/entities/verification-codes.js +44 -0
  51. package/dist/server/entities/verification-codes.js.map +1 -0
  52. package/dist/server/routes/auth/index.d.ts +10 -0
  53. package/dist/server/routes/auth/index.js +4475 -0
  54. package/dist/server/routes/auth/index.js.map +1 -0
  55. package/dist/server/routes/index.d.ts +6 -0
  56. package/dist/server/routes/index.js +6352 -0
  57. package/dist/server/routes/index.js.map +1 -0
  58. package/dist/server/routes/invitations/index.d.ts +10 -0
  59. package/dist/server/routes/invitations/index.js +4209 -0
  60. package/dist/server/routes/invitations/index.js.map +1 -0
  61. package/dist/server.d.ts +1243 -0
  62. package/dist/server.js +2281 -0
  63. package/dist/server.js.map +1 -0
  64. package/migrations/0000_tired_gambit.sql +165 -0
  65. package/migrations/meta/0000_snapshot.json +1395 -0
  66. package/migrations/meta/_journal.json +13 -0
  67. package/package.json +32 -24
@@ -0,0 +1,1243 @@
1
+ import { User } from './server/entities/users.js';
2
+ import { Role } from './server/entities/roles.js';
3
+ import { Invitation, InvitationWithDetails, InvitationStatus } from './server/entities/invitations.js';
4
+ import { S as SessionPayload } from './api-BcQM4WKb.js';
5
+ import { Context, Next } from 'hono';
6
+ import 'drizzle-orm/pg-core';
7
+
8
+ /**
9
+ * @spfn/auth - RBAC Type Definitions
10
+ *
11
+ * Type definitions for role and permission configuration
12
+ */
13
+ interface RoleConfig {
14
+ name: string;
15
+ displayName: string;
16
+ description?: string;
17
+ priority?: number;
18
+ isSystem?: boolean;
19
+ isBuiltin?: boolean;
20
+ }
21
+ interface PermissionConfig {
22
+ name: string;
23
+ displayName: string;
24
+ description?: string;
25
+ category?: string;
26
+ isSystem?: boolean;
27
+ isBuiltin?: boolean;
28
+ }
29
+ interface AuthInitOptions {
30
+ /**
31
+ * Additional roles to create
32
+ * Built-in roles (user, admin, superadmin) are automatically included
33
+ */
34
+ roles?: RoleConfig[];
35
+ /**
36
+ * Additional permissions to create
37
+ * Built-in permissions are automatically included
38
+ */
39
+ permissions?: PermissionConfig[];
40
+ /**
41
+ * Role-Permission mappings
42
+ * Built-in mappings are automatically included
43
+ * You can extend built-in roles or define mappings for custom roles
44
+ *
45
+ * @example
46
+ * ```typescript
47
+ * {
48
+ * // Extend built-in admin role
49
+ * admin: ['post:create', 'post:publish'],
50
+ *
51
+ * // Define custom role permissions
52
+ * 'content-creator': ['post:create', 'post:publish'],
53
+ * }
54
+ * ```
55
+ */
56
+ rolePermissions?: Record<string, string[]>;
57
+ /**
58
+ * Use all preset roles and permissions
59
+ * Includes: moderator, editor, viewer and related permissions
60
+ * @default false
61
+ */
62
+ usePresets?: boolean;
63
+ /**
64
+ * Select specific preset roles to include
65
+ * Available: MODERATOR, EDITOR, VIEWER
66
+ */
67
+ presetRoles?: Array<'MODERATOR' | 'EDITOR' | 'VIEWER'>;
68
+ /**
69
+ * Select specific preset permissions to include
70
+ */
71
+ presetPermissions?: Array<'CONTENT_READ' | 'CONTENT_WRITE' | 'CONTENT_DELETE' | 'CONTENT_PUBLISH' | 'COMMENT_MODERATE' | 'SYSTEM_CONFIG' | 'ANALYTICS_VIEW'>;
72
+ /**
73
+ * Default role name for new users
74
+ * Must be a valid role name that exists after initialization
75
+ * @default 'user'
76
+ */
77
+ defaultRole?: string;
78
+ }
79
+
80
+ /**
81
+ * @spfn/auth - Built-in Roles and Permissions
82
+ *
83
+ * Core roles and permissions required by the auth package
84
+ * These cannot be deleted and are automatically created on initialization
85
+ */
86
+
87
+ /**
88
+ * Built-in roles (required by package)
89
+ * These roles are always created and cannot be deleted
90
+ */
91
+ declare const BUILTIN_ROLES: Record<string, RoleConfig>;
92
+ /**
93
+ * Built-in permissions (required by package)
94
+ * These permissions are always created and cannot be deleted
95
+ */
96
+ declare const BUILTIN_PERMISSIONS: Record<string, PermissionConfig>;
97
+ /**
98
+ * Built-in role-permission mappings
99
+ * Defines default permissions for each built-in role
100
+ */
101
+ declare const BUILTIN_ROLE_PERMISSIONS: Record<string, string[]>;
102
+ type BuiltinRoleName = keyof typeof BUILTIN_ROLE_PERMISSIONS;
103
+ type BuiltinPermissionName = typeof BUILTIN_PERMISSIONS[keyof typeof BUILTIN_PERMISSIONS]['name'];
104
+
105
+ /**
106
+ * @spfn/auth - Preset Roles and Permissions
107
+ *
108
+ * Optional preset roles and permissions for common use cases
109
+ * Developers can choose to use these or define their own
110
+ */
111
+
112
+ /**
113
+ * Preset roles (optional)
114
+ * Common roles that developers can optionally include
115
+ */
116
+ declare const PRESET_ROLES: Record<string, RoleConfig>;
117
+ /**
118
+ * Preset permissions (optional)
119
+ * Common permissions for typical application features
120
+ */
121
+ declare const PRESET_PERMISSIONS: Record<string, PermissionConfig>;
122
+ /**
123
+ * Preset role-permission mappings
124
+ * Recommended permissions for each preset role
125
+ */
126
+ declare const PRESET_ROLE_PERMISSIONS: Record<string, string[]>;
127
+
128
+ /**
129
+ * @spfn/auth - Auth Service
130
+ *
131
+ * Core authentication logic: registration, login, logout, password management
132
+ */
133
+ interface CheckAccountExistsParams {
134
+ email?: string;
135
+ phone?: string;
136
+ }
137
+ interface CheckAccountExistsResult {
138
+ exists: boolean;
139
+ identifier: string;
140
+ identifierType: 'email' | 'phone';
141
+ }
142
+ interface RegisterParams {
143
+ email?: string;
144
+ phone?: string;
145
+ verificationToken: string;
146
+ password: string;
147
+ publicKey: string;
148
+ keyId: string;
149
+ fingerprint: string;
150
+ algorithm?: 'ES256' | 'RS256';
151
+ }
152
+ interface RegisterResult {
153
+ userId: string;
154
+ email?: string;
155
+ phone?: string;
156
+ }
157
+ interface LoginParams {
158
+ email?: string;
159
+ phone?: string;
160
+ password: string;
161
+ publicKey: string;
162
+ keyId: string;
163
+ fingerprint: string;
164
+ oldKeyId?: string;
165
+ algorithm?: 'ES256' | 'RS256';
166
+ }
167
+ interface LoginResult {
168
+ userId: string;
169
+ email?: string;
170
+ phone?: string;
171
+ passwordChangeRequired: boolean;
172
+ }
173
+ interface LogoutParams {
174
+ userId: number;
175
+ keyId: string;
176
+ }
177
+ interface ChangePasswordParams {
178
+ userId: number;
179
+ currentPassword: string;
180
+ newPassword: string;
181
+ passwordHash?: string;
182
+ }
183
+ /**
184
+ * Check if an account exists by email or phone
185
+ */
186
+ declare function checkAccountExistsService(params: CheckAccountExistsParams): Promise<CheckAccountExistsResult>;
187
+ /**
188
+ * Register a new user account
189
+ */
190
+ declare function registerService(params: RegisterParams): Promise<RegisterResult>;
191
+ /**
192
+ * Authenticate user and create session
193
+ */
194
+ declare function loginService(params: LoginParams): Promise<LoginResult>;
195
+ /**
196
+ * Logout user (revoke current key)
197
+ */
198
+ declare function logoutService(params: LogoutParams): Promise<void>;
199
+ /**
200
+ * Change user password
201
+ */
202
+ declare function changePasswordService(params: ChangePasswordParams): Promise<void>;
203
+
204
+ /**
205
+ * @spfn/auth - Verification Service
206
+ *
207
+ * Handles OTP code generation, validation, and delivery
208
+ */
209
+ interface SendVerificationCodeParams {
210
+ target: string;
211
+ targetType: 'email' | 'phone';
212
+ purpose: 'registration' | 'login' | 'password_reset';
213
+ }
214
+ interface SendVerificationCodeResult {
215
+ success: boolean;
216
+ expiresAt: string;
217
+ }
218
+ interface VerifyCodeParams {
219
+ target: string;
220
+ targetType: 'email' | 'phone';
221
+ code: string;
222
+ purpose: 'registration' | 'login' | 'password_reset';
223
+ }
224
+ interface VerifyCodeResult {
225
+ valid: boolean;
226
+ verificationToken: string;
227
+ }
228
+ /**
229
+ * Send verification code via email or SMS
230
+ */
231
+ declare function sendVerificationCodeService(params: SendVerificationCodeParams): Promise<SendVerificationCodeResult>;
232
+ /**
233
+ * Verify OTP code and return verification token
234
+ */
235
+ declare function verifyCodeService(params: VerifyCodeParams): Promise<VerifyCodeResult>;
236
+
237
+ /**
238
+ * @spfn/auth - Key Service
239
+ *
240
+ * Handles public key registration, rotation, and revocation
241
+ */
242
+ interface RegisterPublicKeyParams {
243
+ userId: number;
244
+ keyId: string;
245
+ publicKey: string;
246
+ fingerprint: string;
247
+ algorithm?: 'ES256' | 'RS256';
248
+ }
249
+ interface RotateKeyParams {
250
+ userId: number;
251
+ oldKeyId: string;
252
+ newKeyId: string;
253
+ newPublicKey: string;
254
+ fingerprint: string;
255
+ algorithm?: 'ES256' | 'RS256';
256
+ }
257
+ interface RotateKeyResult {
258
+ success: boolean;
259
+ keyId: string;
260
+ }
261
+ interface RevokeKeyParams {
262
+ userId: number;
263
+ keyId: string;
264
+ reason: string;
265
+ }
266
+ /**
267
+ * Register a new public key for a user
268
+ */
269
+ declare function registerPublicKeyService(params: RegisterPublicKeyParams): Promise<void>;
270
+ /**
271
+ * Rotate user's public key (revoke old, register new)
272
+ */
273
+ declare function rotateKeyService(params: RotateKeyParams): Promise<RotateKeyResult>;
274
+ /**
275
+ * Revoke a user's public key
276
+ */
277
+ declare function revokeKeyService(params: RevokeKeyParams): Promise<void>;
278
+
279
+ /**
280
+ * @spfn/auth - User Service
281
+ *
282
+ * Handles user CRUD operations
283
+ */
284
+
285
+ /**
286
+ * Get user by ID
287
+ */
288
+ declare function getUserByIdService(userId: number): Promise<User | null>;
289
+ /**
290
+ * Get user by email
291
+ */
292
+ declare function getUserByEmailService(email: string): Promise<User | null>;
293
+ /**
294
+ * Get user by phone
295
+ */
296
+ declare function getUserByPhoneService(phone: string): Promise<User | null>;
297
+ /**
298
+ * Update user's last login timestamp
299
+ */
300
+ declare function updateLastLoginService(userId: number): Promise<void>;
301
+ /**
302
+ * Update user data
303
+ */
304
+ declare function updateUserService(userId: number, updates: Partial<Omit<User, 'id' | 'createdAt'>>): Promise<void>;
305
+
306
+ /**
307
+ * @spfn/auth - RBAC Initialization Service
308
+ *
309
+ * Initialize roles, permissions, and their mappings
310
+ */
311
+
312
+ /**
313
+ * Initialize auth package with RBAC system
314
+ *
315
+ * Creates built-in roles, permissions, and optionally presets or custom configurations
316
+ *
317
+ * @param options - Initialization options
318
+ *
319
+ * @example
320
+ * ```typescript
321
+ * // Minimal - only built-in roles
322
+ * await initializeAuth();
323
+ *
324
+ * // With presets
325
+ * await initializeAuth({ usePresets: true });
326
+ *
327
+ * // Custom roles and permissions
328
+ * await initializeAuth({
329
+ * roles: [{ name: 'editor', displayName: 'Editor', priority: 30 }],
330
+ * permissions: [{ name: 'post:create', displayName: 'Create Posts' }],
331
+ * rolePermissions: { editor: ['post:create'] },
332
+ * });
333
+ * ```
334
+ */
335
+ declare function initializeAuth(options?: AuthInitOptions): Promise<void>;
336
+
337
+ /**
338
+ * @spfn/auth - Permission Service
339
+ *
340
+ * Permission checking and validation logic
341
+ */
342
+ /**
343
+ * Get all permissions for a user
344
+ *
345
+ * Combines role-based permissions with user-specific overrides
346
+ * Handles expiration of temporary permissions
347
+ *
348
+ * @param userId - User ID (string or bigint)
349
+ * @returns Array of permission names
350
+ *
351
+ * @example
352
+ * ```typescript
353
+ * const perms = await getUserPermissions('123');
354
+ * // ['auth:self:manage', 'user:read', 'post:create']
355
+ * ```
356
+ */
357
+ declare function getUserPermissions(userId: string | bigint): Promise<string[]>;
358
+ /**
359
+ * Check if user has a specific permission
360
+ *
361
+ * @param userId - User ID
362
+ * @param permissionName - Permission name (e.g., 'user:delete')
363
+ * @returns true if user has permission
364
+ *
365
+ * @example
366
+ * ```typescript
367
+ * if (await hasPermission('123', 'user:delete')) {
368
+ * // User can delete users
369
+ * }
370
+ * ```
371
+ */
372
+ declare function hasPermission(userId: string | bigint, permissionName: string): Promise<boolean>;
373
+ /**
374
+ * Check if user has any of the specified permissions
375
+ *
376
+ * @param userId - User ID
377
+ * @param permissionNames - Array of permission names
378
+ * @returns true if user has at least one permission
379
+ *
380
+ * @example
381
+ * ```typescript
382
+ * if (await hasAnyPermission('123', ['post:read', 'admin:access'])) {
383
+ * // User can access content
384
+ * }
385
+ * ```
386
+ */
387
+ declare function hasAnyPermission(userId: string | bigint, permissionNames: string[]): Promise<boolean>;
388
+ /**
389
+ * Check if user has all of the specified permissions
390
+ *
391
+ * @param userId - User ID
392
+ * @param permissionNames - Array of permission names
393
+ * @returns true if user has all permissions
394
+ *
395
+ * @example
396
+ * ```typescript
397
+ * if (await hasAllPermissions('123', ['post:write', 'post:publish'])) {
398
+ * // User can write AND publish
399
+ * }
400
+ * ```
401
+ */
402
+ declare function hasAllPermissions(userId: string | bigint, permissionNames: string[]): Promise<boolean>;
403
+ /**
404
+ * Check if user has a specific role
405
+ *
406
+ * @param userId - User ID
407
+ * @param roleName - Role name (e.g., 'admin', 'superadmin')
408
+ * @returns true if user has role
409
+ *
410
+ * @example
411
+ * ```typescript
412
+ * if (await hasRole('123', 'admin')) {
413
+ * // User is admin
414
+ * }
415
+ * ```
416
+ */
417
+ declare function hasRole(userId: string | bigint, roleName: string): Promise<boolean>;
418
+ /**
419
+ * Check if user has any of the specified roles
420
+ *
421
+ * @param userId - User ID
422
+ * @param roleNames - Array of role names
423
+ * @returns true if user has at least one role
424
+ */
425
+ declare function hasAnyRole(userId: string | bigint, roleNames: string[]): Promise<boolean>;
426
+
427
+ /**
428
+ * @spfn/auth - Role Service
429
+ *
430
+ * Role management functions for runtime role creation and modification
431
+ */
432
+
433
+ /**
434
+ * Create a new custom role
435
+ *
436
+ * @param data - Role configuration
437
+ * @returns Created role
438
+ * @throws Error if role name already exists
439
+ *
440
+ * @example
441
+ * ```typescript
442
+ * const role = await createRole({
443
+ * name: 'content-creator',
444
+ * displayName: 'Content Creator',
445
+ * description: 'Can create and publish content',
446
+ * priority: 20,
447
+ * permissionIds: [1n, 2n, 3n],
448
+ * });
449
+ * ```
450
+ */
451
+ declare function createRole(data: {
452
+ name: string;
453
+ displayName: string;
454
+ description?: string;
455
+ priority?: number;
456
+ permissionIds?: number[];
457
+ }): Promise<Role>;
458
+ /**
459
+ * Update an existing role
460
+ *
461
+ * @param roleId - Role ID
462
+ * @param data - Update data
463
+ * @returns Updated role
464
+ * @throws Error if role is built-in (cannot modify)
465
+ *
466
+ * @example
467
+ * ```typescript
468
+ * await updateRole(1n, {
469
+ * displayName: 'Senior Content Creator',
470
+ * priority: 25,
471
+ * });
472
+ * ```
473
+ */
474
+ declare function updateRole(roleId: number, data: {
475
+ displayName?: string;
476
+ description?: string;
477
+ priority?: number;
478
+ isActive?: boolean;
479
+ }): Promise<Role>;
480
+ /**
481
+ * Delete a role
482
+ *
483
+ * @param roleId - Role ID
484
+ * @throws Error if role is built-in or system role
485
+ *
486
+ * @example
487
+ * ```typescript
488
+ * await deleteRole(5n); // Delete custom role
489
+ * ```
490
+ */
491
+ declare function deleteRole(roleId: number): Promise<void>;
492
+ /**
493
+ * Add permission to role
494
+ *
495
+ * @param roleId - Role ID
496
+ * @param permissionId - Permission ID
497
+ *
498
+ * @example
499
+ * ```typescript
500
+ * await addPermissionToRole(1n, 5n);
501
+ * ```
502
+ */
503
+ declare function addPermissionToRole(roleId: number, permissionId: number): Promise<void>;
504
+ /**
505
+ * Remove permission from role
506
+ *
507
+ * @param roleId - Role ID
508
+ * @param permissionId - Permission ID
509
+ *
510
+ * @example
511
+ * ```typescript
512
+ * await removePermissionFromRole(1n, 5n);
513
+ * ```
514
+ */
515
+ declare function removePermissionFromRole(roleId: number, permissionId: number): Promise<void>;
516
+ /**
517
+ * Set permissions for a role (replaces all existing permissions)
518
+ *
519
+ * @param roleId - Role ID
520
+ * @param permissionIds - Array of permission IDs
521
+ *
522
+ * @example
523
+ * ```typescript
524
+ * await setRolePermissions(1n, [1n, 2n, 3n]);
525
+ * ```
526
+ */
527
+ declare function setRolePermissions(roleId: number, permissionIds: number[]): Promise<void>;
528
+ /**
529
+ * Get all roles
530
+ *
531
+ * @param includeInactive - Include inactive roles
532
+ * @returns Array of roles
533
+ *
534
+ * @example
535
+ * ```typescript
536
+ * const roles = await getAllRoles();
537
+ * ```
538
+ */
539
+ declare function getAllRoles(includeInactive?: boolean): Promise<Role[]>;
540
+ /**
541
+ * Get role by name
542
+ *
543
+ * @param name - Role name
544
+ * @returns Role or null
545
+ *
546
+ * @example
547
+ * ```typescript
548
+ * const role = await getRoleByName('admin');
549
+ * ```
550
+ */
551
+ declare function getRoleByName(name: string): Promise<Role | null>;
552
+ /**
553
+ * Get role permissions
554
+ *
555
+ * @param roleId - Role ID
556
+ * @returns Array of permission names
557
+ *
558
+ * @example
559
+ * ```typescript
560
+ * const perms = await getRolePermissions(1n);
561
+ * // ['user:read', 'user:write']
562
+ * ```
563
+ */
564
+ declare function getRolePermissions(roleId: number): Promise<string[]>;
565
+
566
+ /**
567
+ * @spfn/auth - Invitation Service
568
+ *
569
+ * User invitation management for invite-only registration
570
+ */
571
+
572
+ /**
573
+ * Create a new invitation
574
+ *
575
+ * @param params - Invitation parameters
576
+ * @returns Created invitation
577
+ * @throws Error if validation fails
578
+ *
579
+ * @example
580
+ * ```typescript
581
+ * const invitation = await createInvitation({
582
+ * email: 'newuser@example.com',
583
+ * roleId: 2n,
584
+ * invitedBy: 1n,
585
+ * expiresInDays: 7,
586
+ * metadata: { message: 'Welcome!' }
587
+ * });
588
+ * ```
589
+ */
590
+ declare function createInvitation(params: {
591
+ email: string;
592
+ roleId: number;
593
+ invitedBy: number;
594
+ expiresInDays?: number;
595
+ metadata?: Record<string, any>;
596
+ }): Promise<Invitation>;
597
+ /**
598
+ * Get invitation by token
599
+ *
600
+ * @param token - Invitation token (UUID)
601
+ * @returns Invitation or null if not found
602
+ */
603
+ declare function getInvitationByToken(token: string): Promise<Invitation | null>;
604
+ /**
605
+ * Get invitation with role and inviter details
606
+ *
607
+ * @param token - Invitation token
608
+ * @returns Invitation with joined data or null
609
+ */
610
+ declare function getInvitationWithDetails(token: string): Promise<InvitationWithDetails | null>;
611
+ /**
612
+ * Validate invitation
613
+ *
614
+ * Checks if invitation is valid for acceptance
615
+ *
616
+ * @param token - Invitation token
617
+ * @returns Validation result
618
+ */
619
+ declare function validateInvitation(token: string): Promise<{
620
+ valid: boolean;
621
+ invitation?: Invitation;
622
+ error?: string;
623
+ }>;
624
+ /**
625
+ * Accept invitation and create user account
626
+ *
627
+ * @param params - Acceptance parameters
628
+ * @returns Created user info
629
+ * @throws Error if invitation is invalid or user creation fails
630
+ *
631
+ * @example
632
+ * ```typescript
633
+ * const user = await acceptInvitation({
634
+ * token: 'uuid-v4',
635
+ * password: 'SecurePass123!',
636
+ * publicKey: 'base64-der...',
637
+ * keyId: 'uuid-v4',
638
+ * fingerprint: 'sha256-hex',
639
+ * algorithm: 'ES256'
640
+ * });
641
+ * ```
642
+ */
643
+ declare function acceptInvitation(params: {
644
+ token: string;
645
+ password: string;
646
+ publicKey: string;
647
+ keyId: string;
648
+ fingerprint: string;
649
+ algorithm: 'ES256' | 'RS256';
650
+ }): Promise<{
651
+ userId: number;
652
+ email: string;
653
+ role: string;
654
+ }>;
655
+ /**
656
+ * List invitations with filtering and pagination
657
+ *
658
+ * @param params - Query parameters
659
+ * @returns Paginated invitations
660
+ *
661
+ * @example
662
+ * ```typescript
663
+ * const result = await listInvitations({
664
+ * status: 'pending',
665
+ * invitedBy: 1n,
666
+ * page: 1,
667
+ * limit: 20
668
+ * });
669
+ * ```
670
+ */
671
+ declare function listInvitations(params: {
672
+ status?: InvitationStatus;
673
+ invitedBy?: number;
674
+ page?: number;
675
+ limit?: number;
676
+ }): Promise<{
677
+ invitations: InvitationWithDetails[];
678
+ total: number;
679
+ page: number;
680
+ limit: number;
681
+ totalPages: number;
682
+ }>;
683
+ /**
684
+ * Cancel invitation
685
+ *
686
+ * Only pending invitations can be cancelled
687
+ *
688
+ * @param id - Invitation ID
689
+ * @param cancelledBy - User ID who cancelled
690
+ * @param reason - Optional cancellation reason
691
+ * @throws Error if invitation cannot be cancelled
692
+ */
693
+ declare function cancelInvitation(id: number, cancelledBy: number, reason?: string): Promise<void>;
694
+ /**
695
+ * Delete invitation
696
+ *
697
+ * Permanently removes invitation record
698
+ * Typically only for superadmin cleanup
699
+ *
700
+ * @param id - Invitation ID
701
+ */
702
+ declare function deleteInvitation(id: number): Promise<void>;
703
+ /**
704
+ * Expire old invitations (cron job)
705
+ *
706
+ * Updates status of expired pending invitations
707
+ *
708
+ * @returns Number of invitations expired
709
+ */
710
+ declare function expireOldInvitations(): Promise<number>;
711
+ /**
712
+ * Resend invitation email
713
+ *
714
+ * Extends expiration and triggers email resend
715
+ *
716
+ * @param id - Invitation ID
717
+ * @param expiresInDays - New expiration period (default: 7)
718
+ * @returns Updated invitation
719
+ * @throws Error if invitation cannot be resent
720
+ */
721
+ declare function resendInvitation(id: number, expiresInDays?: number): Promise<Invitation>;
722
+
723
+ /**
724
+ * @spfn/auth - Password Helpers
725
+ *
726
+ * Password hashing and verification using bcrypt
727
+ *
728
+ * Security:
729
+ * - Adaptive hashing (configurable rounds)
730
+ * - Automatic salt generation (per-password)
731
+ * - Constant-time comparison (timing attack protection)
732
+ * - Rainbow table protection
733
+ */
734
+ /**
735
+ * Hash a plain text password using bcrypt
736
+ *
737
+ * Algorithm:
738
+ * 1. Generate random salt (128-bit)
739
+ * 2. Apply bcrypt key derivation (2^rounds iterations)
740
+ * 3. Return $2b$rounds$[salt][hash] (60 chars)
741
+ *
742
+ * @param password - Plain text password to hash
743
+ * @returns Bcrypt hash string (includes salt)
744
+ * @throws Error if password is empty or invalid
745
+ *
746
+ * @example
747
+ * ```typescript
748
+ * const hash = await hashPassword('mySecurePassword123');
749
+ * // Returns: "$2b$10$N9qo8uLOickgx2ZMRZoMyeIjZAgcfl7p92ldGxad68LJZdL17lhWy"
750
+ * ```
751
+ */
752
+ declare function hashPassword(password: string): Promise<string>;
753
+ /**
754
+ * Verify a password against a bcrypt hash
755
+ *
756
+ * Uses constant-time comparison to prevent timing attacks
757
+ * Automatically extracts salt from hash for verification
758
+ *
759
+ * @param password - Plain text password to verify
760
+ * @param hash - Bcrypt hash string (from hashPassword)
761
+ * @returns True if password matches hash
762
+ * @throws Error if inputs are invalid
763
+ *
764
+ * @example
765
+ * ```typescript
766
+ * const isValid = await verifyPassword(
767
+ * 'mySecurePassword123',
768
+ * '$2b$10$N9qo8uLOickgx2ZMRZoMyeIjZAgcfl7p92ldGxad68LJZdL17lhWy'
769
+ * );
770
+ * // Returns: true
771
+ * ```
772
+ */
773
+ declare function verifyPassword(password: string, hash: string): Promise<boolean>;
774
+ /**
775
+ * Validate password strength
776
+ *
777
+ * Requirements:
778
+ * - Minimum 8 characters
779
+ * - At least one uppercase letter
780
+ * - At least one lowercase letter
781
+ * - At least one number
782
+ * - At least one special character
783
+ *
784
+ * @param password - Password to validate
785
+ * @returns Validation result with error messages
786
+ *
787
+ * @example
788
+ * ```typescript
789
+ * const result = validatePasswordStrength('weak');
790
+ * // Returns: { valid: false, errors: ['Too short', 'Missing uppercase', ...] }
791
+ *
792
+ * const result = validatePasswordStrength('SecurePass123!');
793
+ * // Returns: { valid: true, errors: [] }
794
+ * ```
795
+ */
796
+ declare function validatePasswordStrength(password: string): {
797
+ valid: boolean;
798
+ errors: string[];
799
+ };
800
+
801
+ /**
802
+ * @spfn/auth - JWT Helpers
803
+ *
804
+ * JWT token generation and verification
805
+ * Supports both server-signed (legacy) and client-signed (asymmetric) tokens
806
+ *
807
+ * Architecture:
808
+ * - Legacy: Server signs/verifies with SPFN_AUTH_JWT_SECRET (symmetric HMAC)
809
+ * - New: Client signs with privateKey, server verifies with publicKey (asymmetric)
810
+ */
811
+
812
+ interface TokenPayload extends SessionPayload {
813
+ exp?: number;
814
+ iat?: number;
815
+ keyId?: string;
816
+ timestamp?: number;
817
+ }
818
+ /**
819
+ * Generate a JWT token (legacy server-signed)
820
+ *
821
+ * @deprecated Use client-side signing with private keys instead
822
+ * This method uses symmetric HMAC which requires sharing the secret
823
+ *
824
+ * @param payload - Token payload
825
+ * @returns JWT token string
826
+ */
827
+ declare function generateToken(payload: SessionPayload): string;
828
+ /**
829
+ * Verify and decode a JWT token (legacy server-signed)
830
+ *
831
+ * @deprecated Use verifyClientToken for client-signed tokens
832
+ * This method uses symmetric HMAC verification
833
+ *
834
+ * @param token - JWT token to verify
835
+ * @returns Decoded payload
836
+ * @throws Error if verification fails
837
+ */
838
+ declare function verifyToken(token: string): TokenPayload;
839
+ /**
840
+ * Verify client-signed JWT token with public key (DER format)
841
+ *
842
+ * Flow:
843
+ * 1. Decode Base64 DER to Buffer
844
+ * 2. Create KeyObject from DER
845
+ * 3. Verify JWT signature with public key
846
+ * 4. Validate issuer claim
847
+ *
848
+ * @param token - JWT token signed by client's private key
849
+ * @param publicKeyB64 - Base64 encoded DER public key (SPKI format)
850
+ * @param algorithm - Algorithm used for signing (ES256 or RS256)
851
+ * @returns Decoded token payload
852
+ * @throws Error if verification fails
853
+ *
854
+ * @example
855
+ * ```typescript
856
+ * const payload = verifyClientToken(
857
+ * token,
858
+ * 'MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE...',
859
+ * 'ES256'
860
+ * );
861
+ * ```
862
+ */
863
+ declare function verifyClientToken(token: string, publicKeyB64: string, algorithm: 'ES256' | 'RS256'): TokenPayload;
864
+ /**
865
+ * Decode a JWT token without verification (for debugging)
866
+ *
867
+ * WARNING: Does not verify signature! Only use for debugging/logging.
868
+ * Never trust decoded data without verification.
869
+ *
870
+ * @param token - JWT token to decode
871
+ * @returns Decoded payload or null if invalid
872
+ */
873
+ declare function decodeToken(token: string): TokenPayload | null;
874
+ /**
875
+ * Verify public key fingerprint matches
876
+ *
877
+ * Used during registration/login to ensure the public key wasn't tampered with
878
+ * during transmission.
879
+ *
880
+ * Security:
881
+ * - Client sends: publicKey + fingerprint
882
+ * - Server calculates: SHA-256(publicKey)
883
+ * - Server compares: calculated === received
884
+ *
885
+ * @param publicKeyB64 - Base64 encoded DER public key
886
+ * @param expectedFingerprint - SHA-256 hex fingerprint (64 chars)
887
+ * @returns True if fingerprint matches
888
+ *
889
+ * @example
890
+ * ```typescript
891
+ * const isValid = verifyKeyFingerprint(
892
+ * publicKey,
893
+ * 'a1b2c3d4e5f6...' // 64-char hex string
894
+ * );
895
+ * if (!isValid) {
896
+ * throw new Error('Public key fingerprint mismatch');
897
+ * }
898
+ * ```
899
+ */
900
+ declare function verifyKeyFingerprint(publicKeyB64: string, expectedFingerprint: string): boolean;
901
+
902
+ /**
903
+ * @spfn/auth - Verification Code Helpers
904
+ *
905
+ * Helper functions for email/phone verification codes
906
+ */
907
+ /**
908
+ * Verification token payload
909
+ */
910
+ interface VerificationTokenPayload {
911
+ target: string;
912
+ targetType: 'email' | 'phone';
913
+ purpose: 'registration' | 'login' | 'password_reset';
914
+ codeId: number;
915
+ }
916
+ /**
917
+ * Generate a random 6-digit verification code
918
+ *
919
+ * @returns 6-digit code as string
920
+ */
921
+ declare function generateVerificationCode(): string;
922
+ /**
923
+ * Store verification code in database
924
+ *
925
+ * @param target - Email or phone number
926
+ * @param targetType - Type of target (email or phone)
927
+ * @param code - 6-digit verification code
928
+ * @param purpose - Purpose of verification
929
+ * @returns Created verification code record
930
+ */
931
+ declare function storeVerificationCode(target: string, targetType: 'email' | 'phone', code: string, purpose: 'registration' | 'login' | 'password_reset'): Promise<{
932
+ id: number;
933
+ createdAt: Date;
934
+ updatedAt: Date;
935
+ expiresAt: Date;
936
+ target: string;
937
+ targetType: "email" | "phone";
938
+ code: string;
939
+ purpose: "registration" | "login" | "password_reset" | "email_change" | "phone_change";
940
+ usedAt: Date | null;
941
+ attempts: string;
942
+ }>;
943
+ /**
944
+ * Validate verification code
945
+ *
946
+ * @param target - Email or phone number
947
+ * @param targetType - Type of target
948
+ * @param code - 6-digit code to validate
949
+ * @param purpose - Purpose of verification
950
+ * @returns Validation result with code ID if valid
951
+ */
952
+ declare function validateVerificationCode(target: string, targetType: 'email' | 'phone', code: string, purpose: 'registration' | 'login' | 'password_reset'): Promise<{
953
+ valid: boolean;
954
+ codeId?: number;
955
+ error?: string;
956
+ }>;
957
+ /**
958
+ * Mark verification code as used
959
+ *
960
+ * @param codeId - Verification code ID
961
+ */
962
+ declare function markCodeAsUsed(codeId: number): Promise<void>;
963
+ /**
964
+ * Create verification token (JWT)
965
+ *
966
+ * @param payload - Token payload
967
+ * @returns Signed JWT token
968
+ */
969
+ declare function createVerificationToken(payload: VerificationTokenPayload): string;
970
+ /**
971
+ * Validate verification token (JWT)
972
+ *
973
+ * @param token - JWT token to validate
974
+ * @returns Decoded payload if valid, null otherwise
975
+ */
976
+ declare function validateVerificationToken(token: string): VerificationTokenPayload | null;
977
+ /**
978
+ * Send verification code via email
979
+ *
980
+ * @param email - Email address
981
+ * @param code - 6-digit verification code
982
+ * @param purpose - Purpose of verification
983
+ */
984
+ declare function sendVerificationEmail(email: string, code: string, purpose: string): Promise<void>;
985
+ /**
986
+ * Send verification code via SMS
987
+ *
988
+ * @param phone - Phone number in E.164 format
989
+ * @param code - 6-digit verification code
990
+ * @param purpose - Purpose of verification
991
+ */
992
+ declare function sendVerificationSMS(phone: string, code: string, purpose: string): Promise<void>;
993
+
994
+ /**
995
+ * @spfn/auth - Authentication Middleware
996
+ *
997
+ * Verify client-signed JWT token with public key
998
+ *
999
+ * Flow:
1000
+ * 1. Extract Authorization header + X-Key-Id header
1001
+ * 2. Fetch public key from database
1002
+ * 3. Verify JWT signature with public key
1003
+ * 4. Validate user status
1004
+ * 5. Attach user to context
1005
+ *
1006
+ * Security Checks:
1007
+ * - Token signature verification
1008
+ * - Key expiration check
1009
+ * - User status check (active/inactive/suspended)
1010
+ * - Key revocation check (isActive flag)
1011
+ */
1012
+
1013
+ interface AuthContext {
1014
+ user: User;
1015
+ userId: string;
1016
+ keyId: string;
1017
+ }
1018
+ declare module 'hono' {
1019
+ interface ContextVariableMap {
1020
+ auth: AuthContext;
1021
+ }
1022
+ }
1023
+ /**
1024
+ * Authentication middleware
1025
+ *
1026
+ * Verifies client-signed JWT token using stored public key
1027
+ * Must be applied to routes that require authentication
1028
+ *
1029
+ * @example
1030
+ * ```typescript
1031
+ * // In route file
1032
+ * app.bind(logoutContract, [authenticate], async (c) => {
1033
+ * const auth = c.raw.get('auth'); // Get auth context
1034
+ * const { user, userId, keyId } = auth;
1035
+ * // Or access directly: c.raw.get('auth').user
1036
+ * });
1037
+ * ```
1038
+ */
1039
+ declare function authenticate(c: Context, next: Next): Promise<Response | void>;
1040
+
1041
+ /**
1042
+ * Auth Context Helpers
1043
+ *
1044
+ * Helper functions to access authenticated user data from route context
1045
+ */
1046
+
1047
+ /**
1048
+ * Get auth context from route context
1049
+ *
1050
+ * Accepts both raw Hono Context and RouteContext with raw property
1051
+ *
1052
+ * @example
1053
+ * ```typescript
1054
+ * // With RouteContext (RPC routes)
1055
+ * app.bind(logoutContract, [authenticate], async (c) => {
1056
+ * const { user, userId, keyId } = getAuth(c);
1057
+ * // Use authenticated data...
1058
+ * });
1059
+ *
1060
+ * // With raw Context (middleware)
1061
+ * const auth = getAuth(c);
1062
+ * ```
1063
+ */
1064
+ declare function getAuth(c: Context | {
1065
+ raw: Context;
1066
+ }): AuthContext;
1067
+ /**
1068
+ * Get authenticated user from route context
1069
+ *
1070
+ * @example
1071
+ * ```typescript
1072
+ * app.bind(profileContract, [authenticate], async (c) => {
1073
+ * const user = getUser(c);
1074
+ * return c.success({ email: user.email });
1075
+ * });
1076
+ * ```
1077
+ */
1078
+ declare function getUser(c: Context | {
1079
+ raw: Context;
1080
+ }): {
1081
+ id: number;
1082
+ createdAt: Date;
1083
+ updatedAt: Date;
1084
+ email: string | null;
1085
+ phone: string | null;
1086
+ passwordHash: string | null;
1087
+ passwordChangeRequired: boolean;
1088
+ roleId: number;
1089
+ status: "active" | "inactive" | "suspended";
1090
+ emailVerifiedAt: Date | null;
1091
+ phoneVerifiedAt: Date | null;
1092
+ lastLoginAt: Date | null;
1093
+ };
1094
+ /**
1095
+ * Get authenticated user ID from route context
1096
+ *
1097
+ * @example
1098
+ * ```typescript
1099
+ * app.bind(postsContract, [authenticate], async (c) => {
1100
+ * const userId = getUserId(c);
1101
+ * const posts = await findPosts({ authorId: userId });
1102
+ * });
1103
+ * ```
1104
+ */
1105
+ declare function getUserId(c: Context | {
1106
+ raw: Context;
1107
+ }): string;
1108
+ /**
1109
+ * Get current key ID from route context
1110
+ *
1111
+ * @example
1112
+ * ```typescript
1113
+ * app.bind(rotateKeyContract, [authenticate], async (c) => {
1114
+ * const oldKeyId = getKeyId(c);
1115
+ * // Revoke old key...
1116
+ * });
1117
+ * ```
1118
+ */
1119
+ declare function getKeyId(c: Context | {
1120
+ raw: Context;
1121
+ }): string;
1122
+
1123
+ /**
1124
+ * @spfn/auth - Permission Middleware
1125
+ *
1126
+ * Middleware functions for permission-based access control
1127
+ */
1128
+
1129
+ /**
1130
+ * Require user to have all specified permissions
1131
+ *
1132
+ * Must be used after authenticate middleware
1133
+ *
1134
+ * @param permissionNames - Permission names (e.g., 'user:delete', 'post:publish')
1135
+ * @returns Middleware function
1136
+ *
1137
+ * @example
1138
+ * ```typescript
1139
+ * app.bind(
1140
+ * deleteUserContract,
1141
+ * [authenticate, requirePermissions('user:delete')],
1142
+ * async (c) => {
1143
+ * // Only users with user:delete permission
1144
+ * }
1145
+ * );
1146
+ *
1147
+ * // Multiple permissions (all required)
1148
+ * app.bind(
1149
+ * publishPostContract,
1150
+ * [authenticate, requirePermissions('post:write', 'post:publish')],
1151
+ * async (c) => {
1152
+ * // Needs both permissions
1153
+ * }
1154
+ * );
1155
+ * ```
1156
+ */
1157
+ declare function requirePermissions(...permissionNames: string[]): (c: Context, next: Next) => Promise<void>;
1158
+ /**
1159
+ * Require user to have at least one of the specified permissions
1160
+ *
1161
+ * Must be used after authenticate middleware
1162
+ *
1163
+ * @param permissionNames - Permission names
1164
+ * @returns Middleware function
1165
+ *
1166
+ * @example
1167
+ * ```typescript
1168
+ * app.bind(
1169
+ * viewContentContract,
1170
+ * [authenticate, requireAnyPermission('content:read', 'admin:access')],
1171
+ * async (c) => {
1172
+ * // User has either content:read OR admin:access
1173
+ * }
1174
+ * );
1175
+ * ```
1176
+ */
1177
+ declare function requireAnyPermission(...permissionNames: string[]): (c: Context, next: Next) => Promise<void>;
1178
+
1179
+ /**
1180
+ * @spfn/auth - Role Middleware
1181
+ *
1182
+ * Middleware functions for role-based access control
1183
+ */
1184
+
1185
+ /**
1186
+ * Require user to have one of the specified roles
1187
+ *
1188
+ * Must be used after authenticate middleware
1189
+ *
1190
+ * @param roleNames - Role names (e.g., 'admin', 'superadmin')
1191
+ * @returns Middleware function
1192
+ *
1193
+ * @example
1194
+ * ```typescript
1195
+ * app.bind(
1196
+ * adminDashboardContract,
1197
+ * [authenticate, requireRole('admin', 'superadmin')],
1198
+ * async (c) => {
1199
+ * // Only admin or superadmin
1200
+ * }
1201
+ * );
1202
+ *
1203
+ * // Single role
1204
+ * app.bind(
1205
+ * systemConfigContract,
1206
+ * [authenticate, requireRole('superadmin')],
1207
+ * async (c) => {
1208
+ * // Only superadmin
1209
+ * }
1210
+ * );
1211
+ * ```
1212
+ */
1213
+ declare function requireRole(...roleNames: string[]): (c: Context, next: Next) => Promise<void>;
1214
+
1215
+ /**
1216
+ * @spfn/auth - Setup Functions
1217
+ *
1218
+ * Initial setup and admin account creation
1219
+ */
1220
+ /**
1221
+ * Ensure admin accounts exist from environment variables
1222
+ *
1223
+ * Supports multiple admin account creation via three formats:
1224
+ * 1. JSON format (SPFN_AUTH_ADMIN_ACCOUNTS)
1225
+ * 2. Comma-separated format (SPFN_AUTH_ADMIN_EMAILS + SPFN_AUTH_ADMIN_PASSWORDS + SPFN_AUTH_ADMIN_ROLES)
1226
+ * 3. Single account format (SPFN_AUTH_ADMIN_EMAIL + SPFN_AUTH_ADMIN_PASSWORD) - legacy
1227
+ *
1228
+ * Default behavior for created accounts:
1229
+ * - emailVerifiedAt: current timestamp (auto-verified)
1230
+ * - passwordChangeRequired: true (must change on first login)
1231
+ * - status: 'active'
1232
+ *
1233
+ * @example
1234
+ * ```typescript
1235
+ * // In your server startup code:
1236
+ * import { ensureAdminExists } from '@spfn/auth/server';
1237
+ *
1238
+ * await ensureAdminExists();
1239
+ * ```
1240
+ */
1241
+ declare function ensureAdminExists(): Promise<void>;
1242
+
1243
+ export { type AuthContext, type AuthInitOptions, BUILTIN_PERMISSIONS, BUILTIN_ROLES, BUILTIN_ROLE_PERMISSIONS, type BuiltinPermissionName, type BuiltinRoleName, type ChangePasswordParams, type CheckAccountExistsParams, type CheckAccountExistsResult, type LoginParams, type LoginResult, type LogoutParams, PRESET_PERMISSIONS, PRESET_ROLES, PRESET_ROLE_PERMISSIONS, type PermissionConfig, type RegisterParams, type RegisterPublicKeyParams, type RegisterResult, type RevokeKeyParams, type RoleConfig, type RotateKeyParams, type RotateKeyResult, type SendVerificationCodeParams, type SendVerificationCodeResult, type TokenPayload, type VerificationTokenPayload, type VerifyCodeParams, type VerifyCodeResult, acceptInvitation, addPermissionToRole, authenticate, cancelInvitation, changePasswordService, checkAccountExistsService, createInvitation, createRole, createVerificationToken, decodeToken, deleteInvitation, deleteRole, ensureAdminExists, expireOldInvitations, generateToken, generateVerificationCode, getAllRoles, getAuth, getInvitationByToken, getInvitationWithDetails, getKeyId, getRoleByName, getRolePermissions, getUser, getUserByEmailService, getUserByIdService, getUserByPhoneService, getUserId, getUserPermissions, hasAllPermissions, hasAnyPermission, hasAnyRole, hasPermission, hasRole, hashPassword, initializeAuth, listInvitations, loginService, logoutService, markCodeAsUsed, registerPublicKeyService, registerService, removePermissionFromRole, requireAnyPermission, requirePermissions, requireRole, resendInvitation, revokeKeyService, rotateKeyService, sendVerificationCodeService, sendVerificationEmail, sendVerificationSMS, setRolePermissions, storeVerificationCode, updateLastLoginService, updateRole, updateUserService, validateInvitation, validatePasswordStrength, validateVerificationCode, validateVerificationToken, verifyClientToken, verifyCodeService, verifyKeyFingerprint, verifyPassword, verifyToken };