@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.
package/dist/server.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { k as AuthInitOptions, l as KeyAlgorithmType, n as InvitationStatus, f as VerificationPurpose, j as PermissionCategory, q as AuthContext } from './dto-Bb2qFUO6.js';
2
- export { B as ChangePasswordParams, w as CheckAccountExistsParams, C as CheckAccountExistsResult, X as EmailSchema, I as INVITATION_STATUSES, K as KEY_ALGORITHM, y as LoginParams, L as LoginResult, z as LogoutParams, Z as PasswordSchema, Y as PhoneSchema, x as RegisterParams, O as RegisterPublicKeyParams, b as RegisterResult, T as RevokeKeyParams, Q as RotateKeyParams, c as RotateKeyResult, e as SOCIAL_PROVIDERS, F as SendVerificationCodeParams, S as SendVerificationCodeResult, p as SocialProvider, _ as TargetTypeSchema, d as USER_STATUSES, o as UserStatus, h as VERIFICATION_PURPOSES, g as VERIFICATION_TARGET_TYPES, $ as VerificationPurposeSchema, V as VerificationTargetType, G as VerifyCodeParams, H as VerifyCodeResult, m as authRouter, W as authenticate, v as changePasswordService, r as checkAccountExistsService, t as loginService, u as logoutService, J as registerPublicKeyService, s as registerService, N as revokeKeyService, M as rotateKeyService, D as sendVerificationCodeService, E as verifyCodeService } from './dto-Bb2qFUO6.js';
1
+ import { k as AuthInitOptions, l as KeyAlgorithmType, n as InvitationStatus, f as VerificationPurpose, j as PermissionCategory, p as SocialProvider, q as AuthContext } from './authenticate-2953PCm8.js';
2
+ export { B as ChangePasswordParams, w as CheckAccountExistsParams, C as CheckAccountExistsResult, a6 as EmailSchema, I as INVITATION_STATUSES, K as KEY_ALGORITHM, y as LoginParams, L as LoginResult, z as LogoutParams, a2 as OAuthCallbackParams, a3 as OAuthCallbackResult, a1 as OAuthStartParams, O as OAuthStartResult, a8 as PasswordSchema, a7 as PhoneSchema, x as RegisterParams, Q as RegisterPublicKeyParams, a as RegisterResult, W as RevokeKeyParams, T as RotateKeyParams, b as RotateKeyResult, e as SOCIAL_PROVIDERS, F as SendVerificationCodeParams, S as SendVerificationCodeResult, a9 as TargetTypeSchema, d as USER_STATUSES, o as UserStatus, h as VERIFICATION_PURPOSES, g as VERIFICATION_TARGET_TYPES, aa as VerificationPurposeSchema, V as VerificationTargetType, G as VerifyCodeParams, H as VerifyCodeResult, m as authRouter, a4 as authenticate, Z as buildOAuthErrorUrl, v as changePasswordService, r as checkAccountExistsService, $ as getEnabledOAuthProviders, a0 as getGoogleAccessToken, _ as isOAuthProviderEnabled, t as loginService, u as logoutService, Y as oauthCallbackService, X as oauthStartService, a5 as optionalAuth, J as registerPublicKeyService, s as registerService, N as revokeKeyService, M as rotateKeyService, D as sendVerificationCodeService, E as verifyCodeService } from './authenticate-2953PCm8.js';
3
3
  import * as drizzle_orm_pg_core from 'drizzle-orm/pg-core';
4
4
  import { UserProfile as UserProfile$1, ProfileInfo } from '@spfn/auth';
5
5
  import { BaseRepository } from '@spfn/core/db';
@@ -7,7 +7,8 @@ import { Context } from 'hono';
7
7
  import * as _spfn_core_route from '@spfn/core/route';
8
8
  import { Algorithm } from 'jsonwebtoken';
9
9
  import * as _spfn_core_logger from '@spfn/core/logger';
10
- import '@sinclair/typebox';
10
+ import * as _spfn_core_event from '@spfn/core/event';
11
+ import * as _sinclair_typebox from '@sinclair/typebox';
11
12
  import '@spfn/auth/server';
12
13
 
13
14
  /**
@@ -112,6 +113,23 @@ declare const users: drizzle_orm_pg_core.PgTableWithColumns<{
112
113
  identity: undefined;
113
114
  generated: undefined;
114
115
  }, {}, {}>;
116
+ username: drizzle_orm_pg_core.PgColumn<{
117
+ name: "username";
118
+ tableName: "users";
119
+ dataType: "string";
120
+ columnType: "PgText";
121
+ data: string;
122
+ driverParam: string;
123
+ notNull: false;
124
+ hasDefault: false;
125
+ isPrimaryKey: false;
126
+ isAutoincrement: false;
127
+ hasRuntimeDefault: false;
128
+ enumValues: [string, ...string[]];
129
+ baseColumn: never;
130
+ identity: undefined;
131
+ generated: undefined;
132
+ }, {}, {}>;
115
133
  passwordHash: drizzle_orm_pg_core.PgColumn<{
116
134
  name: "password_hash";
117
135
  tableName: "users";
@@ -150,11 +168,11 @@ declare const users: drizzle_orm_pg_core.PgTableWithColumns<{
150
168
  name: `${string}_id`;
151
169
  tableName: "users";
152
170
  dataType: "number";
153
- columnType: "PgBigSerial53";
171
+ columnType: "PgBigInt53";
154
172
  data: number;
155
- driverParam: number;
173
+ driverParam: string | number;
156
174
  notNull: true;
157
- hasDefault: true;
175
+ hasDefault: false;
158
176
  isPrimaryKey: false;
159
177
  isAutoincrement: false;
160
178
  hasRuntimeDefault: false;
@@ -252,6 +270,7 @@ declare function getUserByIdService(userId: number): Promise<{
252
270
  id: number;
253
271
  email: string | null;
254
272
  phone: string | null;
273
+ username: string | null;
255
274
  passwordHash: string | null;
256
275
  passwordChangeRequired: boolean;
257
276
  roleId: number;
@@ -269,6 +288,7 @@ declare function getUserByEmailService(email: string): Promise<{
269
288
  id: number;
270
289
  email: string | null;
271
290
  phone: string | null;
291
+ username: string | null;
272
292
  passwordHash: string | null;
273
293
  passwordChangeRequired: boolean;
274
294
  roleId: number;
@@ -286,6 +306,7 @@ declare function getUserByPhoneService(phone: string): Promise<{
286
306
  id: number;
287
307
  email: string | null;
288
308
  phone: string | null;
309
+ username: string | null;
289
310
  passwordHash: string | null;
290
311
  passwordChangeRequired: boolean;
291
312
  roleId: number;
@@ -302,6 +323,35 @@ declare function updateLastLoginService(userId: number): Promise<void>;
302
323
  * Update user data
303
324
  */
304
325
  declare function updateUserService(userId: number, updates: Partial<NewUser>): Promise<void>;
326
+ /**
327
+ * Check if username is available
328
+ *
329
+ * @returns true if the username is available (not taken and not reserved)
330
+ */
331
+ declare function checkUsernameAvailableService(username: string): Promise<boolean>;
332
+ /**
333
+ * Update username with reserved word and duplicate check
334
+ *
335
+ * @param userId - User ID (string, number, or bigint)
336
+ * @param username - New username or null to clear
337
+ * @throws ReservedUsernameError if username is reserved
338
+ * @throws UsernameAlreadyTakenError if username is already in use by another user
339
+ */
340
+ declare function updateUsernameService(userId: string | number | bigint, username: string | null): Promise<{
341
+ createdAt: Date;
342
+ updatedAt: Date;
343
+ id: number;
344
+ email: string | null;
345
+ phone: string | null;
346
+ username: string | null;
347
+ passwordHash: string | null;
348
+ passwordChangeRequired: boolean;
349
+ roleId: number;
350
+ status: "active" | "inactive" | "suspended";
351
+ emailVerifiedAt: Date | null;
352
+ phoneVerifiedAt: Date | null;
353
+ lastLoginAt: Date | null;
354
+ }>;
305
355
 
