@spfn/auth 0.2.0-beta.3 → 0.2.0-beta.31
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/README.md +689 -180
- package/dist/{dto-CLYtuAom.d.ts → authenticate-Brx2N-Ip.d.ts} +413 -147
- package/dist/config.d.ts +100 -44
- package/dist/config.js +64 -35
- package/dist/config.js.map +1 -1
- package/dist/errors.d.ts +16 -2
- package/dist/errors.js +12 -0
- package/dist/errors.js.map +1 -1
- package/dist/index.d.ts +279 -100
- package/dist/index.js +47 -1
- package/dist/index.js.map +1 -1
- package/dist/nextjs/api.js +202 -1
- package/dist/nextjs/api.js.map +1 -1
- package/dist/nextjs/client.d.ts +28 -0
- package/dist/nextjs/client.js +80 -0
- package/dist/nextjs/client.js.map +1 -0
- package/dist/nextjs/server.d.ts +89 -2
- package/dist/nextjs/server.js +147 -22
- package/dist/nextjs/server.js.map +1 -1
- package/dist/server.d.ts +576 -360
- package/dist/server.js +1089 -484
- package/dist/server.js.map +1 -1
- package/migrations/0001_smooth_the_fury.sql +3 -0
- package/migrations/meta/0001_snapshot.json +1660 -0
- package/migrations/meta/_journal.json +7 -0
- package/package.json +14 -10
package/dist/server.d.ts
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
|
-
import { k as AuthInitOptions, l as KeyAlgorithmType, n as InvitationStatus, f as VerificationPurpose, j as PermissionCategory, q as AuthContext } from './
|
|
2
|
-
export { B as ChangePasswordParams, w as CheckAccountExistsParams, C as CheckAccountExistsResult,
|
|
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-Brx2N-Ip.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-Brx2N-Ip.js';
|
|
3
3
|
import * as drizzle_orm_pg_core from 'drizzle-orm/pg-core';
|
|
4
|
-
import { UserProfile as UserProfile$1 } from '@spfn/auth';
|
|
4
|
+
import { UserProfile as UserProfile$1, ProfileInfo } from '@spfn/auth';
|
|
5
5
|
import { BaseRepository } from '@spfn/core/db';
|
|
6
6
|
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 '@
|
|
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";
|
|
@@ -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,34 @@ 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
|
|
330
|
+
*/
|
|
331
|
+
declare function checkUsernameAvailableService(username: string): Promise<boolean>;
|
|
332
|
+
/**
|
|
333
|
+
* Update username with duplicate check
|
|
334
|
+
*
|
|
335
|
+
* @param userId - User ID (string, number, or bigint)
|
|
336
|
+
* @param username - New username or null to clear
|
|
337
|
+
* @throws UsernameAlreadyTakenError if username is already in use by another user
|
|
338
|
+
*/
|
|
339
|
+
declare function updateUsernameService(userId: string | number | bigint, username: string | null): Promise<{
|
|
340
|
+
createdAt: Date;
|
|
341
|
+
updatedAt: Date;
|
|
342
|
+
id: number;
|
|
343
|
+
email: string | null;
|
|
344
|
+
phone: string | null;
|
|
345
|
+
username: string | null;
|
|
346
|
+
passwordHash: string | null;
|
|
347
|
+
passwordChangeRequired: boolean;
|
|
348
|
+
roleId: number;
|
|
349
|
+
status: "active" | "inactive" | "suspended";
|
|
350
|
+
emailVerifiedAt: Date | null;
|
|
351
|
+
phoneVerifiedAt: Date | null;
|
|
352
|
+
lastLoginAt: Date | null;
|
|
353
|
+
}>;
|
|
305
354
|
|
|
306
355
|
/**
|
|
307
356
|
* @spfn/auth - RBAC Initialization Service
|
|
@@ -406,6 +455,19 @@ declare function hasAnyPermission(userId: string | number | bigint, permissionNa
|
|
|
406
455
|
* ```
|
|
407
456
|
*/
|
|
408
457
|
declare function hasAllPermissions(userId: string | number | bigint, permissionNames: string[]): Promise<boolean>;
|
|
458
|
+
/**
|
|
459
|
+
* Get user's role name
|
|
460
|
+
*
|
|
461
|
+
* @param userId - User ID
|
|
462
|
+
* @returns Role name or null if user has no role
|
|
463
|
+
*
|
|
464
|
+
* @example
|
|
465
|
+
* ```typescript
|
|
466
|
+
* const role = await getUserRole('123');
|
|
467
|
+
* // 'admin' or null
|
|
468
|
+
* ```
|
|
469
|
+
*/
|
|
470
|
+
declare function getUserRole(userId: string | number | bigint): Promise<string | null>;
|
|
409
471
|
/**
|
|
410
472
|
* Check if user has a specific role
|
|
411
473
|
*
|
|
@@ -1253,10 +1315,30 @@ declare function getAuthSessionService(userId: string | number | bigint): Promis
|
|
|
1253
1315
|
/**
|
|
1254
1316
|
* @spfn/auth - User Profile Service
|
|
1255
1317
|
*
|
|
1256
|
-
* Service for retrieving user profile information
|
|
1318
|
+
* Service for retrieving and updating user profile information
|
|
1257
1319
|
* Returns full user info with profile data
|
|
1258
1320
|
*/
|
|
1259
1321
|
|
|
1322
|
+
/**
|
|
1323
|
+
* Profile update parameters
|
|
1324
|
+
* All fields are optional, empty string will be converted to null
|
|
1325
|
+
*/
|
|
1326
|
+
interface UpdateProfileParams {
|
|
1327
|
+
displayName?: string;
|
|
1328
|
+
firstName?: string;
|
|
1329
|
+
lastName?: string;
|
|
1330
|
+
avatarUrl?: string;
|
|
1331
|
+
bio?: string;
|
|
1332
|
+
locale?: string;
|
|
1333
|
+
timezone?: string;
|
|
1334
|
+
dateOfBirth?: string;
|
|
1335
|
+
gender?: string;
|
|
1336
|
+
website?: string;
|
|
1337
|
+
location?: string;
|
|
1338
|
+
company?: string;
|
|
1339
|
+
jobTitle?: string;
|
|
1340
|
+
metadata?: Record<string, any>;
|
|
1341
|
+
}
|
|
1260
1342
|
/**
|
|
1261
1343
|
* Get user profile information
|
|
1262
1344
|
*
|
|
@@ -1272,369 +1354,26 @@ declare function getAuthSessionService(userId: string | number | bigint): Promis
|
|
|
1272
1354
|
* ```
|
|
1273
1355
|
*/
|
|
1274
1356
|
declare function getUserProfileService(userId: string | number | bigint): Promise<UserProfile$1>;
|
|
1275
|
-
|
|
1276
|
-
/**
|
|
1277
|
-
* @spfn/auth - Email Template Types
|
|
1278
|
-
*
|
|
1279
|
-
* Type definitions for customizable email templates
|
|
1280
|
-
*/
|
|
1281
|
-
/**
|
|
1282
|
-
* Common template result
|
|
1283
|
-
*/
|
|
1284
|
-
interface EmailTemplateResult {
|
|
1285
|
-
subject: string;
|
|
1286
|
-
text: string;
|
|
1287
|
-
html: string;
|
|
1288
|
-
}
|
|
1289
|
-
/**
|
|
1290
|
-
* Verification code template parameters
|
|
1291
|
-
*/
|
|
1292
|
-
interface VerificationCodeParams {
|
|
1293
|
-
code: string;
|
|
1294
|
-
purpose: 'registration' | 'login' | 'password_reset' | string;
|
|
1295
|
-
expiresInMinutes?: number;
|
|
1296
|
-
appName?: string;
|
|
1297
|
-
}
|
|
1298
1357
|
/**
|
|
1299
|
-
*
|
|
1358
|
+
* Update user profile (upsert)
|
|
1300
1359
|
*
|
|
1301
|
-
*
|
|
1360
|
+
* Creates profile if not exists, updates if exists
|
|
1361
|
+
* Empty strings are converted to null
|
|
1302
1362
|
*
|
|
1303
|
-
* @
|
|
1304
|
-
*
|
|
1305
|
-
*
|
|
1306
|
-
*
|
|
1307
|
-
* registerEmailTemplates({
|
|
1308
|
-
* verificationCode: (params) => ({
|
|
1309
|
-
* subject: 'Your Code',
|
|
1310
|
-
* text: `Code: ${params.code}`,
|
|
1311
|
-
* html: `<h1>Code: ${params.code}</h1>`,
|
|
1312
|
-
* }),
|
|
1313
|
-
* });
|
|
1314
|
-
* ```
|
|
1315
|
-
*/
|
|
1316
|
-
interface EmailTemplateProvider {
|
|
1317
|
-
/**
|
|
1318
|
-
* Verification code email template
|
|
1319
|
-
*/
|
|
1320
|
-
verificationCode?(params: VerificationCodeParams): EmailTemplateResult;
|
|
1321
|
-
/**
|
|
1322
|
-
* Welcome email template (after registration)
|
|
1323
|
-
*/
|
|
1324
|
-
welcome?(params: {
|
|
1325
|
-
email: string;
|
|
1326
|
-
appName?: string;
|
|
1327
|
-
}): EmailTemplateResult;
|
|
1328
|
-
/**
|
|
1329
|
-
* Password reset email template
|
|
1330
|
-
*/
|
|
1331
|
-
passwordReset?(params: {
|
|
1332
|
-
resetLink: string;
|
|
1333
|
-
expiresInMinutes?: number;
|
|
1334
|
-
appName?: string;
|
|
1335
|
-
}): EmailTemplateResult;
|
|
1336
|
-
/**
|
|
1337
|
-
* Invitation email template
|
|
1338
|
-
*/
|
|
1339
|
-
invitation?(params: {
|
|
1340
|
-
inviteLink: string;
|
|
1341
|
-
inviterName?: string;
|
|
1342
|
-
roleName?: string;
|
|
1343
|
-
appName?: string;
|
|
1344
|
-
}): EmailTemplateResult;
|
|
1345
|
-
}
|
|
1346
|
-
|
|
1347
|
-
/**
|
|
1348
|
-
* @spfn/auth - Email Template Registry
|
|
1349
|
-
*
|
|
1350
|
-
* Manages custom email template registration and fallback to defaults
|
|
1351
|
-
*/
|
|
1352
|
-
|
|
1353
|
-
/**
|
|
1354
|
-
* Register custom email templates
|
|
1355
|
-
*
|
|
1356
|
-
* Templates not provided will fall back to defaults
|
|
1357
|
-
*
|
|
1358
|
-
* @param templates - Custom template implementations
|
|
1363
|
+
* @param userId - User ID
|
|
1364
|
+
* @param params - Profile fields to update
|
|
1365
|
+
* @returns Updated profile info
|
|
1359
1366
|
*
|
|
1360
1367
|
* @example
|
|
1361
1368
|
* ```typescript
|
|
1362
|
-
*
|
|
1363
|
-
*
|
|
1364
|
-
*
|
|
1365
|
-
*
|
|
1366
|
-
* verificationCode: ({ code, purpose, expiresInMinutes }) => ({
|
|
1367
|
-
* subject: `[MyApp] Your verification code`,
|
|
1368
|
-
* text: `Your code is: ${code}`,
|
|
1369
|
-
* html: `
|
|
1370
|
-
* <div style="font-family: Arial;">
|
|
1371
|
-
* <h1>Welcome to MyApp!</h1>
|
|
1372
|
-
* <p>Your code: <strong>${code}</strong></p>
|
|
1373
|
-
* </div>
|
|
1374
|
-
* `,
|
|
1375
|
-
* }),
|
|
1369
|
+
* const profile = await updateUserProfileService(123, {
|
|
1370
|
+
* displayName: 'John Doe',
|
|
1371
|
+
* bio: 'Software Engineer',
|
|
1372
|
+
* location: '', // will be saved as null
|
|
1376
1373
|
* });
|
|
1377
1374
|
* ```
|
|
1378
1375
|
*/
|
|
1379
|
-
declare function
|
|
1380
|
-
/**
|
|
1381
|
-
* Get verification code template
|
|
1382
|
-
*
|
|
1383
|
-
* Uses custom template if registered, otherwise falls back to default
|
|
1384
|
-
*/
|
|
1385
|
-
declare function getVerificationCodeTemplate(params: VerificationCodeParams): EmailTemplateResult;
|
|
1386
|
-
/**
|
|
1387
|
-
* Get welcome template
|
|
1388
|
-
*/
|
|
1389
|
-
declare function getWelcomeTemplate(params: {
|
|
1390
|
-
email: string;
|
|
1391
|
-
appName?: string;
|
|
1392
|
-
}): EmailTemplateResult;
|
|
1393
|
-
/**
|
|
1394
|
-
* Get password reset template
|
|
1395
|
-
*/
|
|
1396
|
-
declare function getPasswordResetTemplate(params: {
|
|
1397
|
-
resetLink: string;
|
|
1398
|
-
expiresInMinutes?: number;
|
|
1399
|
-
appName?: string;
|
|
1400
|
-
}): EmailTemplateResult;
|
|
1401
|
-
/**
|
|
1402
|
-
* Get invitation template
|
|
1403
|
-
*/
|
|
1404
|
-
declare function getInvitationTemplate(params: {
|
|
1405
|
-
inviteLink: string;
|
|
1406
|
-
inviterName?: string;
|
|
1407
|
-
roleName?: string;
|
|
1408
|
-
appName?: string;
|
|
1409
|
-
}): EmailTemplateResult;
|
|
1410
|
-
|
|
1411
|
-
/**
|
|
1412
|
-
* @spfn/auth - Email Service Types
|
|
1413
|
-
*
|
|
1414
|
-
* Type definitions for email sending service
|
|
1415
|
-
*/
|
|
1416
|
-
/**
|
|
1417
|
-
* Parameters for sending email
|
|
1418
|
-
*/
|
|
1419
|
-
interface SendEmailParams {
|
|
1420
|
-
/**
|
|
1421
|
-
* Recipient email address
|
|
1422
|
-
*/
|
|
1423
|
-
to: string;
|
|
1424
|
-
/**
|
|
1425
|
-
* Email subject
|
|
1426
|
-
*/
|
|
1427
|
-
subject: string;
|
|
1428
|
-
/**
|
|
1429
|
-
* Plain text content
|
|
1430
|
-
*/
|
|
1431
|
-
text?: string;
|
|
1432
|
-
/**
|
|
1433
|
-
* HTML content
|
|
1434
|
-
*/
|
|
1435
|
-
html?: string;
|
|
1436
|
-
/**
|
|
1437
|
-
* Purpose of the email (for logging)
|
|
1438
|
-
*/
|
|
1439
|
-
purpose?: string;
|
|
1440
|
-
}
|
|
1441
|
-
/**
|
|
1442
|
-
* Result of sending email
|
|
1443
|
-
*/
|
|
1444
|
-
interface SendEmailResult {
|
|
1445
|
-
/**
|
|
1446
|
-
* Whether email was sent successfully
|
|
1447
|
-
*/
|
|
1448
|
-
success: boolean;
|
|
1449
|
-
/**
|
|
1450
|
-
* Message ID from email provider (if successful)
|
|
1451
|
-
*/
|
|
1452
|
-
messageId?: string;
|
|
1453
|
-
/**
|
|
1454
|
-
* Error message (if failed)
|
|
1455
|
-
*/
|
|
1456
|
-
error?: string;
|
|
1457
|
-
}
|
|
1458
|
-
/**
|
|
1459
|
-
* Email Provider Interface
|
|
1460
|
-
*
|
|
1461
|
-
* Implement this interface to create custom email providers
|
|
1462
|
-
*
|
|
1463
|
-
* @example
|
|
1464
|
-
* ```typescript
|
|
1465
|
-
* import { EmailProvider, registerEmailProvider } from '@spfn/auth/server/services/email';
|
|
1466
|
-
*
|
|
1467
|
-
* const sendgridProvider: EmailProvider = {
|
|
1468
|
-
* name: 'sendgrid',
|
|
1469
|
-
* sendEmail: async (params) => {
|
|
1470
|
-
* // Your SendGrid implementation
|
|
1471
|
-
* return { success: true, messageId: '...' };
|
|
1472
|
-
* }
|
|
1473
|
-
* };
|
|
1474
|
-
*
|
|
1475
|
-
* registerEmailProvider(sendgridProvider);
|
|
1476
|
-
* ```
|
|
1477
|
-
*/
|
|
1478
|
-
interface EmailProvider {
|
|
1479
|
-
/**
|
|
1480
|
-
* Provider name (e.g., 'aws-ses', 'sendgrid', 'custom')
|
|
1481
|
-
*/
|
|
1482
|
-
name: string;
|
|
1483
|
-
/**
|
|
1484
|
-
* Send email via this provider
|
|
1485
|
-
*
|
|
1486
|
-
* @param params - Email parameters
|
|
1487
|
-
* @returns Send result
|
|
1488
|
-
*/
|
|
1489
|
-
sendEmail(params: SendEmailParams): Promise<SendEmailResult>;
|
|
1490
|
-
}
|
|
1491
|
-
|
|
1492
|
-
/**
|
|
1493
|
-
* @spfn/auth - Email Provider Management
|
|
1494
|
-
*
|
|
1495
|
-
* Manages email provider registration and fallback behavior
|
|
1496
|
-
*/
|
|
1497
|
-
|
|
1498
|
-
/**
|
|
1499
|
-
* Register a custom email provider
|
|
1500
|
-
*
|
|
1501
|
-
* @param provider - Custom email provider implementation
|
|
1502
|
-
*
|
|
1503
|
-
* @example
|
|
1504
|
-
* ```typescript
|
|
1505
|
-
* import { registerEmailProvider } from '@spfn/auth/server/services/email';
|
|
1506
|
-
*
|
|
1507
|
-
* const sendgridProvider = {
|
|
1508
|
-
* name: 'sendgrid',
|
|
1509
|
-
* sendEmail: async (params) => {
|
|
1510
|
-
* // SendGrid implementation
|
|
1511
|
-
* return { success: true, messageId: '...' };
|
|
1512
|
-
* }
|
|
1513
|
-
* };
|
|
1514
|
-
*
|
|
1515
|
-
* registerEmailProvider(sendgridProvider);
|
|
1516
|
-
* ```
|
|
1517
|
-
*/
|
|
1518
|
-
declare function registerEmailProvider(provider: EmailProvider): void;
|
|
1519
|
-
/**
|
|
1520
|
-
* Send email using the registered provider
|
|
1521
|
-
*
|
|
1522
|
-
* Falls back to development mode (console only) if no provider is registered
|
|
1523
|
-
*
|
|
1524
|
-
* @param params - Email parameters
|
|
1525
|
-
* @returns Send result
|
|
1526
|
-
*/
|
|
1527
|
-
declare function sendEmail(params: SendEmailParams): Promise<SendEmailResult>;
|
|
1528
|
-
|
|
1529
|
-
/**
|
|
1530
|
-
* @spfn/auth - SMS Service Types
|
|
1531
|
-
*
|
|
1532
|
-
* Type definitions for SMS sending service
|
|
1533
|
-
*/
|
|
1534
|
-
/**
|
|
1535
|
-
* Parameters for sending SMS
|
|
1536
|
-
*/
|
|
1537
|
-
interface SendSMSParams {
|
|
1538
|
-
/**
|
|
1539
|
-
* Phone number in E.164 format (e.g., +821012345678)
|
|
1540
|
-
*/
|
|
1541
|
-
phone: string;
|
|
1542
|
-
/**
|
|
1543
|
-
* SMS message content
|
|
1544
|
-
*/
|
|
1545
|
-
message: string;
|
|
1546
|
-
/**
|
|
1547
|
-
* Purpose of the SMS (for logging)
|
|
1548
|
-
*/
|
|
1549
|
-
purpose?: string;
|
|
1550
|
-
}
|
|
1551
|
-
/**
|
|
1552
|
-
* Result of sending SMS
|
|
1553
|
-
*/
|
|
1554
|
-
interface SendSMSResult {
|
|
1555
|
-
/**
|
|
1556
|
-
* Whether SMS was sent successfully
|
|
1557
|
-
*/
|
|
1558
|
-
success: boolean;
|
|
1559
|
-
/**
|
|
1560
|
-
* Message ID from SMS provider (if successful)
|
|
1561
|
-
*/
|
|
1562
|
-
messageId?: string;
|
|
1563
|
-
/**
|
|
1564
|
-
* Error message (if failed)
|
|
1565
|
-
*/
|
|
1566
|
-
error?: string;
|
|
1567
|
-
}
|
|
1568
|
-
/**
|
|
1569
|
-
* SMS Provider Interface
|
|
1570
|
-
*
|
|
1571
|
-
* Implement this interface to create custom SMS providers
|
|
1572
|
-
*
|
|
1573
|
-
* @example
|
|
1574
|
-
* ```typescript
|
|
1575
|
-
* import { SMSProvider, registerSMSProvider } from '@spfn/auth/server/services/sms';
|
|
1576
|
-
*
|
|
1577
|
-
* const twilioProvider: SMSProvider = {
|
|
1578
|
-
* name: 'twilio',
|
|
1579
|
-
* sendSMS: async (params) => {
|
|
1580
|
-
* // Your Twilio implementation
|
|
1581
|
-
* return { success: true, messageId: '...' };
|
|
1582
|
-
* }
|
|
1583
|
-
* };
|
|
1584
|
-
*
|
|
1585
|
-
* registerSMSProvider(twilioProvider);
|
|
1586
|
-
* ```
|
|
1587
|
-
*/
|
|
1588
|
-
interface SMSProvider {
|
|
1589
|
-
/**
|
|
1590
|
-
* Provider name (e.g., 'aws-sns', 'twilio', 'custom')
|
|
1591
|
-
*/
|
|
1592
|
-
name: string;
|
|
1593
|
-
/**
|
|
1594
|
-
* Send SMS via this provider
|
|
1595
|
-
*
|
|
1596
|
-
* @param params - SMS parameters
|
|
1597
|
-
* @returns Send result
|
|
1598
|
-
*/
|
|
1599
|
-
sendSMS(params: SendSMSParams): Promise<SendSMSResult>;
|
|
1600
|
-
}
|
|
1601
|
-
|
|
1602
|
-
/**
|
|
1603
|
-
* @spfn/auth - SMS Provider Management
|
|
1604
|
-
*
|
|
1605
|
-
* Manages SMS provider registration and fallback behavior
|
|
1606
|
-
*/
|
|
1607
|
-
|
|
1608
|
-
/**
|
|
1609
|
-
* Register a custom SMS provider
|
|
1610
|
-
*
|
|
1611
|
-
* @param provider - Custom SMS provider implementation
|
|
1612
|
-
*
|
|
1613
|
-
* @example
|
|
1614
|
-
* ```typescript
|
|
1615
|
-
* import { registerSMSProvider } from '@spfn/auth/server/services/sms';
|
|
1616
|
-
*
|
|
1617
|
-
* const twilioProvider = {
|
|
1618
|
-
* name: 'twilio',
|
|
1619
|
-
* sendSMS: async (params) => {
|
|
1620
|
-
* // Twilio implementation
|
|
1621
|
-
* return { success: true, messageId: '...' };
|
|
1622
|
-
* }
|
|
1623
|
-
* };
|
|
1624
|
-
*
|
|
1625
|
-
* registerSMSProvider(twilioProvider);
|
|
1626
|
-
* ```
|
|
1627
|
-
*/
|
|
1628
|
-
declare function registerSMSProvider(provider: SMSProvider): void;
|
|
1629
|
-
/**
|
|
1630
|
-
* Send SMS using the registered provider
|
|
1631
|
-
*
|
|
1632
|
-
* Falls back to development mode (console only) if no provider is registered
|
|
1633
|
-
*
|
|
1634
|
-
* @param params - SMS parameters
|
|
1635
|
-
* @returns Send result
|
|
1636
|
-
*/
|
|
1637
|
-
declare function sendSMS(params: SendSMSParams): Promise<SendSMSResult>;
|
|
1376
|
+
declare function updateUserProfileService(userId: string | number | bigint, params: UpdateProfileParams): Promise<ProfileInfo>;
|
|
1638
1377
|
|
|
1639
1378
|
/**
|
|
1640
1379
|
* @spfn/auth - Database Schema Definition
|
|
@@ -3074,6 +2813,7 @@ declare class UsersRepository extends BaseRepository {
|
|
|
3074
2813
|
id: number;
|
|
3075
2814
|
email: string | null;
|
|
3076
2815
|
phone: string | null;
|
|
2816
|
+
username: string | null;
|
|
3077
2817
|
passwordHash: string | null;
|
|
3078
2818
|
passwordChangeRequired: boolean;
|
|
3079
2819
|
roleId: number;
|
|
@@ -3092,6 +2832,7 @@ declare class UsersRepository extends BaseRepository {
|
|
|
3092
2832
|
id: number;
|
|
3093
2833
|
email: string | null;
|
|
3094
2834
|
phone: string | null;
|
|
2835
|
+
username: string | null;
|
|
3095
2836
|
passwordHash: string | null;
|
|
3096
2837
|
passwordChangeRequired: boolean;
|
|
3097
2838
|
roleId: number;
|
|
@@ -3110,6 +2851,26 @@ declare class UsersRepository extends BaseRepository {
|
|
|
3110
2851
|
id: number;
|
|
3111
2852
|
email: string | null;
|
|
3112
2853
|
phone: string | null;
|
|
2854
|
+
username: string | null;
|
|
2855
|
+
passwordHash: string | null;
|
|
2856
|
+
passwordChangeRequired: boolean;
|
|
2857
|
+
roleId: number;
|
|
2858
|
+
status: "active" | "inactive" | "suspended";
|
|
2859
|
+
emailVerifiedAt: Date | null;
|
|
2860
|
+
phoneVerifiedAt: Date | null;
|
|
2861
|
+
lastLoginAt: Date | null;
|
|
2862
|
+
}>;
|
|
2863
|
+
/**
|
|
2864
|
+
* 사용자명으로 사용자 조회
|
|
2865
|
+
* Read replica 사용
|
|
2866
|
+
*/
|
|
2867
|
+
findByUsername(username: string): Promise<{
|
|
2868
|
+
createdAt: Date;
|
|
2869
|
+
updatedAt: Date;
|
|
2870
|
+
id: number;
|
|
2871
|
+
email: string | null;
|
|
2872
|
+
phone: string | null;
|
|
2873
|
+
username: string | null;
|
|
3113
2874
|
passwordHash: string | null;
|
|
3114
2875
|
passwordChangeRequired: boolean;
|
|
3115
2876
|
roleId: number;
|
|
@@ -3128,6 +2889,7 @@ declare class UsersRepository extends BaseRepository {
|
|
|
3128
2889
|
id: number;
|
|
3129
2890
|
email: string | null;
|
|
3130
2891
|
phone: string | null;
|
|
2892
|
+
username: string | null;
|
|
3131
2893
|
passwordHash: string | null;
|
|
3132
2894
|
passwordChangeRequired: boolean;
|
|
3133
2895
|
roleId: number;
|
|
@@ -3136,6 +2898,34 @@ declare class UsersRepository extends BaseRepository {
|
|
|
3136
2898
|
phoneVerifiedAt: Date | null;
|
|
3137
2899
|
lastLoginAt: Date | null;
|
|
3138
2900
|
} | null>;
|
|
2901
|
+
/**
|
|
2902
|
+
* ID로 사용자 + Role 조회 (leftJoin)
|
|
2903
|
+
* Read replica 사용
|
|
2904
|
+
*
|
|
2905
|
+
* roleId가 null인 유저는 role: null 반환
|
|
2906
|
+
*/
|
|
2907
|
+
findByIdWithRole(id: number): Promise<{
|
|
2908
|
+
user: {
|
|
2909
|
+
createdAt: Date;
|
|
2910
|
+
updatedAt: Date;
|
|
2911
|
+
id: number;
|
|
2912
|
+
email: string | null;
|
|
2913
|
+
phone: string | null;
|
|
2914
|
+
username: string | null;
|
|
2915
|
+
passwordHash: string | null;
|
|
2916
|
+
passwordChangeRequired: boolean;
|
|
2917
|
+
roleId: number;
|
|
2918
|
+
status: "active" | "inactive" | "suspended";
|
|
2919
|
+
emailVerifiedAt: Date | null;
|
|
2920
|
+
phoneVerifiedAt: Date | null;
|
|
2921
|
+
lastLoginAt: Date | null;
|
|
2922
|
+
};
|
|
2923
|
+
role: {
|
|
2924
|
+
name: string;
|
|
2925
|
+
displayName: string;
|
|
2926
|
+
priority: number;
|
|
2927
|
+
} | null;
|
|
2928
|
+
} | null>;
|
|
3139
2929
|
/**
|
|
3140
2930
|
* 사용자 생성
|
|
3141
2931
|
* Write primary 사용
|
|
@@ -3144,6 +2934,7 @@ declare class UsersRepository extends BaseRepository {
|
|
|
3144
2934
|
email: string | null;
|
|
3145
2935
|
phone: string | null;
|
|
3146
2936
|
id: number;
|
|
2937
|
+
username: string | null;
|
|
3147
2938
|
passwordHash: string | null;
|
|
3148
2939
|
passwordChangeRequired: boolean;
|
|
3149
2940
|
roleId: number;
|
|
@@ -3164,6 +2955,7 @@ declare class UsersRepository extends BaseRepository {
|
|
|
3164
2955
|
id: number;
|
|
3165
2956
|
email: string | null;
|
|
3166
2957
|
phone: string | null;
|
|
2958
|
+
username: string | null;
|
|
3167
2959
|
passwordHash: string | null;
|
|
3168
2960
|
passwordChangeRequired: boolean;
|
|
3169
2961
|
roleId: number;
|
|
@@ -3182,6 +2974,7 @@ declare class UsersRepository extends BaseRepository {
|
|
|
3182
2974
|
id: number;
|
|
3183
2975
|
email: string | null;
|
|
3184
2976
|
phone: string | null;
|
|
2977
|
+
username: string | null;
|
|
3185
2978
|
passwordHash: string | null;
|
|
3186
2979
|
passwordChangeRequired: boolean;
|
|
3187
2980
|
roleId: number;
|
|
@@ -3200,6 +2993,7 @@ declare class UsersRepository extends BaseRepository {
|
|
|
3200
2993
|
id: number;
|
|
3201
2994
|
email: string | null;
|
|
3202
2995
|
phone: string | null;
|
|
2996
|
+
username: string | null;
|
|
3203
2997
|
passwordHash: string | null;
|
|
3204
2998
|
passwordChangeRequired: boolean;
|
|
3205
2999
|
roleId: number;
|
|
@@ -3216,6 +3010,7 @@ declare class UsersRepository extends BaseRepository {
|
|
|
3216
3010
|
email: string | null;
|
|
3217
3011
|
phone: string | null;
|
|
3218
3012
|
id: number;
|
|
3013
|
+
username: string | null;
|
|
3219
3014
|
passwordHash: string | null;
|
|
3220
3015
|
passwordChangeRequired: boolean;
|
|
3221
3016
|
roleId: number;
|
|
@@ -3257,6 +3052,7 @@ declare class UsersRepository extends BaseRepository {
|
|
|
3257
3052
|
fetchMinimalUserData(userId: number): Promise<{
|
|
3258
3053
|
userId: number;
|
|
3259
3054
|
email: string | null;
|
|
3055
|
+
username: string | null;
|
|
3260
3056
|
isEmailVerified: boolean;
|
|
3261
3057
|
isPhoneVerified: boolean;
|
|
3262
3058
|
}>;
|
|
@@ -3270,6 +3066,7 @@ declare class UsersRepository extends BaseRepository {
|
|
|
3270
3066
|
fetchFullUserData(userId: number): Promise<{
|
|
3271
3067
|
userId: number;
|
|
3272
3068
|
email: string | null;
|
|
3069
|
+
username: string | null;
|
|
3273
3070
|
isEmailVerified: boolean;
|
|
3274
3071
|
isPhoneVerified: boolean;
|
|
3275
3072
|
lastLoginAt: Date | null;
|
|
@@ -4130,6 +3927,32 @@ declare class UserProfilesRepository extends BaseRepository {
|
|
|
4130
3927
|
company: string | null;
|
|
4131
3928
|
jobTitle: string | null;
|
|
4132
3929
|
}>;
|
|
3930
|
+
/**
|
|
3931
|
+
* 프로필 Upsert (by User ID)
|
|
3932
|
+
*
|
|
3933
|
+
* 프로필이 없으면 생성, 있으면 업데이트
|
|
3934
|
+
* 새로 생성 시 displayName은 필수 (없으면 'User'로 설정)
|
|
3935
|
+
*/
|
|
3936
|
+
upsertByUserId(userId: number, data: Partial<Omit<NewUserProfile, 'userId'>>): Promise<{
|
|
3937
|
+
userId: number;
|
|
3938
|
+
id: number;
|
|
3939
|
+
displayName: string;
|
|
3940
|
+
createdAt: Date;
|
|
3941
|
+
updatedAt: Date;
|
|
3942
|
+
metadata: Record<string, any> | null;
|
|
3943
|
+
firstName: string | null;
|
|
3944
|
+
lastName: string | null;
|
|
3945
|
+
avatarUrl: string | null;
|
|
3946
|
+
bio: string | null;
|
|
3947
|
+
locale: string | null;
|
|
3948
|
+
timezone: string | null;
|
|
3949
|
+
dateOfBirth: string | null;
|
|
3950
|
+
gender: string | null;
|
|
3951
|
+
website: string | null;
|
|
3952
|
+
location: string | null;
|
|
3953
|
+
company: string | null;
|
|
3954
|
+
jobTitle: string | null;
|
|
3955
|
+
}>;
|
|
4133
3956
|
/**
|
|
4134
3957
|
* User ID로 프로필 데이터 조회 (formatted)
|
|
4135
3958
|
*
|
|
@@ -4148,6 +3971,7 @@ declare class UserProfilesRepository extends BaseRepository {
|
|
|
4148
3971
|
location: string | null;
|
|
4149
3972
|
company: string | null;
|
|
4150
3973
|
jobTitle: string | null;
|
|
3974
|
+
metadata: Record<string, any> | null;
|
|
4151
3975
|
createdAt: Date;
|
|
4152
3976
|
updatedAt: Date;
|
|
4153
3977
|
} | null>;
|
|
@@ -4422,6 +4246,136 @@ declare class InvitationsRepository extends BaseRepository {
|
|
|
4422
4246
|
}
|
|
4423
4247
|
declare const invitationsRepository: InvitationsRepository;
|
|
4424
4248
|
|
|
4249
|
+
/**
|
|
4250
|
+
* Social Accounts Repository
|
|
4251
|
+
*
|
|
4252
|
+
* OAuth 소셜 계정 데이터 관리를 위한 Repository
|
|
4253
|
+
* BaseRepository를 상속받아 자동 트랜잭션 컨텍스트 지원 및 Read/Write 분리
|
|
4254
|
+
*/
|
|
4255
|
+
|
|
4256
|
+
/**
|
|
4257
|
+
* Social Accounts Repository 클래스
|
|
4258
|
+
*/
|
|
4259
|
+
declare class SocialAccountsRepository extends BaseRepository {
|
|
4260
|
+
/**
|
|
4261
|
+
* provider와 providerUserId로 소셜 계정 조회
|
|
4262
|
+
* Read replica 사용
|
|
4263
|
+
*/
|
|
4264
|
+
findByProviderAndProviderId(provider: SocialProvider, providerUserId: string): Promise<{
|
|
4265
|
+
createdAt: Date;
|
|
4266
|
+
updatedAt: Date;
|
|
4267
|
+
id: number;
|
|
4268
|
+
userId: number;
|
|
4269
|
+
provider: "google" | "github" | "kakao" | "naver";
|
|
4270
|
+
providerUserId: string;
|
|
4271
|
+
providerEmail: string | null;
|
|
4272
|
+
accessToken: string | null;
|
|
4273
|
+
refreshToken: string | null;
|
|
4274
|
+
tokenExpiresAt: Date | null;
|
|
4275
|
+
}>;
|
|
4276
|
+
/**
|
|
4277
|
+
* userId로 모든 소셜 계정 조회
|
|
4278
|
+
* Read replica 사용
|
|
4279
|
+
*/
|
|
4280
|
+
findByUserId(userId: number): Promise<{
|
|
4281
|
+
createdAt: Date;
|
|
4282
|
+
updatedAt: Date;
|
|
4283
|
+
id: number;
|
|
4284
|
+
userId: number;
|
|
4285
|
+
provider: "google" | "github" | "kakao" | "naver";
|
|
4286
|
+
providerUserId: string;
|
|
4287
|
+
providerEmail: string | null;
|
|
4288
|
+
accessToken: string | null;
|
|
4289
|
+
refreshToken: string | null;
|
|
4290
|
+
tokenExpiresAt: Date | null;
|
|
4291
|
+
}[]>;
|
|
4292
|
+
/**
|
|
4293
|
+
* userId와 provider로 소셜 계정 조회
|
|
4294
|
+
* Read replica 사용
|
|
4295
|
+
*/
|
|
4296
|
+
findByUserIdAndProvider(userId: number, provider: SocialProvider): Promise<{
|
|
4297
|
+
createdAt: Date;
|
|
4298
|
+
updatedAt: Date;
|
|
4299
|
+
id: number;
|
|
4300
|
+
userId: number;
|
|
4301
|
+
provider: "google" | "github" | "kakao" | "naver";
|
|
4302
|
+
providerUserId: string;
|
|
4303
|
+
providerEmail: string | null;
|
|
4304
|
+
accessToken: string | null;
|
|
4305
|
+
refreshToken: string | null;
|
|
4306
|
+
tokenExpiresAt: Date | null;
|
|
4307
|
+
}>;
|
|
4308
|
+
/**
|
|
4309
|
+
* 소셜 계정 생성
|
|
4310
|
+
* Write primary 사용
|
|
4311
|
+
*/
|
|
4312
|
+
create(data: NewUserSocialAccount): Promise<{
|
|
4313
|
+
userId: number;
|
|
4314
|
+
id: number;
|
|
4315
|
+
createdAt: Date;
|
|
4316
|
+
updatedAt: Date;
|
|
4317
|
+
provider: "google" | "github" | "kakao" | "naver";
|
|
4318
|
+
providerUserId: string;
|
|
4319
|
+
providerEmail: string | null;
|
|
4320
|
+
accessToken: string | null;
|
|
4321
|
+
refreshToken: string | null;
|
|
4322
|
+
tokenExpiresAt: Date | null;
|
|
4323
|
+
}>;
|
|
4324
|
+
/**
|
|
4325
|
+
* 토큰 정보 업데이트
|
|
4326
|
+
* Write primary 사용
|
|
4327
|
+
*/
|
|
4328
|
+
updateTokens(id: number, data: {
|
|
4329
|
+
accessToken?: string | null;
|
|
4330
|
+
refreshToken?: string | null;
|
|
4331
|
+
tokenExpiresAt?: Date | null;
|
|
4332
|
+
}): Promise<{
|
|
4333
|
+
createdAt: Date;
|
|
4334
|
+
updatedAt: Date;
|
|
4335
|
+
id: number;
|
|
4336
|
+
userId: number;
|
|
4337
|
+
provider: "google" | "github" | "kakao" | "naver";
|
|
4338
|
+
providerUserId: string;
|
|
4339
|
+
providerEmail: string | null;
|
|
4340
|
+
accessToken: string | null;
|
|
4341
|
+
refreshToken: string | null;
|
|
4342
|
+
tokenExpiresAt: Date | null;
|
|
4343
|
+
}>;
|
|
4344
|
+
/**
|
|
4345
|
+
* 소셜 계정 삭제
|
|
4346
|
+
* Write primary 사용
|
|
4347
|
+
*/
|
|
4348
|
+
deleteById(id: number): Promise<{
|
|
4349
|
+
userId: number;
|
|
4350
|
+
id: number;
|
|
4351
|
+
createdAt: Date;
|
|
4352
|
+
updatedAt: Date;
|
|
4353
|
+
provider: "google" | "github" | "kakao" | "naver";
|
|
4354
|
+
providerUserId: string;
|
|
4355
|
+
providerEmail: string | null;
|
|
4356
|
+
accessToken: string | null;
|
|
4357
|
+
refreshToken: string | null;
|
|
4358
|
+
tokenExpiresAt: Date | null;
|
|
4359
|
+
}>;
|
|
4360
|
+
/**
|
|
4361
|
+
* userId와 provider로 소셜 계정 삭제
|
|
4362
|
+
* Write primary 사용
|
|
4363
|
+
*/
|
|
4364
|
+
deleteByUserIdAndProvider(userId: number, provider: SocialProvider): Promise<{
|
|
4365
|
+
userId: number;
|
|
4366
|
+
id: number;
|
|
4367
|
+
createdAt: Date;
|
|
4368
|
+
updatedAt: Date;
|
|
4369
|
+
provider: "google" | "github" | "kakao" | "naver";
|
|
4370
|
+
providerUserId: string;
|
|
4371
|
+
providerEmail: string | null;
|
|
4372
|
+
accessToken: string | null;
|
|
4373
|
+
refreshToken: string | null;
|
|
4374
|
+
tokenExpiresAt: Date | null;
|
|
4375
|
+
}>;
|
|
4376
|
+
}
|
|
4377
|
+
declare const socialAccountsRepository: SocialAccountsRepository;
|
|
4378
|
+
|
|
4425
4379
|
/**
|
|
4426
4380
|
* @spfn/auth - Password Helpers
|
|
4427
4381
|
*
|
|
@@ -4715,6 +4669,57 @@ declare const requireAnyPermission: _spfn_core_route.NamedMiddlewareFactory<"any
|
|
|
4715
4669
|
*/
|
|
4716
4670
|
declare const requireRole: _spfn_core_route.NamedMiddlewareFactory<"role", string[]>;
|
|
4717
4671
|
|
|
4672
|
+
/**
|
|
4673
|
+
* @spfn/auth - Role Guard Middleware
|
|
4674
|
+
*
|
|
4675
|
+
* Middleware for role-based access control with allow/deny options
|
|
4676
|
+
*/
|
|
4677
|
+
/**
|
|
4678
|
+
* Role guard options
|
|
4679
|
+
*/
|
|
4680
|
+
interface RoleGuardOptions {
|
|
4681
|
+
/**
|
|
4682
|
+
* Roles to allow (OR condition)
|
|
4683
|
+
* User must have at least one of these roles
|
|
4684
|
+
*/
|
|
4685
|
+
allow?: string[];
|
|
4686
|
+
/**
|
|
4687
|
+
* Roles to deny
|
|
4688
|
+
* User with any of these roles will be rejected
|
|
4689
|
+
*/
|
|
4690
|
+
deny?: string[];
|
|
4691
|
+
}
|
|
4692
|
+
/**
|
|
4693
|
+
* Role-based access control middleware
|
|
4694
|
+
*
|
|
4695
|
+
* Must be used after authenticate middleware
|
|
4696
|
+
*
|
|
4697
|
+
* @param options - Role guard options (allow/deny)
|
|
4698
|
+
* @returns Middleware function
|
|
4699
|
+
*
|
|
4700
|
+
* @example Allow specific roles
|
|
4701
|
+
* ```typescript
|
|
4702
|
+
* export const adminRoute = route.get('/admin')
|
|
4703
|
+
* .use([authenticate, roleGuard({ allow: ['admin', 'superadmin'] })])
|
|
4704
|
+
* .handler(async (c) => { ... });
|
|
4705
|
+
* ```
|
|
4706
|
+
*
|
|
4707
|
+
* @example Deny specific roles
|
|
4708
|
+
* ```typescript
|
|
4709
|
+
* export const publicRoute = route.get('/content')
|
|
4710
|
+
* .use([authenticate, roleGuard({ deny: ['banned', 'suspended'] })])
|
|
4711
|
+
* .handler(async (c) => { ... });
|
|
4712
|
+
* ```
|
|
4713
|
+
*
|
|
4714
|
+
* @example Combined allow and deny
|
|
4715
|
+
* ```typescript
|
|
4716
|
+
* export const managerRoute = route.get('/manage')
|
|
4717
|
+
* .use([authenticate, roleGuard({ allow: ['admin', 'manager'], deny: ['suspended'] })])
|
|
4718
|
+
* .handler(async (c) => { ... });
|
|
4719
|
+
* ```
|
|
4720
|
+
*/
|
|
4721
|
+
declare const roleGuard: _spfn_core_route.NamedMiddlewareFactory<"roleGuard", [options: RoleGuardOptions]>;
|
|
4722
|
+
|
|
4718
4723
|
/**
|
|
4719
4724
|
* Auth Context Helpers
|
|
4720
4725
|
*
|
|
@@ -4741,6 +4746,32 @@ declare const requireRole: _spfn_core_route.NamedMiddlewareFactory<"role", strin
|
|
|
4741
4746
|
declare function getAuth(c: Context | {
|
|
4742
4747
|
raw: Context;
|
|
4743
4748
|
}): AuthContext;
|
|
4749
|
+
/**
|
|
4750
|
+
* Get optional auth context from route context
|
|
4751
|
+
*
|
|
4752
|
+
* Returns AuthContext if authenticated, undefined otherwise.
|
|
4753
|
+
* Use with `optionalAuth` middleware for routes that serve both
|
|
4754
|
+
* authenticated and unauthenticated users.
|
|
4755
|
+
*
|
|
4756
|
+
* @example
|
|
4757
|
+
* ```typescript
|
|
4758
|
+
* export const getProducts = route.get('/products')
|
|
4759
|
+
* .use([optionalAuth])
|
|
4760
|
+
* .handler(async (c) => {
|
|
4761
|
+
* const auth = getOptionalAuth(c);
|
|
4762
|
+
*
|
|
4763
|
+
* if (auth)
|
|
4764
|
+
* {
|
|
4765
|
+
* return getPersonalizedProducts(auth.userId);
|
|
4766
|
+
* }
|
|
4767
|
+
*
|
|
4768
|
+
* return getPublicProducts();
|
|
4769
|
+
* });
|
|
4770
|
+
* ```
|
|
4771
|
+
*/
|
|
4772
|
+
declare function getOptionalAuth(c: Context | {
|
|
4773
|
+
raw: Context;
|
|
4774
|
+
}): AuthContext | undefined;
|
|
4744
4775
|
/**
|
|
4745
4776
|
* Get authenticated user from route context
|
|
4746
4777
|
*
|
|
@@ -4758,6 +4789,7 @@ declare function getUser(c: Context | {
|
|
|
4758
4789
|
email: string | null;
|
|
4759
4790
|
phone: string | null;
|
|
4760
4791
|
id: number;
|
|
4792
|
+
username: string | null;
|
|
4761
4793
|
passwordHash: string | null;
|
|
4762
4794
|
passwordChangeRequired: boolean;
|
|
4763
4795
|
roleId: number;
|
|
@@ -4782,6 +4814,22 @@ declare function getUser(c: Context | {
|
|
|
4782
4814
|
declare function getUserId(c: Context | {
|
|
4783
4815
|
raw: Context;
|
|
4784
4816
|
}): string;
|
|
4817
|
+
/**
|
|
4818
|
+
* Get authenticated user's role from route context
|
|
4819
|
+
*
|
|
4820
|
+
* @returns Role name or null if user has no role
|
|
4821
|
+
*
|
|
4822
|
+
* @example
|
|
4823
|
+
* ```typescript
|
|
4824
|
+
* app.bind(adminContract, [authenticate], async (c) => {
|
|
4825
|
+
* const role = getRole(c);
|
|
4826
|
+
* // 'admin' | 'superadmin' | null
|
|
4827
|
+
* });
|
|
4828
|
+
* ```
|
|
4829
|
+
*/
|
|
4830
|
+
declare function getRole(c: Context | {
|
|
4831
|
+
raw: Context;
|
|
4832
|
+
}): string | null;
|
|
4785
4833
|
/**
|
|
4786
4834
|
* Get current key ID from route context
|
|
4787
4835
|
*
|
|
@@ -4917,6 +4965,8 @@ declare const COOKIE_NAMES: {
|
|
|
4917
4965
|
readonly SESSION: "spfn_session";
|
|
4918
4966
|
/** Current key ID (for key rotation) */
|
|
4919
4967
|
readonly SESSION_KEY_ID: "spfn_session_key_id";
|
|
4968
|
+
/** Pending OAuth session (privateKey, keyId, algorithm) - temporary during OAuth flow */
|
|
4969
|
+
readonly OAUTH_PENDING: "spfn_oauth_pending";
|
|
4920
4970
|
};
|
|
4921
4971
|
/**
|
|
4922
4972
|
* Parse duration string to seconds
|
|
@@ -4973,6 +5023,114 @@ declare function getAuthConfig(): AuthConfig;
|
|
|
4973
5023
|
*/
|
|
4974
5024
|
declare function getSessionTtl(override?: string | number): number;
|
|
4975
5025
|
|
|
5026
|
+
/**
|
|
5027
|
+
* Google OAuth 2.0 Client
|
|
5028
|
+
*
|
|
5029
|
+
* Authorization Code Flow 구현
|
|
5030
|
+
* - getGoogleAuthUrl: Google 로그인 URL 생성
|
|
5031
|
+
* - exchangeCodeForTokens: Code를 Token으로 교환
|
|
5032
|
+
* - getGoogleUserInfo: 사용자 정보 조회
|
|
5033
|
+
*/
|
|
5034
|
+
interface GoogleTokenResponse {
|
|
5035
|
+
access_token: string;
|
|
5036
|
+
expires_in: number;
|
|
5037
|
+
refresh_token?: string;
|
|
5038
|
+
scope: string;
|
|
5039
|
+
token_type: string;
|
|
5040
|
+
id_token?: string;
|
|
5041
|
+
}
|
|
5042
|
+
interface GoogleUserInfo {
|
|
5043
|
+
id: string;
|
|
5044
|
+
email: string;
|
|
5045
|
+
verified_email: boolean;
|
|
5046
|
+
name?: string;
|
|
5047
|
+
given_name?: string;
|
|
5048
|
+
family_name?: string;
|
|
5049
|
+
picture?: string;
|
|
5050
|
+
locale?: string;
|
|
5051
|
+
}
|
|
5052
|
+
/**
|
|
5053
|
+
* Google OAuth가 활성화되어 있는지 확인
|
|
5054
|
+
*/
|
|
5055
|
+
declare function isGoogleOAuthEnabled(): boolean;
|
|
5056
|
+
/**
|
|
5057
|
+
* Google OAuth 설정 가져오기
|
|
5058
|
+
*/
|
|
5059
|
+
declare function getGoogleOAuthConfig(): {
|
|
5060
|
+
clientId: string;
|
|
5061
|
+
clientSecret: string;
|
|
5062
|
+
redirectUri: string;
|
|
5063
|
+
};
|
|
5064
|
+
/**
|
|
5065
|
+
* Google 로그인 URL 생성
|
|
5066
|
+
*
|
|
5067
|
+
* @param state - CSRF 방지용 state 파라미터 (암호화된 returnUrl + nonce 포함)
|
|
5068
|
+
* @param scopes - 요청할 OAuth scopes (기본: env 또는 email, profile)
|
|
5069
|
+
*/
|
|
5070
|
+
declare function getGoogleAuthUrl(state: string, scopes?: string[]): string;
|
|
5071
|
+
/**
|
|
5072
|
+
* Authorization Code를 Token으로 교환
|
|
5073
|
+
*
|
|
5074
|
+
* @param code - Google에서 받은 authorization code
|
|
5075
|
+
*/
|
|
5076
|
+
declare function exchangeCodeForTokens(code: string): Promise<GoogleTokenResponse>;
|
|
5077
|
+
/**
|
|
5078
|
+
* Access Token으로 Google 사용자 정보 조회
|
|
5079
|
+
*
|
|
5080
|
+
* @param accessToken - Google access token
|
|
5081
|
+
*/
|
|
5082
|
+
declare function getGoogleUserInfo(accessToken: string): Promise<GoogleUserInfo>;
|
|
5083
|
+
/**
|
|
5084
|
+
* Refresh Token으로 새 Access Token 획득
|
|
5085
|
+
*
|
|
5086
|
+
* @param refreshToken - Google refresh token
|
|
5087
|
+
*/
|
|
5088
|
+
declare function refreshAccessToken(refreshToken: string): Promise<GoogleTokenResponse>;
|
|
5089
|
+
|
|
5090
|
+
/**
|
|
5091
|
+
* OAuth State Management
|
|
5092
|
+
*
|
|
5093
|
+
* CSRF 방지를 위한 state 파라미터 암호화/복호화
|
|
5094
|
+
* - returnUrl: OAuth 성공 후 리다이렉트할 URL
|
|
5095
|
+
* - nonce: CSRF 방지용 일회용 토큰
|
|
5096
|
+
* - provider: OAuth provider (google, github 등)
|
|
5097
|
+
* - publicKey, keyId, fingerprint, algorithm: 클라이언트 키 정보
|
|
5098
|
+
* - expiresAt: state 만료 시간
|
|
5099
|
+
*/
|
|
5100
|
+
|
|
5101
|
+
interface OAuthState {
|
|
5102
|
+
returnUrl: string;
|
|
5103
|
+
nonce: string;
|
|
5104
|
+
provider: string;
|
|
5105
|
+
publicKey: string;
|
|
5106
|
+
keyId: string;
|
|
5107
|
+
fingerprint: string;
|
|
5108
|
+
algorithm: KeyAlgorithmType;
|
|
5109
|
+
}
|
|
5110
|
+
interface CreateOAuthStateParams {
|
|
5111
|
+
provider: string;
|
|
5112
|
+
returnUrl: string;
|
|
5113
|
+
publicKey: string;
|
|
5114
|
+
keyId: string;
|
|
5115
|
+
fingerprint: string;
|
|
5116
|
+
algorithm: KeyAlgorithmType;
|
|
5117
|
+
}
|
|
5118
|
+
/**
|
|
5119
|
+
* OAuth state 생성 및 암호화
|
|
5120
|
+
*
|
|
5121
|
+
* @param params - state 생성에 필요한 파라미터
|
|
5122
|
+
* @returns 암호화된 state 문자열
|
|
5123
|
+
*/
|
|
5124
|
+
declare function createOAuthState(params: CreateOAuthStateParams): Promise<string>;
|
|
5125
|
+
/**
|
|
5126
|
+
* OAuth state 복호화 및 검증
|
|
5127
|
+
*
|
|
5128
|
+
* @param encryptedState - 암호화된 state 문자열
|
|
5129
|
+
* @returns 복호화된 state 객체
|
|
5130
|
+
* @throws Error if state is invalid or expired (JWE exp claim으로 자동 검증)
|
|
5131
|
+
*/
|
|
5132
|
+
declare function verifyOAuthState(encryptedState: string): Promise<OAuthState>;
|
|
5133
|
+
|
|
4976
5134
|
/**
|
|
4977
5135
|
* @spfn/auth - Centralized Logger
|
|
4978
5136
|
*
|
|
@@ -4985,6 +5143,7 @@ declare const authLogger: {
|
|
|
4985
5143
|
general: _spfn_core_logger.Logger;
|
|
4986
5144
|
login: _spfn_core_logger.Logger;
|
|
4987
5145
|
keyRotation: _spfn_core_logger.Logger;
|
|
5146
|
+
oauth: _spfn_core_logger.Logger;
|
|
4988
5147
|
};
|
|
4989
5148
|
service: _spfn_core_logger.Logger;
|
|
4990
5149
|
setup: _spfn_core_logger.Logger;
|
|
@@ -5068,4 +5227,61 @@ interface AuthLifecycleConfig {
|
|
|
5068
5227
|
*/
|
|
5069
5228
|
declare function createAuthLifecycle(options?: AuthInitOptions): AuthLifecycleConfig;
|
|
5070
5229
|
|
|
5071
|
-
|
|
5230
|
+
/**
|
|
5231
|
+
* @spfn/auth - Auth Events
|
|
5232
|
+
*
|
|
5233
|
+
* 인증 관련 이벤트 정의
|
|
5234
|
+
* - auth.login: 로그인 성공 시 (기존 사용자만)
|
|
5235
|
+
* - auth.register: 회원가입 성공 시 (OAuth 신규 가입 포함)
|
|
5236
|
+
*/
|
|
5237
|
+
/**
|
|
5238
|
+
* Auth provider type
|
|
5239
|
+
*/
|
|
5240
|
+
declare const AuthProviderSchema: _sinclair_typebox.TUnion<[_sinclair_typebox.TLiteral<"email">, _sinclair_typebox.TLiteral<"phone">, _sinclair_typebox.TLiteral<"google">]>;
|
|
5241
|
+
/**
|
|
5242
|
+
* auth.login - 로그인 성공 이벤트
|
|
5243
|
+
*
|
|
5244
|
+
* 발행 시점:
|
|
5245
|
+
* - 이메일/전화 로그인 성공 시
|
|
5246
|
+
* - OAuth 기존 사용자 로그인 시
|
|
5247
|
+
*
|
|
5248
|
+
* @example
|
|
5249
|
+
* ```typescript
|
|
5250
|
+
* authLoginEvent.subscribe(async (payload) => {
|
|
5251
|
+
* await analytics.trackLogin(payload.userId, payload.provider);
|
|
5252
|
+
* });
|
|
5253
|
+
* ```
|
|
5254
|
+
*/
|
|
5255
|
+
declare const authLoginEvent: _spfn_core_event.EventDef<{
|
|
5256
|
+
email?: string | undefined;
|
|
5257
|
+
phone?: string | undefined;
|
|
5258
|
+
userId: string;
|
|
5259
|
+
provider: "email" | "phone" | "google";
|
|
5260
|
+
}>;
|
|
5261
|
+
/**
|
|
5262
|
+
* auth.register - 회원가입 성공 이벤트
|
|
5263
|
+
*
|
|
5264
|
+
* 발행 시점:
|
|
5265
|
+
* - 이메일/전화 회원가입 성공 시
|
|
5266
|
+
* - OAuth 신규 사용자 가입 시
|
|
5267
|
+
*
|
|
5268
|
+
* @example
|
|
5269
|
+
* ```typescript
|
|
5270
|
+
* authRegisterEvent.subscribe(async (payload) => {
|
|
5271
|
+
* await emailService.sendWelcome(payload.email);
|
|
5272
|
+
* });
|
|
5273
|
+
* ```
|
|
5274
|
+
*/
|
|
5275
|
+
declare const authRegisterEvent: _spfn_core_event.EventDef<{
|
|
5276
|
+
email?: string | undefined;
|
|
5277
|
+
phone?: string | undefined;
|
|
5278
|
+
userId: string;
|
|
5279
|
+
provider: "email" | "phone" | "google";
|
|
5280
|
+
}>;
|
|
5281
|
+
/**
|
|
5282
|
+
* Auth event payload types
|
|
5283
|
+
*/
|
|
5284
|
+
type AuthLoginPayload = typeof authLoginEvent._payload;
|
|
5285
|
+
type AuthRegisterPayload = typeof authRegisterEvent._payload;
|
|
5286
|
+
|
|
5287
|
+
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, 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, updateRole, updateUserProfileService, updateUserService, updateUsernameService, userInvitations, userPermissions, userPermissionsRepository, userProfiles, userProfilesRepository, userPublicKeys, userSocialAccounts, users, usersRepository, validateInvitation, validatePasswordStrength, verificationCodes, verificationCodesRepository, verifyClientToken, verifyKeyFingerprint, verifyOAuthState, verifyPassword, verifyToken };
|