@spfn/auth 0.2.0-beta.4 → 0.2.0-beta.41

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.
@@ -1,8 +1,86 @@
1
+ import * as _spfn_core_route from '@spfn/core/route';
1
2
  import * as _sinclair_typebox from '@sinclair/typebox';
2
3
  import { Static } from '@sinclair/typebox';
3
- import * as _spfn_core_route from '@spfn/core/route';
4
4
  import { User } from '@spfn/auth/server';
5
5
 
6
+ /**
7
+ * Role information for client/API responses
8
+ */
9
+ interface Role {
10
+ id: number;
11
+ name: string;
12
+ displayName: string;
13
+ description: string | null;
14
+ isBuiltin: boolean;
15
+ isSystem: boolean;
16
+ isActive: boolean;
17
+ priority: number;
18
+ createdAt: Date;
19
+ updatedAt: Date;
20
+ }
21
+ /**
22
+ * Permission information for client/API responses
23
+ */
24
+ interface Permission {
25
+ id: number;
26
+ name: string;
27
+ displayName: string;
28
+ description: string | null;
29
+ category: string | null;
30
+ isBuiltin: boolean;
31
+ isSystem: boolean;
32
+ isActive: boolean;
33
+ metadata: Record<string, any> | null;
34
+ createdAt: Date;
35
+ updatedAt: Date;
36
+ }
37
+ interface AuthSession {
38
+ userId: number;
39
+ email: string | null;
40
+ emailVerified: boolean;
41
+ phoneVerified: boolean;
42
+ role: Role;
43
+ permissions: Permission[];
44
+ }
45
+ interface ProfileInfo {
46
+ profileId: number;
47
+ displayName: string;
48
+ firstName: string | null;
49
+ lastName: string | null;
50
+ avatarUrl: string | null;
51
+ bio: string | null;
52
+ locale: string;
53
+ timezone: string;
54
+ website: string | null;
55
+ location: string | null;
56
+ company: string | null;
57
+ jobTitle: string | null;
58
+ metadata: Record<string, any> | null;
59
+ createdAt: Date;
60
+ updatedAt: Date;
61
+ }
62
+ /**
63
+ * User Profile Response
64
+ *
65
+ * Complete user data including:
66
+ * - User fields at top level (userId, email, etc.)
67
+ * - Profile data as nested field (optional)
68
+ *
69
+ * Excludes:
70
+ * - Role and permissions (use auth session API)
71
+ */
72
+ interface UserProfile {
73
+ userId: number;
74
+ email: string | null;
75
+ username: string | null;
76
+ emailVerified: boolean;
77
+ phoneVerified: boolean;
78
+ lastLoginAt: Date | null;
79
+ createdAt: Date;
80
+ updatedAt: Date;
81
+ profile: ProfileInfo | null;
82
+ }
83
+
6
84
  /**
7
85
  * @spfn/auth - Shared Types
8
86
  *
@@ -71,6 +149,7 @@ interface RegisterParams {
71
149
  keyId: string;
72
150
  fingerprint: string;
73
151
  algorithm?: KeyAlgorithmType;
152
+ metadata?: Record<string, unknown>;
74
153
  }
75
154
  interface RegisterResult {
76
155
  userId: string;
@@ -299,6 +378,74 @@ interface AuthInitOptions {
299
378
  sessionTtl?: string | number;
300
379
  }
301
380
 
381
+ /**
382
+ * @spfn/auth - OAuth Service
383
+ *
384
+ * OAuth 인증 비즈니스 로직
385
+ * - Google OAuth Authorization Code Flow
386
+ * - 소셜 계정 연결/생성
387
+ * - publicKey는 state에서 추출하여 등록
388
+ */
389
+
390
+ interface OAuthStartParams {
391
+ provider: SocialProvider;
392
+ returnUrl: string;
393
+ publicKey: string;
394
+ keyId: string;
395
+ fingerprint: string;
396
+ algorithm: KeyAlgorithmType;
397
+ metadata?: Record<string, unknown>;
398
+ }
399
+ interface OAuthStartResult {
400
+ authUrl: string;
401
+ }
402
+ interface OAuthCallbackParams {
403
+ provider: SocialProvider;
404
+ code: string;
405
+ state: string;
406
+ }
407
+ interface OAuthCallbackResult {
408
+ redirectUrl: string;
409
+ userId: string;
410
+ keyId: string;
411
+ isNewUser: boolean;
412
+ }
413
+ /**
414
+ * OAuth 로그인 시작 - Provider 로그인 페이지로 리다이렉트할 URL 생성
415
+ *
416
+ * Next.js에서 키쌍을 생성한 후, publicKey를 state에 포함하여 호출
417
+ */
418
+ declare function oauthStartService(params: OAuthStartParams): Promise<OAuthStartResult>;
419
+ /**
420
+ * OAuth 콜백 처리 - Code를 Token으로 교환하고 사용자 생성/연결
421
+ *
422
+ * state에서 publicKey를 추출하여 서버에 등록
423
+ * Next.js는 반환된 userId, keyId로 세션을 구성
424
+ */
425
+ declare function oauthCallbackService(params: OAuthCallbackParams): Promise<OAuthCallbackResult>;
426
+ /**
427
+ * OAuth 에러 리다이렉트 URL 생성
428
+ */
429
+ declare function buildOAuthErrorUrl(error: string): string;
430
+ /**
431
+ * OAuth provider가 활성화되어 있는지 확인
432
+ */
433
+ declare function isOAuthProviderEnabled(provider: SocialProvider): boolean;
434
+ /**
435
+ * 활성화된 모든 OAuth provider 목록
436
+ */
437
+ declare function getEnabledOAuthProviders(): SocialProvider[];
438
+ /**
439
+ * Google access token 조회 (만료 시 자동 리프레시)
440
+ *
441
+ * 저장된 토큰이 만료 임박(5분 이내) 또는 만료 상태이면
442
+ * refresh token으로 자동 갱신 후 DB 업데이트하여 유효한 토큰 반환.
443
+ *
444
+ * @param userId - 사용자 ID
445
+ * @returns 유효한 Google access token
446
+ */
447
+ declare function getGoogleAccessToken(userId: number): Promise<string>;
448
+
302
449
  /**
303
450
  * @spfn/auth - Main Router
304
451
  *
@@ -310,29 +457,148 @@ interface AuthInitOptions {
310
457
  *
311
458
  * Routes:
312
459
  * - Auth: /_auth/exists, /_auth/codes, /_auth/login, /_auth/logout, etc.
460
+ * - OAuth: /_auth/oauth/google, /_auth/oauth/google/callback, etc.
313
461
  * - Invitations: /_auth/invitations/*
314
462
  * - Users: /_auth/users/*
463
+ * - Admin: /_auth/admin/* (superadmin only)
315
464
  */