306
356
  /**
307
357
  * @spfn/auth - RBAC Initialization Service
@@ -880,11 +930,11 @@ declare const userInvitations: drizzle_orm_pg_core.PgTableWithColumns<{
880
930
  name: `${string}_id`;
881
931
  tableName: "user_invitations";
882
932
  dataType: "number";
883
- columnType: "PgBigSerial53";
933
+ columnType: "PgBigInt53";
884
934
  data: number;
885
- driverParam: number;
935
+ driverParam: string | number;
886
936
  notNull: true;
887
- hasDefault: true;
937
+ hasDefault: false;
888
938
  isPrimaryKey: false;
889
939
  isAutoincrement: false;
890
940
  hasRuntimeDefault: false;
@@ -897,11 +947,11 @@ declare const userInvitations: drizzle_orm_pg_core.PgTableWithColumns<{
897
947
  name: `${string}_id`;
898
948
  tableName: "user_invitations";
899
949
  dataType: "number";
900
- columnType: "PgBigSerial53";
950
+ columnType: "PgBigInt53";
901
951
  data: number;
902
- driverParam: number;
952
+ driverParam: string | number;
903
953
  notNull: true;
904
- hasDefault: true;
954
+ hasDefault: false;
905
955
  isPrimaryKey: false;
906
956
  isAutoincrement: false;
907
957
  hasRuntimeDefault: false;
@@ -1255,7 +1305,7 @@ declare function getAuthSessionService(userId: string | number | bigint): Promis
1255
1305
  id: number;
1256
1306
  name: string;
1257
1307
  displayName: string;
1258
- category: "auth" | "custom" | "user" | "rbac" | "system" | undefined;
1308
+ category: "custom" | "user" | "auth" | "rbac" | "system" | undefined;
1259
1309
  }[];
1260
1310
  userId: number;
1261
1311
  email: string | null;
@@ -1305,6 +1355,16 @@ interface UpdateProfileParams {
1305
1355
  * ```
1306
1356
  */
1307
1357
  declare function getUserProfileService(userId: string | number | bigint): Promise<UserProfile$1>;
1358
+ /**
1359
+ * Update user locale
1360
+ *
1361
+ * @param userId - User ID
1362
+ * @param locale - Locale code (e.g., 'en', 'ko', 'ja')
1363
+ * @returns Updated locale
1364
+ */
1365
+ declare function updateLocaleService(userId: string | number | bigint, locale: string): Promise<{
1366
+ locale: string;
1367
+ }>;
1308
1368
  /**
1309
1369
  * Update user profile (upsert)
1310
1370
  *
@@ -1326,369 +1386,6 @@ declare function getUserProfileService(userId: string | number | bigint): Promis
1326
1386
  */
1327
1387
  declare function updateUserProfileService(userId: string | number | bigint, params: UpdateProfileParams): Promise<ProfileInfo>;
1328
1388
 
