@spfn/auth 0.2.0-beta.74 → 0.2.0-beta.80
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 +267 -15
- package/dist/{authenticate-DXVtYh8X.d.ts → authenticate-ofdEmk6x.d.ts} +43 -13
- package/dist/config.d.ts +150 -0
- package/dist/config.js +71 -4
- package/dist/config.js.map +1 -1
- package/dist/errors.d.ts +75 -3
- package/dist/errors.js +50 -1
- package/dist/errors.js.map +1 -1
- package/dist/index.d.ts +28 -6
- package/dist/index.js +53 -5
- package/dist/index.js.map +1 -1
- package/dist/nextjs/api.js +13 -11
- package/dist/nextjs/api.js.map +1 -1
- package/dist/nextjs/server.d.ts +2 -2
- package/dist/nextjs/server.js +3 -3
- package/dist/nextjs/server.js.map +1 -1
- package/dist/server.d.ts +1040 -42
- package/dist/server.js +1894 -397
- package/dist/server.js.map +1 -1
- package/dist/{session-s_hiXmXC.d.ts → session-CGxgH3C9.d.ts} +1 -1
- package/dist/types-1BMx0OX1.d.ts +84 -0
- package/migrations/0006_easy_hardball.sql +24 -0
- package/migrations/0007_glossy_major_mapleleaf.sql +1 -0
- package/migrations/meta/0006_snapshot.json +1921 -0
- package/migrations/meta/0007_snapshot.json +1916 -0
- package/migrations/meta/_journal.json +15 -1
- package/package.json +29 -27
- package/dist/types-BtksCI9X.d.ts +0 -45
package/dist/server.d.ts
CHANGED
|
@@ -1,17 +1,18 @@
|
|
|
1
|
-
import { j as AuthInitOptions, k as OAuthProvider, e as VerificationPurpose, i as PermissionCategory, l as AuthContext } from './authenticate-
|
|
2
|
-
export { C as ChangePasswordParams, a3 as EmailSchema, I as IssueOneTimeTokenResult, s as LoginParams, L as LoginResult, t as LogoutParams, aa as NativeVerifyOptions, a8 as NormalizedIdentity, Z as OAuthCallbackParams, _ as OAuthCallbackResult, a0 as OAuthNativeParams, c as OAuthNativeResult, Y as OAuthStartParams, O as OAuthStartResult, a9 as OAuthTokens, a5 as PasswordSchema, a4 as PhoneSchema, q as RegisterParams, E as RegisterPublicKeyParams, a as RegisterResult, G as RevokeKeyParams, F as RotateKeyParams, b as RotateKeyResult, w as SendVerificationCodeParams, S as SendVerificationCodeResult, a6 as TargetTypeSchema, g as VERIFICATION_PURPOSES, f as VERIFICATION_TARGET_TYPES, a7 as VerificationPurposeSchema, V as VerificationTargetType, x as VerifyCodeParams, y as VerifyCodeResult, m as authRouter, a1 as authenticate, N as buildOAuthErrorUrl, p as changePasswordService, W as getEnabledOAuthProviders, X as getGoogleAccessToken,
|
|
1
|
+
import { j as AuthInitOptions, k as OAuthProvider, e as VerificationPurpose, i as PermissionCategory, l as AuthContext } from './authenticate-ofdEmk6x.js';
|
|
2
|
+
export { C as ChangePasswordParams, a3 as EmailSchema, I as IssueOneTimeTokenResult, s as LoginParams, L as LoginResult, t as LogoutParams, aa as NativeVerifyOptions, a8 as NormalizedIdentity, Z as OAuthCallbackParams, _ as OAuthCallbackResult, ab as OAuthCodeExchangeOptions, a0 as OAuthNativeParams, c as OAuthNativeResult, Y as OAuthStartParams, O as OAuthStartResult, a9 as OAuthTokens, a5 as PasswordSchema, a4 as PhoneSchema, q as RegisterParams, E as RegisterPublicKeyParams, a as RegisterResult, G as RevokeKeyParams, F as RotateKeyParams, b as RotateKeyResult, w as SendVerificationCodeParams, S as SendVerificationCodeResult, a6 as TargetTypeSchema, g as VERIFICATION_PURPOSES, f as VERIFICATION_TARGET_TYPES, a7 as VerificationPurposeSchema, V as VerificationTargetType, x as VerifyCodeParams, y as VerifyCodeResult, m as authRouter, a1 as authenticate, N as buildOAuthErrorUrl, p as changePasswordService, W as getEnabledOAuthProviders, X as getGoogleAccessToken, ad as getOAuthProvider, ae as getRegisteredProviders, Q as isOAuthProviderEnabled, H as issueOneTimeTokenService, n as loginService, o as logoutService, M as oauthCallbackService, $ as oauthNativeService, K as oauthStartService, a2 as optionalAuth, ac as registerOAuthProvider, z as registerPublicKeyService, r as registerService, T as requireEnabledProvider, D as revokeKeyService, B as rotateKeyService, u as sendVerificationCodeService, v as verifyCodeService, J as verifyOneTimeTokenService } from './authenticate-ofdEmk6x.js';
|
|
3
3
|
import * as drizzle_orm_pg_core from 'drizzle-orm/pg-core';
|
|
4
|
-
import { K as KeyAlgorithmType,
|
|
5
|
-
export { I as INVITATION_STATUSES, a as KEY_ALGORITHM, S as SOCIAL_PROVIDERS, U as USER_STATUSES,
|
|
4
|
+
import { K as KeyAlgorithmType, c as InvitationStatus, e as SocialProvider, g as AccountDeletionRequestedBy, h as PurgeStrategy } from './types-1BMx0OX1.js';
|
|
5
|
+
export { b as ACCOUNT_DELETION_REQUESTED_BY, A as ACCOUNT_DELETION_REQUEST_STATUSES, f as AccountDeletionRequestStatus, I as INVITATION_STATUSES, a as KEY_ALGORITHM, P as PURGE_STRATEGIES, S as SOCIAL_PROVIDERS, U as USER_STATUSES, d as UserStatus } from './types-1BMx0OX1.js';
|
|
6
6
|
import { UserProfile as UserProfile$1, ProfileInfo } from '@spfn/auth';
|
|
7
7
|
import { BaseRepository } from '@spfn/core/db';
|
|
8
8
|
import { Context } from 'hono';
|
|
9
9
|
import * as _spfn_core_route from '@spfn/core/route';
|
|
10
10
|
import { Algorithm } from 'jsonwebtoken';
|
|
11
|
-
export { S as SessionData, g as getSessionInfo, s as sealSession, a as shouldRefreshSession, u as unsealSession } from './session-
|
|
11
|
+
export { S as SessionData, g as getSessionInfo, s as sealSession, a as shouldRefreshSession, u as unsealSession } from './session-CGxgH3C9.js';
|
|
12
12
|
import { JWTPayload } from 'jose';
|
|
13
13
|
import { SSETokenStore, SSETokenManager } from '@spfn/core/event/sse';
|
|
14
14
|
import * as _spfn_core_logger from '@spfn/core/logger';
|
|
15
|
+
import * as _spfn_core_job from '@spfn/core/job';
|
|
15
16
|
import * as _spfn_core_event from '@spfn/core/event';
|
|
16
17
|
import * as _sinclair_typebox from '@sinclair/typebox';
|
|
17
18
|
import '@spfn/auth/server';
|
|
@@ -33,6 +34,40 @@ declare const users: drizzle_orm_pg_core.PgTableWithColumns<{
|
|
|
33
34
|
name: "users";
|
|
34
35
|
schema: string;
|
|
35
36
|
columns: {
|
|
37
|
+
deletedAt: drizzle_orm_pg_core.PgColumn<{
|
|
38
|
+
name: "deleted_at";
|
|
39
|
+
tableName: "users";
|
|
40
|
+
dataType: "date";
|
|
41
|
+
columnType: "PgTimestamp";
|
|
42
|
+
data: Date;
|
|
43
|
+
driverParam: string;
|
|
44
|
+
notNull: false;
|
|
45
|
+
hasDefault: false;
|
|
46
|
+
isPrimaryKey: false;
|
|
47
|
+
isAutoincrement: false;
|
|
48
|
+
hasRuntimeDefault: false;
|
|
49
|
+
enumValues: undefined;
|
|
50
|
+
baseColumn: never;
|
|
51
|
+
identity: undefined;
|
|
52
|
+
generated: undefined;
|
|
53
|
+
}, {}, {}>;
|
|
54
|
+
deletedBy: drizzle_orm_pg_core.PgColumn<{
|
|
55
|
+
name: "deleted_by";
|
|
56
|
+
tableName: "users";
|
|
57
|
+
dataType: "string";
|
|
58
|
+
columnType: "PgText";
|
|
59
|
+
data: string;
|
|
60
|
+
driverParam: string;
|
|
61
|
+
notNull: false;
|
|
62
|
+
hasDefault: false;
|
|
63
|
+
isPrimaryKey: false;
|
|
64
|
+
isAutoincrement: false;
|
|
65
|
+
hasRuntimeDefault: false;
|
|
66
|
+
enumValues: [string, ...string[]];
|
|
67
|
+
baseColumn: never;
|
|
68
|
+
identity: undefined;
|
|
69
|
+
generated: undefined;
|
|
70
|
+
}, {}, {}>;
|
|
36
71
|
createdAt: drizzle_orm_pg_core.PgColumn<{
|
|
37
72
|
name: "created_at";
|
|
38
73
|
tableName: "users";
|
|
@@ -208,14 +243,14 @@ declare const users: drizzle_orm_pg_core.PgTableWithColumns<{
|
|
|
208
243
|
tableName: "users";
|
|
209
244
|
dataType: "string";
|
|
210
245
|
columnType: "PgText";
|
|
211
|
-
data: "active" | "inactive" | "suspended";
|
|
246
|
+
data: "active" | "inactive" | "suspended" | "pending_deletion" | "deleted";
|
|
212
247
|
driverParam: string;
|
|
213
248
|
notNull: true;
|
|
214
249
|
hasDefault: true;
|
|
215
250
|
isPrimaryKey: false;
|
|
216
251
|
isAutoincrement: false;
|
|
217
252
|
hasRuntimeDefault: false;
|
|
218
|
-
enumValues: ["active", "inactive", "suspended"] & [string, ...string[]];
|
|
253
|
+
enumValues: ["active", "inactive", "suspended", "pending_deletion", "deleted"] & [string, ...string[]];
|
|
219
254
|
baseColumn: never;
|
|
220
255
|
identity: undefined;
|
|
221
256
|
generated: undefined;
|
|
@@ -287,6 +322,8 @@ type NewUser = typeof users.$inferInsert;
|
|
|
287
322
|
* Get user by ID
|
|
288
323
|
*/
|
|
289
324
|
declare function getUserByIdService(userId: number): Promise<{
|
|
325
|
+
deletedAt: Date | null;
|
|
326
|
+
deletedBy: string | null;
|
|
290
327
|
createdAt: Date;
|
|
291
328
|
updatedAt: Date;
|
|
292
329
|
id: number;
|
|
@@ -297,7 +334,7 @@ declare function getUserByIdService(userId: number): Promise<{
|
|
|
297
334
|
passwordHash: string | null;
|
|
298
335
|
passwordChangeRequired: boolean;
|
|
299
336
|
roleId: number;
|
|
300
|
-
status: "active" | "inactive" | "suspended";
|
|
337
|
+
status: "active" | "inactive" | "suspended" | "pending_deletion" | "deleted";
|
|
301
338
|
emailVerifiedAt: Date | null;
|
|
302
339
|
phoneVerifiedAt: Date | null;
|
|
303
340
|
lastLoginAt: Date | null;
|
|
@@ -306,6 +343,8 @@ declare function getUserByIdService(userId: number): Promise<{
|
|
|
306
343
|
* Get user by email
|
|
307
344
|
*/
|
|
308
345
|
declare function getUserByEmailService(email: string): Promise<{
|
|
346
|
+
deletedAt: Date | null;
|
|
347
|
+
deletedBy: string | null;
|
|
309
348
|
createdAt: Date;
|
|
310
349
|
updatedAt: Date;
|
|
311
350
|
id: number;
|
|
@@ -316,7 +355,7 @@ declare function getUserByEmailService(email: string): Promise<{
|
|
|
316
355
|
passwordHash: string | null;
|
|
317
356
|
passwordChangeRequired: boolean;
|
|
318
357
|
roleId: number;
|
|
319
|
-
status: "active" | "inactive" | "suspended";
|
|
358
|
+
status: "active" | "inactive" | "suspended" | "pending_deletion" | "deleted";
|
|
320
359
|
emailVerifiedAt: Date | null;
|
|
321
360
|
phoneVerifiedAt: Date | null;
|
|
322
361
|
lastLoginAt: Date | null;
|
|
@@ -325,6 +364,8 @@ declare function getUserByEmailService(email: string): Promise<{
|
|
|
325
364
|
* Get user by phone
|
|
326
365
|
*/
|
|
327
366
|
declare function getUserByPhoneService(phone: string): Promise<{
|
|
367
|
+
deletedAt: Date | null;
|
|
368
|
+
deletedBy: string | null;
|
|
328
369
|
createdAt: Date;
|
|
329
370
|
updatedAt: Date;
|
|
330
371
|
id: number;
|
|
@@ -335,7 +376,7 @@ declare function getUserByPhoneService(phone: string): Promise<{
|
|
|
335
376
|
passwordHash: string | null;
|
|
336
377
|
passwordChangeRequired: boolean;
|
|
337
378
|
roleId: number;
|
|
338
|
-
status: "active" | "inactive" | "suspended";
|
|
379
|
+
status: "active" | "inactive" | "suspended" | "pending_deletion" | "deleted";
|
|
339
380
|
emailVerifiedAt: Date | null;
|
|
340
381
|
phoneVerifiedAt: Date | null;
|
|
341
382
|
lastLoginAt: Date | null;
|
|
@@ -363,6 +404,8 @@ declare function checkUsernameAvailableService(username: string): Promise<boolea
|
|
|
363
404
|
* @throws UsernameAlreadyTakenError if username is already in use by another user
|
|
364
405
|
*/
|
|
365
406
|
declare function updateUsernameService(userId: string | number | bigint, username: string | null): Promise<{
|
|
407
|
+
deletedAt: Date | null;
|
|
408
|
+
deletedBy: string | null;
|
|
366
409
|
createdAt: Date;
|
|
367
410
|
updatedAt: Date;
|
|
368
411
|
id: number;
|
|
@@ -373,7 +416,7 @@ declare function updateUsernameService(userId: string | number | bigint, usernam
|
|
|
373
416
|
passwordHash: string | null;
|
|
374
417
|
passwordChangeRequired: boolean;
|
|
375
418
|
roleId: number;
|
|
376
|
-
status: "active" | "inactive" | "suspended";
|
|
419
|
+
status: "active" | "inactive" | "suspended" | "pending_deletion" | "deleted";
|
|
377
420
|
emailVerifiedAt: Date | null;
|
|
378
421
|
phoneVerifiedAt: Date | null;
|
|
379
422
|
lastLoginAt: Date | null;
|
|
@@ -1581,6 +1624,45 @@ interface VerifyIdTokenParams {
|
|
|
1581
1624
|
*/
|
|
1582
1625
|
declare function verifyIdToken(params: VerifyIdTokenParams): Promise<JWTPayload>;
|
|
1583
1626
|
|
|
1627
|
+
/**
|
|
1628
|
+
* @spfn/auth - Social Token At-Rest Encryption
|
|
1629
|
+
*
|
|
1630
|
+
* OAuth access/refresh tokens are encrypted with a backend-only rotating keyring.
|
|
1631
|
+
* The active key is the first entry in SPFN_AUTH_TOKEN_ENCRYPTION_KEYS; remaining
|
|
1632
|
+
* keys are decrypt-only grace keys. Ciphertext is bound to its provider account
|
|
1633
|
+
* and token type with AES-GCM additional authenticated data (AAD).
|
|
1634
|
+
*
|
|
1635
|
+
* v2 format: enc:v2:<keyId>:<base64url(iv | authTag | ciphertext)>
|
|
1636
|
+
* v1 format: enc:v1:<base64(iv | authTag | ciphertext)> (legacy session-secret key)
|
|
1637
|
+
*
|
|
1638
|
+
* Never include token or key material in logs or error messages.
|
|
1639
|
+
*/
|
|
1640
|
+
|
|
1641
|
+
type OAuthTokenType = 'access' | 'refresh';
|
|
1642
|
+
interface OAuthTokenContext {
|
|
1643
|
+
provider: SocialProvider;
|
|
1644
|
+
providerUserId: string;
|
|
1645
|
+
tokenType: OAuthTokenType;
|
|
1646
|
+
}
|
|
1647
|
+
interface DecryptedOAuthToken {
|
|
1648
|
+
value: string;
|
|
1649
|
+
/** True for plaintext, v1, or ciphertext encrypted with a non-active v2 key. */
|
|
1650
|
+
needsRotation: boolean;
|
|
1651
|
+
}
|
|
1652
|
+
interface OAuthTokenCipher {
|
|
1653
|
+
encrypt(value: string, context: OAuthTokenContext): Promise<string>;
|
|
1654
|
+
decrypt(value: string, context: OAuthTokenContext): Promise<DecryptedOAuthToken>;
|
|
1655
|
+
}
|
|
1656
|
+
declare class EnvironmentKeyringTokenCipher implements OAuthTokenCipher {
|
|
1657
|
+
encrypt(value: string, context: OAuthTokenContext): Promise<string>;
|
|
1658
|
+
decrypt(value: string, context: OAuthTokenContext): Promise<DecryptedOAuthToken>;
|
|
1659
|
+
}
|
|
1660
|
+
/** Configure an external/KMS-backed cipher before the auth server starts. */
|
|
1661
|
+
declare function configureOAuthTokenCipher(cipher: OAuthTokenCipher): void;
|
|
1662
|
+
declare function encryptToken(value: string, context: OAuthTokenContext): Promise<string>;
|
|
1663
|
+
declare function decryptToken(value: string, context: OAuthTokenContext): Promise<DecryptedOAuthToken>;
|
|
1664
|
+
declare function isEncrypted(value: string): boolean;
|
|
1665
|
+
|
|
1584
1666
|
/**
|
|
1585
1667
|
* Google OAuthProvider 구현
|
|
1586
1668
|
*
|
|
@@ -1593,18 +1675,362 @@ declare function verifyIdToken(params: VerifyIdTokenParams): Promise<JWTPayload>
|
|
|
1593
1675
|
declare const googleProvider: OAuthProvider;
|
|
1594
1676
|
|
|
1595
1677
|
/**
|
|
1596
|
-
* Apple OAuthProvider 구현 (native id_token 검증 전용)
|
|
1678
|
+
* Apple OAuthProvider 구현 (native id_token 검증 전용)
|
|
1679
|
+
*
|
|
1680
|
+
* Apple은 Android·웹에 네이티브 SDK를 제공하지 않으므로, web 흐름(Sign in with Apple JS,
|
|
1681
|
+
* Android Custom Tab)도 결국 id_token을 클라이언트가 받아 서버로 보낸다. 서버는 그 id_token을
|
|
1682
|
+
* Apple JWKS로 검증만 한다(authorization code 교환·client secret 없음).
|
|
1683
|
+
*
|
|
1684
|
+
* 따라서 web 메서드(getAuthUrl/exchangeCodeForTokens/getUserInfo)는 지원하지 않는다.
|
|
1685
|
+
*
|
|
1686
|
+
* 이 모듈을 import 하는 것만으로 apple provider가 registry에 자기 등록된다.
|
|
1687
|
+
*/
|
|
1688
|
+
|
|
1689
|
+
declare const appleProvider: OAuthProvider;
|
|
1690
|
+
|
|
1691
|
+
/**
|
|
1692
|
+
* Kakao Login OAuthProvider (web authorization-code flow).
|
|
1693
|
+
*/
|
|
1694
|
+
|
|
1695
|
+
declare const kakaoProvider: OAuthProvider;
|
|
1696
|
+
|
|
1697
|
+
/**
|
|
1698
|
+
* Naver Login OAuthProvider (web authorization-code flow).
|
|
1699
|
+
*/
|
|
1700
|
+
|
|
1701
|
+
declare const naverProvider: OAuthProvider;
|
|
1702
|
+
|
|
1703
|
+
/**
|
|
1704
|
+
* @spfn/auth - Account Deletion Requests Entity
|
|
1705
|
+
*
|
|
1706
|
+
* Audit trail for account deletion/recovery. Rows are never deleted — even after
|
|
1707
|
+
* a hard-delete purge — so "who requested/recovered/purged what, when" survives
|
|
1708
|
+
* the user row itself (개인정보보호법 제21조 3항 분리 보존 원칙).
|
|
1709
|
+
*/
|
|
1710
|
+
declare const accountDeletionRequests: drizzle_orm_pg_core.PgTableWithColumns<{
|
|
1711
|
+
name: "account_deletion_requests";
|
|
1712
|
+
schema: string;
|
|
1713
|
+
columns: {
|
|
1714
|
+
createdAt: drizzle_orm_pg_core.PgColumn<{
|
|
1715
|
+
name: "created_at";
|
|
1716
|
+
tableName: "account_deletion_requests";
|
|
1717
|
+
dataType: "date";
|
|
1718
|
+
columnType: "PgTimestamp";
|
|
1719
|
+
data: Date;
|
|
1720
|
+
driverParam: string;
|
|
1721
|
+
notNull: true;
|
|
1722
|
+
hasDefault: true;
|
|
1723
|
+
isPrimaryKey: false;
|
|
1724
|
+
isAutoincrement: false;
|
|
1725
|
+
hasRuntimeDefault: false;
|
|
1726
|
+
enumValues: undefined;
|
|
1727
|
+
baseColumn: never;
|
|
1728
|
+
identity: undefined;
|
|
1729
|
+
generated: undefined;
|
|
1730
|
+
}, {}, {}>;
|
|
1731
|
+
updatedAt: drizzle_orm_pg_core.PgColumn<{
|
|
1732
|
+
name: "updated_at";
|
|
1733
|
+
tableName: "account_deletion_requests";
|
|
1734
|
+
dataType: "date";
|
|
1735
|
+
columnType: "PgTimestamp";
|
|
1736
|
+
data: Date;
|
|
1737
|
+
driverParam: string;
|
|
1738
|
+
notNull: true;
|
|
1739
|
+
hasDefault: true;
|
|
1740
|
+
isPrimaryKey: false;
|
|
1741
|
+
isAutoincrement: false;
|
|
1742
|
+
hasRuntimeDefault: false;
|
|
1743
|
+
enumValues: undefined;
|
|
1744
|
+
baseColumn: never;
|
|
1745
|
+
identity: undefined;
|
|
1746
|
+
generated: undefined;
|
|
1747
|
+
}, {}, {}>;
|
|
1748
|
+
id: drizzle_orm_pg_core.PgColumn<{
|
|
1749
|
+
name: "id";
|
|
1750
|
+
tableName: "account_deletion_requests";
|
|
1751
|
+
dataType: "number";
|
|
1752
|
+
columnType: "PgBigSerial53";
|
|
1753
|
+
data: number;
|
|
1754
|
+
driverParam: number;
|
|
1755
|
+
notNull: true;
|
|
1756
|
+
hasDefault: true;
|
|
1757
|
+
isPrimaryKey: true;
|
|
1758
|
+
isAutoincrement: false;
|
|
1759
|
+
hasRuntimeDefault: false;
|
|
1760
|
+
enumValues: undefined;
|
|
1761
|
+
baseColumn: never;
|
|
1762
|
+
identity: undefined;
|
|
1763
|
+
generated: undefined;
|
|
1764
|
+
}, {}, {}>;
|
|
1765
|
+
userId: drizzle_orm_pg_core.PgColumn<{
|
|
1766
|
+
name: `${string}_id`;
|
|
1767
|
+
tableName: "account_deletion_requests";
|
|
1768
|
+
dataType: "number";
|
|
1769
|
+
columnType: "PgBigInt53";
|
|
1770
|
+
data: number;
|
|
1771
|
+
driverParam: string | number;
|
|
1772
|
+
notNull: false;
|
|
1773
|
+
hasDefault: false;
|
|
1774
|
+
isPrimaryKey: false;
|
|
1775
|
+
isAutoincrement: false;
|
|
1776
|
+
hasRuntimeDefault: false;
|
|
1777
|
+
enumValues: undefined;
|
|
1778
|
+
baseColumn: never;
|
|
1779
|
+
identity: undefined;
|
|
1780
|
+
generated: undefined;
|
|
1781
|
+
}, {}, {}>;
|
|
1782
|
+
userPublicId: drizzle_orm_pg_core.PgColumn<{
|
|
1783
|
+
name: "user_public_id";
|
|
1784
|
+
tableName: "account_deletion_requests";
|
|
1785
|
+
dataType: "string";
|
|
1786
|
+
columnType: "PgText";
|
|
1787
|
+
data: string;
|
|
1788
|
+
driverParam: string;
|
|
1789
|
+
notNull: true;
|
|
1790
|
+
hasDefault: false;
|
|
1791
|
+
isPrimaryKey: false;
|
|
1792
|
+
isAutoincrement: false;
|
|
1793
|
+
hasRuntimeDefault: false;
|
|
1794
|
+
enumValues: [string, ...string[]];
|
|
1795
|
+
baseColumn: never;
|
|
1796
|
+
identity: undefined;
|
|
1797
|
+
generated: undefined;
|
|
1798
|
+
}, {}, {}>;
|
|
1799
|
+
requestedAt: drizzle_orm_pg_core.PgColumn<{
|
|
1800
|
+
name: string;
|
|
1801
|
+
tableName: "account_deletion_requests";
|
|
1802
|
+
dataType: "date";
|
|
1803
|
+
columnType: "PgTimestamp";
|
|
1804
|
+
data: Date;
|
|
1805
|
+
driverParam: string;
|
|
1806
|
+
notNull: true;
|
|
1807
|
+
hasDefault: true;
|
|
1808
|
+
isPrimaryKey: false;
|
|
1809
|
+
isAutoincrement: false;
|
|
1810
|
+
hasRuntimeDefault: false;
|
|
1811
|
+
enumValues: undefined;
|
|
1812
|
+
baseColumn: never;
|
|
1813
|
+
identity: undefined;
|
|
1814
|
+
generated: undefined;
|
|
1815
|
+
}, {}, {}>;
|
|
1816
|
+
purgeScheduledAt: drizzle_orm_pg_core.PgColumn<{
|
|
1817
|
+
name: string;
|
|
1818
|
+
tableName: "account_deletion_requests";
|
|
1819
|
+
dataType: "date";
|
|
1820
|
+
columnType: "PgTimestamp";
|
|
1821
|
+
data: Date;
|
|
1822
|
+
driverParam: string;
|
|
1823
|
+
notNull: true;
|
|
1824
|
+
hasDefault: false;
|
|
1825
|
+
isPrimaryKey: false;
|
|
1826
|
+
isAutoincrement: false;
|
|
1827
|
+
hasRuntimeDefault: false;
|
|
1828
|
+
enumValues: undefined;
|
|
1829
|
+
baseColumn: never;
|
|
1830
|
+
identity: undefined;
|
|
1831
|
+
generated: undefined;
|
|
1832
|
+
}, {}, {}>;
|
|
1833
|
+
status: drizzle_orm_pg_core.PgColumn<{
|
|
1834
|
+
name: string;
|
|
1835
|
+
tableName: "account_deletion_requests";
|
|
1836
|
+
dataType: "string";
|
|
1837
|
+
columnType: "PgText";
|
|
1838
|
+
data: "pending" | "cancelled" | "completed";
|
|
1839
|
+
driverParam: string;
|
|
1840
|
+
notNull: true;
|
|
1841
|
+
hasDefault: true;
|
|
1842
|
+
isPrimaryKey: false;
|
|
1843
|
+
isAutoincrement: false;
|
|
1844
|
+
hasRuntimeDefault: false;
|
|
1845
|
+
enumValues: ["pending", "cancelled", "completed"] & [string, ...string[]];
|
|
1846
|
+
baseColumn: never;
|
|
1847
|
+
identity: undefined;
|
|
1848
|
+
generated: undefined;
|
|
1849
|
+
}, {}, {}>;
|
|
1850
|
+
requestedBy: drizzle_orm_pg_core.PgColumn<{
|
|
1851
|
+
name: string;
|
|
1852
|
+
tableName: "account_deletion_requests";
|
|
1853
|
+
dataType: "string";
|
|
1854
|
+
columnType: "PgText";
|
|
1855
|
+
data: "admin" | "self";
|
|
1856
|
+
driverParam: string;
|
|
1857
|
+
notNull: true;
|
|
1858
|
+
hasDefault: true;
|
|
1859
|
+
isPrimaryKey: false;
|
|
1860
|
+
isAutoincrement: false;
|
|
1861
|
+
hasRuntimeDefault: false;
|
|
1862
|
+
enumValues: ["self", "admin"] & [string, ...string[]];
|
|
1863
|
+
baseColumn: never;
|
|
1864
|
+
identity: undefined;
|
|
1865
|
+
generated: undefined;
|
|
1866
|
+
}, {}, {}>;
|
|
1867
|
+
reason: drizzle_orm_pg_core.PgColumn<{
|
|
1868
|
+
name: "reason";
|
|
1869
|
+
tableName: "account_deletion_requests";
|
|
1870
|
+
dataType: "string";
|
|
1871
|
+
columnType: "PgText";
|
|
1872
|
+
data: string;
|
|
1873
|
+
driverParam: string;
|
|
1874
|
+
notNull: false;
|
|
1875
|
+
hasDefault: false;
|
|
1876
|
+
isPrimaryKey: false;
|
|
1877
|
+
isAutoincrement: false;
|
|
1878
|
+
hasRuntimeDefault: false;
|
|
1879
|
+
enumValues: [string, ...string[]];
|
|
1880
|
+
baseColumn: never;
|
|
1881
|
+
identity: undefined;
|
|
1882
|
+
generated: undefined;
|
|
1883
|
+
}, {}, {}>;
|
|
1884
|
+
cancelledAt: drizzle_orm_pg_core.PgColumn<{
|
|
1885
|
+
name: string;
|
|
1886
|
+
tableName: "account_deletion_requests";
|
|
1887
|
+
dataType: "date";
|
|
1888
|
+
columnType: "PgTimestamp";
|
|
1889
|
+
data: Date;
|
|
1890
|
+
driverParam: string;
|
|
1891
|
+
notNull: false;
|
|
1892
|
+
hasDefault: false;
|
|
1893
|
+
isPrimaryKey: false;
|
|
1894
|
+
isAutoincrement: false;
|
|
1895
|
+
hasRuntimeDefault: false;
|
|
1896
|
+
enumValues: undefined;
|
|
1897
|
+
baseColumn: never;
|
|
1898
|
+
identity: undefined;
|
|
1899
|
+
generated: undefined;
|
|
1900
|
+
}, {}, {}>;
|
|
1901
|
+
completedAt: drizzle_orm_pg_core.PgColumn<{
|
|
1902
|
+
name: string;
|
|
1903
|
+
tableName: "account_deletion_requests";
|
|
1904
|
+
dataType: "date";
|
|
1905
|
+
columnType: "PgTimestamp";
|
|
1906
|
+
data: Date;
|
|
1907
|
+
driverParam: string;
|
|
1908
|
+
notNull: false;
|
|
1909
|
+
hasDefault: false;
|
|
1910
|
+
isPrimaryKey: false;
|
|
1911
|
+
isAutoincrement: false;
|
|
1912
|
+
hasRuntimeDefault: false;
|
|
1913
|
+
enumValues: undefined;
|
|
1914
|
+
baseColumn: never;
|
|
1915
|
+
identity: undefined;
|
|
1916
|
+
generated: undefined;
|
|
1917
|
+
}, {}, {}>;
|
|
1918
|
+
purgeStrategy: drizzle_orm_pg_core.PgColumn<{
|
|
1919
|
+
name: string;
|
|
1920
|
+
tableName: "account_deletion_requests";
|
|
1921
|
+
dataType: "string";
|
|
1922
|
+
columnType: "PgText";
|
|
1923
|
+
data: "anonymize" | "hard-delete";
|
|
1924
|
+
driverParam: string;
|
|
1925
|
+
notNull: false;
|
|
1926
|
+
hasDefault: false;
|
|
1927
|
+
isPrimaryKey: false;
|
|
1928
|
+
isAutoincrement: false;
|
|
1929
|
+
hasRuntimeDefault: false;
|
|
1930
|
+
enumValues: ["anonymize", "hard-delete"] & [string, ...string[]];
|
|
1931
|
+
baseColumn: never;
|
|
1932
|
+
identity: undefined;
|
|
1933
|
+
generated: undefined;
|
|
1934
|
+
}, {}, {}>;
|
|
1935
|
+
};
|
|
1936
|
+
dialect: "pg";
|
|
1937
|
+
}>;
|
|
1938
|
+
type AccountDeletionRequest = typeof accountDeletionRequests.$inferSelect;
|
|
1939
|
+
type NewAccountDeletionRequest = typeof accountDeletionRequests.$inferInsert;
|
|
1940
|
+
|
|
1941
|
+
/**
|
|
1942
|
+
* @spfn/auth - Account Deletion Service
|
|
1943
|
+
*
|
|
1944
|
+
* Request / cancel (recovery) / purge for the account deletion lifecycle.
|
|
1945
|
+
*
|
|
1946
|
+
* Lifecycle:
|
|
1947
|
+
* active --request(reauth)--> pending_deletion --grace expires(cron)--> deleted (anonymize) | row removed (hard-delete)
|
|
1948
|
+
* ^ |
|
|
1949
|
+
* +-------cancel(reauth)---------+ immediate = grace period of 0, same pipeline
|
|
1950
|
+
*/
|
|
1951
|
+
|
|
1952
|
+
interface PendingDeletionInfo {
|
|
1953
|
+
purgeScheduledAt: Date;
|
|
1954
|
+
}
|
|
1955
|
+
/**
|
|
1956
|
+
* Look up the pending deletion request's `purgeScheduledAt` for a `pending_deletion`
|
|
1957
|
+
* user, so login/OAuth/authenticate can surface it on `AccountPendingDeletionError`.
|
|
1958
|
+
* Returns null if there is no pending row (shouldn't normally happen for a user in
|
|
1959
|
+
* that status, but the caller falls back to an error without the date).
|
|
1960
|
+
*
|
|
1961
|
+
* Reads from the write primary, not a replica — this backs the same status gates
|
|
1962
|
+
* that decide whether to grant a session, so a replica-lag window must not let a
|
|
1963
|
+
* just-requested deletion go unnoticed.
|
|
1964
|
+
*/
|
|
1965
|
+
declare function getPendingDeletionInfo(userId: number): Promise<PendingDeletionInfo | null>;
|
|
1966
|
+
interface RequestAccountDeletionParams {
|
|
1967
|
+
/** Who initiated this — 'self' requires re-auth via password/verificationToken; 'admin' does not. */
|
|
1968
|
+
requestedBy: AccountDeletionRequestedBy;
|
|
1969
|
+
password?: string;
|
|
1970
|
+
verificationToken?: string;
|
|
1971
|
+
reason?: string;
|
|
1972
|
+
/** Skip the grace period and purge inline. Self-service requires `deletion.allowSelfImmediate`. */
|
|
1973
|
+
immediate?: boolean;
|
|
1974
|
+
}
|
|
1975
|
+
interface RequestAccountDeletionResult {
|
|
1976
|
+
requestId: number;
|
|
1977
|
+
purgeScheduledAt: Date;
|
|
1978
|
+
}
|
|
1979
|
+
/**
|
|
1980
|
+
* Request account deletion (self-service re-auth gate, or trusted admin/DSR call).
|
|
1981
|
+
*
|
|
1982
|
+
* Sets status -> 'pending_deletion', records the request, revokes every active
|
|
1983
|
+
* session key, and (after commit) emits `auth.deletion.requested` and sends the
|
|
1984
|
+
* request-received notice. With a zero grace period (explicit `immediate: true`,
|
|
1985
|
+
* gated for self-service by `allowSelfImmediate`), purges inline instead of
|
|
1986
|
+
* waiting for the cron sweep.
|
|
1987
|
+
*/
|
|
1988
|
+
declare function requestAccountDeletionService(userId: number, params: RequestAccountDeletionParams): Promise<RequestAccountDeletionResult>;
|
|
1989
|
+
interface CancelAccountDeletionParams {
|
|
1990
|
+
email?: string;
|
|
1991
|
+
phone?: string;
|
|
1992
|
+
password?: string;
|
|
1993
|
+
verificationToken?: string;
|
|
1994
|
+
}
|
|
1995
|
+
interface CancelAccountDeletionResult {
|
|
1996
|
+
userId: string;
|
|
1997
|
+
}
|
|
1998
|
+
/**
|
|
1999
|
+
* Cancel a pending deletion (recovery). All sessions were revoked at request
|
|
2000
|
+
* time, so this is credential-based (no Bearer token) rather than auth-context-based.
|
|
1597
2001
|
*
|
|
1598
|
-
*
|
|
1599
|
-
*
|
|
1600
|
-
*
|
|
2002
|
+
* Credential verification always runs before the caller learns whether the
|
|
2003
|
+
* account exists / is pending deletion — otherwise this endpoint could be used
|
|
2004
|
+
* to enumerate accounts or probe deletion status without a valid credential,
|
|
2005
|
+
* the same posture `loginService` takes for missing accounts.
|
|
1601
2006
|
*
|
|
1602
|
-
*
|
|
2007
|
+
* Claims the `account_deletion_requests` row (conditional `WHERE status =
|
|
2008
|
+
* 'pending'`) before touching `users` — see the comment at that claim below for
|
|
2009
|
+
* why the `users` row must not move until the claim succeeds.
|
|
2010
|
+
*/
|
|
2011
|
+
declare function cancelAccountDeletionService(params: CancelAccountDeletionParams): Promise<CancelAccountDeletionResult>;
|
|
2012
|
+
interface PurgeUserResult {
|
|
2013
|
+
outcome: 'purged' | 'skipped' | 'not-found';
|
|
2014
|
+
}
|
|
2015
|
+
/**
|
|
2016
|
+
* Purge a user's pending deletion request immediately, ignoring `purgeScheduledAt`.
|
|
2017
|
+
* Admin/GDPR-response entry point — the route (if any) belongs to the app.
|
|
1603
2018
|
*
|
|
1604
|
-
*
|
|
2019
|
+
* @throws DeletionNotRequestedError if the user has no pending request
|
|
1605
2020
|
*/
|
|
1606
|
-
|
|
1607
|
-
|
|
2021
|
+
declare function purgeUserService(userId: number): Promise<PurgeUserResult>;
|
|
2022
|
+
interface SweepDuePurgesResult {
|
|
2023
|
+
processed: number;
|
|
2024
|
+
purged: number;
|
|
2025
|
+
skipped: number;
|
|
2026
|
+
}
|
|
2027
|
+
/**
|
|
2028
|
+
* Sweep every request whose grace period has elapsed and purge it. Called by the
|
|
2029
|
+
* `auth.deletion.purge` cron job. One user's failure (thrown error, not just an
|
|
2030
|
+
* `onBeforePurge` skip) is logged and does not stop the rest of the sweep — it
|
|
2031
|
+
* stays `pending` and is retried on the next tick.
|
|
2032
|
+
*/
|
|
2033
|
+
declare function sweepDuePurges(now?: Date): Promise<SweepDuePurgesResult>;
|
|
1608
2034
|
|
|
1609
2035
|
/**
|
|
1610
2036
|
* @spfn/auth - Database Schema Definition
|
|
@@ -2473,14 +2899,14 @@ declare const verificationCodes: drizzle_orm_pg_core.PgTableWithColumns<{
|
|
|
2473
2899
|
tableName: "verification_codes";
|
|
2474
2900
|
dataType: "string";
|
|
2475
2901
|
columnType: "PgText";
|
|
2476
|
-
data: "registration" | "login" | "password_reset" | "email_change" | "phone_change";
|
|
2902
|
+
data: "registration" | "login" | "password_reset" | "email_change" | "phone_change" | "account_deletion";
|
|
2477
2903
|
driverParam: string;
|
|
2478
2904
|
notNull: true;
|
|
2479
2905
|
hasDefault: false;
|
|
2480
2906
|
isPrimaryKey: false;
|
|
2481
2907
|
isAutoincrement: false;
|
|
2482
2908
|
hasRuntimeDefault: false;
|
|
2483
|
-
enumValues: ["registration", "login", "password_reset", "email_change", "phone_change"] & [string, ...string[]];
|
|
2909
|
+
enumValues: ["registration", "login", "password_reset", "email_change", "phone_change", "account_deletion"] & [string, ...string[]];
|
|
2484
2910
|
baseColumn: never;
|
|
2485
2911
|
identity: undefined;
|
|
2486
2912
|
generated: undefined;
|
|
@@ -3106,6 +3532,33 @@ declare class UsersRepository extends BaseRepository {
|
|
|
3106
3532
|
* Read replica 사용
|
|
3107
3533
|
*/
|
|
3108
3534
|
findById(id: number): Promise<{
|
|
3535
|
+
deletedAt: Date | null;
|
|
3536
|
+
deletedBy: string | null;
|
|
3537
|
+
createdAt: Date;
|
|
3538
|
+
updatedAt: Date;
|
|
3539
|
+
id: number;
|
|
3540
|
+
publicId: string;
|
|
3541
|
+
email: string | null;
|
|
3542
|
+
phone: string | null;
|
|
3543
|
+
username: string | null;
|
|
3544
|
+
passwordHash: string | null;
|
|
3545
|
+
passwordChangeRequired: boolean;
|
|
3546
|
+
roleId: number;
|
|
3547
|
+
status: "active" | "inactive" | "suspended" | "pending_deletion" | "deleted";
|
|
3548
|
+
emailVerifiedAt: Date | null;
|
|
3549
|
+
phoneVerifiedAt: Date | null;
|
|
3550
|
+
lastLoginAt: Date | null;
|
|
3551
|
+
}>;
|
|
3552
|
+
/**
|
|
3553
|
+
* ID로 사용자 조회 — Write primary에서 직접 읽는다.
|
|
3554
|
+
*
|
|
3555
|
+
* 복제 지연 창에서 status 전이(예: 삭제 요청으로 pending_deletion 전환)를 놓치면
|
|
3556
|
+
* 안 되는 게이트(OAuth 세션 발급 등)가 사용한다. 일반 조회는 `findById`(replica)를
|
|
3557
|
+
* 계속 사용할 것.
|
|
3558
|
+
*/
|
|
3559
|
+
findByIdOnPrimary(id: number): Promise<{
|
|
3560
|
+
deletedAt: Date | null;
|
|
3561
|
+
deletedBy: string | null;
|
|
3109
3562
|
createdAt: Date;
|
|
3110
3563
|
updatedAt: Date;
|
|
3111
3564
|
id: number;
|
|
@@ -3116,7 +3569,7 @@ declare class UsersRepository extends BaseRepository {
|
|
|
3116
3569
|
passwordHash: string | null;
|
|
3117
3570
|
passwordChangeRequired: boolean;
|
|
3118
3571
|
roleId: number;
|
|
3119
|
-
status: "active" | "inactive" | "suspended";
|
|
3572
|
+
status: "active" | "inactive" | "suspended" | "pending_deletion" | "deleted";
|
|
3120
3573
|
emailVerifiedAt: Date | null;
|
|
3121
3574
|
phoneVerifiedAt: Date | null;
|
|
3122
3575
|
lastLoginAt: Date | null;
|
|
@@ -3126,6 +3579,8 @@ declare class UsersRepository extends BaseRepository {
|
|
|
3126
3579
|
* Read replica 사용
|
|
3127
3580
|
*/
|
|
3128
3581
|
findByEmail(email: string): Promise<{
|
|
3582
|
+
deletedAt: Date | null;
|
|
3583
|
+
deletedBy: string | null;
|
|
3129
3584
|
createdAt: Date;
|
|
3130
3585
|
updatedAt: Date;
|
|
3131
3586
|
id: number;
|
|
@@ -3136,7 +3591,7 @@ declare class UsersRepository extends BaseRepository {
|
|
|
3136
3591
|
passwordHash: string | null;
|
|
3137
3592
|
passwordChangeRequired: boolean;
|
|
3138
3593
|
roleId: number;
|
|
3139
|
-
status: "active" | "inactive" | "suspended";
|
|
3594
|
+
status: "active" | "inactive" | "suspended" | "pending_deletion" | "deleted";
|
|
3140
3595
|
emailVerifiedAt: Date | null;
|
|
3141
3596
|
phoneVerifiedAt: Date | null;
|
|
3142
3597
|
lastLoginAt: Date | null;
|
|
@@ -3146,6 +3601,8 @@ declare class UsersRepository extends BaseRepository {
|
|
|
3146
3601
|
* Read replica 사용
|
|
3147
3602
|
*/
|
|
3148
3603
|
findByPhone(phone: string): Promise<{
|
|
3604
|
+
deletedAt: Date | null;
|
|
3605
|
+
deletedBy: string | null;
|
|
3149
3606
|
createdAt: Date;
|
|
3150
3607
|
updatedAt: Date;
|
|
3151
3608
|
id: number;
|
|
@@ -3156,7 +3613,7 @@ declare class UsersRepository extends BaseRepository {
|
|
|
3156
3613
|
passwordHash: string | null;
|
|
3157
3614
|
passwordChangeRequired: boolean;
|
|
3158
3615
|
roleId: number;
|
|
3159
|
-
status: "active" | "inactive" | "suspended";
|
|
3616
|
+
status: "active" | "inactive" | "suspended" | "pending_deletion" | "deleted";
|
|
3160
3617
|
emailVerifiedAt: Date | null;
|
|
3161
3618
|
phoneVerifiedAt: Date | null;
|
|
3162
3619
|
lastLoginAt: Date | null;
|
|
@@ -3166,6 +3623,8 @@ declare class UsersRepository extends BaseRepository {
|
|
|
3166
3623
|
* Read replica 사용
|
|
3167
3624
|
*/
|
|
3168
3625
|
findByUsername(username: string): Promise<{
|
|
3626
|
+
deletedAt: Date | null;
|
|
3627
|
+
deletedBy: string | null;
|
|
3169
3628
|
createdAt: Date;
|
|
3170
3629
|
updatedAt: Date;
|
|
3171
3630
|
id: number;
|
|
@@ -3176,7 +3635,7 @@ declare class UsersRepository extends BaseRepository {
|
|
|
3176
3635
|
passwordHash: string | null;
|
|
3177
3636
|
passwordChangeRequired: boolean;
|
|
3178
3637
|
roleId: number;
|
|
3179
|
-
status: "active" | "inactive" | "suspended";
|
|
3638
|
+
status: "active" | "inactive" | "suspended" | "pending_deletion" | "deleted";
|
|
3180
3639
|
emailVerifiedAt: Date | null;
|
|
3181
3640
|
phoneVerifiedAt: Date | null;
|
|
3182
3641
|
lastLoginAt: Date | null;
|
|
@@ -3186,6 +3645,8 @@ declare class UsersRepository extends BaseRepository {
|
|
|
3186
3645
|
* Read replica 사용
|
|
3187
3646
|
*/
|
|
3188
3647
|
findByPublicId(publicId: string): Promise<{
|
|
3648
|
+
deletedAt: Date | null;
|
|
3649
|
+
deletedBy: string | null;
|
|
3189
3650
|
createdAt: Date;
|
|
3190
3651
|
updatedAt: Date;
|
|
3191
3652
|
id: number;
|
|
@@ -3196,7 +3657,7 @@ declare class UsersRepository extends BaseRepository {
|
|
|
3196
3657
|
passwordHash: string | null;
|
|
3197
3658
|
passwordChangeRequired: boolean;
|
|
3198
3659
|
roleId: number;
|
|
3199
|
-
status: "active" | "inactive" | "suspended";
|
|
3660
|
+
status: "active" | "inactive" | "suspended" | "pending_deletion" | "deleted";
|
|
3200
3661
|
emailVerifiedAt: Date | null;
|
|
3201
3662
|
phoneVerifiedAt: Date | null;
|
|
3202
3663
|
lastLoginAt: Date | null;
|
|
@@ -3206,6 +3667,8 @@ declare class UsersRepository extends BaseRepository {
|
|
|
3206
3667
|
* Read replica 사용
|
|
3207
3668
|
*/
|
|
3208
3669
|
findByEmailOrPhone(email?: string, phone?: string): Promise<{
|
|
3670
|
+
deletedAt: Date | null;
|
|
3671
|
+
deletedBy: string | null;
|
|
3209
3672
|
createdAt: Date;
|
|
3210
3673
|
updatedAt: Date;
|
|
3211
3674
|
id: number;
|
|
@@ -3216,7 +3679,7 @@ declare class UsersRepository extends BaseRepository {
|
|
|
3216
3679
|
passwordHash: string | null;
|
|
3217
3680
|
passwordChangeRequired: boolean;
|
|
3218
3681
|
roleId: number;
|
|
3219
|
-
status: "active" | "inactive" | "suspended";
|
|
3682
|
+
status: "active" | "inactive" | "suspended" | "pending_deletion" | "deleted";
|
|
3220
3683
|
emailVerifiedAt: Date | null;
|
|
3221
3684
|
phoneVerifiedAt: Date | null;
|
|
3222
3685
|
lastLoginAt: Date | null;
|
|
@@ -3229,6 +3692,8 @@ declare class UsersRepository extends BaseRepository {
|
|
|
3229
3692
|
*/
|
|
3230
3693
|
findByIdWithRole(id: number): Promise<{
|
|
3231
3694
|
user: {
|
|
3695
|
+
deletedAt: Date | null;
|
|
3696
|
+
deletedBy: string | null;
|
|
3232
3697
|
createdAt: Date;
|
|
3233
3698
|
updatedAt: Date;
|
|
3234
3699
|
id: number;
|
|
@@ -3239,7 +3704,7 @@ declare class UsersRepository extends BaseRepository {
|
|
|
3239
3704
|
passwordHash: string | null;
|
|
3240
3705
|
passwordChangeRequired: boolean;
|
|
3241
3706
|
roleId: number;
|
|
3242
|
-
status: "active" | "inactive" | "suspended";
|
|
3707
|
+
status: "active" | "inactive" | "suspended" | "pending_deletion" | "deleted";
|
|
3243
3708
|
emailVerifiedAt: Date | null;
|
|
3244
3709
|
phoneVerifiedAt: Date | null;
|
|
3245
3710
|
lastLoginAt: Date | null;
|
|
@@ -3265,16 +3730,47 @@ declare class UsersRepository extends BaseRepository {
|
|
|
3265
3730
|
roleId: number;
|
|
3266
3731
|
createdAt: Date;
|
|
3267
3732
|
updatedAt: Date;
|
|
3268
|
-
status: "active" | "inactive" | "suspended";
|
|
3733
|
+
status: "active" | "inactive" | "suspended" | "pending_deletion" | "deleted";
|
|
3269
3734
|
emailVerifiedAt: Date | null;
|
|
3270
3735
|
phoneVerifiedAt: Date | null;
|
|
3271
3736
|
lastLoginAt: Date | null;
|
|
3737
|
+
deletedAt: Date | null;
|
|
3738
|
+
deletedBy: string | null;
|
|
3272
3739
|
}>;
|
|
3273
3740
|
/**
|
|
3274
3741
|
* 사용자 정보 업데이트
|
|
3275
3742
|
* Write primary 사용
|
|
3276
3743
|
*/
|
|
3277
3744
|
updateById(id: number, data: Partial<NewUser>): Promise<{
|
|
3745
|
+
deletedAt: Date | null;
|
|
3746
|
+
deletedBy: string | null;
|
|
3747
|
+
createdAt: Date;
|
|
3748
|
+
updatedAt: Date;
|
|
3749
|
+
id: number;
|
|
3750
|
+
publicId: string;
|
|
3751
|
+
email: string | null;
|
|
3752
|
+
phone: string | null;
|
|
3753
|
+
username: string | null;
|
|
3754
|
+
passwordHash: string | null;
|
|
3755
|
+
passwordChangeRequired: boolean;
|
|
3756
|
+
roleId: number;
|
|
3757
|
+
status: "active" | "inactive" | "suspended" | "pending_deletion" | "deleted";
|
|
3758
|
+
emailVerifiedAt: Date | null;
|
|
3759
|
+
phoneVerifiedAt: Date | null;
|
|
3760
|
+
lastLoginAt: Date | null;
|
|
3761
|
+
}>;
|
|
3762
|
+
/**
|
|
3763
|
+
* 계정 삭제 취소(복구) — `WHERE status = 'pending_deletion'` 조건부 UPDATE.
|
|
3764
|
+
*
|
|
3765
|
+
* cancelAccountDeletionService가 account_deletion_requests claim(조건부
|
|
3766
|
+
* markCancelled)에 성공한 **이후에만** 호출한다. 그 claim이 이미 purge와의
|
|
3767
|
+
* 경합을 해결하므로 이 조건은 방어적 이중 안전장치 — 0 row 매치(= 이미
|
|
3768
|
+
* status가 바뀐 상태) 시 null을 반환하며 예외를 던지지 않는다.
|
|
3769
|
+
* Write primary 사용
|
|
3770
|
+
*/
|
|
3771
|
+
reactivateFromPendingDeletion(id: number): Promise<{
|
|
3772
|
+
deletedAt: Date | null;
|
|
3773
|
+
deletedBy: string | null;
|
|
3278
3774
|
createdAt: Date;
|
|
3279
3775
|
updatedAt: Date;
|
|
3280
3776
|
id: number;
|
|
@@ -3285,7 +3781,7 @@ declare class UsersRepository extends BaseRepository {
|
|
|
3285
3781
|
passwordHash: string | null;
|
|
3286
3782
|
passwordChangeRequired: boolean;
|
|
3287
3783
|
roleId: number;
|
|
3288
|
-
status: "active" | "inactive" | "suspended";
|
|
3784
|
+
status: "active" | "inactive" | "suspended" | "pending_deletion" | "deleted";
|
|
3289
3785
|
emailVerifiedAt: Date | null;
|
|
3290
3786
|
phoneVerifiedAt: Date | null;
|
|
3291
3787
|
lastLoginAt: Date | null;
|
|
@@ -3295,6 +3791,8 @@ declare class UsersRepository extends BaseRepository {
|
|
|
3295
3791
|
* Write primary 사용
|
|
3296
3792
|
*/
|
|
3297
3793
|
updatePassword(id: number, passwordHash: string, clearPasswordChangeRequired?: boolean): Promise<{
|
|
3794
|
+
deletedAt: Date | null;
|
|
3795
|
+
deletedBy: string | null;
|
|
3298
3796
|
createdAt: Date;
|
|
3299
3797
|
updatedAt: Date;
|
|
3300
3798
|
id: number;
|
|
@@ -3305,7 +3803,7 @@ declare class UsersRepository extends BaseRepository {
|
|
|
3305
3803
|
passwordHash: string | null;
|
|
3306
3804
|
passwordChangeRequired: boolean;
|
|
3307
3805
|
roleId: number;
|
|
3308
|
-
status: "active" | "inactive" | "suspended";
|
|
3806
|
+
status: "active" | "inactive" | "suspended" | "pending_deletion" | "deleted";
|
|
3309
3807
|
emailVerifiedAt: Date | null;
|
|
3310
3808
|
phoneVerifiedAt: Date | null;
|
|
3311
3809
|
lastLoginAt: Date | null;
|
|
@@ -3315,6 +3813,8 @@ declare class UsersRepository extends BaseRepository {
|
|
|
3315
3813
|
* Write primary 사용
|
|
3316
3814
|
*/
|
|
3317
3815
|
updateLastLogin(id: number): Promise<{
|
|
3816
|
+
deletedAt: Date | null;
|
|
3817
|
+
deletedBy: string | null;
|
|
3318
3818
|
createdAt: Date;
|
|
3319
3819
|
updatedAt: Date;
|
|
3320
3820
|
id: number;
|
|
@@ -3325,7 +3825,7 @@ declare class UsersRepository extends BaseRepository {
|
|
|
3325
3825
|
passwordHash: string | null;
|
|
3326
3826
|
passwordChangeRequired: boolean;
|
|
3327
3827
|
roleId: number;
|
|
3328
|
-
status: "active" | "inactive" | "suspended";
|
|
3828
|
+
status: "active" | "inactive" | "suspended" | "pending_deletion" | "deleted";
|
|
3329
3829
|
emailVerifiedAt: Date | null;
|
|
3330
3830
|
phoneVerifiedAt: Date | null;
|
|
3331
3831
|
lastLoginAt: Date | null;
|
|
@@ -3345,10 +3845,12 @@ declare class UsersRepository extends BaseRepository {
|
|
|
3345
3845
|
roleId: number;
|
|
3346
3846
|
createdAt: Date;
|
|
3347
3847
|
updatedAt: Date;
|
|
3348
|
-
status: "active" | "inactive" | "suspended";
|
|
3848
|
+
status: "active" | "inactive" | "suspended" | "pending_deletion" | "deleted";
|
|
3349
3849
|
emailVerifiedAt: Date | null;
|
|
3350
3850
|
phoneVerifiedAt: Date | null;
|
|
3351
3851
|
lastLoginAt: Date | null;
|
|
3852
|
+
deletedAt: Date | null;
|
|
3853
|
+
deletedBy: string | null;
|
|
3352
3854
|
}>;
|
|
3353
3855
|
/**
|
|
3354
3856
|
* User의 Role과 Permissions 조회 (JOIN)
|
|
@@ -3553,6 +4055,14 @@ declare class KeysRepository extends BaseRepository {
|
|
|
3553
4055
|
revokedAt: Date | null;
|
|
3554
4056
|
revokedReason: string | null;
|
|
3555
4057
|
}>;
|
|
4058
|
+
/**
|
|
4059
|
+
* 사용자의 모든 공개키 삭제 (계정 익명화 파기용)
|
|
4060
|
+
*
|
|
4061
|
+
* hard-delete는 FK cascade로 자동 처리되지만, anonymize 모드는 users row를
|
|
4062
|
+
* 남기므로 자식 row를 직접 지워야 한다.
|
|
4063
|
+
* Write primary 사용
|
|
4064
|
+
*/
|
|
4065
|
+
deleteAllByUserId(userId: number): Promise<number>;
|
|
3556
4066
|
/**
|
|
3557
4067
|
* 마지막 사용 시간 업데이트
|
|
3558
4068
|
* Write primary 사용
|
|
@@ -3630,7 +4140,7 @@ declare class VerificationCodesRepository extends BaseRepository {
|
|
|
3630
4140
|
target: string;
|
|
3631
4141
|
targetType: "email" | "phone";
|
|
3632
4142
|
code: string;
|
|
3633
|
-
purpose: "registration" | "login" | "password_reset" | "email_change" | "phone_change";
|
|
4143
|
+
purpose: "registration" | "login" | "password_reset" | "email_change" | "phone_change" | "account_deletion";
|
|
3634
4144
|
expiresAt: Date;
|
|
3635
4145
|
usedAt: Date | null;
|
|
3636
4146
|
attempts: number;
|
|
@@ -3646,7 +4156,7 @@ declare class VerificationCodesRepository extends BaseRepository {
|
|
|
3646
4156
|
target: string;
|
|
3647
4157
|
targetType: "email" | "phone";
|
|
3648
4158
|
code: string;
|
|
3649
|
-
purpose: "registration" | "login" | "password_reset" | "email_change" | "phone_change";
|
|
4159
|
+
purpose: "registration" | "login" | "password_reset" | "email_change" | "phone_change" | "account_deletion";
|
|
3650
4160
|
expiresAt: Date;
|
|
3651
4161
|
usedAt: Date | null;
|
|
3652
4162
|
attempts: number;
|
|
@@ -3658,7 +4168,7 @@ declare class VerificationCodesRepository extends BaseRepository {
|
|
|
3658
4168
|
create(data: NewVerificationCode): Promise<{
|
|
3659
4169
|
target: string;
|
|
3660
4170
|
targetType: "email" | "phone";
|
|
3661
|
-
purpose: "registration" | "login" | "password_reset" | "email_change" | "phone_change";
|
|
4171
|
+
purpose: "registration" | "login" | "password_reset" | "email_change" | "phone_change" | "account_deletion";
|
|
3662
4172
|
code: string;
|
|
3663
4173
|
id: number;
|
|
3664
4174
|
createdAt: Date;
|
|
@@ -3678,7 +4188,7 @@ declare class VerificationCodesRepository extends BaseRepository {
|
|
|
3678
4188
|
target: string;
|
|
3679
4189
|
targetType: "email" | "phone";
|
|
3680
4190
|
code: string;
|
|
3681
|
-
purpose: "registration" | "login" | "password_reset" | "email_change" | "phone_change";
|
|
4191
|
+
purpose: "registration" | "login" | "password_reset" | "email_change" | "phone_change" | "account_deletion";
|
|
3682
4192
|
expiresAt: Date;
|
|
3683
4193
|
usedAt: Date | null;
|
|
3684
4194
|
attempts: number;
|
|
@@ -3694,7 +4204,7 @@ declare class VerificationCodesRepository extends BaseRepository {
|
|
|
3694
4204
|
target: string;
|
|
3695
4205
|
targetType: "email" | "phone";
|
|
3696
4206
|
code: string;
|
|
3697
|
-
purpose: "registration" | "login" | "password_reset" | "email_change" | "phone_change";
|
|
4207
|
+
purpose: "registration" | "login" | "password_reset" | "email_change" | "phone_change" | "account_deletion";
|
|
3698
4208
|
expiresAt: Date;
|
|
3699
4209
|
usedAt: Date | null;
|
|
3700
4210
|
attempts: number;
|
|
@@ -3704,6 +4214,14 @@ declare class VerificationCodesRepository extends BaseRepository {
|
|
|
3704
4214
|
* Write primary 사용
|
|
3705
4215
|
*/
|
|
3706
4216
|
deleteExpired(): Promise<number>;
|
|
4217
|
+
/**
|
|
4218
|
+
* Target(email/phone)의 모든 인증 코드 삭제 (계정 파기용)
|
|
4219
|
+
*
|
|
4220
|
+
* verificationCodes는 userId FK가 없고 target 텍스트로만 연결되므로, 파기 시
|
|
4221
|
+
* 원래 email/phone을 이 메서드로 직접 정리해야 한다.
|
|
4222
|
+
* Write primary 사용
|
|
4223
|
+
*/
|
|
4224
|
+
deleteByTarget(target: string): Promise<number>;
|
|
3707
4225
|
/**
|
|
3708
4226
|
* Target의 모든 이전 코드 무효화 (새 코드 발급 시)
|
|
3709
4227
|
* Write primary 사용
|
|
@@ -4059,8 +4577,8 @@ declare class UserPermissionsRepository extends BaseRepository {
|
|
|
4059
4577
|
createdAt: Date;
|
|
4060
4578
|
updatedAt: Date;
|
|
4061
4579
|
permissionId: number;
|
|
4062
|
-
expiresAt: Date | null;
|
|
4063
4580
|
reason: string | null;
|
|
4581
|
+
expiresAt: Date | null;
|
|
4064
4582
|
granted: boolean;
|
|
4065
4583
|
}>;
|
|
4066
4584
|
/**
|
|
@@ -4085,8 +4603,8 @@ declare class UserPermissionsRepository extends BaseRepository {
|
|
|
4085
4603
|
createdAt: Date;
|
|
4086
4604
|
updatedAt: Date;
|
|
4087
4605
|
permissionId: number;
|
|
4088
|
-
expiresAt: Date | null;
|
|
4089
4606
|
reason: string | null;
|
|
4607
|
+
expiresAt: Date | null;
|
|
4090
4608
|
granted: boolean;
|
|
4091
4609
|
}>;
|
|
4092
4610
|
/**
|
|
@@ -4730,6 +5248,14 @@ declare class SocialAccountsRepository extends BaseRepository {
|
|
|
4730
5248
|
refreshToken: string | null;
|
|
4731
5249
|
tokenExpiresAt: Date | null;
|
|
4732
5250
|
}>;
|
|
5251
|
+
/**
|
|
5252
|
+
* 사용자의 모든 소셜 계정 삭제 (계정 익명화 파기용)
|
|
5253
|
+
*
|
|
5254
|
+
* provider unique index(provider, providerUserId)를 해제해 같은 소셜 계정으로
|
|
5255
|
+
* 재가입할 수 있게 한다.
|
|
5256
|
+
* Write primary 사용
|
|
5257
|
+
*/
|
|
5258
|
+
deleteAllByUserId(userId: number): Promise<number>;
|
|
4733
5259
|
}
|
|
4734
5260
|
declare const socialAccountsRepository: SocialAccountsRepository;
|
|
4735
5261
|
|
|
@@ -4752,6 +5278,168 @@ declare class AuthMetadataRepository extends BaseRepository {
|
|
|
4752
5278
|
}
|
|
4753
5279
|
declare const authMetadataRepository: AuthMetadataRepository;
|
|
4754
5280
|
|
|
5281
|
+
/**
|
|
5282
|
+
* Account Deletion Requests Repository
|
|
5283
|
+
*
|
|
5284
|
+
* 계정 탈퇴 요청/복구/파기 감사 이력 관리를 위한 Repository
|
|
5285
|
+
* BaseRepository를 상속받아 자동 트랜잭션 컨텍스트 지원 및 Read/Write 분리
|
|
5286
|
+
*
|
|
5287
|
+
* Row는 절대 삭제하지 않는다 — status 전이(pending -> cancelled|completed)로만 갱신.
|
|
5288
|
+
*/
|
|
5289
|
+
|
|
5290
|
+
/**
|
|
5291
|
+
* Account Deletion Requests Repository 클래스
|
|
5292
|
+
*/
|
|
5293
|
+
declare class AccountDeletionRequestsRepository extends BaseRepository {
|
|
5294
|
+
/**
|
|
5295
|
+
* ID로 요청 조회
|
|
5296
|
+
* Read replica 사용
|
|
5297
|
+
*/
|
|
5298
|
+
findById(id: number): Promise<{
|
|
5299
|
+
createdAt: Date;
|
|
5300
|
+
updatedAt: Date;
|
|
5301
|
+
id: number;
|
|
5302
|
+
userId: number | null;
|
|
5303
|
+
userPublicId: string;
|
|
5304
|
+
requestedAt: Date;
|
|
5305
|
+
purgeScheduledAt: Date;
|
|
5306
|
+
status: "pending" | "cancelled" | "completed";
|
|
5307
|
+
requestedBy: "admin" | "self";
|
|
5308
|
+
reason: string | null;
|
|
5309
|
+
cancelledAt: Date | null;
|
|
5310
|
+
completedAt: Date | null;
|
|
5311
|
+
purgeStrategy: "anonymize" | "hard-delete" | null;
|
|
5312
|
+
}>;
|
|
5313
|
+
/**
|
|
5314
|
+
* User ID로 pending 요청 조회 (유저당 최대 1건, partial unique index로 보장)
|
|
5315
|
+
* Read replica 사용
|
|
5316
|
+
*/
|
|
5317
|
+
findPendingByUserId(userId: number): Promise<{
|
|
5318
|
+
createdAt: Date;
|
|
5319
|
+
updatedAt: Date;
|
|
5320
|
+
id: number;
|
|
5321
|
+
userId: number | null;
|
|
5322
|
+
userPublicId: string;
|
|
5323
|
+
requestedAt: Date;
|
|
5324
|
+
purgeScheduledAt: Date;
|
|
5325
|
+
status: "pending" | "cancelled" | "completed";
|
|
5326
|
+
requestedBy: "admin" | "self";
|
|
5327
|
+
reason: string | null;
|
|
5328
|
+
cancelledAt: Date | null;
|
|
5329
|
+
completedAt: Date | null;
|
|
5330
|
+
purgeStrategy: "anonymize" | "hard-delete" | null;
|
|
5331
|
+
}>;
|
|
5332
|
+
/**
|
|
5333
|
+
* User ID로 pending 요청 조회 — Write primary에서 직접 읽는다.
|
|
5334
|
+
*
|
|
5335
|
+
* 로그인/OAuth/authenticate 게이트가 pending_deletion 유저의 purgeScheduledAt을
|
|
5336
|
+
* 표시하는 데 쓴다. 이 경로들은 복제 지연이 있으면 방금 커밋된 상태 전이를 놓칠 수
|
|
5337
|
+
* 있어(예: 삭제 요청 직후 OAuth 로그인 시도), replica가 아닌 primary에서 읽는다.
|
|
5338
|
+
*/
|
|
5339
|
+
findPendingByUserIdOnPrimary(userId: number): Promise<{
|
|
5340
|
+
createdAt: Date;
|
|
5341
|
+
updatedAt: Date;
|
|
5342
|
+
id: number;
|
|
5343
|
+
userId: number | null;
|
|
5344
|
+
userPublicId: string;
|
|
5345
|
+
requestedAt: Date;
|
|
5346
|
+
purgeScheduledAt: Date;
|
|
5347
|
+
status: "pending" | "cancelled" | "completed";
|
|
5348
|
+
requestedBy: "admin" | "self";
|
|
5349
|
+
reason: string | null;
|
|
5350
|
+
cancelledAt: Date | null;
|
|
5351
|
+
completedAt: Date | null;
|
|
5352
|
+
purgeStrategy: "anonymize" | "hard-delete" | null;
|
|
5353
|
+
}>;
|
|
5354
|
+
/**
|
|
5355
|
+
* 파기 스윕 대상 조회 — status='pending' AND purgeScheduledAt <= now
|
|
5356
|
+
* Read replica 사용
|
|
5357
|
+
*/
|
|
5358
|
+
findDueForPurge(now: Date): Promise<{
|
|
5359
|
+
createdAt: Date;
|
|
5360
|
+
updatedAt: Date;
|
|
5361
|
+
id: number;
|
|
5362
|
+
userId: number | null;
|
|
5363
|
+
userPublicId: string;
|
|
5364
|
+
requestedAt: Date;
|
|
5365
|
+
purgeScheduledAt: Date;
|
|
5366
|
+
status: "pending" | "cancelled" | "completed";
|
|
5367
|
+
requestedBy: "admin" | "self";
|
|
5368
|
+
reason: string | null;
|
|
5369
|
+
cancelledAt: Date | null;
|
|
5370
|
+
completedAt: Date | null;
|
|
5371
|
+
purgeStrategy: "anonymize" | "hard-delete" | null;
|
|
5372
|
+
}[]>;
|
|
5373
|
+
/**
|
|
5374
|
+
* 요청 생성
|
|
5375
|
+
* Write primary 사용
|
|
5376
|
+
*/
|
|
5377
|
+
create(data: NewAccountDeletionRequest): Promise<{
|
|
5378
|
+
userId: number | null;
|
|
5379
|
+
id: number;
|
|
5380
|
+
createdAt: Date;
|
|
5381
|
+
updatedAt: Date;
|
|
5382
|
+
status: "pending" | "cancelled" | "completed";
|
|
5383
|
+
reason: string | null;
|
|
5384
|
+
purgeScheduledAt: Date;
|
|
5385
|
+
cancelledAt: Date | null;
|
|
5386
|
+
userPublicId: string;
|
|
5387
|
+
requestedAt: Date;
|
|
5388
|
+
requestedBy: "admin" | "self";
|
|
5389
|
+
completedAt: Date | null;
|
|
5390
|
+
purgeStrategy: "anonymize" | "hard-delete" | null;
|
|
5391
|
+
}>;
|
|
5392
|
+
/**
|
|
5393
|
+
* 요청 취소 (복구)
|
|
5394
|
+
*
|
|
5395
|
+
* `WHERE status = 'pending'` 조건부 UPDATE — 이미 completed(파기 완료)된 row를
|
|
5396
|
+
* 뒤늦게 도착한 cancel이 덮어쓰지 않도록 한다. 0 row 매치(= 이미 completed거나
|
|
5397
|
+
* cancelled) 시 null을 반환하니 호출자가 그 결과를 확인해야 한다.
|
|
5398
|
+
* Write primary 사용
|
|
5399
|
+
*/
|
|
5400
|
+
markCancelled(id: number): Promise<{
|
|
5401
|
+
createdAt: Date;
|
|
5402
|
+
updatedAt: Date;
|
|
5403
|
+
id: number;
|
|
5404
|
+
userId: number | null;
|
|
5405
|
+
userPublicId: string;
|
|
5406
|
+
requestedAt: Date;
|
|
5407
|
+
purgeScheduledAt: Date;
|
|
5408
|
+
status: "pending" | "cancelled" | "completed";
|
|
5409
|
+
requestedBy: "admin" | "self";
|
|
5410
|
+
reason: string | null;
|
|
5411
|
+
cancelledAt: Date | null;
|
|
5412
|
+
completedAt: Date | null;
|
|
5413
|
+
purgeStrategy: "anonymize" | "hard-delete" | null;
|
|
5414
|
+
}>;
|
|
5415
|
+
/**
|
|
5416
|
+
* 요청 완료 처리 (파기 실행 직전에 호출하는 "claim" — 파기 실행 후가 아니다)
|
|
5417
|
+
*
|
|
5418
|
+
* `WHERE status = 'pending'` 조건부 UPDATE. Postgres UPDATE는 매치되는 row에 락을
|
|
5419
|
+
* 걸고 최신 커밋 상태로 WHERE를 재평가하므로, 이 호출 하나로 (1) 동시에 취소된
|
|
5420
|
+
* row를 안전하게 걸러내고 (2) row-level 락으로 동시 파기 시도를 직렬화한다.
|
|
5421
|
+
* 0 row 매치(= 이미 취소되었거나 다른 파기가 먼저 처리함) 시 null을 반환 — 호출자는
|
|
5422
|
+
* destructive DML을 실행하기 **전에** 반드시 이 결과를 확인해야 한다.
|
|
5423
|
+
* Write primary 사용
|
|
5424
|
+
*/
|
|
5425
|
+
markCompleted(id: number, purgeStrategy: PurgeStrategy): Promise<{
|
|
5426
|
+
createdAt: Date;
|
|
5427
|
+
updatedAt: Date;
|
|
5428
|
+
id: number;
|
|
5429
|
+
userId: number | null;
|
|
5430
|
+
userPublicId: string;
|
|
5431
|
+
requestedAt: Date;
|
|
5432
|
+
purgeScheduledAt: Date;
|
|
5433
|
+
status: "pending" | "cancelled" | "completed";
|
|
5434
|
+
requestedBy: "admin" | "self";
|
|
5435
|
+
reason: string | null;
|
|
5436
|
+
cancelledAt: Date | null;
|
|
5437
|
+
completedAt: Date | null;
|
|
5438
|
+
purgeStrategy: "anonymize" | "hard-delete" | null;
|
|
5439
|
+
}>;
|
|
5440
|
+
}
|
|
5441
|
+
declare const accountDeletionRequestsRepository: AccountDeletionRequestsRepository;
|
|
5442
|
+
|
|
4755
5443
|
/**
|
|
4756
5444
|
* @spfn/auth - Password Helpers
|
|
4757
5445
|
*
|
|
@@ -4815,6 +5503,7 @@ declare function hashPassword(password: string): Promise<string>;
|
|
|
4815
5503
|
* ```
|
|
4816
5504
|
*/
|
|
4817
5505
|
declare function verifyPassword(password: string, hash: string): Promise<boolean>;
|
|
5506
|
+
declare function getDummyPasswordHash(): Promise<string>;
|
|
4818
5507
|
/**
|
|
4819
5508
|
* Validate password strength
|
|
4820
5509
|
*
|
|
@@ -5202,10 +5891,12 @@ declare function getUser(c: Context | {
|
|
|
5202
5891
|
roleId: number;
|
|
5203
5892
|
createdAt: Date;
|
|
5204
5893
|
updatedAt: Date;
|
|
5205
|
-
status: "active" | "inactive" | "suspended";
|
|
5894
|
+
status: "active" | "inactive" | "suspended" | "pending_deletion" | "deleted";
|
|
5206
5895
|
emailVerifiedAt: Date | null;
|
|
5207
5896
|
phoneVerifiedAt: Date | null;
|
|
5208
5897
|
lastLoginAt: Date | null;
|
|
5898
|
+
deletedAt: Date | null;
|
|
5899
|
+
deletedBy: string | null;
|
|
5209
5900
|
};
|
|
5210
5901
|
/**
|
|
5211
5902
|
* Get authenticated user ID from route context
|
|
@@ -5330,6 +6021,7 @@ declare function shouldRotateKey(createdAt: Date, rotationDays?: number): {
|
|
|
5330
6021
|
*
|
|
5331
6022
|
* Manages global auth configuration including session TTL
|
|
5332
6023
|
*/
|
|
6024
|
+
|
|
5333
6025
|
/**
|
|
5334
6026
|
* Cookie names used by SPFN Auth
|
|
5335
6027
|
*
|
|
@@ -5346,6 +6038,18 @@ declare const COOKIE_NAMES: {
|
|
|
5346
6038
|
/** OAuth CSRF nonce — double-submit against the (encrypted) state.nonce at callback */
|
|
5347
6039
|
readonly OAUTH_CSRF: string;
|
|
5348
6040
|
};
|
|
6041
|
+
/**
|
|
6042
|
+
* OAuth CSRF 쿠키를 PORT 접미사와 무관하게 전부 수집한다.
|
|
6043
|
+
*
|
|
6044
|
+
* 쿠키를 심는 쪽은 Next.js 프로세스, 읽는 쪽은 API 프로세스라 분리 배포에서는
|
|
6045
|
+
* 두 프로세스의 PORT가 달라 COOKIE_NAMES.OAUTH_CSRF 정확 일치 조회가 빗나간다.
|
|
6046
|
+
* nonce 자체가 랜덤값이고 암호화된 state의 nonce와 대조되므로, 접미사가 다른
|
|
6047
|
+
* spfn_oauth_csrf* 후보를 모두 대조 대상으로 넘겨도 안전하다.
|
|
6048
|
+
*/
|
|
6049
|
+
declare function matchOAuthCsrfCookies(cookies: Record<string, string>): {
|
|
6050
|
+
name: string;
|
|
6051
|
+
value: string;
|
|
6052
|
+
}[];
|
|
5349
6053
|
/**
|
|
5350
6054
|
* Parse duration string to seconds
|
|
5351
6055
|
*
|
|
@@ -5358,6 +6062,36 @@ declare const COOKIE_NAMES: {
|
|
|
5358
6062
|
* parseDuration('3600') // 3600
|
|
5359
6063
|
*/
|
|
5360
6064
|
declare function parseDuration(duration: string | number): number;
|
|
6065
|
+
/**
|
|
6066
|
+
* Registration channel passed to the beforeRegister hook
|
|
6067
|
+
*
|
|
6068
|
+
* - credentials: email/phone + password registration
|
|
6069
|
+
* - oauth: new-user signup through a social provider (web or native flow)
|
|
6070
|
+
* - invitation: invitation acceptance
|
|
6071
|
+
*/
|
|
6072
|
+
type RegisterChannel = 'credentials' | 'oauth' | 'invitation';
|
|
6073
|
+
/**
|
|
6074
|
+
* Context passed to the beforeRegister hook
|
|
6075
|
+
*
|
|
6076
|
+
* Credentials (password, keys) are intentionally excluded — the hook is a
|
|
6077
|
+
* policy gate, not a credential handler.
|
|
6078
|
+
*/
|
|
6079
|
+
interface BeforeRegisterContext {
|
|
6080
|
+
channel: RegisterChannel;
|
|
6081
|
+
/** Social provider — only set when channel is 'oauth' */
|
|
6082
|
+
provider?: SocialProvider;
|
|
6083
|
+
email?: string;
|
|
6084
|
+
/**
|
|
6085
|
+
* Whether the email is verified — only set when channel is 'oauth'.
|
|
6086
|
+
* OAuth providers may report an unverified (spoofable) email; the created
|
|
6087
|
+
* account stores it as null in that case, so email-based policies must
|
|
6088
|
+
* check this flag. credentials/invitation emails are already verified.
|
|
6089
|
+
*/
|
|
6090
|
+
emailVerified?: boolean;
|
|
6091
|
+
phone?: string;
|
|
6092
|
+
/** App-supplied registration metadata (register params / OAuth start params / invitation) */
|
|
6093
|
+
metadata?: Record<string, unknown>;
|
|
6094
|
+
}
|
|
5361
6095
|
/**
|
|
5362
6096
|
* Auth configuration
|
|
5363
6097
|
*/
|
|
@@ -5372,6 +6106,35 @@ interface AuthConfig {
|
|
|
5372
6106
|
* @default 7d (7 days)
|
|
5373
6107
|
*/
|
|
5374
6108
|
sessionTtl?: string | number;
|
|
6109
|
+
/**
|
|
6110
|
+
* App-injected validator that runs before a new user row is created,
|
|
6111
|
+
* on every registration channel (credentials, oauth, invitation).
|
|
6112
|
+
*
|
|
6113
|
+
* Throw to reject the registration — RegistrationRejectedError (403) is
|
|
6114
|
+
* the recommended error; any HttpError subclass keeps its own status.
|
|
6115
|
+
* Runs after built-in checks (verification token, duplicate account),
|
|
6116
|
+
* so existing error precedence is unchanged. Not called for admin
|
|
6117
|
+
* seeding (initializeAuth) or when linking a social account to an
|
|
6118
|
+
* existing user.
|
|
6119
|
+
*
|
|
6120
|
+
* Runs inside the registration DB transaction on every channel — keep it
|
|
6121
|
+
* fast. A slow call (e.g. an external policy API) holds a pooled DB
|
|
6122
|
+
* connection open for its full duration on every signup.
|
|
6123
|
+
*
|
|
6124
|
+
* @example
|
|
6125
|
+
* ```typescript
|
|
6126
|
+
* configureAuth({
|
|
6127
|
+
* beforeRegister: async ({ channel, metadata }) =>
|
|
6128
|
+
* {
|
|
6129
|
+
* if (channel === 'credentials' && !isOldEnough(metadata?.birthDate))
|
|
6130
|
+
* {
|
|
6131
|
+
* throw new RegistrationRejectedError({ message: 'Age requirement not met' });
|
|
6132
|
+
* }
|
|
6133
|
+
* },
|
|
6134
|
+
* });
|
|
6135
|
+
* ```
|
|
6136
|
+
*/
|
|
6137
|
+
beforeRegister?: (context: BeforeRegisterContext) => void | Promise<void>;
|
|
5375
6138
|
}
|
|
5376
6139
|
/**
|
|
5377
6140
|
* Configure global auth settings
|
|
@@ -5390,6 +6153,14 @@ declare function configureAuth(config: AuthConfig): void;
|
|
|
5390
6153
|
* Get current auth configuration
|
|
5391
6154
|
*/
|
|
5392
6155
|
declare function getAuthConfig(): AuthConfig;
|
|
6156
|
+
/**
|
|
6157
|
+
* Run the app-injected beforeRegister hook if configured — throws to reject.
|
|
6158
|
+
*
|
|
6159
|
+
* Single entry point for every registration channel so a new channel cannot
|
|
6160
|
+
* forget the configured-check. Callers invoke this right before creating the
|
|
6161
|
+
* user row.
|
|
6162
|
+
*/
|
|
6163
|
+
declare function runBeforeRegister(context: BeforeRegisterContext): Promise<void>;
|
|
5393
6164
|
/**
|
|
5394
6165
|
* Get session TTL in seconds
|
|
5395
6166
|
*
|
|
@@ -5442,6 +6213,66 @@ declare function initOneTimeTokenManager(config?: {
|
|
|
5442
6213
|
*/
|
|
5443
6214
|
declare function getOneTimeTokenManager(): SSETokenManager;
|
|
5444
6215
|
|
|
6216
|
+
/**
|
|
6217
|
+
* Account Deletion Configuration
|
|
6218
|
+
*
|
|
6219
|
+
* Singleton config for the account deletion/recovery lifecycle, mirroring the
|
|
6220
|
+
* one-time-token manager pattern (`lib/one-time-token.ts`): a mutable module-level
|
|
6221
|
+
* value, set once during `createAuthLifecycle()` and read at request/handler time.
|
|
6222
|
+
*
|
|
6223
|
+
* `purgeCron` is the one field this module does NOT make effective on its own —
|
|
6224
|
+
* `job('auth.deletion.purge').cron(expression)` bakes the cron string in at
|
|
6225
|
+
* *module-import* time, which always runs before `createAuthLifecycle()` executes
|
|
6226
|
+
* (ESM evaluates imports before the importing module's own statements). So a
|
|
6227
|
+
* statically-exported job router can never see a `purgeCron` set here. Apps that
|
|
6228
|
+
* need a non-default cron must build the router themselves, after configuring
|
|
6229
|
+
* deletion, with `createAuthDeletionJobRouter({ purgeCron })` — see
|
|
6230
|
+
* `server/jobs/deletion-purge.ts` and the README.
|
|
6231
|
+
*/
|
|
6232
|
+
|
|
6233
|
+
interface AccountDeletionPurgeUser {
|
|
6234
|
+
id: number;
|
|
6235
|
+
publicId: string;
|
|
6236
|
+
email: string | null;
|
|
6237
|
+
phone: string | null;
|
|
6238
|
+
}
|
|
6239
|
+
interface AuthDeletionConfig {
|
|
6240
|
+
/** Days between a deletion request and the purge becoming eligible. 0 = immediate. */
|
|
6241
|
+
gracePeriodDays: number;
|
|
6242
|
+
/** How the purge job destroys the account once the grace period elapses. */
|
|
6243
|
+
purgeStrategy: PurgeStrategy;
|
|
6244
|
+
/** Whether a self-service caller may request `immediate: true` (skip the grace period). */
|
|
6245
|
+
allowSelfImmediate: boolean;
|
|
6246
|
+
/**
|
|
6247
|
+
* Cron schedule for the purge sweep. NOT read automatically by the static
|
|
6248
|
+
* `authJobRouter` export — see the module doc comment above.
|
|
6249
|
+
*/
|
|
6250
|
+
purgeCron: string;
|
|
6251
|
+
/** Whether to email users (when they have one) at request/recovery/purge time. */
|
|
6252
|
+
sendNotifications: boolean;
|
|
6253
|
+
/**
|
|
6254
|
+
* Synchronous hook invoked immediately before a user is purged. Throw to skip
|
|
6255
|
+
* that user for this sweep (they stay `pending`, retried on the next tick).
|
|
6256
|
+
*/
|
|
6257
|
+
onBeforePurge?: (user: AccountDeletionPurgeUser) => Promise<void>;
|
|
6258
|
+
}
|
|
6259
|
+
declare const DEFAULT_DELETION_GRACE_PERIOD_DAYS = 30;
|
|
6260
|
+
declare const DEFAULT_DELETION_PURGE_STRATEGY: PurgeStrategy;
|
|
6261
|
+
declare const DEFAULT_DELETION_ALLOW_SELF_IMMEDIATE = false;
|
|
6262
|
+
declare const DEFAULT_DELETION_PURGE_CRON = "0 4 * * *";
|
|
6263
|
+
declare const DEFAULT_DELETION_SEND_NOTIFICATIONS = true;
|
|
6264
|
+
/**
|
|
6265
|
+
* Set the resolved deletion config. Called synchronously from `createAuthLifecycle()`
|
|
6266
|
+
* (not from `afterInfrastructure`) so it takes effect before any route/job handler
|
|
6267
|
+
* that reads `getDeletionConfig()` can run.
|
|
6268
|
+
*/
|
|
6269
|
+
declare function configureDeletion(options?: Partial<AuthDeletionConfig>): void;
|
|
6270
|
+
/**
|
|
6271
|
+
* Read the current deletion config. Safe to call any time — defaults apply even
|
|
6272
|
+
* if `createAuthLifecycle()` was never given a `deletion` block.
|
|
6273
|
+
*/
|
|
6274
|
+
declare function getDeletionConfig(): AuthDeletionConfig;
|
|
6275
|
+
|
|
5445
6276
|
/**
|
|
5446
6277
|
* @spfn/auth - Centralized Logger
|
|
5447
6278
|
*
|
|
@@ -5581,9 +6412,131 @@ interface AuthLifecycleOptions extends AuthInitOptions {
|
|
|
5581
6412
|
*/
|
|
5582
6413
|
store?: SSETokenStore;
|
|
5583
6414
|
};
|
|
6415
|
+
/**
|
|
6416
|
+
* Account deletion/recovery lifecycle configuration
|
|
6417
|
+
*
|
|
6418
|
+
* Controls the grace-period request → recover → purge flow exposed by
|
|
6419
|
+
* `POST /_auth/deletion/request` and `POST /_auth/deletion/cancel`.
|
|
6420
|
+
* Registering the purge job itself is a separate step — see `authJobRouter`
|
|
6421
|
+
* (`@spfn/auth/server`) and the README, since job registration happens after
|
|
6422
|
+
* this lifecycle hook runs and can't be triggered from here.
|
|
6423
|
+
*
|
|
6424
|
+
* @example
|
|
6425
|
+
* ```typescript
|
|
6426
|
+
* createAuthLifecycle({
|
|
6427
|
+
* deletion: {
|
|
6428
|
+
* gracePeriodDays: 14,
|
|
6429
|
+
* purgeStrategy: 'anonymize',
|
|
6430
|
+
* allowSelfImmediate: false,
|
|
6431
|
+
* sendNotifications: true,
|
|
6432
|
+
* onBeforePurge: async (user) => {
|
|
6433
|
+
* await appDataCleanup(user.id); // throw to skip this user this sweep
|
|
6434
|
+
* },
|
|
6435
|
+
* },
|
|
6436
|
+
* })
|
|
6437
|
+
* ```
|
|
6438
|
+
*/
|
|
6439
|
+
deletion?: {
|
|
6440
|
+
/**
|
|
6441
|
+
* Days between a deletion request and the purge becoming eligible.
|
|
6442
|
+
* 0 = immediate (still goes through the same request/purge pipeline).
|
|
6443
|
+
* @default 30
|
|
6444
|
+
*/
|
|
6445
|
+
gracePeriodDays?: number;
|
|
6446
|
+
/**
|
|
6447
|
+
* How the purge job destroys the account once the grace period elapses.
|
|
6448
|
+
* - 'anonymize': scrub PII, keep the row (status -> 'deleted') — recommended default
|
|
6449
|
+
* - 'hard-delete': physically remove the `users` row (cascades to child rows)
|
|
6450
|
+
* @default 'anonymize'
|
|
6451
|
+
*/
|
|
6452
|
+
purgeStrategy?: PurgeStrategy;
|
|
6453
|
+
/**
|
|
6454
|
+
* Whether a self-service caller may pass `immediate: true` on
|
|
6455
|
+
* `POST /_auth/deletion/request` to skip the grace period entirely.
|
|
6456
|
+
* @default false
|
|
6457
|
+
*/
|
|
6458
|
+
allowSelfImmediate?: boolean;
|
|
6459
|
+
/**
|
|
6460
|
+
* Cron schedule for the purge sweep. NOTE: this does not reach the static
|
|
6461
|
+
* `authJobRouter` export automatically — job schedules are fixed at
|
|
6462
|
+
* module-import time, before this lifecycle hook runs. For a non-default
|
|
6463
|
+
* cron, build the router yourself after this call with
|
|
6464
|
+
* `createAuthDeletionJobRouter({ purgeCron })` (see `@spfn/auth/server`).
|
|
6465
|
+
* @default '0 4 * * *'
|
|
6466
|
+
*/
|
|
6467
|
+
purgeCron?: string;
|
|
6468
|
+
/**
|
|
6469
|
+
* Whether to email users (when they have one on file) at request,
|
|
6470
|
+
* recovery, and final-purge time.
|
|
6471
|
+
* @default true
|
|
6472
|
+
*/
|
|
6473
|
+
sendNotifications?: boolean;
|
|
6474
|
+
/**
|
|
6475
|
+
* Invoked immediately before a user is purged (both the immediate inline
|
|
6476
|
+
* path and the cron sweep). Throw to skip that user for this run — they
|
|
6477
|
+
* stay `pending` and are retried on the next sweep.
|
|
6478
|
+
*/
|
|
6479
|
+
onBeforePurge?: (user: AccountDeletionPurgeUser) => Promise<void>;
|
|
6480
|
+
};
|
|
5584
6481
|
}
|
|
5585
6482
|
declare function createAuthLifecycle(options?: AuthLifecycleOptions): AuthLifecycleConfig;
|
|
5586
6483
|
|
|
6484
|
+
/**
|
|
6485
|
+
* @spfn/auth - Account Deletion Purge Job
|
|
6486
|
+
*
|
|
6487
|
+
* The package's first background job (`@spfn/core/job`). Sweeps
|
|
6488
|
+
* `account_deletion_requests` for rows whose grace period elapsed and purges
|
|
6489
|
+
* each one (see `sweepDuePurges` in `account-deletion.service.ts`).
|
|
6490
|
+
*
|
|
6491
|
+
* Registration is NOT automatic. `createAuthLifecycle()`'s `afterInfrastructure`
|
|
6492
|
+
* hook runs *before* `initBoss`/`registerJobs` in `@spfn/core`'s server startup
|
|
6493
|
+
* (`initializeInfrastructure()`), so the lifecycle has no opportunity to register
|
|
6494
|
+
* jobs itself. Apps must register explicitly:
|
|
6495
|
+
*
|
|
6496
|
+
* ```typescript
|
|
6497
|
+
* import { authJobRouter } from '@spfn/auth/server';
|
|
6498
|
+
*
|
|
6499
|
+
* export default defineServerConfig()
|
|
6500
|
+
* .lifecycle(createAuthLifecycle())
|
|
6501
|
+
* .jobs(authJobRouter)
|
|
6502
|
+
* .routes(appRouter)
|
|
6503
|
+
* .build();
|
|
6504
|
+
* ```
|
|
6505
|
+
*
|
|
6506
|
+
* Cron schedule caveat: `job(...).cron(expression)` bakes the cron string in at
|
|
6507
|
+
* *module-import* time, which always happens before `createAuthLifecycle()` runs
|
|
6508
|
+
* in the app's own module (ESM evaluates imports before the importing module's
|
|
6509
|
+
* statements). So the static `authJobRouter` export below always uses the default
|
|
6510
|
+
* cron — `deletion.purgeCron` passed to `createAuthLifecycle()` cannot reach it.
|
|
6511
|
+
* To use a custom cron, build the router yourself, after calling
|
|
6512
|
+
* `createAuthLifecycle()`, with `createAuthDeletionJobRouter({ purgeCron })` and
|
|
6513
|
+
* register that instead of the static export.
|
|
6514
|
+
*/
|
|
6515
|
+
/**
|
|
6516
|
+
* Build the `auth.deletion.purge` job with a given cron schedule.
|
|
6517
|
+
*
|
|
6518
|
+
* @param cronExpression - Defaults to `deletion-config`'s default (daily at 04:00).
|
|
6519
|
+
*/
|
|
6520
|
+
declare function createAuthDeletionPurgeJob(cronExpression?: string): _spfn_core_job.JobDef<void, void>;
|
|
6521
|
+
/**
|
|
6522
|
+
* Build a job router containing only the deletion purge job, with a given cron.
|
|
6523
|
+
* Use this (after calling `createAuthLifecycle({ deletion: { purgeCron } })`) when
|
|
6524
|
+
* you need a non-default schedule — see the module doc comment above for why the
|
|
6525
|
+
* static `authJobRouter` export can't pick up `deletion.purgeCron` automatically.
|
|
6526
|
+
*/
|
|
6527
|
+
declare function createAuthDeletionJobRouter(options?: {
|
|
6528
|
+
purgeCron?: string;
|
|
6529
|
+
}): _spfn_core_job.JobRouter<{
|
|
6530
|
+
deletionPurge: _spfn_core_job.JobDef<void, void>;
|
|
6531
|
+
}>;
|
|
6532
|
+
/**
|
|
6533
|
+
* Default job router — the default cron (`0 4 * * *`). Register with
|
|
6534
|
+
* `.jobs(authJobRouter)` in `server.config.ts`.
|
|
6535
|
+
*/
|
|
6536
|
+
declare const authJobRouter: _spfn_core_job.JobRouter<{
|
|
6537
|
+
deletionPurge: _spfn_core_job.JobDef<void, void>;
|
|
6538
|
+
}>;
|
|
6539
|
+
|
|
5587
6540
|
/**
|
|
5588
6541
|
* @spfn/auth - Auth Events
|
|
5589
6542
|
*
|
|
@@ -5695,6 +6648,48 @@ declare const invitationAcceptedEvent: _spfn_core_event.EventDef<{
|
|
|
5695
6648
|
invitedBy: string;
|
|
5696
6649
|
invitationId: string;
|
|
5697
6650
|
}>;
|
|
6651
|
+
/**
|
|
6652
|
+
* auth.deletion.requested - 계정 탈퇴 요청 이벤트
|
|
6653
|
+
*
|
|
6654
|
+
* 발행 시점:
|
|
6655
|
+
* - requestAccountDeletionService() 성공 시 (self/admin 공통)
|
|
6656
|
+
*
|
|
6657
|
+
* @example
|
|
6658
|
+
* ```typescript
|
|
6659
|
+
* authDeletionRequestedEvent.subscribe(async (payload) => {
|
|
6660
|
+
* await analytics.trackChurnRisk(payload.userId);
|
|
6661
|
+
* });
|
|
6662
|
+
* ```
|
|
6663
|
+
*/
|
|
6664
|
+
declare const authDeletionRequestedEvent: _spfn_core_event.EventDef<{
|
|
6665
|
+
userId: string;
|
|
6666
|
+
purgeScheduledAt: string;
|
|
6667
|
+
userPublicId: string;
|
|
6668
|
+
requestedBy: "admin" | "self";
|
|
6669
|
+
}>;
|
|
6670
|
+
/**
|
|
6671
|
+
* auth.deletion.cancelled - 계정 탈퇴 복구 이벤트
|
|
6672
|
+
*
|
|
6673
|
+
* 발행 시점:
|
|
6674
|
+
* - cancelAccountDeletionService() 성공 시 (유예 기간 내 복구)
|
|
6675
|
+
*/
|
|
6676
|
+
declare const authDeletionCancelledEvent: _spfn_core_event.EventDef<{
|
|
6677
|
+
userId: string;
|
|
6678
|
+
userPublicId: string;
|
|
6679
|
+
}>;
|
|
6680
|
+
/**
|
|
6681
|
+
* auth.deletion.completed - 계정 파기 완료 이벤트
|
|
6682
|
+
*
|
|
6683
|
+
* 발행 시점:
|
|
6684
|
+
* - purge job(또는 즉시 파기 경로)이 유저를 파기한 직후
|
|
6685
|
+
*
|
|
6686
|
+
* PII를 담지 않는다 — userId(내부 순번)/email/phone 없이 userPublicId만 실어
|
|
6687
|
+
* 파기 완료 이후에도 구독자가 식별 정보를 다시 축적하지 않도록 한다.
|
|
6688
|
+
*/
|
|
6689
|
+
declare const authDeletionCompletedEvent: _spfn_core_event.EventDef<{
|
|
6690
|
+
userPublicId: string;
|
|
6691
|
+
purgeStrategy: "anonymize" | "hard-delete";
|
|
6692
|
+
}>;
|
|
5698
6693
|
/**
|
|
5699
6694
|
* Auth event payload types
|
|
5700
6695
|
*/
|
|
@@ -5702,5 +6697,8 @@ type AuthLoginPayload = typeof authLoginEvent._payload;
|
|
|
5702
6697
|
type AuthRegisterPayload = typeof authRegisterEvent._payload;
|
|
5703
6698
|
type InvitationCreatedPayload = typeof invitationCreatedEvent._payload;
|
|
5704
6699
|
type InvitationAcceptedPayload = typeof invitationAcceptedEvent._payload;
|
|
6700
|
+
type AuthDeletionRequestedPayload = typeof authDeletionRequestedEvent._payload;
|
|
6701
|
+
type AuthDeletionCancelledPayload = typeof authDeletionCancelledEvent._payload;
|
|
6702
|
+
type AuthDeletionCompletedPayload = typeof authDeletionCompletedEvent._payload;
|
|
5705
6703
|
|
|
5706
|
-
export { type AuthConfig, AuthContext, type AuthLifecycleConfig, type AuthLifecycleOptions, type AuthLoginPayload, type AuthMetadataEntity, AuthMetadataRepository, AuthProviderSchema, type AuthRegisterPayload, COOKIE_NAMES, type CreateOAuthStateParams, type GoogleTokenResponse, type GoogleUserInfo, type Invitation, type InvitationAcceptedPayload, type InvitationCreatedPayload, InvitationStatus, InvitationsRepository, KeyAlgorithmType, type KeyPair, KeysRepository, type NewAuthMetadataEntity, type NewInvitation, type NewPermission, type NewPermissionEntity, type NewRole, type NewRoleEntity, type NewRolePermission, type NewUser, type NewUserPermission, type NewUserProfile, type NewUserPublicKey, type NewUserSocialAccount, type NewVerificationCode, OAuthProvider, type OAuthState, type Permission, type PermissionEntity, PermissionsRepository, type Role, type RoleEntity, type RoleGuardOptions, type RolePermission, RolePermissionsRepository, RolesRepository, 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, type VerifyIdTokenParams, acceptInvitation, addPermissionToRole, appleProvider, assertCanAssignRole, authLogger, authLoginEvent, authMetadata, authMetadataRepository, authRegisterEvent, authSchema, cancelInvitation, checkUsernameAvailableService, configureAuth, createAuthLifecycle, createInvitation, createOAuthState, createRole, decodeToken, deleteInvitation, deleteRole, exchangeCodeForTokens, expireOldInvitations, generateClientToken, generateKeyPair, generateKeyPairES256, generateKeyPairRS256, generateOAuthNonce, generateToken, getAllRoles, getAuth, getAuthConfig, getAuthSessionService, getGoogleAuthUrl, getGoogleOAuthConfig, getGoogleUserInfo, getInvitationByToken, getInvitationWithDetails, getKeyId, getKeySize, getLocale, getOneTimeTokenManager, getOptionalAuth, getRole, getRoleByName, getRolePermissions, getSessionTtl, getUser, getUserByEmailService, getUserByIdService, getUserByPhoneService, getUserId, getUserPermissions, getUserProfileService, getUserRole, googleProvider, hasAllPermissions, hasAnyPermission, hasAnyRole, hasPermission, hasRole, hashPassword, initOneTimeTokenManager, initializeAuth, invitationAcceptedEvent, invitationCreatedEvent, invitationsRepository, isGoogleOAuthEnabled, keysRepository, listInvitations, oneTimeTokenAuth, parseDuration, permissions, permissionsRepository, refreshAccessToken, removePermissionFromRole, requireAnyPermission, requirePermissions, requireRole, resendInvitation, roleGuard, rolePermissions, rolePermissionsRepository, roles, rolesRepository, setRolePermissions, shouldRotateKey, socialAccountsRepository, updateLastLoginService, updateLocaleService, updateRole, updateUserProfileService, updateUserService, updateUsernameService, userInvitations, userPermissions, userPermissionsRepository, userProfiles, userProfilesRepository, userPublicKeys, userSocialAccounts, users, usersRepository, validateInvitation, validatePasswordStrength, verificationCodes, verificationCodesRepository, verifyClientToken, verifyIdToken, verifyKeyFingerprint, verifyOAuthState, verifyPassword, verifyToken };
|
|
6704
|
+
export { type AccountDeletionPurgeUser, type AccountDeletionRequest, AccountDeletionRequestedBy, AccountDeletionRequestsRepository, type AuthConfig, AuthContext, type AuthDeletionCancelledPayload, type AuthDeletionCompletedPayload, type AuthDeletionConfig, type AuthDeletionRequestedPayload, type AuthLifecycleConfig, type AuthLifecycleOptions, type AuthLoginPayload, type AuthMetadataEntity, AuthMetadataRepository, AuthProviderSchema, type AuthRegisterPayload, type BeforeRegisterContext, COOKIE_NAMES, type CancelAccountDeletionParams, type CancelAccountDeletionResult, type CreateOAuthStateParams, DEFAULT_DELETION_ALLOW_SELF_IMMEDIATE, DEFAULT_DELETION_GRACE_PERIOD_DAYS, DEFAULT_DELETION_PURGE_CRON, DEFAULT_DELETION_PURGE_STRATEGY, DEFAULT_DELETION_SEND_NOTIFICATIONS, type DecryptedOAuthToken, EnvironmentKeyringTokenCipher, type GoogleTokenResponse, type GoogleUserInfo, type Invitation, type InvitationAcceptedPayload, type InvitationCreatedPayload, InvitationStatus, InvitationsRepository, KeyAlgorithmType, type KeyPair, KeysRepository, type NewAccountDeletionRequest, type NewAuthMetadataEntity, type NewInvitation, type NewPermission, type NewPermissionEntity, type NewRole, type NewRoleEntity, type NewRolePermission, type NewUser, type NewUserPermission, type NewUserProfile, type NewUserPublicKey, type NewUserSocialAccount, type NewVerificationCode, OAuthProvider, type OAuthState, type OAuthTokenCipher, type OAuthTokenContext, type OAuthTokenType, type PendingDeletionInfo, type Permission, type PermissionEntity, PermissionsRepository, PurgeStrategy, type PurgeUserResult, type RegisterChannel, type RequestAccountDeletionParams, type RequestAccountDeletionResult, type Role, type RoleEntity, type RoleGuardOptions, type RolePermission, RolePermissionsRepository, RolesRepository, type SessionPayload, SocialAccountsRepository, SocialProvider, type SweepDuePurgesResult, type TokenPayload, type UpdateProfileParams, type User, type UserPermission, UserPermissionsRepository, type UserProfile, UserProfilesRepository, type UserPublicKey, type UserSocialAccount, UsersRepository, type VerificationCode, VerificationCodesRepository, VerificationPurpose, type VerifyIdTokenParams, acceptInvitation, accountDeletionRequests, accountDeletionRequestsRepository, addPermissionToRole, appleProvider, assertCanAssignRole, authDeletionCancelledEvent, authDeletionCompletedEvent, authDeletionRequestedEvent, authJobRouter, authLogger, authLoginEvent, authMetadata, authMetadataRepository, authRegisterEvent, authSchema, cancelAccountDeletionService, cancelInvitation, checkUsernameAvailableService, configureAuth, configureDeletion, configureOAuthTokenCipher, createAuthDeletionJobRouter, createAuthDeletionPurgeJob, createAuthLifecycle, createInvitation, createOAuthState, createRole, decodeToken, decryptToken, deleteInvitation, deleteRole, encryptToken, exchangeCodeForTokens, expireOldInvitations, generateClientToken, generateKeyPair, generateKeyPairES256, generateKeyPairRS256, generateOAuthNonce, generateToken, getAllRoles, getAuth, getAuthConfig, getAuthSessionService, getDeletionConfig, getDummyPasswordHash, getGoogleAuthUrl, getGoogleOAuthConfig, getGoogleUserInfo, getInvitationByToken, getInvitationWithDetails, getKeyId, getKeySize, getLocale, getOneTimeTokenManager, getOptionalAuth, getPendingDeletionInfo, getRole, getRoleByName, getRolePermissions, getSessionTtl, getUser, getUserByEmailService, getUserByIdService, getUserByPhoneService, getUserId, getUserPermissions, getUserProfileService, getUserRole, googleProvider, hasAllPermissions, hasAnyPermission, hasAnyRole, hasPermission, hasRole, hashPassword, initOneTimeTokenManager, initializeAuth, invitationAcceptedEvent, invitationCreatedEvent, invitationsRepository, isEncrypted, isGoogleOAuthEnabled, kakaoProvider, keysRepository, listInvitations, matchOAuthCsrfCookies, naverProvider, oneTimeTokenAuth, parseDuration, permissions, permissionsRepository, purgeUserService, refreshAccessToken, removePermissionFromRole, requestAccountDeletionService, requireAnyPermission, requirePermissions, requireRole, resendInvitation, roleGuard, rolePermissions, rolePermissionsRepository, roles, rolesRepository, runBeforeRegister, setRolePermissions, shouldRotateKey, socialAccountsRepository, sweepDuePurges, updateLastLoginService, updateLocaleService, updateRole, updateUserProfileService, updateUserService, updateUsernameService, userInvitations, userPermissions, userPermissionsRepository, userProfiles, userProfilesRepository, userPublicKeys, userSocialAccounts, users, usersRepository, validateInvitation, validatePasswordStrength, verificationCodes, verificationCodesRepository, verifyClientToken, verifyIdToken, verifyKeyFingerprint, verifyOAuthState, verifyPassword, verifyToken };
|