316
465
  declare const mainAuthRouter: _spfn_core_route.Router<{
317
- getUserProfile: _spfn_core_route.RouteDef<{}, {}, UserProfile>;
318
- updateUserProfile: _spfn_core_route.RouteDef<{
466
+ checkAccountExists: _spfn_core_route.RouteDef<{
467
+ body: _sinclair_typebox.TUnion<[_sinclair_typebox.TObject<{
468
+ email: _sinclair_typebox.TString;
469
+ }>, _sinclair_typebox.TObject<{
470
+ phone: _sinclair_typebox.TString;
471
+ }>]>;
472
+ }, {}, CheckAccountExistsResult>;
473
+ sendVerificationCode: _spfn_core_route.RouteDef<{
319
474
  body: _sinclair_typebox.TObject<{
320
- displayName: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
321
- firstName: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
322
- lastName: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
323
- avatarUrl: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
324
- bio: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
325
- locale: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
326
- timezone: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
327
- dateOfBirth: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
328
- gender: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
329
- website: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
330
- location: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
331
- company: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
332
- jobTitle: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
333
- metadata: _sinclair_typebox.TOptional<_sinclair_typebox.TRecord<_sinclair_typebox.TString, _sinclair_typebox.TAny>>;
475
+ target: _sinclair_typebox.TString;
476
+ targetType: _sinclair_typebox.TUnion<[_sinclair_typebox.TLiteral<"email">, _sinclair_typebox.TLiteral<"phone">]>;
477
+ purpose: _sinclair_typebox.TUnion<[_sinclair_typebox.TLiteral<"registration">, _sinclair_typebox.TLiteral<"login">, _sinclair_typebox.TLiteral<"password_reset">, _sinclair_typebox.TLiteral<"email_change">, _sinclair_typebox.TLiteral<"phone_change">]>;
334
478
  }>;
335
- }, {}, ProfileInfo>;
479
+ }, {}, SendVerificationCodeResult>;
480
+ verifyCode: _spfn_core_route.RouteDef<{
481
+ body: _sinclair_typebox.TObject<{
482
+ target: _sinclair_typebox.TString;
483
+ targetType: _sinclair_typebox.TUnion<[_sinclair_typebox.TLiteral<"email">, _sinclair_typebox.TLiteral<"phone">]>;
484
+ code: _sinclair_typebox.TString;
485
+ purpose: _sinclair_typebox.TUnion<[_sinclair_typebox.TLiteral<"registration">, _sinclair_typebox.TLiteral<"login">, _sinclair_typebox.TLiteral<"password_reset">, _sinclair_typebox.TLiteral<"email_change">, _sinclair_typebox.TLiteral<"phone_change">]>;
486
+ }>;
487
+ }, {}, {
488
+ valid: boolean;
489
+ verificationToken: string;
490
+ }>;
491
+ register: _spfn_core_route.RouteDef<{
492
+ body: _sinclair_typebox.TObject<{
493
+ email: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
494
+ phone: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
495
+ verificationToken: _sinclair_typebox.TString;
496
+ password: _sinclair_typebox.TString;
497
+ metadata: _sinclair_typebox.TOptional<_sinclair_typebox.TRecord<_sinclair_typebox.TString, _sinclair_typebox.TUnknown>>;
498
+ }>;
499
+ }, {
500
+ body: _sinclair_typebox.TObject<{
501
+ publicKey: _sinclair_typebox.TString;
502
+ keyId: _sinclair_typebox.TString;
503
+ fingerprint: _sinclair_typebox.TString;
504
+ algorithm: _sinclair_typebox.TUnion<_sinclair_typebox.TLiteral<"ES256" | "RS256">[]>;
505
+ }>;
506
+ }, RegisterResult>;
507
+ login: _spfn_core_route.RouteDef<{
508
+ body: _sinclair_typebox.TObject<{
509
+ email: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
510
+ phone: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
511
+ password: _sinclair_typebox.TString;
512
+ }>;
513
+ }, {
514
+ body: _sinclair_typebox.TObject<{
515
+ publicKey: _sinclair_typebox.TString;
516
+ keyId: _sinclair_typebox.TString;
517
+ fingerprint: _sinclair_typebox.TString;
518
+ algorithm: _sinclair_typebox.TUnion<_sinclair_typebox.TLiteral<"ES256" | "RS256">[]>;
519
+ oldKeyId: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
520
+ }>;
521
+ }, LoginResult>;
522
+ logout: _spfn_core_route.RouteDef<{}, {}, void>;
523
+ rotateKey: _spfn_core_route.RouteDef<{}, {
524
+ body: _sinclair_typebox.TObject<{
525
+ publicKey: _sinclair_typebox.TString;
526
+ keyId: _sinclair_typebox.TString;
527
+ fingerprint: _sinclair_typebox.TString;
528
+ algorithm: _sinclair_typebox.TUnion<_sinclair_typebox.TLiteral<"ES256" | "RS256">[]>;
529
+ }>;
530
+ }, RotateKeyResult>;
531
+ changePassword: _spfn_core_route.RouteDef<{
532
+ body: _sinclair_typebox.TObject<{
533
+ currentPassword: _sinclair_typebox.TString;
534
+ newPassword: _sinclair_typebox.TString;
535
+ }>;
536
+ }, {}, void>;
537
+ getAuthSession: _spfn_core_route.RouteDef<{}, {}, {
538
+ role: {
539
+ id: number;
540
+ name: string;
541
+ displayName: string;
542
+ priority: number;
543
+ };
544
+ permissions: {
545
+ id: number;
546
+ name: string;
547
+ displayName: string;
548
+ category: "custom" | "user" | "auth" | "rbac" | "system" | undefined;
549
+ }[];
550
+ userId: number;
551
+ email: string | null;
552
+ emailVerified: boolean;
553
+ phoneVerified: boolean;
554
+ }>;
555
+ oauthGoogleStart: _spfn_core_route.RouteDef<{
556
+ query: _sinclair_typebox.TObject<{
557
+ state: _sinclair_typebox.TString;
558
+ }>;
559
+ }, {}, Response>;
560
+ oauthGoogleCallback: _spfn_core_route.RouteDef<{
561
+ query: _sinclair_typebox.TObject<{
562
+ code: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
563
+ state: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
564
+ error: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
565
+ error_description: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
566
+ }>;
567
+ }, {}, Response>;
568
+ oauthStart: _spfn_core_route.RouteDef<{
569
+ body: _sinclair_typebox.TObject<{
570
+ provider: _sinclair_typebox.TUnion<_sinclair_typebox.TLiteral<"google" | "github" | "kakao" | "naver">[]>;
571
+ returnUrl: _sinclair_typebox.TString;
572
+ publicKey: _sinclair_typebox.TString;
573
+ keyId: _sinclair_typebox.TString;
574
+ fingerprint: _sinclair_typebox.TString;
575
+ algorithm: _sinclair_typebox.TUnion<_sinclair_typebox.TLiteral<"ES256" | "RS256">[]>;
576
+ metadata: _sinclair_typebox.TOptional<_sinclair_typebox.TRecord<_sinclair_typebox.TString, _sinclair_typebox.TUnknown>>;
577
+ }>;
578
+ }, {}, OAuthStartResult>;
579
+ oauthProviders: _spfn_core_route.RouteDef<{}, {}, {
580
+ providers: ("google" | "github" | "kakao" | "naver")[];
581
+ }>;
582
+ getGoogleOAuthUrl: _spfn_core_route.RouteDef<{
583
+ body: _sinclair_typebox.TObject<{
584
+ returnUrl: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
585
+ state: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
586
+ }>;
587
+ }, {}, {
588
+ authUrl: string;
589
+ }>;
590
+ oauthFinalize: _spfn_core_route.RouteDef<{
591
+ body: _sinclair_typebox.TObject<{
592
+ userId: _sinclair_typebox.TString;
593
+ keyId: _sinclair_typebox.TString;
594
+ returnUrl: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
595
+ }>;
596
+ }, {}, {
597
+ success: boolean;
598
+ userId: string;
599
+ keyId: string;
600
+ returnUrl: string;
601
+ }>;
336
602
  getInvitation: _spfn_core_route.RouteDef<{
337
603
  params: _sinclair_typebox.TObject<{
338
604
  token: _sinclair_typebox.TString;
@@ -433,97 +699,137 @@ declare const mainAuthRouter: _spfn_core_route.Router<{
433
699
  id: _sinclair_typebox.TNumber;
434
700
  }>;
435
701
  }, {}, void>;
436
- checkAccountExists: _spfn_core_route.RouteDef<{
437
- body: _sinclair_typebox.TUnion<[_sinclair_typebox.TObject<{
438
- email: _sinclair_typebox.TString;
439
- }>, _sinclair_typebox.TObject<{
440
- phone: _sinclair_typebox.TString;
441
- }>]>;
442
- }, {}, CheckAccountExistsResult>;
443
- sendVerificationCode: _spfn_core_route.RouteDef<{
702
+ getUserProfile: _spfn_core_route.RouteDef<{}, {}, UserProfile>;
703
+ updateUserProfile: _spfn_core_route.RouteDef<{
444
704
  body: _sinclair_typebox.TObject<{
445
- target: _sinclair_typebox.TString;
446
- targetType: _sinclair_typebox.TUnion<[_sinclair_typebox.TLiteral<"email">, _sinclair_typebox.TLiteral<"phone">]>;
447
- purpose: _sinclair_typebox.TUnion<[_sinclair_typebox.TLiteral<"registration">, _sinclair_typebox.TLiteral<"login">, _sinclair_typebox.TLiteral<"password_reset">, _sinclair_typebox.TLiteral<"email_change">, _sinclair_typebox.TLiteral<"phone_change">]>;
705
+ displayName: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
706
+ firstName: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
707
+ lastName: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
708
+ avatarUrl: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
709
+ bio: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
710
+ locale: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
711
+ timezone: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
712
+ dateOfBirth: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
713
+ gender: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
714
+ website: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
715
+ location: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
716
+ company: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
717
+ jobTitle: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
718
+ metadata: _sinclair_typebox.TOptional<_sinclair_typebox.TRecord<_sinclair_typebox.TString, _sinclair_typebox.TAny>>;
448
719
  }>;
449
- }, {}, SendVerificationCodeResult>;
450
- verifyCode: _spfn_core_route.RouteDef<{
451
- body: _sinclair_typebox.TObject<{
452
- target: _sinclair_typebox.TString;
453
- targetType: _sinclair_typebox.TUnion<[_sinclair_typebox.TLiteral<"email">, _sinclair_typebox.TLiteral<"phone">]>;
454
- code: _sinclair_typebox.TString;
455
- purpose: _sinclair_typebox.TUnion<[_sinclair_typebox.TLiteral<"registration">, _sinclair_typebox.TLiteral<"login">, _sinclair_typebox.TLiteral<"password_reset">, _sinclair_typebox.TLiteral<"email_change">, _sinclair_typebox.TLiteral<"phone_change">]>;
720
+ }, {}, ProfileInfo>;
721
+ checkUsername: _spfn_core_route.RouteDef<{
722
+ query: _sinclair_typebox.TObject<{
723
+ username: _sinclair_typebox.TString;
456
724
  }>;
457
725
  }, {}, {
458
- valid: boolean;
459
- verificationToken: string;
726
+ available: boolean;
460
727
  }>;
461
- register: _spfn_core_route.RouteDef<{
462
- body: _sinclair_typebox.TObject<{
463
- email: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
464
- phone: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
465
- verificationToken: _sinclair_typebox.TString;
466
- password: _sinclair_typebox.TString;
467
- }>;
468
- }, {
469
- body: _sinclair_typebox.TObject<{
470
- publicKey: _sinclair_typebox.TString;
471
- keyId: _sinclair_typebox.TString;
472
- fingerprint: _sinclair_typebox.TString;
473
- algorithm: _sinclair_typebox.TUnion<_sinclair_typebox.TLiteral<"ES256" | "RS256">[]>;
474
- }>;
475
- }, RegisterResult>;
476
- login: _spfn_core_route.RouteDef<{
728
+ updateUsername: _spfn_core_route.RouteDef<{
477
729
  body: _sinclair_typebox.TObject<{
478
- email: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
479
- phone: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
480
- password: _sinclair_typebox.TString;
730
+ username: _sinclair_typebox.TUnion<[_sinclair_typebox.TString, _sinclair_typebox.TNull]>;
481
731
  }>;
482
- }, {
732
+ }, {}, {
733
+ createdAt: Date;
734
+ updatedAt: Date;
735
+ id: number;
736
+ email: string | null;
737
+ phone: string | null;
738
+ username: string | null;
739
+ passwordHash: string | null;
740
+ passwordChangeRequired: boolean;
741
+ roleId: number;
742
+ status: "active" | "inactive" | "suspended";
743
+ emailVerifiedAt: Date | null;
744
+ phoneVerifiedAt: Date | null;
745
+ lastLoginAt: Date | null;
746
+ }>;
747
+ updateLocale: _spfn_core_route.RouteDef<{
483
748
  body: _sinclair_typebox.TObject<{
484
- publicKey: _sinclair_typebox.TString;
485
- keyId: _sinclair_typebox.TString;
486
- fingerprint: _sinclair_typebox.TString;
487
- algorithm: _sinclair_typebox.TUnion<_sinclair_typebox.TLiteral<"ES256" | "RS256">[]>;
488
- oldKeyId: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
749
+ locale: _sinclair_typebox.TString;
489
750
  }>;
490
- }, LoginResult>;
491
- logout: _spfn_core_route.RouteDef<{
492
- body: _sinclair_typebox.TObject<{}>;
493
- }, {}, void>;
494
- rotateKey: _spfn_core_route.RouteDef<{
495
- body: _sinclair_typebox.TObject<{}>;
496
- }, {
497
- body: _sinclair_typebox.TObject<{
498
- publicKey: _sinclair_typebox.TString;
499
- keyId: _sinclair_typebox.TString;
500
- fingerprint: _sinclair_typebox.TString;
501
- algorithm: _sinclair_typebox.TUnion<_sinclair_typebox.TLiteral<"ES256" | "RS256">[]>;
751
+ }, {}, {
752
+ locale: string;
753
+ }>;
754
+ listRoles: _spfn_core_route.RouteDef<{
755
+ query: _sinclair_typebox.TObject<{
756
+ includeInactive: _sinclair_typebox.TOptional<_sinclair_typebox.TBoolean>;
502
757
  }>;
503
- }, RotateKeyResult>;
504
- changePassword: _spfn_core_route.RouteDef<{
758
+ }, {}, {
759
+ roles: {
760
+ description: string | null;
761
+ id: number;
762
+ name: string;
763
+ displayName: string;
764
+ isBuiltin: boolean;
765
+ isSystem: boolean;
766
+ isActive: boolean;
767
+ priority: number;
768
+ createdAt: Date;
769
+ updatedAt: Date;
770
+ }[];
771
+ }>;
772
+ createAdminRole: _spfn_core_route.RouteDef<{
505
773
  body: _sinclair_typebox.TObject<{
506
- currentPassword: _sinclair_typebox.TString;
507
- newPassword: _sinclair_typebox.TString;
774
+ name: _sinclair_typebox.TString;
775
+ displayName: _sinclair_typebox.TString;
776
+ description: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
777
+ priority: _sinclair_typebox.TOptional<_sinclair_typebox.TNumber>;
778
+ permissionIds: _sinclair_typebox.TOptional<_sinclair_typebox.TArray<_sinclair_typebox.TNumber>>;
508
779
  }>;
509
- }, {}, void>;
510
- getAuthSession: _spfn_core_route.RouteDef<{}, {}, {
780
+ }, {}, {
511
781
  role: {
782
+ description: string | null;
512
783
  id: number;
513
784
  name: string;
514
785
  displayName: string;
786
+ isBuiltin: boolean;
787
+ isSystem: boolean;
788
+ isActive: boolean;
515
789
  priority: number;
790
+ createdAt: Date;
791
+ updatedAt: Date;
516
792
  };
517
- permissions: {
793
+ }>;
794
+ updateAdminRole: _spfn_core_route.RouteDef<{
795
+ params: _sinclair_typebox.TObject<{
796
+ id: _sinclair_typebox.TNumber;
797
+ }>;
798
+ body: _sinclair_typebox.TObject<{
799
+ displayName: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
800
+ description: _sinclair_typebox.TOptional<_sinclair_typebox.TString>;
801
+ priority: _sinclair_typebox.TOptional<_sinclair_typebox.TNumber>;
802
+ isActive: _sinclair_typebox.TOptional<_sinclair_typebox.TBoolean>;
803
+ }>;
804
+ }, {}, {
805
+ role: {
806
+ description: string | null;
518
807
  id: number;
519
808
  name: string;
520
809
  displayName: string;
521
- category: "auth" | "custom" | "user" | "rbac" | "system" | undefined;
522
- }[];
810
+ isBuiltin: boolean;
811
+ isSystem: boolean;
812
+ isActive: boolean;
813
+ priority: number;
814
+ createdAt: Date;
815
+ updatedAt: Date;
816
+ };
817
+ }>;
818
+ deleteAdminRole: _spfn_core_route.RouteDef<{
819
+ params: _sinclair_typebox.TObject<{
820
+ id: _sinclair_typebox.TNumber;
821
+ }>;
822
+ }, {}, void>;
823
+ updateUserRole: _spfn_core_route.RouteDef<{
824
+ params: _sinclair_typebox.TObject<{
825
+ userId: _sinclair_typebox.TNumber;
826
+ }>;
827
+ body: _sinclair_typebox.TObject<{
828
+ roleId: _sinclair_typebox.TNumber;
829
+ }>;
830
+ }, {}, {
523
831
  userId: number;
524
- email: string | null;
525
- emailVerified: boolean;
526
- phoneVerified: boolean;
832
+ roleId: number;
527
833
  }>;
528
834
  }>;
529
835
 
@@ -531,6 +837,8 @@ interface AuthContext {
531
837
  user: User;
532
838
  userId: string;
533
839
  keyId: string;
840
+ role: string | null;
841
+ locale: string;
534
842
  }
535
843
  declare module 'hono' {
536
844
  interface ContextVariableMap {
@@ -568,82 +876,33 @@ declare module 'hono' {
568
876
  * ```
569
877
  */
570
878
  declare const authenticate: _spfn_core_route.NamedMiddleware<"auth">;
571
-
572
879
  /**
573
- * Role information for client/API responses
574
- */
575
- interface Role {
576
- id: number;
577
- name: string;
578
- displayName: string;
579
- description: string | null;
580
- isBuiltin: boolean;
581
- isSystem: boolean;
582
- isActive: boolean;
583
- priority: number;
584
- createdAt: Date;
585
- updatedAt: Date;
586
- }
587
- /**
588
- * Permission information for client/API responses
589
- */
590
- interface Permission {
591
- id: number;
592
- name: string;
593
- displayName: string;
594
- description: string | null;
595
- category: string | null;
596
- isBuiltin: boolean;
597
- isSystem: boolean;
598
- isActive: boolean;
599
- metadata: Record<string, any> | null;
600
- createdAt: Date;
601
- updatedAt: Date;
602
- }
603
- interface AuthSession {
604
- userId: number;
605
- email: string | null;
606
- emailVerified: boolean;
607
- phoneVerified: boolean;
608
- role: Role;
609
- permissions: Permission[];
610
- }
611
- interface ProfileInfo {
612
- profileId: number;
613
- displayName: string;
614
- firstName: string | null;
615
- lastName: string | null;
616
- avatarUrl: string | null;
617
- bio: string | null;
618
- locale: string;
619
- timezone: string;
620
- website: string | null;
621
- location: string | null;
622
- company: string | null;
623
- jobTitle: string | null;
624
- metadata: Record<string, any> | null;
625
- createdAt: Date;
626
- updatedAt: Date;
627
- }
628
- /**
629
- * User Profile Response
880
+ * Optional authentication middleware
630
881
  *
631
- * Complete user data including:
632
- * - User fields at top level (userId, email, etc.)
633
- * - Profile data as nested field (optional)
882
+ * Same as `authenticate` but does NOT reject unauthenticated requests.
883
+ * - No token continues without auth context
884
+ * - Invalid token continues without auth context
885
+ * - Valid token → sets auth context normally
634
886
  *
635
- * Excludes:
636
- * - Role and permissions (use auth session API)
887
+ * Auto-skips the global 'auth' middleware when used at route level.
888
+ *
889
+ * @example
890
+ * ```typescript
891
+ * // No need for .skip(['auth']) — handled automatically
892
+ * export const getProducts = route.get('/products')
893
+ * .use([optionalAuth])
894
+ * .handler(async (c) => {
895
+ * const auth = getOptionalAuth(c); // AuthContext | undefined
896
+ *
897
+ * if (auth)
898
+ * {
899
+ * return getPersonalizedProducts(auth.userId);
900
+ * }
901
+ *
902
+ * return getPublicProducts();
903
+ * });
904
+ * ```
637
905
  */
638
- interface UserProfile {
639
- userId: number;
640
- email: string | null;
641
- emailVerified: boolean;
642
- phoneVerified: boolean;
643
- lastLoginAt: Date | null;
644
- createdAt: Date;
645
- updatedAt: Date;
646
- profile: ProfileInfo | null;
647
- }
906
+ declare const optionalAuth: _spfn_core_route.NamedMiddleware<"optionalAuth">;
648
907
 
649
- export { VerificationPurposeSchema as $, type AuthSession as A, type ChangePasswordParams as B, type CheckAccountExistsResult as C, sendVerificationCodeService as D, verifyCodeService as E, type SendVerificationCodeParams as F, type VerifyCodeParams as G, type VerifyCodeResult as H, INVITATION_STATUSES as I, registerPublicKeyService as J, KEY_ALGORITHM as K, type LoginResult as L, rotateKeyService as M, revokeKeyService as N, type RegisterPublicKeyParams as O, type PermissionConfig as P, type RotateKeyParams as Q, type RoleConfig as R, type SendVerificationCodeResult as S, type RevokeKeyParams as T, type UserProfile as U, type VerificationTargetType as V, authenticate as W, EmailSchema as X, PhoneSchema as Y, PasswordSchema as Z, TargetTypeSchema as _, type ProfileInfo as a, type RegisterResult as b, type RotateKeyResult as c, USER_STATUSES as d, SOCIAL_PROVIDERS as e, type VerificationPurpose as f, VERIFICATION_TARGET_TYPES as g, VERIFICATION_PURPOSES as h, PERMISSION_CATEGORIES as i, type PermissionCategory as j, type AuthInitOptions as k, type KeyAlgorithmType as l, mainAuthRouter as m, type InvitationStatus as n, type UserStatus as o, type SocialProvider as p, type AuthContext as q, checkAccountExistsService as r, registerService as s, loginService as t, logoutService as u, changePasswordService as v, type CheckAccountExistsParams as w, type RegisterParams as x, type LoginParams as y, type LogoutParams as z };
908
+ export { getEnabledOAuthProviders as $, type AuthSession as A, type ChangePasswordParams as B, type CheckAccountExistsResult as C, sendVerificationCodeService as D, verifyCodeService as E, type SendVerificationCodeParams as F, type VerifyCodeParams as G, type VerifyCodeResult as H, INVITATION_STATUSES as I, registerPublicKeyService as J, KEY_ALGORITHM as K, type LoginResult as L, rotateKeyService as M, revokeKeyService as N, type OAuthStartResult as O, type PermissionConfig as P, type RegisterPublicKeyParams as Q, type RoleConfig as R, type SendVerificationCodeResult as S, type RotateKeyParams as T, type UserProfile as U, type VerificationTargetType as V, type RevokeKeyParams as W, oauthStartService as X, oauthCallbackService as Y, buildOAuthErrorUrl as Z, isOAuthProviderEnabled as _, type RegisterResult as a, getGoogleAccessToken as a0, type OAuthStartParams as a1, type OAuthCallbackParams as a2, type OAuthCallbackResult as a3, authenticate as a4, optionalAuth as a5, EmailSchema as a6, PhoneSchema as a7, PasswordSchema as a8, TargetTypeSchema as a9, VerificationPurposeSchema as aa, type RotateKeyResult as b, type ProfileInfo as c, USER_STATUSES as d, SOCIAL_PROVIDERS as e, type VerificationPurpose as f, VERIFICATION_TARGET_TYPES as g, VERIFICATION_PURPOSES as h, PERMISSION_CATEGORIES as i, type PermissionCategory as j, type AuthInitOptions as k, type KeyAlgorithmType as l, mainAuthRouter as m, type InvitationStatus as n, type UserStatus as o, type SocialProvider as p, type AuthContext as q, checkAccountExistsService as r, registerService as s, loginService as t, logoutService as u, changePasswordService as v, type CheckAccountExistsParams as w, type RegisterParams as x, type LoginParams as y, type LogoutParams as z };