1329
- /**
1330
- * @spfn/auth - Email Template Types
1331
- *
1332
- * Type definitions for customizable email templates
1333
- */
1334
- /**
1335
- * Common template result
1336
- */
1337
- interface EmailTemplateResult {
1338
- subject: string;
1339
- text: string;
1340
- html: string;
1341
- }
1342
- /**
1343
- * Verification code template parameters
1344
- */
1345
- interface VerificationCodeParams {
1346
- code: string;
1347
- purpose: 'registration' | 'login' | 'password_reset' | string;
1348
- expiresInMinutes?: number;
1349
- appName?: string;
1350
- }
1351
- /**
1352
- * Email template provider interface
1353
- *
1354
- * Implement this interface to create custom email templates
1355
- *
1356
- * @example
1357
- * ```typescript
1358
- * import { registerEmailTemplates } from '@spfn/auth/server';
1359
- *
1360
- * registerEmailTemplates({
1361
- * verificationCode: (params) => ({
1362
- * subject: 'Your Code',
1363
- * text: `Code: ${params.code}`,
1364
- * html: `<h1>Code: ${params.code}</h1>`,
1365
- * }),
1366
- * });
1367
- * ```
1368
- */
1369
- interface EmailTemplateProvider {
1370
- /**
1371
- * Verification code email template
1372
- */
1373
- verificationCode?(params: VerificationCodeParams): EmailTemplateResult;
1374
- /**
1375
- * Welcome email template (after registration)
1376
- */
1377
- welcome?(params: {
1378
- email: string;
1379
- appName?: string;
1380
- }): EmailTemplateResult;
1381
- /**
1382
- * Password reset email template
1383
- */
1384
- passwordReset?(params: {
1385
- resetLink: string;
1386
- expiresInMinutes?: number;
1387
- appName?: string;
1388
- }): EmailTemplateResult;
1389
- /**
1390
- * Invitation email template
1391
- */
1392
- invitation?(params: {
1393
- inviteLink: string;
1394
- inviterName?: string;
1395
- roleName?: string;
1396
- appName?: string;
1397
- }): EmailTemplateResult;
1398
- }
1399
-
1400
- /**
1401
- * @spfn/auth - Email Template Registry
1402
- *
1403
- * Manages custom email template registration and fallback to defaults
1404
- */
1405
-
1406
- /**
1407
- * Register custom email templates
1408
- *
1409
- * Templates not provided will fall back to defaults
1410
- *
1411
- * @param templates - Custom template implementations
1412
- *
1413
- * @example
1414
- * ```typescript
1415
- * import { registerEmailTemplates } from '@spfn/auth/server';
1416
- *
1417
- * // Override verification code template with custom design
1418
- * registerEmailTemplates({
1419
- * verificationCode: ({ code, purpose, expiresInMinutes }) => ({
1420
- * subject: `[MyApp] Your verification code`,
1421
- * text: `Your code is: ${code}`,
1422
- * html: `
1423
- * <div style="font-family: Arial;">
1424
- * <h1>Welcome to MyApp!</h1>
1425
- * <p>Your code: <strong>${code}</strong></p>
1426
- * </div>
1427
- * `,
1428
- * }),
1429
- * });
1430
- * ```
1431
- */
1432
- declare function registerEmailTemplates(templates: Partial<EmailTemplateProvider>): void;
1433
- /**
1434
- * Get verification code template
1435
- *
1436
- * Uses custom template if registered, otherwise falls back to default
1437
- */
1438
- declare function getVerificationCodeTemplate(params: VerificationCodeParams): EmailTemplateResult;
1439
- /**
1440
- * Get welcome template
1441
- */
1442
- declare function getWelcomeTemplate(params: {
1443
- email: string;
1444
- appName?: string;
1445
- }): EmailTemplateResult;
1446
- /**
1447
- * Get password reset template
1448
- */
1449
- declare function getPasswordResetTemplate(params: {
1450
- resetLink: string;
1451
- expiresInMinutes?: number;
1452
- appName?: string;
1453
- }): EmailTemplateResult;
1454
- /**
1455
- * Get invitation template
1456
- */
1457
- declare function getInvitationTemplate(params: {
1458
- inviteLink: string;
1459
- inviterName?: string;
1460
- roleName?: string;
1461
- appName?: string;
1462
- }): EmailTemplateResult;
1463
-
1464
- /**
1465
- * @spfn/auth - Email Service Types
1466
- *
1467
- * Type definitions for email sending service
1468
- */
1469
- /**
1470
- * Parameters for sending email
1471
- */
1472
- interface SendEmailParams {
1473
- /**
1474
- * Recipient email address
1475
- */
1476
- to: string;
1477
- /**
1478
- * Email subject
1479
- */
1480
- subject: string;
1481
- /**
1482
- * Plain text content
1483
- */
1484
- text?: string;
1485
- /**
1486
- * HTML content
1487
- */
1488
- html?: string;
1489
- /**
1490
- * Purpose of the email (for logging)
1491
- */
1492
- purpose?: string;
1493
- }
1494
- /**
1495
- * Result of sending email
1496
- */
1497
- interface SendEmailResult {
1498
- /**
1499
- * Whether email was sent successfully
1500
- */
1501
- success: boolean;
1502
- /**
1503
- * Message ID from email provider (if successful)
1504
- */
1505
- messageId?: string;
1506
- /**
1507
- * Error message (if failed)
1508
- */
1509
- error?: string;
1510
- }
1511
- /**
1512
- * Email Provider Interface
1513
- *
1514
- * Implement this interface to create custom email providers
1515
- *
1516
- * @example
1517
- * ```typescript
1518
- * import { EmailProvider, registerEmailProvider } from '@spfn/auth/server/services/email';
1519
- *
1520
- * const sendgridProvider: EmailProvider = {
1521
- * name: 'sendgrid',
1522
- * sendEmail: async (params) => {
1523
- * // Your SendGrid implementation
1524
- * return { success: true, messageId: '...' };
1525
- * }
1526
- * };
1527
- *
1528
- * registerEmailProvider(sendgridProvider);
1529
- * ```
1530
- */
1531
- interface EmailProvider {
1532
- /**
1533
- * Provider name (e.g., 'aws-ses', 'sendgrid', 'custom')
1534
- */
1535
- name: string;
1536
- /**
1537
- * Send email via this provider
1538
- *
1539
- * @param params - Email parameters
1540
- * @returns Send result
1541
- */
1542
- sendEmail(params: SendEmailParams): Promise<SendEmailResult>;
1543
- }
1544
-
1545
- /**
1546
- * @spfn/auth - Email Provider Management
1547
- *
1548
- * Manages email provider registration and fallback behavior
1549
- */
1550
-
1551
- /**
1552
- * Register a custom email provider
1553
- *
1554
- * @param provider - Custom email provider implementation
1555
- *
1556
- * @example
1557
- * ```typescript
1558
- * import { registerEmailProvider } from '@spfn/auth/server/services/email';
1559
- *
1560
- * const sendgridProvider = {
1561
- * name: 'sendgrid',
1562
- * sendEmail: async (params) => {
1563
- * // SendGrid implementation
1564
- * return { success: true, messageId: '...' };
1565
- * }
1566
- * };
1567
- *
1568
- * registerEmailProvider(sendgridProvider);
1569
- * ```
1570
- */
1571
- declare function registerEmailProvider(provider: EmailProvider): void;
1572
- /**
1573
- * Send email using the registered provider
1574
- *
1575
- * Falls back to development mode (console only) if no provider is registered
1576
- *
1577
- * @param params - Email parameters
1578
- * @returns Send result
1579
- */
1580
- declare function sendEmail(params: SendEmailParams): Promise<SendEmailResult>;
1581
-
1582
- /**
1583
- * @spfn/auth - SMS Service Types
1584
- *
1585
- * Type definitions for SMS sending service
1586
- */
1587
- /**
1588
- * Parameters for sending SMS
1589
- */
1590
- interface SendSMSParams {
1591
- /**
1592
- * Phone number in E.164 format (e.g., +821012345678)
1593
- */
1594
- phone: string;
1595
- /**
1596
- * SMS message content
1597
- */
1598
- message: string;
1599
- /**
1600
- * Purpose of the SMS (for logging)
1601
- */
1602
- purpose?: string;
1603
- }
1604
- /**
1605
- * Result of sending SMS
1606
- */
1607
- interface SendSMSResult {
1608
- /**
1609
- * Whether SMS was sent successfully
1610
- */
1611
- success: boolean;
1612
- /**
1613
- * Message ID from SMS provider (if successful)
1614
- */
1615
- messageId?: string;
1616
- /**
1617
- * Error message (if failed)
1618
- */
1619
- error?: string;
1620
- }
1621
- /**
1622
- * SMS Provider Interface
1623
- *
1624
- * Implement this interface to create custom SMS providers
1625
- *
1626
- * @example
1627
- * ```typescript
1628
- * import { SMSProvider, registerSMSProvider } from '@spfn/auth/server/services/sms';
1629
- *
1630
- * const twilioProvider: SMSProvider = {
1631
- * name: 'twilio',
1632
- * sendSMS: async (params) => {
1633
- * // Your Twilio implementation
1634
- * return { success: true, messageId: '...' };
1635
- * }
1636
- * };
1637
- *
1638
- * registerSMSProvider(twilioProvider);
1639
- * ```
1640
- */
1641
- interface SMSProvider {
1642
- /**
1643
- * Provider name (e.g., 'aws-sns', 'twilio', 'custom')
1644
- */
1645
- name: string;
1646
- /**
1647
- * Send SMS via this provider
1648
- *
1649
- * @param params - SMS parameters
1650
- * @returns Send result
1651
- */
1652
- sendSMS(params: SendSMSParams): Promise<SendSMSResult>;
1653
- }
1654
-
1655
- /**
1656
- * @spfn/auth - SMS Provider Management
1657
- *
1658
- * Manages SMS provider registration and fallback behavior
1659
- */
1660
-
1661
- /**
1662
- * Register a custom SMS provider
1663
- *
1664
- * @param provider - Custom SMS provider implementation
1665
- *
1666
- * @example
1667
- * ```typescript
1668
- * import { registerSMSProvider } from '@spfn/auth/server/services/sms';
1669
- *
1670
- * const twilioProvider = {
1671
- * name: 'twilio',
1672
- * sendSMS: async (params) => {
1673
- * // Twilio implementation
1674
- * return { success: true, messageId: '...' };
1675
- * }
1676
- * };
1677
- *
1678
- * registerSMSProvider(twilioProvider);
1679
- * ```
1680
- */
1681
- declare function registerSMSProvider(provider: SMSProvider): void;
1682
- /**
1683
- * Send SMS using the registered provider
1684
- *
1685
- * Falls back to development mode (console only) if no provider is registered
1686
- *
1687
- * @param params - SMS parameters
1688
- * @returns Send result
1689
- */
1690
- declare function sendSMS(params: SendSMSParams): Promise<SendSMSResult>;
1691
-
1692
1389
  /**
1693
1390
  * @spfn/auth - Database Schema Definition
1694
1391
  *
@@ -1771,11 +1468,11 @@ declare const userProfiles: drizzle_orm_pg_core.PgTableWithColumns<{
1771
1468
  name: `${string}_id`;
1772
1469
  tableName: "user_profiles";
1773
1470
  dataType: "number";
1774
- columnType: "PgBigSerial53";
1471
+ columnType: "PgBigInt53";
1775
1472
  data: number;
1776
- driverParam: number;
1473
+ driverParam: string | number;
1777
1474
  notNull: true;
1778
- hasDefault: true;
1475
+ hasDefault: false;
1779
1476
  isPrimaryKey: false;
1780
1477
  isAutoincrement: false;
1781
1478
  hasRuntimeDefault: false;
@@ -2065,11 +1762,11 @@ declare const userPublicKeys: drizzle_orm_pg_core.PgTableWithColumns<{
2065
1762
  name: `${string}_id`;
2066
1763
  tableName: "user_public_keys";
2067
1764
  dataType: "number";
2068
- columnType: "PgBigSerial53";
1765
+ columnType: "PgBigInt53";
2069
1766
  data: number;
2070
- driverParam: number;
1767
+ driverParam: string | number;
2071
1768
  notNull: true;
2072
- hasDefault: true;
1769
+ hasDefault: false;
2073
1770
  isPrimaryKey: false;
2074
1771
  isAutoincrement: false;
2075
1772
  hasRuntimeDefault: false;
@@ -2318,11 +2015,11 @@ declare const userSocialAccounts: drizzle_orm_pg_core.PgTableWithColumns<{
2318
2015
  name: `${string}_id`;
2319
2016
  tableName: "user_social_accounts";
2320
2017
  dataType: "number";
2321
- columnType: "PgBigSerial53";
2018
+ columnType: "PgBigInt53";
2322
2019
  data: number;
2323
- driverParam: number;
2020
+ driverParam: string | number;
2324
2021
  notNull: true;
2325
- hasDefault: true;
2022
+ hasDefault: false;
2326
2023
  isPrimaryKey: false;
2327
2024
  isAutoincrement: false;
2328
2025
  hasRuntimeDefault: false;
@@ -2747,7 +2444,7 @@ declare const permissions: drizzle_orm_pg_core.PgTableWithColumns<{
2747
2444
  tableName: "permissions";
2748
2445
  dataType: "string";
2749
2446
  columnType: "PgText";
2750
- data: "auth" | "custom" | "user" | "rbac" | "system";
2447
+ data: "custom" | "user" | "auth" | "rbac" | "system";
2751
2448
  driverParam: string;
2752
2449
  notNull: false;
2753
2450
  hasDefault: false;
@@ -2905,11 +2602,11 @@ declare const rolePermissions: drizzle_orm_pg_core.PgTableWithColumns<{
2905
2602
  name: `${string}_id`;
2906
2603
  tableName: "role_permissions";
2907
2604
  dataType: "number";
2908
- columnType: "PgBigSerial53";
2605
+ columnType: "PgBigInt53";
2909
2606
  data: number;
2910
- driverParam: number;
2607
+ driverParam: string | number;
2911
2608
  notNull: true;
2912
- hasDefault: true;
2609
+ hasDefault: false;
2913
2610
  isPrimaryKey: false;
2914
2611
  isAutoincrement: false;
2915
2612
  hasRuntimeDefault: false;
@@ -2922,11 +2619,11 @@ declare const rolePermissions: drizzle_orm_pg_core.PgTableWithColumns<{
2922
2619
  name: `${string}_id`;
2923
2620
  tableName: "role_permissions";
2924
2621
  dataType: "number";
2925
- columnType: "PgBigSerial53";
2622
+ columnType: "PgBigInt53";
2926
2623
  data: number;
2927
- driverParam: number;
2624
+ driverParam: string | number;
2928
2625
  notNull: true;
2929
- hasDefault: true;
2626
+ hasDefault: false;
2930
2627
  isPrimaryKey: false;
2931
2628
  isAutoincrement: false;
2932
2629
  hasRuntimeDefault: false;
@@ -3014,11 +2711,11 @@ declare const userPermissions: drizzle_orm_pg_core.PgTableWithColumns<{
3014
2711
  name: `${string}_id`;
3015
2712
  tableName: "user_permissions";
3016
2713
  dataType: "number";
3017
- columnType: "PgBigSerial53";
2714
+ columnType: "PgBigInt53";
3018
2715
  data: number;
3019
- driverParam: number;
2716
+ driverParam: string | number;
3020
2717
  notNull: true;
3021
- hasDefault: true;
2718
+ hasDefault: false;
3022
2719
  isPrimaryKey: false;
3023
2720
  isAutoincrement: false;
3024
2721
  hasRuntimeDefault: false;
@@ -3031,11 +2728,11 @@ declare const userPermissions: drizzle_orm_pg_core.PgTableWithColumns<{
3031
2728
  name: `${string}_id`;
3032
2729
  tableName: "user_permissions";
3033
2730
  dataType: "number";
3034
- columnType: "PgBigSerial53";
2731
+ columnType: "PgBigInt53";
3035
2732
  data: number;
3036
- driverParam: number;
2733
+ driverParam: string | number;
3037
2734
  notNull: true;
3038
- hasDefault: true;
2735
+ hasDefault: false;
3039
2736
  isPrimaryKey: false;
3040
2737
  isAutoincrement: false;
3041
2738
  hasRuntimeDefault: false;
@@ -3127,6 +2824,7 @@ declare class UsersRepository extends BaseRepository {
3127
2824
  id: number;
3128
2825
  email: string | null;
3129
2826
  phone: string | null;
2827
+ username: string | null;
3130
2828
  passwordHash: string | null;
3131
2829
  passwordChangeRequired: boolean;
3132
2830
  roleId: number;
@@ -3145,6 +2843,7 @@ declare class UsersRepository extends BaseRepository {
3145
2843
  id: number;
3146
2844
  email: string | null;
3147
2845
  phone: string | null;
2846
+ username: string | null;
3148
2847
  passwordHash: string | null;
3149
2848
  passwordChangeRequired: boolean;
3150
2849
  roleId: number;
@@ -3163,6 +2862,26 @@ declare class UsersRepository extends BaseRepository {
3163
2862
  id: number;
3164
2863
  email: string | null;
3165
2864
  phone: string | null;
2865
+ username: string | null;
2866
+ passwordHash: string | null;
2867
+ passwordChangeRequired: boolean;
2868
+ roleId: number;
2869
+ status: "active" | "inactive" | "suspended";
2870
+ emailVerifiedAt: Date | null;
2871
+ phoneVerifiedAt: Date | null;
2872
+ lastLoginAt: Date | null;
2873
+ }>;
2874
+ /**
2875
+ * 사용자명으로 사용자 조회
2876
+ * Read replica 사용
2877
+ */
2878
+ findByUsername(username: string): Promise<{
2879
+ createdAt: Date;
2880
+ updatedAt: Date;
2881
+ id: number;
2882
+ email: string | null;
2883
+ phone: string | null;
2884
+ username: string | null;
3166
2885
  passwordHash: string | null;
3167
2886
  passwordChangeRequired: boolean;
3168
2887
  roleId: number;
@@ -3181,6 +2900,7 @@ declare class UsersRepository extends BaseRepository {
3181
2900
  id: number;
3182
2901
  email: string | null;
3183
2902
  phone: string | null;
2903
+ username: string | null;
3184
2904
  passwordHash: string | null;
3185
2905
  passwordChangeRequired: boolean;
3186
2906
  roleId: number;
@@ -3189,6 +2909,34 @@ declare class UsersRepository extends BaseRepository {
3189
2909
  phoneVerifiedAt: Date | null;
3190
2910
  lastLoginAt: Date | null;
3191
2911
  } | null>;
2912
+ /**
2913
+ * ID로 사용자 + Role 조회 (leftJoin)
2914
+ * Read replica 사용
2915
+ *
2916
+ * roleId가 null인 유저는 role: null 반환
2917
+ */
2918
+ findByIdWithRole(id: number): Promise<{
2919
+ user: {
2920
+ createdAt: Date;
2921
+ updatedAt: Date;
2922
+ id: number;
2923
+ email: string | null;
2924
+ phone: string | null;
2925
+ username: string | null;
2926
+ passwordHash: string | null;
2927
+ passwordChangeRequired: boolean;
2928
+ roleId: number;
2929
+ status: "active" | "inactive" | "suspended";
2930
+ emailVerifiedAt: Date | null;
2931
+ phoneVerifiedAt: Date | null;
2932
+ lastLoginAt: Date | null;
2933
+ };
2934
+ role: {
2935
+ name: string;
2936
+ displayName: string;
2937
+ priority: number;
2938
+ } | null;
2939
+ } | null>;
3192
2940
  /**
3193
2941
  * 사용자 생성
3194
2942
  * Write primary 사용
@@ -3196,13 +2944,14 @@ declare class UsersRepository extends BaseRepository {
3196
2944
  create(data: NewUser): Promise<{
3197
2945
  email: string | null;
3198
2946
  phone: string | null;
2947
+ status: "active" | "inactive" | "suspended";
2948
+ username: string | null;
3199
2949
  id: number;
2950
+ createdAt: Date;
2951
+ updatedAt: Date;
3200
2952
  passwordHash: string | null;
3201
2953
  passwordChangeRequired: boolean;
3202
2954
  roleId: number;
3203
- createdAt: Date;
3204
- updatedAt: Date;
3205
- status: "active" | "inactive" | "suspended";
3206
2955
  emailVerifiedAt: Date | null;
3207
2956
  phoneVerifiedAt: Date | null;
3208
2957
  lastLoginAt: Date | null;
@@ -3217,6 +2966,7 @@ declare class UsersRepository extends BaseRepository {
3217
2966
  id: number;
3218
2967
  email: string | null;
3219
2968
  phone: string | null;
2969
+ username: string | null;
3220
2970
  passwordHash: string | null;
3221
2971
  passwordChangeRequired: boolean;
3222
2972
  roleId: number;
@@ -3235,6 +2985,7 @@ declare class UsersRepository extends BaseRepository {
3235
2985
  id: number;
3236
2986
  email: string | null;
3237
2987
  phone: string | null;
2988
+ username: string | null;
3238
2989
  passwordHash: string | null;
3239
2990
  passwordChangeRequired: boolean;
3240
2991
  roleId: number;
@@ -3253,6 +3004,7 @@ declare class UsersRepository extends BaseRepository {
3253
3004
  id: number;
3254
3005
  email: string | null;
3255
3006
  phone: string | null;
3007
+ username: string | null;
3256
3008
  passwordHash: string | null;
3257
3009
  passwordChangeRequired: boolean;
3258
3010
  roleId: number;
@@ -3268,13 +3020,14 @@ declare class UsersRepository extends BaseRepository {
3268
3020
  deleteById(id: number): Promise<{
3269
3021
  email: string | null;
3270
3022
  phone: string | null;
3023
+ status: "active" | "inactive" | "suspended";
3024
+ username: string | null;
3271
3025
  id: number;
3026
+ createdAt: Date;
3027
+ updatedAt: Date;
3272
3028
  passwordHash: string | null;
3273
3029
  passwordChangeRequired: boolean;
3274
3030
  roleId: number;
3275
- createdAt: Date;
3276
- updatedAt: Date;
3277
- status: "active" | "inactive" | "suspended";
3278
3031
  emailVerifiedAt: Date | null;
3279
3032
  phoneVerifiedAt: Date | null;
3280
3033
  lastLoginAt: Date | null;
@@ -3297,7 +3050,7 @@ declare class UsersRepository extends BaseRepository {
3297
3050
  id: number;
3298
3051
  name: string;
3299
3052
  displayName: string;
3300
- category: "auth" | "custom" | "user" | "rbac" | "system" | undefined;
3053
+ category: "custom" | "user" | "auth" | "rbac" | "system" | undefined;
3301
3054
  }[];
3302
3055
  }>;
3303
3056
  /**
@@ -3310,6 +3063,7 @@ declare class UsersRepository extends BaseRepository {
3310
3063
  fetchMinimalUserData(userId: number): Promise<{
3311
3064
  userId: number;
3312
3065
  email: string | null;
3066
+ username: string | null;
3313
3067
  isEmailVerified: boolean;
3314
3068
  isPhoneVerified: boolean;
3315
3069
  }>;
@@ -3323,6 +3077,7 @@ declare class UsersRepository extends BaseRepository {
3323
3077
  fetchFullUserData(userId: number): Promise<{
3324
3078
  userId: number;
3325
3079
  email: string | null;
3080
+ username: string | null;
3326
3081
  isEmailVerified: boolean;
3327
3082
  isPhoneVerified: boolean;
3328
3083
  lastLoginAt: Date | null;
@@ -3407,16 +3162,16 @@ declare class KeysRepository extends BaseRepository {
3407
3162
  * Write primary 사용
3408
3163
  */
3409
3164
  create(data: NewUserPublicKey): Promise<{
3410
- publicKey: string;
3411
- keyId: string;
3412
- fingerprint: string;
3413
- algorithm: "ES256" | "RS256";
3414
3165
  userId: number;
3166
+ keyId: string;
3415
3167
  id: number;
3416
3168
  isActive: boolean;
3417
3169
  createdAt: Date;
3418
- expiresAt: Date | null;
3170
+ publicKey: string;
3171
+ algorithm: "ES256" | "RS256";
3172
+ fingerprint: string;
3419
3173
  lastUsedAt: Date | null;
3174
+ expiresAt: Date | null;
3420
3175
  revokedAt: Date | null;
3421
3176
  revokedReason: string | null;
3422
3177
  }>;
@@ -3443,16 +3198,16 @@ declare class KeysRepository extends BaseRepository {
3443
3198
  * Write primary 사용
3444
3199
  */
3445
3200
  deleteByKeyIdAndUserId(keyId: string, userId: number): Promise<{
3446
- publicKey: string;
3447
- keyId: string;
3448
- fingerprint: string;
3449
- algorithm: "ES256" | "RS256";
3450
3201
  userId: number;
3202
+ keyId: string;
3451
3203
  id: number;
3452
3204
  isActive: boolean;
3453
3205
  createdAt: Date;
3454
- expiresAt: Date | null;
3206
+ publicKey: string;
3207
+ algorithm: "ES256" | "RS256";
3208
+ fingerprint: string;
3455
3209
  lastUsedAt: Date | null;
3210
+ expiresAt: Date | null;
3456
3211
  revokedAt: Date | null;
3457
3212
  revokedReason: string | null;
3458
3213
  }>;
@@ -3567,14 +3322,14 @@ declare class VerificationCodesRepository extends BaseRepository {
3567
3322
  * Write primary 사용
3568
3323
  */
3569
3324
  create(data: NewVerificationCode): Promise<{
3570
- target: string;
3571
- targetType: "email" | "phone";
3572
- purpose: "registration" | "login" | "password_reset" | "email_change" | "phone_change";
3573
- code: string;
3574
3325
  id: number;
3575
3326
  createdAt: Date;
3576
3327
  updatedAt: Date;
3577
3328
  expiresAt: Date;
3329
+ target: string;
3330
+ targetType: "email" | "phone";
3331
+ code: string;
3332
+ purpose: "registration" | "login" | "password_reset" | "email_change" | "phone_change";
3578
3333
  usedAt: Date | null;
3579
3334
  attempts: number;
3580
3335
  }>;
@@ -3763,7 +3518,7 @@ declare class PermissionsRepository extends BaseRepository {
3763
3518
  name: string;
3764
3519
  displayName: string;
3765
3520
  description: string | null;
3766
- category: "auth" | "custom" | "user" | "rbac" | "system" | null;
3521
+ category: "custom" | "user" | "auth" | "rbac" | "system" | null;
3767
3522
  isBuiltin: boolean;
3768
3523
  isSystem: boolean;
3769
3524
  isActive: boolean;
@@ -3779,7 +3534,7 @@ declare class PermissionsRepository extends BaseRepository {
3779
3534
  name: string;
3780
3535
  displayName: string;
3781
3536
  description: string | null;
3782
- category: "auth" | "custom" | "user" | "rbac" | "system" | null;
3537
+ category: "custom" | "user" | "auth" | "rbac" | "system" | null;
3783
3538
  isBuiltin: boolean;
3784
3539
  isSystem: boolean;
3785
3540
  isActive: boolean;
@@ -3819,7 +3574,7 @@ declare class PermissionsRepository extends BaseRepository {
3819
3574
  name: string;
3820
3575
  displayName: string;
3821
3576
  description: string | null;
3822
- category: "auth" | "custom" | "user" | "rbac" | "system" | null;
3577
+ category: "custom" | "user" | "auth" | "rbac" | "system" | null;
3823
3578
  isBuiltin: boolean;
3824
3579
  isSystem: boolean;
3825
3580
  isActive: boolean;
@@ -3838,8 +3593,8 @@ declare class PermissionsRepository extends BaseRepository {
3838
3593
  isActive: boolean;
3839
3594
  createdAt: Date;
3840
3595
  updatedAt: Date;
3841
- category: "auth" | "custom" | "user" | "rbac" | "system" | null;
3842
3596
  metadata: Record<string, any> | null;
3597
+ category: "custom" | "user" | "auth" | "rbac" | "system" | null;
3843
3598
  }>;
3844
3599
  }
3845
3600
  declare const permissionsRepository: PermissionsRepository;
@@ -3884,9 +3639,9 @@ declare class RolePermissionsRepository extends BaseRepository {
3884
3639
  */
3885
3640
  createMany(data: NewRolePermission[]): Promise<{
3886
3641
  id: number;
3887
- roleId: number;
3888
3642
  createdAt: Date;
3889
3643
  updatedAt: Date;
3644
+ roleId: number;
3890
3645
  permissionId: number;
3891
3646
  }[]>;
3892
3647
  /**
@@ -3902,9 +3657,9 @@ declare class RolePermissionsRepository extends BaseRepository {
3902
3657
  */
3903
3658
  setPermissionsForRole(roleId: number, permissionIds: number[]): Promise<{
3904
3659
  id: number;
3905
- roleId: number;
3906
3660
  createdAt: Date;
3907
3661
  updatedAt: Date;
3662
+ roleId: number;
3908
3663
  permissionId: number;
3909
3664
  }[]>;
3910
3665
  }
@@ -3969,10 +3724,10 @@ declare class UserPermissionsRepository extends BaseRepository {
3969
3724
  id: number;
3970
3725
  createdAt: Date;
3971
3726
  updatedAt: Date;
3972
- permissionId: number;
3973
3727
  expiresAt: Date | null;
3974
- reason: string | null;
3728
+ permissionId: number;
3975
3729
  granted: boolean;
3730
+ reason: string | null;
3976
3731
  }>;
3977
3732
  /**
3978
3733
  * 사용자 권한 오버라이드 업데이트
@@ -3995,10 +3750,10 @@ declare class UserPermissionsRepository extends BaseRepository {
3995
3750
  id: number;
3996
3751
  createdAt: Date;
3997
3752
  updatedAt: Date;
3998
- permissionId: number;
3999
3753
  expiresAt: Date | null;
4000
- reason: string | null;
3754
+ permissionId: number;
4001
3755
  granted: boolean;
3756
+ reason: string | null;
4002
3757
  }>;
4003
3758
  /**
4004
3759
  * 사용자의 모든 권한 오버라이드 삭제
@@ -4045,6 +3800,10 @@ declare class UserProfilesRepository extends BaseRepository {
4045
3800
  jobTitle: string | null;
4046
3801
  metadata: Record<string, any> | null;
4047
3802
  }>;
3803
+ /**
3804
+ * User ID로 locale만 조회 (경량)
3805
+ */
3806
+ findLocaleByUserId(userId: number): Promise<string>;
4048
3807
  /**
4049
3808
  * User ID로 프로필 조회
4050
3809
  */
@@ -4077,7 +3836,6 @@ declare class UserProfilesRepository extends BaseRepository {
4077
3836
  displayName: string;
4078
3837
  createdAt: Date;
4079
3838
  updatedAt: Date;
4080
- metadata: Record<string, any> | null;
4081
3839
  firstName: string | null;
4082
3840
  lastName: string | null;
4083
3841
  avatarUrl: string | null;
@@ -4090,6 +3848,7 @@ declare class UserProfilesRepository extends BaseRepository {
4090
3848
  location: string | null;
4091
3849
  company: string | null;
4092
3850
  jobTitle: string | null;
3851
+ metadata: Record<string, any> | null;
4093
3852
  }>;
4094
3853
  /**
4095
3854
  * 프로필 업데이트 (by ID)
@@ -4146,7 +3905,6 @@ declare class UserProfilesRepository extends BaseRepository {
4146
3905
  displayName: string;
4147
3906
  createdAt: Date;
4148
3907
  updatedAt: Date;
4149
- metadata: Record<string, any> | null;
4150
3908
  firstName: string | null;
4151
3909
  lastName: string | null;
4152
3910
  avatarUrl: string | null;
@@ -4159,6 +3917,7 @@ declare class UserProfilesRepository extends BaseRepository {
4159
3917
  location: string | null;
4160
3918
  company: string | null;
4161
3919
  jobTitle: string | null;
3920
+ metadata: Record<string, any> | null;
4162
3921
  }>;
4163
3922
  /**
4164
3923
  * 프로필 삭제 (by User ID)
@@ -4169,7 +3928,6 @@ declare class UserProfilesRepository extends BaseRepository {
4169
3928
  displayName: string;
4170
3929
  createdAt: Date;
4171
3930
  updatedAt: Date;
4172
- metadata: Record<string, any> | null;
4173
3931
  firstName: string | null;
4174
3932
  lastName: string | null;
4175
3933
  avatarUrl: string | null;
@@ -4182,6 +3940,7 @@ declare class UserProfilesRepository extends BaseRepository {
4182
3940
  location: string | null;
4183
3941
  company: string | null;
4184
3942
  jobTitle: string | null;
3943
+ metadata: Record<string, any> | null;
4185
3944
  }>;
4186
3945
  /**
4187
3946
  * 프로필 Upsert (by User ID)
@@ -4195,7 +3954,6 @@ declare class UserProfilesRepository extends BaseRepository {
4195
3954
  displayName: string;
4196
3955
  createdAt: Date;
4197
3956
  updatedAt: Date;
4198
- metadata: Record<string, any> | null;
4199
3957
  firstName: string | null;
4200
3958
  lastName: string | null;
4201
3959
  avatarUrl: string | null;
@@ -4208,6 +3966,7 @@ declare class UserProfilesRepository extends BaseRepository {
4208
3966
  location: string | null;
4209
3967
  company: string | null;
4210
3968
  jobTitle: string | null;
3969
+ metadata: Record<string, any> | null;
4211
3970
  }>;
4212
3971
  /**
4213
3972
  * User ID로 프로필 데이터 조회 (formatted)
@@ -4335,15 +4094,15 @@ declare class InvitationsRepository extends BaseRepository {
4335
4094
  */
4336
4095
  create(data: NewInvitation): Promise<{
4337
4096
  email: string;
4097
+ status: "pending" | "accepted" | "expired" | "cancelled";
4338
4098
  id: number;
4339
- roleId: number;
4340
4099
  createdAt: Date;
4341
4100
  updatedAt: Date;
4342
- status: "pending" | "accepted" | "expired" | "cancelled";
4101
+ roleId: number;
4343
4102
  metadata: Record<string, any> | null;
4103
+ expiresAt: Date;
4344
4104
  token: string;
4345
4105
  invitedBy: number;
4346
- expiresAt: Date;
4347
4106
  acceptedAt: Date | null;
4348
4107
  cancelledAt: Date | null;
4349
4108
  }>;
@@ -4369,15 +4128,15 @@ declare class InvitationsRepository extends BaseRepository {
4369
4128
  */
4370
4129
  deleteById(id: number): Promise<{
4371
4130
  email: string;
4131
+ status: "pending" | "accepted" | "expired" | "cancelled";
4372
4132
  id: number;
4373
- roleId: number;
4374
4133
  createdAt: Date;
4375
4134
  updatedAt: Date;
4376
- status: "pending" | "accepted" | "expired" | "cancelled";
4135
+ roleId: number;
4377
4136
  metadata: Record<string, any> | null;
4137
+ expiresAt: Date;
4378
4138
  token: string;
4379
4139
  invitedBy: number;
4380
- expiresAt: Date;
4381
4140
  acceptedAt: Date | null;
4382
4141
  cancelledAt: Date | null;
4383
4142
  }>;
@@ -4502,6 +4261,136 @@ declare class InvitationsRepository extends BaseRepository {
4502
4261
  }
4503
4262
  declare const invitationsRepository: InvitationsRepository;
4504
4263
 
4264
+ /**
4265
+ * Social Accounts Repository
4266
+ *
4267
+ * OAuth 소셜 계정 데이터 관리를 위한 Repository
4268
+ * BaseRepository를 상속받아 자동 트랜잭션 컨텍스트 지원 및 Read/Write 분리
4269
+ */
4270
+
4271
+ /**
4272
+ * Social Accounts Repository 클래스
4273
+ */
4274
+ declare class SocialAccountsRepository extends BaseRepository {
4275
+ /**
4276
+ * provider와 providerUserId로 소셜 계정 조회
4277
+ * Read replica 사용
4278
+ */
4279
+ findByProviderAndProviderId(provider: SocialProvider, providerUserId: string): Promise<{
4280
+ createdAt: Date;
4281
+ updatedAt: Date;
4282
+ id: number;
4283
+ userId: number;
4284
+ provider: "google" | "github" | "kakao" | "naver";
4285
+ providerUserId: string;
4286
+ providerEmail: string | null;
4287
+ accessToken: string | null;
4288
+ refreshToken: string | null;
4289
+ tokenExpiresAt: Date | null;
4290
+ }>;
4291
+ /**
4292
+ * userId로 모든 소셜 계정 조회
4293
+ * Read replica 사용
4294
+ */
4295
+ findByUserId(userId: number): Promise<{
4296
+ createdAt: Date;
4297
+ updatedAt: Date;
4298
+ id: number;
4299
+ userId: number;
4300
+ provider: "google" | "github" | "kakao" | "naver";
4301
+ providerUserId: string;
4302
+ providerEmail: string | null;
4303
+ accessToken: string | null;
4304
+ refreshToken: string | null;
4305
+ tokenExpiresAt: Date | null;
4306
+ }[]>;
4307
+ /**
4308
+ * userId와 provider로 소셜 계정 조회
4309
+ * Read replica 사용
4310
+ */
4311
+ findByUserIdAndProvider(userId: number, provider: SocialProvider): Promise<{
4312
+ createdAt: Date;
4313
+ updatedAt: Date;
4314
+ id: number;
4315
+ userId: number;
4316
+ provider: "google" | "github" | "kakao" | "naver";
4317
+ providerUserId: string;
4318
+ providerEmail: string | null;
4319
+ accessToken: string | null;
4320
+ refreshToken: string | null;
4321
+ tokenExpiresAt: Date | null;
4322
+ }>;
4323
+ /**
4324
+ * 소셜 계정 생성
4325
+ * Write primary 사용
4326
+ */
4327
+ create(data: NewUserSocialAccount): Promise<{
4328
+ userId: number;
4329
+ id: number;
4330
+ createdAt: Date;
4331
+ updatedAt: Date;
4332
+ provider: "google" | "github" | "kakao" | "naver";
4333
+ providerUserId: string;
4334
+ providerEmail: string | null;
4335
+ accessToken: string | null;
4336
+ refreshToken: string | null;
4337
+ tokenExpiresAt: Date | null;
4338
+ }>;
4339
+ /**
4340
+ * 토큰 정보 업데이트
4341
+ * Write primary 사용
4342
+ */
4343
+ updateTokens(id: number, data: {
4344
+ accessToken?: string | null;
4345
+ refreshToken?: string | null;
4346
+ tokenExpiresAt?: Date | null;
4347
+ }): Promise<{
4348
+ createdAt: Date;
4349
+ updatedAt: Date;
4350
+ id: number;
4351
+ userId: number;
4352
+ provider: "google" | "github" | "kakao" | "naver";
4353
+ providerUserId: string;
4354
+ providerEmail: string | null;
4355
+ accessToken: string | null;
4356
+ refreshToken: string | null;
4357
+ tokenExpiresAt: Date | null;
4358
+ }>;
4359
+ /**
4360
+ * 소셜 계정 삭제
4361
+ * Write primary 사용
4362
+ */
4363
+ deleteById(id: number): Promise<{
4364
+ userId: number;
4365
+ id: number;
4366
+ createdAt: Date;
4367
+ updatedAt: Date;
4368
+ provider: "google" | "github" | "kakao" | "naver";
4369
+ providerUserId: string;
4370
+ providerEmail: string | null;
4371
+ accessToken: string | null;
4372
+ refreshToken: string | null;
4373
+ tokenExpiresAt: Date | null;
4374
+ }>;
4375
+ /**
4376
+ * userId와 provider로 소셜 계정 삭제
4377
+ * Write primary 사용
4378
+ */
4379
+ deleteByUserIdAndProvider(userId: number, provider: SocialProvider): Promise<{
4380
+ userId: number;
4381
+ id: number;
4382
+ createdAt: Date;
4383
+ updatedAt: Date;
4384
+ provider: "google" | "github" | "kakao" | "naver";
4385
+ providerUserId: string;
4386
+ providerEmail: string | null;
4387
+ accessToken: string | null;
4388
+ refreshToken: string | null;
4389
+ tokenExpiresAt: Date | null;
4390
+ }>;
4391
+ }
4392
+ declare const socialAccountsRepository: SocialAccountsRepository;
4393
+
4505
4394
  /**
4506
4395
  * @spfn/auth - Password Helpers
4507
4396
  *
@@ -4872,6 +4761,32 @@ declare const roleGuard: _spfn_core_route.NamedMiddlewareFactory<"roleGuard", [o
4872
4761
  declare function getAuth(c: Context | {
4873
4762
  raw: Context;
4874
4763
  }): AuthContext;
4764
+ /**
4765
+ * Get optional auth context from route context
4766
+ *
4767
+ * Returns AuthContext if authenticated, undefined otherwise.
4768
+ * Use with `optionalAuth` middleware for routes that serve both
4769
+ * authenticated and unauthenticated users.
4770
+ *
4771
+ * @example
4772
+ * ```typescript
4773
+ * export const getProducts = route.get('/products')
4774
+ * .use([optionalAuth])
4775
+ * .handler(async (c) => {
4776
+ * const auth = getOptionalAuth(c);
4777
+ *
4778
+ * if (auth)
4779
+ * {
4780
+ * return getPersonalizedProducts(auth.userId);
4781
+ * }
4782
+ *
4783
+ * return getPublicProducts();
4784
+ * });
4785
+ * ```
4786
+ */
4787
+ declare function getOptionalAuth(c: Context | {
4788
+ raw: Context;
4789
+ }): AuthContext | undefined;
4875
4790
  /**
4876
4791
  * Get authenticated user from route context
4877
4792
  *
@@ -4888,13 +4803,14 @@ declare function getUser(c: Context | {
4888
4803
  }): {
4889
4804
  email: string | null;
4890
4805
  phone: string | null;
4806
+ status: "active" | "inactive" | "suspended";
4807
+ username: string | null;
4891
4808
  id: number;
4809
+ createdAt: Date;
4810
+ updatedAt: Date;
4892
4811
  passwordHash: string | null;
4893
4812
  passwordChangeRequired: boolean;
4894
4813
  roleId: number;
4895
- createdAt: Date;
4896
- updatedAt: Date;
4897
- status: "active" | "inactive" | "suspended";
4898
4814
  emailVerifiedAt: Date | null;
4899
4815
  phoneVerifiedAt: Date | null;
4900
4816
  lastLoginAt: Date | null;
@@ -4913,6 +4829,38 @@ declare function getUser(c: Context | {
4913
4829
  declare function getUserId(c: Context | {
4914
4830
  raw: Context;
4915
4831
  }): string;
4832
+ /**
4833
+ * Get authenticated user's role from route context
4834
+ *
4835
+ * @returns Role name or null if user has no role
4836
+ *
4837
+ * @example
4838
+ * ```typescript
4839
+ * app.bind(adminContract, [authenticate], async (c) => {
4840
+ * const role = getRole(c);
4841
+ * // 'admin' | 'superadmin' | null
4842
+ * });
4843
+ * ```
4844
+ */
4845
+ declare function getRole(c: Context | {
4846
+ raw: Context;
4847
+ }): string | null;
4848
+ /**
4849
+ * Get authenticated user's locale from route context
4850
+ *
4851
+ * @returns Locale string (e.g., 'en', 'ko')
4852
+ *
4853
+ * @example
4854
+ * ```typescript
4855
+ * app.bind(contract, [authenticate], async (c) => {
4856
+ * const locale = getLocale(c);
4857
+ * // 'en' | 'ko' | ...
4858
+ * });
4859
+ * ```
4860
+ */
4861
+ declare function getLocale(c: Context | {
4862
+ raw: Context;
4863
+ }): string;
4916
4864
  /**
4917
4865
  * Get current key ID from route context
4918
4866
  *
@@ -5048,6 +4996,8 @@ declare const COOKIE_NAMES: {
5048
4996
  readonly SESSION: "spfn_session";
5049
4997
  /** Current key ID (for key rotation) */
5050
4998
  readonly SESSION_KEY_ID: "spfn_session_key_id";
4999
+ /** Pending OAuth session (privateKey, keyId, algorithm) - temporary during OAuth flow */
5000
+ readonly OAUTH_PENDING: "spfn_oauth_pending";
5051
5001
  };
5052
5002
  /**
5053
5003
  * Parse duration string to seconds
@@ -5104,6 +5054,116 @@ declare function getAuthConfig(): AuthConfig;
5104
5054
  */
5105
5055
  declare function getSessionTtl(override?: string | number): number;
5106
5056
 
5057
+ /**
5058
+ * Google OAuth 2.0 Client
5059
+ *
5060
+ * Authorization Code Flow 구현
5061
+ * - getGoogleAuthUrl: Google 로그인 URL 생성
5062
+ * - exchangeCodeForTokens: Code를 Token으로 교환
5063
+ * - getGoogleUserInfo: 사용자 정보 조회
5064
+ */
5065
+ interface GoogleTokenResponse {
5066
+ access_token: string;
5067
+ expires_in: number;
5068
+ refresh_token?: string;
5069
+ scope: string;
5070
+ token_type: string;
5071
+ id_token?: string;
5072
+ }
5073
+ interface GoogleUserInfo {
5074
+ id: string;
5075
+ email: string;
5076
+ verified_email: boolean;
5077
+ name?: string;
5078
+ given_name?: string;
5079
+ family_name?: string;
5080
+ picture?: string;
5081
+ locale?: string;
5082
+ }
5083
+ /**
5084
+ * Google OAuth가 활성화되어 있는지 확인
5085
+ */
5086
+ declare function isGoogleOAuthEnabled(): boolean;
5087
+ /**
5088
+ * Google OAuth 설정 가져오기
5089
+ */
5090
+ declare function getGoogleOAuthConfig(): {
5091
+ clientId: string;
5092
+ clientSecret: string;
5093
+ redirectUri: string;
5094
+ };
5095
+ /**
5096
+ * Google 로그인 URL 생성
5097
+ *
5098
+ * @param state - CSRF 방지용 state 파라미터 (암호화된 returnUrl + nonce 포함)
5099
+ * @param scopes - 요청할 OAuth scopes (기본: env 또는 email, profile)
5100
+ */
5101
+ declare function getGoogleAuthUrl(state: string, scopes?: string[]): string;
5102
+ /**
5103
+ * Authorization Code를 Token으로 교환
5104
+ *
5105
+ * @param code - Google에서 받은 authorization code
5106
+ */
5107
+ declare function exchangeCodeForTokens(code: string): Promise<GoogleTokenResponse>;
5108
+ /**
5109
+ * Access Token으로 Google 사용자 정보 조회
5110
+ *
5111
+ * @param accessToken - Google access token
5112
+ */
5113
+ declare function getGoogleUserInfo(accessToken: string): Promise<GoogleUserInfo>;
5114
+ /**
5115
+ * Refresh Token으로 새 Access Token 획득
5116
+ *
5117
+ * @param refreshToken - Google refresh token
5118
+ */
5119
+ declare function refreshAccessToken(refreshToken: string): Promise<GoogleTokenResponse>;
5120
+
5121
+ /**
5122
+ * OAuth State Management
5123
+ *
5124
+ * CSRF 방지를 위한 state 파라미터 암호화/복호화
5125
+ * - returnUrl: OAuth 성공 후 리다이렉트할 URL
5126
+ * - nonce: CSRF 방지용 일회용 토큰
5127
+ * - provider: OAuth provider (google, github 등)
5128
+ * - publicKey, keyId, fingerprint, algorithm: 클라이언트 키 정보
5129
+ * - expiresAt: state 만료 시간
5130
+ */
5131
+
5132
+ interface OAuthState {
5133
+ returnUrl: string;
5134
+ nonce: string;
5135
+ provider: string;
5136
+ publicKey: string;
5137
+ keyId: string;
5138
+ fingerprint: string;
5139
+ algorithm: KeyAlgorithmType;
5140
+ metadata?: Record<string, unknown>;
5141
+ }
5142
+ interface CreateOAuthStateParams {
5143
+ provider: string;
5144
+ returnUrl: string;
5145
+ publicKey: string;
5146
+ keyId: string;
5147
+ fingerprint: string;
5148
+ algorithm: KeyAlgorithmType;
5149
+ metadata?: Record<string, unknown>;
5150
+ }
5151
+ /**
5152
+ * OAuth state 생성 및 암호화
5153
+ *
5154
+ * @param params - state 생성에 필요한 파라미터
5155
+ * @returns 암호화된 state 문자열
5156
+ */
5157
+ declare function createOAuthState(params: CreateOAuthStateParams): Promise<string>;
5158
+ /**
5159
+ * OAuth state 복호화 및 검증
5160
+ *
5161
+ * @param encryptedState - 암호화된 state 문자열
5162
+ * @returns 복호화된 state 객체
5163
+ * @throws Error if state is invalid or expired (JWE exp claim으로 자동 검증)
5164
+ */
5165
+ declare function verifyOAuthState(encryptedState: string): Promise<OAuthState>;
5166
+
5107
5167
  /**
5108
5168
  * @spfn/auth - Centralized Logger
5109
5169
  *
@@ -5116,6 +5176,7 @@ declare const authLogger: {
5116
5176
  general: _spfn_core_logger.Logger;
5117
5177
  login: _spfn_core_logger.Logger;
5118
5178
  keyRotation: _spfn_core_logger.Logger;
5179
+ oauth: _spfn_core_logger.Logger;
5119
5180
  };
5120
5181
  service: _spfn_core_logger.Logger;
5121
5182
  setup: _spfn_core_logger.Logger;
@@ -5199,4 +5260,64 @@ interface AuthLifecycleConfig {
5199
5260
  */
5200
5261
  declare function createAuthLifecycle(options?: AuthInitOptions): AuthLifecycleConfig;
5201
5262
 
5202
- export { type AuthConfig, AuthContext, COOKIE_NAMES, type EmailProvider, type EmailTemplateProvider, type EmailTemplateResult, type Invitation, InvitationStatus, InvitationsRepository, KeyAlgorithmType, type KeyPair, KeysRepository, type NewInvitation, type NewPermission, type NewPermissionEntity, type NewRole, type NewRoleEntity, type NewRolePermission, type NewUser, type NewUserPermission, type NewUserProfile, type NewUserPublicKey, type NewUserSocialAccount, type NewVerificationCode, type Permission, type PermissionEntity, PermissionsRepository, type Role, type RoleEntity, type RoleGuardOptions, type RolePermission, RolePermissionsRepository, RolesRepository, type SMSProvider, type SendEmailParams, type SendEmailResult, type SendSMSParams, type SendSMSResult, type SessionData, type SessionPayload, type TokenPayload, type UpdateProfileParams, type User, type UserPermission, UserPermissionsRepository, type UserProfile, UserProfilesRepository, type UserPublicKey, type UserSocialAccount, UsersRepository, type VerificationCode, type VerificationCodeParams, VerificationCodesRepository, VerificationPurpose, acceptInvitation, addPermissionToRole, authLogger, authSchema, cancelInvitation, configureAuth, createAuthLifecycle, createInvitation, createRole, decodeToken, deleteInvitation, deleteRole, expireOldInvitations, generateClientToken, generateKeyPair, generateKeyPairES256, generateKeyPairRS256, generateToken, getAllRoles, getAuth, getAuthConfig, getAuthSessionService, getInvitationByToken, getInvitationTemplate, getInvitationWithDetails, getKeyId, getKeySize, getPasswordResetTemplate, getRoleByName, getRolePermissions, getSessionInfo, getSessionTtl, getUser, getUserByEmailService, getUserByIdService, getUserByPhoneService, getUserId, getUserPermissions, getUserProfileService, getUserRole, getVerificationCodeTemplate, getWelcomeTemplate, hasAllPermissions, hasAnyPermission, hasAnyRole, hasPermission, hasRole, hashPassword, initializeAuth, invitationsRepository, keysRepository, listInvitations, parseDuration, permissions, permissionsRepository, registerEmailProvider, registerEmailTemplates, registerSMSProvider, removePermissionFromRole, requireAnyPermission, requirePermissions, requireRole, resendInvitation, roleGuard, rolePermissions, rolePermissionsRepository, roles, rolesRepository, sealSession, sendEmail, sendSMS, setRolePermissions, shouldRefreshSession, shouldRotateKey, unsealSession, updateLastLoginService, updateRole, updateUserProfileService, updateUserService, userInvitations, userPermissions, userPermissionsRepository, userProfiles, userProfilesRepository, userPublicKeys, userSocialAccounts, users, usersRepository, validateInvitation, validatePasswordStrength, verificationCodes, verificationCodesRepository, verifyClientToken, verifyKeyFingerprint, verifyPassword, verifyToken };
5263
+ /**
5264
+ * @spfn/auth - Auth Events
5265
+ *
5266
+ * 인증 관련 이벤트 정의
5267
+ * - auth.login: 로그인 성공 시 (기존 사용자만)
5268
+ * - auth.register: 회원가입 성공 시 (OAuth 신규 가입 포함)
5269
+ */
5270
+ /**
5271
+ * Auth provider type
5272
+ */
5273
+ declare const AuthProviderSchema: _sinclair_typebox.TUnion<[_sinclair_typebox.TLiteral<"email">, _sinclair_typebox.TLiteral<"phone">, _sinclair_typebox.TLiteral<"google">]>;
5274
+ /**
5275
+ * auth.login - 로그인 성공 이벤트
5276
+ *
5277
+ * 발행 시점:
5278
+ * - 이메일/전화 로그인 성공 시
5279
+ * - OAuth 기존 사용자 로그인 시
5280
+ *
5281
+ * @example
5282
+ * ```typescript
5283
+ * authLoginEvent.subscribe(async (payload) => {
5284
+ * await analytics.trackLogin(payload.userId, payload.provider);
5285
+ * });
5286
+ * ```
5287
+ */
5288
+ declare const authLoginEvent: _spfn_core_event.EventDef<{
5289
+ email?: string | undefined;
5290
+ phone?: string | undefined;
5291
+ userId: string;
5292
+ provider: "email" | "phone" | "google";
5293
+ }>;
5294
+ /**
5295
+ * auth.register - 회원가입 성공 이벤트
5296
+ *
5297
+ * 발행 시점:
5298
+ * - 이메일/전화 회원가입 성공 시
5299
+ * - OAuth 신규 사용자 가입 시
5300
+ *
5301
+ * @example
5302
+ * ```typescript
5303
+ * authRegisterEvent.subscribe(async (payload) => {
5304
+ * await emailService.sendWelcome(payload.email);
5305
+ * });
5306
+ * ```
5307
+ */
5308
+ declare const authRegisterEvent: _spfn_core_event.EventDef<{
5309
+ email?: string | undefined;
5310
+ phone?: string | undefined;
5311
+ metadata?: {
5312
+ [x: string]: unknown;
5313
+ } | undefined;
5314
+ userId: string;
5315
+ provider: "email" | "phone" | "google";
5316
+ }>;
5317
+ /**
5318
+ * Auth event payload types
5319
+ */
5320
+ type AuthLoginPayload = typeof authLoginEvent._payload;
5321
+ type AuthRegisterPayload = typeof authRegisterEvent._payload;
5322
+
5323
+ export { type AuthConfig, AuthContext, type AuthLoginPayload, AuthProviderSchema, type AuthRegisterPayload, COOKIE_NAMES, type CreateOAuthStateParams, type GoogleTokenResponse, type GoogleUserInfo, type Invitation, InvitationStatus, InvitationsRepository, KeyAlgorithmType, type KeyPair, KeysRepository, type NewInvitation, type NewPermission, type NewPermissionEntity, type NewRole, type NewRoleEntity, type NewRolePermission, type NewUser, type NewUserPermission, type NewUserProfile, type NewUserPublicKey, type NewUserSocialAccount, type NewVerificationCode, type OAuthState, type Permission, type PermissionEntity, PermissionsRepository, type Role, type RoleEntity, type RoleGuardOptions, type RolePermission, RolePermissionsRepository, RolesRepository, type SessionData, type SessionPayload, SocialAccountsRepository, SocialProvider, type TokenPayload, type UpdateProfileParams, type User, type UserPermission, UserPermissionsRepository, type UserProfile, UserProfilesRepository, type UserPublicKey, type UserSocialAccount, UsersRepository, type VerificationCode, VerificationCodesRepository, VerificationPurpose, acceptInvitation, addPermissionToRole, authLogger, authLoginEvent, authRegisterEvent, authSchema, cancelInvitation, checkUsernameAvailableService, configureAuth, createAuthLifecycle, createInvitation, createOAuthState, createRole, decodeToken, deleteInvitation, deleteRole, exchangeCodeForTokens, expireOldInvitations, generateClientToken, generateKeyPair, generateKeyPairES256, generateKeyPairRS256, generateToken, getAllRoles, getAuth, getAuthConfig, getAuthSessionService, getGoogleAuthUrl, getGoogleOAuthConfig, getGoogleUserInfo, getInvitationByToken, getInvitationWithDetails, getKeyId, getKeySize, getLocale, getOptionalAuth, getRole, getRoleByName, getRolePermissions, getSessionInfo, getSessionTtl, getUser, getUserByEmailService, getUserByIdService, getUserByPhoneService, getUserId, getUserPermissions, getUserProfileService, getUserRole, hasAllPermissions, hasAnyPermission, hasAnyRole, hasPermission, hasRole, hashPassword, initializeAuth, invitationsRepository, isGoogleOAuthEnabled, keysRepository, listInvitations, parseDuration, permissions, permissionsRepository, refreshAccessToken, removePermissionFromRole, requireAnyPermission, requirePermissions, requireRole, resendInvitation, roleGuard, rolePermissions, rolePermissionsRepository, roles, rolesRepository, sealSession, setRolePermissions, shouldRefreshSession, shouldRotateKey, socialAccountsRepository, unsealSession, updateLastLoginService, updateLocaleService, updateRole, updateUserProfileService, updateUserService, updateUsernameService, userInvitations, userPermissions, userPermissionsRepository, userProfiles, userProfilesRepository, userPublicKeys, userSocialAccounts, users, usersRepository, validateInvitation, validatePasswordStrength, verificationCodes, verificationCodesRepository, verifyClientToken, verifyKeyFingerprint, verifyOAuthState, verifyPassword, verifyToken };