@withwiz/toolkit 0.8.0 → 0.9.2
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.ko.md +16 -25
- package/README.md +16 -25
- package/dist/{chunk-XXPB4C37.js → chunk-2GK4LDPV.js} +6 -2
- package/dist/chunk-2JUFL4KX.js +41 -0
- package/dist/{chunk-NTZBMWB6.js → chunk-3P4TZM3O.js} +1 -1
- package/dist/chunk-43XXILCX.js +118 -0
- package/dist/{chunk-VWAB4PM7.js → chunk-5S7M2AJL.js} +1 -1
- package/dist/chunk-5VDT3ZB4.js +139 -0
- package/dist/{chunk-SCAFDDJP.js → chunk-BICSVLN7.js} +2 -2
- package/dist/chunk-E4TKORMQ.js +59 -0
- package/dist/chunk-GSRAIDD7.js +134 -0
- package/dist/{chunk-BRBOGLFT.js → chunk-KHXS4DGA.js} +3 -3
- package/dist/{chunk-V3WZFUY3.js → chunk-QMBNFCCK.js} +1 -1
- package/dist/{chunk-OII5BXCZ.js → chunk-U2TGXJ3A.js} +1 -1
- package/dist/{chunk-NLV7IEYM.js → chunk-WSHRBK6Y.js} +1 -1
- package/dist/{chunk-VH57Y5Z4.js → chunk-XDB3K74B.js} +1 -1
- package/dist/{chunk-JHUWZ6YW.js → chunk-YYTA6ERS.js} +6 -36
- package/dist/core/auth/adapters/sql/dialect.d.ts +21 -0
- package/dist/core/auth/adapters/sql/dialect.js +11 -0
- package/dist/core/auth/adapters/sql/email-token-repository.d.ts +17 -0
- package/dist/core/auth/adapters/sql/email-token-repository.js +9 -0
- package/dist/core/auth/adapters/sql/index.d.ts +7 -0
- package/dist/core/auth/adapters/sql/index.js +27 -0
- package/dist/core/auth/adapters/sql/oauth-account-repository.d.ts +18 -0
- package/dist/core/auth/adapters/sql/oauth-account-repository.js +9 -0
- package/dist/core/auth/adapters/sql/types.d.ts +73 -0
- package/dist/core/auth/adapters/sql/types.js +7 -0
- package/dist/core/auth/adapters/sql/user-repository.d.ts +20 -0
- package/dist/core/auth/adapters/sql/user-repository.js +9 -0
- package/dist/core/auth/index.js +9 -9
- package/dist/core/auth/oauth/index.js +7 -7
- package/dist/core/auth/oauth/providers/index.js +6 -6
- package/dist/core/auth/services/index.js +4 -4
- package/dist/core/cache/cache-factory.js +3 -3
- package/dist/core/cache/cache-invalidation.js +4 -4
- package/dist/core/cache/cache-wrapper.js +4 -4
- package/dist/core/cache/cache.js +5 -5
- package/dist/core/cache/hybrid-cache-manager.js +2 -2
- package/dist/core/cache/index.js +5 -5
- package/dist/core/cache/inmemory-cache-manager.d.ts +0 -9
- package/dist/core/cache/inmemory-cache-manager.js +1 -1
- package/dist/core/error/friendly-messages-v2.js +3 -3
- package/dist/core/error/index.js +6 -6
- package/dist/core/error/messages/index.js +2 -2
- package/dist/core/geolocation/index.js +7 -7
- package/dist/core/geolocation/providers/index.js +7 -7
- package/dist/core/system/health-check.js +2 -2
- package/dist/core/system/index.js +5 -5
- package/dist/initialize.js +6 -6
- package/dist/next/auth-handlers/index.js +16 -16
- package/dist/next/auth-handlers/oauth-authorize.handler.js +4 -4
- package/dist/next/auth-handlers/oauth-callback.handler.js +5 -5
- package/dist/next/error/index.js +7 -7
- package/dist/next/middleware/error-handler.js +4 -4
- package/dist/next/middleware/index.js +6 -6
- package/dist/next/middleware/wrappers.js +6 -6
- package/dist/next/utils/index.js +19 -19
- package/package.json +3 -2
- package/dist/{chunk-KKZCNF6U.js → chunk-7WG7XPXC.js} +3 -3
- package/dist/{chunk-SXBDP3CK.js → chunk-JOYW3OZB.js} +3 -3
- package/dist/{chunk-ER6LSA4M.js → chunk-P7WHMKN5.js} +6 -6
- package/dist/{chunk-VDRLJU6C.js → chunk-Q5RPNLET.js} +6 -6
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import {
|
|
2
|
+
resolveConfig
|
|
3
|
+
} from "./chunk-E4TKORMQ.js";
|
|
4
|
+
import {
|
|
5
|
+
ParamBuilder,
|
|
6
|
+
columnList,
|
|
7
|
+
getDialect
|
|
8
|
+
} from "./chunk-2JUFL4KX.js";
|
|
9
|
+
|
|
10
|
+
// src/core/auth/adapters/sql/user-repository.ts
|
|
11
|
+
import { randomUUID } from "crypto";
|
|
12
|
+
var SqlUserRepository = class {
|
|
13
|
+
constructor(exec, config) {
|
|
14
|
+
this.exec = exec;
|
|
15
|
+
this.config = resolveConfig(config);
|
|
16
|
+
this.dialect = getDialect(this.config.dialect);
|
|
17
|
+
}
|
|
18
|
+
get table() {
|
|
19
|
+
return this.dialect.quoteId(this.config.tables.user);
|
|
20
|
+
}
|
|
21
|
+
get cols() {
|
|
22
|
+
return this.config.userColumns;
|
|
23
|
+
}
|
|
24
|
+
/** password 제외 SELECT/매핑 대상 컬럼. */
|
|
25
|
+
selectColumns() {
|
|
26
|
+
const c = this.cols;
|
|
27
|
+
return [c.id, c.email, c.name, c.role, c.image, c.emailVerified, c.isActive, c.createdAt, c.updatedAt];
|
|
28
|
+
}
|
|
29
|
+
async findById(id) {
|
|
30
|
+
const pb = new ParamBuilder(this.dialect);
|
|
31
|
+
const sql = `SELECT ${columnList(this.selectColumns(), this.dialect)} FROM ${this.table} WHERE ${this.dialect.quoteId(this.cols.id)} = ${pb.add(id)}`;
|
|
32
|
+
const rows = await this.exec.query(sql, pb.params);
|
|
33
|
+
return rows[0] ? this.mapToBaseUser(rows[0]) : null;
|
|
34
|
+
}
|
|
35
|
+
async findByEmail(email) {
|
|
36
|
+
var _a;
|
|
37
|
+
const pb = new ParamBuilder(this.dialect);
|
|
38
|
+
const cols = [...this.selectColumns(), this.cols.password];
|
|
39
|
+
const sql = `SELECT ${columnList(cols, this.dialect)} FROM ${this.table} WHERE ${this.dialect.quoteId(this.cols.email)} = ${pb.add(email)}`;
|
|
40
|
+
const rows = await this.exec.query(sql, pb.params);
|
|
41
|
+
if (!rows[0]) return null;
|
|
42
|
+
const baseUser = this.mapToBaseUser(rows[0]);
|
|
43
|
+
return Object.assign(baseUser, { password: (_a = rows[0][this.cols.password]) != null ? _a : null });
|
|
44
|
+
}
|
|
45
|
+
async create(data) {
|
|
46
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _i;
|
|
47
|
+
const c = this.cols;
|
|
48
|
+
const id = randomUUID();
|
|
49
|
+
const now = /* @__PURE__ */ new Date();
|
|
50
|
+
const pb = new ParamBuilder(this.dialect);
|
|
51
|
+
const entries = [
|
|
52
|
+
[c.id, id],
|
|
53
|
+
[c.email, data.email],
|
|
54
|
+
[c.name, (_a = data.name) != null ? _a : null],
|
|
55
|
+
[c.password, (_b = data.password) != null ? _b : null],
|
|
56
|
+
[c.role, (_c = data.role) != null ? _c : null],
|
|
57
|
+
[c.emailVerified, (_d = data.emailVerified) != null ? _d : null],
|
|
58
|
+
[c.image, (_e = data.image) != null ? _e : null],
|
|
59
|
+
[c.isActive, true],
|
|
60
|
+
[c.createdAt, now],
|
|
61
|
+
[c.updatedAt, now]
|
|
62
|
+
];
|
|
63
|
+
const colSql = entries.map(([col]) => this.dialect.quoteId(col)).join(", ");
|
|
64
|
+
const valSql = entries.map(([, val]) => pb.add(val)).join(", ");
|
|
65
|
+
const sql = `INSERT INTO ${this.table} (${colSql}) VALUES (${valSql})`;
|
|
66
|
+
await this.exec.query(sql, pb.params);
|
|
67
|
+
return {
|
|
68
|
+
id,
|
|
69
|
+
email: data.email,
|
|
70
|
+
name: (_f = data.name) != null ? _f : null,
|
|
71
|
+
role: (_g = data.role) != null ? _g : void 0,
|
|
72
|
+
emailVerified: (_h = data.emailVerified) != null ? _h : null,
|
|
73
|
+
image: (_i = data.image) != null ? _i : null,
|
|
74
|
+
isActive: true,
|
|
75
|
+
createdAt: now,
|
|
76
|
+
updatedAt: now
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
async update(id, data) {
|
|
80
|
+
const c = this.cols;
|
|
81
|
+
const pb = new ParamBuilder(this.dialect);
|
|
82
|
+
const sets = [];
|
|
83
|
+
const assign = (col, val) => {
|
|
84
|
+
sets.push(`${this.dialect.quoteId(col)} = ${pb.add(val)}`);
|
|
85
|
+
};
|
|
86
|
+
if (data.email !== void 0) assign(c.email, data.email);
|
|
87
|
+
if (data.name !== void 0) assign(c.name, data.name);
|
|
88
|
+
if (data.isActive !== void 0) assign(c.isActive, data.isActive);
|
|
89
|
+
if (data.password !== void 0) assign(c.password, data.password);
|
|
90
|
+
if (data.role !== void 0) assign(c.role, data.role);
|
|
91
|
+
if (data.emailVerified !== void 0) assign(c.emailVerified, data.emailVerified);
|
|
92
|
+
if (data.image !== void 0) assign(c.image, data.image);
|
|
93
|
+
assign(c.updatedAt, /* @__PURE__ */ new Date());
|
|
94
|
+
const sql = `UPDATE ${this.table} SET ${sets.join(", ")} WHERE ${this.dialect.quoteId(c.id)} = ${pb.add(id)}`;
|
|
95
|
+
await this.exec.query(sql, pb.params);
|
|
96
|
+
const updated = await this.findById(id);
|
|
97
|
+
if (!updated) throw new Error(`User not found after update: ${id}`);
|
|
98
|
+
return updated;
|
|
99
|
+
}
|
|
100
|
+
async delete(id) {
|
|
101
|
+
const pb = new ParamBuilder(this.dialect);
|
|
102
|
+
const sql = `DELETE FROM ${this.table} WHERE ${this.dialect.quoteId(this.cols.id)} = ${pb.add(id)}`;
|
|
103
|
+
await this.exec.query(sql, pb.params);
|
|
104
|
+
}
|
|
105
|
+
async updateLastLoginAt(id) {
|
|
106
|
+
const pb = new ParamBuilder(this.dialect);
|
|
107
|
+
const sql = `UPDATE ${this.table} SET ${this.dialect.quoteId(this.cols.lastLoginAt)} = ${pb.add(/* @__PURE__ */ new Date())} WHERE ${this.dialect.quoteId(this.cols.id)} = ${pb.add(id)}`;
|
|
108
|
+
await this.exec.query(sql, pb.params);
|
|
109
|
+
}
|
|
110
|
+
async verifyEmail(email) {
|
|
111
|
+
const pb = new ParamBuilder(this.dialect);
|
|
112
|
+
const sql = `UPDATE ${this.table} SET ${this.dialect.quoteId(this.cols.emailVerified)} = ${pb.add(/* @__PURE__ */ new Date())} WHERE ${this.dialect.quoteId(this.cols.email)} = ${pb.add(email)}`;
|
|
113
|
+
await this.exec.query(sql, pb.params);
|
|
114
|
+
}
|
|
115
|
+
mapToBaseUser(row) {
|
|
116
|
+
var _a, _b, _c;
|
|
117
|
+
const c = this.cols;
|
|
118
|
+
return {
|
|
119
|
+
id: row[c.id],
|
|
120
|
+
email: row[c.email],
|
|
121
|
+
name: (_a = row[c.name]) != null ? _a : null,
|
|
122
|
+
role: row[c.role],
|
|
123
|
+
emailVerified: (_b = row[c.emailVerified]) != null ? _b : null,
|
|
124
|
+
isActive: row[c.isActive],
|
|
125
|
+
image: (_c = row[c.image]) != null ? _c : null,
|
|
126
|
+
createdAt: row[c.createdAt],
|
|
127
|
+
updatedAt: row[c.updatedAt]
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
export {
|
|
133
|
+
SqlUserRepository
|
|
134
|
+
};
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import {
|
|
2
2
|
AUTH_ERROR_CODE_MAP
|
|
3
3
|
} from "./chunk-R7EFDSPZ.js";
|
|
4
|
-
import {
|
|
5
|
-
getErrorMessage
|
|
6
|
-
} from "./chunk-KKZCNF6U.js";
|
|
7
4
|
import {
|
|
8
5
|
AppError
|
|
9
6
|
} from "./chunk-ATAQRXTH.js";
|
|
7
|
+
import {
|
|
8
|
+
getErrorMessage
|
|
9
|
+
} from "./chunk-7WG7XPXC.js";
|
|
10
10
|
import {
|
|
11
11
|
ERROR_CODES,
|
|
12
12
|
classifyError
|
|
@@ -12,7 +12,6 @@ import {
|
|
|
12
12
|
// src/core/cache/inmemory-cache-manager.ts
|
|
13
13
|
var InMemoryCacheManager = class _InMemoryCacheManager {
|
|
14
14
|
constructor(prefix, config) {
|
|
15
|
-
this.accessOrder = [];
|
|
16
15
|
this.currentMemoryBytes = 0;
|
|
17
16
|
this.cleanupTimer = null;
|
|
18
17
|
this.prefix = prefix;
|
|
@@ -47,7 +46,6 @@ var InMemoryCacheManager = class _InMemoryCacheManager {
|
|
|
47
46
|
if (!entry) {
|
|
48
47
|
this.metrics.misses++;
|
|
49
48
|
this.updateHitRate();
|
|
50
|
-
logger.debug(`[Cache:M] miss: ${fullKey}`);
|
|
51
49
|
return null;
|
|
52
50
|
}
|
|
53
51
|
if (this.isExpired(entry)) {
|
|
@@ -55,17 +53,15 @@ var InMemoryCacheManager = class _InMemoryCacheManager {
|
|
|
55
53
|
this.metrics.misses++;
|
|
56
54
|
this.metrics.expirations++;
|
|
57
55
|
this.updateHitRate();
|
|
58
|
-
logger.debug(`[Cache:M] miss (expired): ${fullKey}`);
|
|
59
56
|
return null;
|
|
60
57
|
}
|
|
61
58
|
entry.accessedAt = Date.now();
|
|
62
|
-
this.
|
|
59
|
+
if (this.config.evictionPolicy === "lru") {
|
|
60
|
+
this.cache.delete(fullKey);
|
|
61
|
+
this.cache.set(fullKey, entry);
|
|
62
|
+
}
|
|
63
63
|
this.metrics.hits++;
|
|
64
64
|
this.updateHitRate();
|
|
65
|
-
logger.debug(`[Cache:M] hit: ${fullKey}`, {
|
|
66
|
-
key: fullKey,
|
|
67
|
-
prefix: this.prefix
|
|
68
|
-
});
|
|
69
65
|
return entry.value;
|
|
70
66
|
}
|
|
71
67
|
/**
|
|
@@ -81,7 +77,7 @@ var InMemoryCacheManager = class _InMemoryCacheManager {
|
|
|
81
77
|
const existingEntry = this.cache.get(fullKey);
|
|
82
78
|
if (existingEntry) {
|
|
83
79
|
this.currentMemoryBytes -= existingEntry.size;
|
|
84
|
-
this.
|
|
80
|
+
this.cache.delete(fullKey);
|
|
85
81
|
}
|
|
86
82
|
const now = Date.now();
|
|
87
83
|
const entry = {
|
|
@@ -92,7 +88,6 @@ var InMemoryCacheManager = class _InMemoryCacheManager {
|
|
|
92
88
|
createdAt: now
|
|
93
89
|
};
|
|
94
90
|
this.cache.set(fullKey, entry);
|
|
95
|
-
this.accessOrder.push(fullKey);
|
|
96
91
|
this.currentMemoryBytes += size;
|
|
97
92
|
}
|
|
98
93
|
/**
|
|
@@ -101,10 +96,6 @@ var InMemoryCacheManager = class _InMemoryCacheManager {
|
|
|
101
96
|
async delete(key) {
|
|
102
97
|
const fullKey = this.getFullKey(key);
|
|
103
98
|
this.deleteEntry(fullKey);
|
|
104
|
-
logger.debug("[InMemoryCache] Cache deleted", {
|
|
105
|
-
key: fullKey,
|
|
106
|
-
prefix: this.prefix
|
|
107
|
-
});
|
|
108
99
|
}
|
|
109
100
|
/**
|
|
110
101
|
* 패턴 매칭으로 캐시 삭제
|
|
@@ -172,7 +163,6 @@ var InMemoryCacheManager = class _InMemoryCacheManager {
|
|
|
172
163
|
*/
|
|
173
164
|
clear() {
|
|
174
165
|
this.cache.clear();
|
|
175
|
-
this.accessOrder = [];
|
|
176
166
|
this.currentMemoryBytes = 0;
|
|
177
167
|
logger.info("[InMemoryCache] Cache cleared", { prefix: this.prefix });
|
|
178
168
|
}
|
|
@@ -258,7 +248,6 @@ var InMemoryCacheManager = class _InMemoryCacheManager {
|
|
|
258
248
|
if (entry) {
|
|
259
249
|
this.currentMemoryBytes -= entry.size;
|
|
260
250
|
this.cache.delete(fullKey);
|
|
261
|
-
this.removeFromAccessOrder(fullKey);
|
|
262
251
|
}
|
|
263
252
|
}
|
|
264
253
|
/**
|
|
@@ -314,7 +303,7 @@ var InMemoryCacheManager = class _InMemoryCacheManager {
|
|
|
314
303
|
* LRU 교체: 가장 오래 접근되지 않은 항목 제거
|
|
315
304
|
*/
|
|
316
305
|
evictLRU() {
|
|
317
|
-
const lruKey = this.
|
|
306
|
+
const lruKey = this.cache.keys().next().value;
|
|
318
307
|
if (lruKey) {
|
|
319
308
|
this.deleteEntry(lruKey);
|
|
320
309
|
logger.debug("[InMemoryCache] LRU eviction", {
|
|
@@ -363,25 +352,6 @@ var InMemoryCacheManager = class _InMemoryCacheManager {
|
|
|
363
352
|
});
|
|
364
353
|
}
|
|
365
354
|
}
|
|
366
|
-
/**
|
|
367
|
-
* 접근 순서 업데이트 (LRU용)
|
|
368
|
-
*/
|
|
369
|
-
updateAccessOrder(key) {
|
|
370
|
-
const index = this.accessOrder.indexOf(key);
|
|
371
|
-
if (index !== -1) {
|
|
372
|
-
this.accessOrder.splice(index, 1);
|
|
373
|
-
}
|
|
374
|
-
this.accessOrder.push(key);
|
|
375
|
-
}
|
|
376
|
-
/**
|
|
377
|
-
* 접근 순서에서 제거
|
|
378
|
-
*/
|
|
379
|
-
removeFromAccessOrder(key) {
|
|
380
|
-
const index = this.accessOrder.indexOf(key);
|
|
381
|
-
if (index !== -1) {
|
|
382
|
-
this.accessOrder.splice(index, 1);
|
|
383
|
-
}
|
|
384
|
-
}
|
|
385
355
|
/**
|
|
386
356
|
* 히트율 업데이트
|
|
387
357
|
*/
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { SqlDialect } from './types';
|
|
2
|
+
export interface DialectStrategy {
|
|
3
|
+
/** 1-based 파라미터 placeholder. postgres: $1,$2.. / mysql: ? */
|
|
4
|
+
placeholder(index: number): string;
|
|
5
|
+
/** 식별자 따옴표. postgres: "id" / mysql: `id` */
|
|
6
|
+
quoteId(id: string): string;
|
|
7
|
+
}
|
|
8
|
+
export declare function getDialect(dialect: SqlDialect): DialectStrategy;
|
|
9
|
+
/**
|
|
10
|
+
* placeholder 순번과 params 배열을 동기화해 누적하는 빌더.
|
|
11
|
+
* add()는 값을 저장하고 그 위치의 placeholder 문자열을 돌려준다.
|
|
12
|
+
*/
|
|
13
|
+
export declare class ParamBuilder {
|
|
14
|
+
private dialect;
|
|
15
|
+
private _params;
|
|
16
|
+
constructor(dialect: DialectStrategy);
|
|
17
|
+
add(value: unknown): string;
|
|
18
|
+
get params(): unknown[];
|
|
19
|
+
}
|
|
20
|
+
/** 컬럼명 배열을 방언 따옴표로 감싸 ', ' 결합. */
|
|
21
|
+
export declare function columnList(columns: string[], dialect: DialectStrategy): string;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { EmailTokenRepository, EmailToken, TokenType } from '@withwiz/toolkit/core/auth/types';
|
|
2
|
+
import type { QueryExecutor, SqlAdapterConfig } from './types';
|
|
3
|
+
export declare class SqlEmailTokenRepository implements EmailTokenRepository {
|
|
4
|
+
private exec;
|
|
5
|
+
private config;
|
|
6
|
+
private dialect;
|
|
7
|
+
constructor(exec: QueryExecutor, config: SqlAdapterConfig);
|
|
8
|
+
private get cols();
|
|
9
|
+
private tableName;
|
|
10
|
+
private quotedTable;
|
|
11
|
+
private selectColumns;
|
|
12
|
+
create(email: string, token: string, type: TokenType, expiresAt: Date): Promise<EmailToken>;
|
|
13
|
+
findByEmailAndToken(email: string, token: string, type: TokenType): Promise<EmailToken | null>;
|
|
14
|
+
delete(email: string, token: string, type: TokenType): Promise<void>;
|
|
15
|
+
deleteExpired(): Promise<void>;
|
|
16
|
+
markAsUsed(id: string): Promise<void>;
|
|
17
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { SqlUserRepository } from './user-repository';
|
|
2
|
+
export { SqlOAuthAccountRepository } from './oauth-account-repository';
|
|
3
|
+
export { SqlEmailTokenRepository } from './email-token-repository';
|
|
4
|
+
export { getDialect, ParamBuilder, columnList } from './dialect';
|
|
5
|
+
export type { DialectStrategy } from './dialect';
|
|
6
|
+
export { resolveConfig } from './types';
|
|
7
|
+
export type { QueryExecutor, SqlDialect, SqlAdapterConfig, ResolvedSqlConfig, UserColumns, OAuthColumns, EmailTokenColumns, } from './types';
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import {
|
|
2
|
+
SqlOAuthAccountRepository
|
|
3
|
+
} from "../../../../chunk-5VDT3ZB4.js";
|
|
4
|
+
import {
|
|
5
|
+
SqlUserRepository
|
|
6
|
+
} from "../../../../chunk-GSRAIDD7.js";
|
|
7
|
+
import {
|
|
8
|
+
SqlEmailTokenRepository
|
|
9
|
+
} from "../../../../chunk-43XXILCX.js";
|
|
10
|
+
import {
|
|
11
|
+
resolveConfig
|
|
12
|
+
} from "../../../../chunk-E4TKORMQ.js";
|
|
13
|
+
import {
|
|
14
|
+
ParamBuilder,
|
|
15
|
+
columnList,
|
|
16
|
+
getDialect
|
|
17
|
+
} from "../../../../chunk-2JUFL4KX.js";
|
|
18
|
+
import "../../../../chunk-N3ETBM74.js";
|
|
19
|
+
export {
|
|
20
|
+
ParamBuilder,
|
|
21
|
+
SqlEmailTokenRepository,
|
|
22
|
+
SqlOAuthAccountRepository,
|
|
23
|
+
SqlUserRepository,
|
|
24
|
+
columnList,
|
|
25
|
+
getDialect,
|
|
26
|
+
resolveConfig
|
|
27
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { OAuthAccountRepository, OAuthAccount, CreateOAuthAccountData, UpdateOAuthAccountData } from '@withwiz/toolkit/core/auth/types';
|
|
2
|
+
import type { QueryExecutor, SqlAdapterConfig } from './types';
|
|
3
|
+
export declare class SqlOAuthAccountRepository implements OAuthAccountRepository {
|
|
4
|
+
private exec;
|
|
5
|
+
private config;
|
|
6
|
+
private dialect;
|
|
7
|
+
constructor(exec: QueryExecutor, config: SqlAdapterConfig);
|
|
8
|
+
private get table();
|
|
9
|
+
private get cols();
|
|
10
|
+
private selectColumns;
|
|
11
|
+
findByProvider(provider: string, providerAccountId: string): Promise<OAuthAccount | null>;
|
|
12
|
+
findByUserId(userId: string): Promise<OAuthAccount[]>;
|
|
13
|
+
create(data: CreateOAuthAccountData): Promise<OAuthAccount>;
|
|
14
|
+
update(id: string, data: UpdateOAuthAccountData): Promise<OAuthAccount>;
|
|
15
|
+
delete(id: string): Promise<void>;
|
|
16
|
+
private selectById;
|
|
17
|
+
private mapToOAuthAccount;
|
|
18
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Raw SQL Auth Adapter — 공유 타입 & config 해석.
|
|
3
|
+
*/
|
|
4
|
+
/** 실행할 SQL 방언. */
|
|
5
|
+
export type SqlDialect = 'postgres' | 'mysql';
|
|
6
|
+
/**
|
|
7
|
+
* 드라이버 독립 쿼리 실행기. 소비자가 자기 드라이버를 한 줄 wrapping 해 주입한다.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* // pg
|
|
11
|
+
* const exec = { query: (sql, p) => pool.query(sql, p).then((r) => r.rows) };
|
|
12
|
+
* // mysql2/promise
|
|
13
|
+
* const exec = { query: (sql, p) => pool.query(sql, p).then(([rows]) => rows) };
|
|
14
|
+
*/
|
|
15
|
+
export interface QueryExecutor {
|
|
16
|
+
query(sql: string, params: unknown[]): Promise<Record<string, unknown>[]>;
|
|
17
|
+
}
|
|
18
|
+
export interface UserColumns {
|
|
19
|
+
id: string;
|
|
20
|
+
email: string;
|
|
21
|
+
name: string;
|
|
22
|
+
password: string;
|
|
23
|
+
role: string;
|
|
24
|
+
image: string;
|
|
25
|
+
emailVerified: string;
|
|
26
|
+
isActive: string;
|
|
27
|
+
createdAt: string;
|
|
28
|
+
updatedAt: string;
|
|
29
|
+
lastLoginAt: string;
|
|
30
|
+
}
|
|
31
|
+
export interface OAuthColumns {
|
|
32
|
+
id: string;
|
|
33
|
+
userId: string;
|
|
34
|
+
provider: string;
|
|
35
|
+
providerAccountId: string;
|
|
36
|
+
accessToken: string;
|
|
37
|
+
refreshToken: string;
|
|
38
|
+
expiresAt: string;
|
|
39
|
+
tokenType: string;
|
|
40
|
+
scope: string;
|
|
41
|
+
createdAt: string;
|
|
42
|
+
updatedAt: string;
|
|
43
|
+
}
|
|
44
|
+
export interface EmailTokenColumns {
|
|
45
|
+
id: string;
|
|
46
|
+
email: string;
|
|
47
|
+
token: string;
|
|
48
|
+
expires: string;
|
|
49
|
+
used: string;
|
|
50
|
+
createdAt: string;
|
|
51
|
+
}
|
|
52
|
+
export interface SqlAdapterConfig {
|
|
53
|
+
dialect: SqlDialect;
|
|
54
|
+
tables?: {
|
|
55
|
+
user?: string;
|
|
56
|
+
oauthAccount?: string;
|
|
57
|
+
emailVerification?: string;
|
|
58
|
+
passwordReset?: string;
|
|
59
|
+
magicLink?: string;
|
|
60
|
+
};
|
|
61
|
+
userColumns?: Partial<UserColumns>;
|
|
62
|
+
oauthColumns?: Partial<OAuthColumns>;
|
|
63
|
+
emailTokenColumns?: Partial<EmailTokenColumns>;
|
|
64
|
+
}
|
|
65
|
+
export interface ResolvedSqlConfig {
|
|
66
|
+
dialect: SqlDialect;
|
|
67
|
+
tables: Required<NonNullable<SqlAdapterConfig['tables']>>;
|
|
68
|
+
userColumns: UserColumns;
|
|
69
|
+
oauthColumns: OAuthColumns;
|
|
70
|
+
emailTokenColumns: EmailTokenColumns;
|
|
71
|
+
}
|
|
72
|
+
/** SqlAdapterConfig를 기본값으로 채워 완전한 ResolvedSqlConfig로 해석한다. */
|
|
73
|
+
export declare function resolveConfig(config: SqlAdapterConfig): ResolvedSqlConfig;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { UserRepository, BaseUser, CreateUserData, UpdateUserData } from '@withwiz/toolkit/core/auth/types';
|
|
2
|
+
import type { QueryExecutor, SqlAdapterConfig } from './types';
|
|
3
|
+
export declare class SqlUserRepository implements UserRepository {
|
|
4
|
+
private exec;
|
|
5
|
+
private config;
|
|
6
|
+
private dialect;
|
|
7
|
+
constructor(exec: QueryExecutor, config: SqlAdapterConfig);
|
|
8
|
+
private get table();
|
|
9
|
+
private get cols();
|
|
10
|
+
/** password 제외 SELECT/매핑 대상 컬럼. */
|
|
11
|
+
private selectColumns;
|
|
12
|
+
findById(id: string): Promise<BaseUser | null>;
|
|
13
|
+
findByEmail(email: string): Promise<BaseUser | null>;
|
|
14
|
+
create(data: CreateUserData): Promise<BaseUser>;
|
|
15
|
+
update(id: string, data: UpdateUserData): Promise<BaseUser>;
|
|
16
|
+
delete(id: string): Promise<void>;
|
|
17
|
+
updateLastLoginAt(id: string): Promise<void>;
|
|
18
|
+
verifyEmail(email: string): Promise<void>;
|
|
19
|
+
private mapToBaseUser;
|
|
20
|
+
}
|
package/dist/core/auth/index.js
CHANGED
|
@@ -36,12 +36,8 @@ import {
|
|
|
36
36
|
} from "../../chunk-5I3EQHR4.js";
|
|
37
37
|
import {
|
|
38
38
|
OAuthManager
|
|
39
|
-
} from "../../chunk-
|
|
39
|
+
} from "../../chunk-P7WHMKN5.js";
|
|
40
40
|
import "../../chunk-CDALZTPN.js";
|
|
41
|
-
import "../../chunk-GSSHHVHF.js";
|
|
42
|
-
import {
|
|
43
|
-
GitHubOAuthProvider
|
|
44
|
-
} from "../../chunk-HIZ7USIF.js";
|
|
45
41
|
import {
|
|
46
42
|
GoogleOAuthProvider
|
|
47
43
|
} from "../../chunk-GF3DKZIW.js";
|
|
@@ -49,11 +45,11 @@ import {
|
|
|
49
45
|
KakaoOAuthProvider
|
|
50
46
|
} from "../../chunk-65HVR74O.js";
|
|
51
47
|
import "../../chunk-33RIHX7O.js";
|
|
52
|
-
import "../../chunk-
|
|
48
|
+
import "../../chunk-GSSHHVHF.js";
|
|
53
49
|
import {
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
50
|
+
GitHubOAuthProvider
|
|
51
|
+
} from "../../chunk-HIZ7USIF.js";
|
|
52
|
+
import "../../chunk-JLRMET4V.js";
|
|
57
53
|
import {
|
|
58
54
|
TokenGenerator
|
|
59
55
|
} from "../../chunk-ZZABL54F.js";
|
|
@@ -62,6 +58,10 @@ import {
|
|
|
62
58
|
PasswordStrength,
|
|
63
59
|
TokenType
|
|
64
60
|
} from "../../chunk-GH3U4WRE.js";
|
|
61
|
+
import {
|
|
62
|
+
JWTManager,
|
|
63
|
+
JWTService
|
|
64
|
+
} from "../../chunk-LWHLB2Y6.js";
|
|
65
65
|
import {
|
|
66
66
|
AUTH_ERROR_CODES,
|
|
67
67
|
AuthError,
|
|
@@ -1,13 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
OAuthManager
|
|
3
|
-
} from "../../../chunk-
|
|
3
|
+
} from "../../../chunk-P7WHMKN5.js";
|
|
4
4
|
import "../../../chunk-CDALZTPN.js";
|
|
5
|
-
import {
|
|
6
|
-
MicrosoftOAuthProvider
|
|
7
|
-
} from "../../../chunk-GSSHHVHF.js";
|
|
8
|
-
import {
|
|
9
|
-
GitHubOAuthProvider
|
|
10
|
-
} from "../../../chunk-HIZ7USIF.js";
|
|
11
5
|
import {
|
|
12
6
|
GoogleOAuthProvider
|
|
13
7
|
} from "../../../chunk-GF3DKZIW.js";
|
|
@@ -17,6 +11,12 @@ import {
|
|
|
17
11
|
import {
|
|
18
12
|
MetaOAuthProvider
|
|
19
13
|
} from "../../../chunk-33RIHX7O.js";
|
|
14
|
+
import {
|
|
15
|
+
MicrosoftOAuthProvider
|
|
16
|
+
} from "../../../chunk-GSSHHVHF.js";
|
|
17
|
+
import {
|
|
18
|
+
GitHubOAuthProvider
|
|
19
|
+
} from "../../../chunk-HIZ7USIF.js";
|
|
20
20
|
import {
|
|
21
21
|
OAUTH_STATE_COOKIE,
|
|
22
22
|
clearOAuthStateCookie,
|
|
@@ -1,10 +1,4 @@
|
|
|
1
1
|
import "../../../../chunk-CDALZTPN.js";
|
|
2
|
-
import {
|
|
3
|
-
MicrosoftOAuthProvider
|
|
4
|
-
} from "../../../../chunk-GSSHHVHF.js";
|
|
5
|
-
import {
|
|
6
|
-
GitHubOAuthProvider
|
|
7
|
-
} from "../../../../chunk-HIZ7USIF.js";
|
|
8
2
|
import {
|
|
9
3
|
GoogleOAuthProvider
|
|
10
4
|
} from "../../../../chunk-GF3DKZIW.js";
|
|
@@ -14,6 +8,12 @@ import {
|
|
|
14
8
|
import {
|
|
15
9
|
MetaOAuthProvider
|
|
16
10
|
} from "../../../../chunk-33RIHX7O.js";
|
|
11
|
+
import {
|
|
12
|
+
MicrosoftOAuthProvider
|
|
13
|
+
} from "../../../../chunk-GSSHHVHF.js";
|
|
14
|
+
import {
|
|
15
|
+
GitHubOAuthProvider
|
|
16
|
+
} from "../../../../chunk-HIZ7USIF.js";
|
|
17
17
|
import "../../../../chunk-5GWGARXI.js";
|
|
18
18
|
import "../../../../chunk-N3ETBM74.js";
|
|
19
19
|
export {
|
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
LoginService
|
|
3
3
|
} from "../../../chunk-TNDEYJEL.js";
|
|
4
|
-
import {
|
|
5
|
-
EmailVerificationService
|
|
6
|
-
} from "../../../chunk-VWKZMGPJ.js";
|
|
7
4
|
import {
|
|
8
5
|
OAuthCallbackService
|
|
9
6
|
} from "../../../chunk-MTZXWVW3.js";
|
|
@@ -13,12 +10,15 @@ import {
|
|
|
13
10
|
import {
|
|
14
11
|
RegisterService
|
|
15
12
|
} from "../../../chunk-Y4ME3Q5K.js";
|
|
13
|
+
import {
|
|
14
|
+
EmailVerificationService
|
|
15
|
+
} from "../../../chunk-VWKZMGPJ.js";
|
|
16
16
|
import {
|
|
17
17
|
PasswordResetService
|
|
18
18
|
} from "../../../chunk-75UDFONR.js";
|
|
19
|
-
import "../../../chunk-LWHLB2Y6.js";
|
|
20
19
|
import "../../../chunk-ZZABL54F.js";
|
|
21
20
|
import "../../../chunk-GH3U4WRE.js";
|
|
21
|
+
import "../../../chunk-LWHLB2Y6.js";
|
|
22
22
|
import "../../../chunk-5GWGARXI.js";
|
|
23
23
|
import "../../../chunk-PRPMEHRE.js";
|
|
24
24
|
import "../../../chunk-N3TCQ5BF.js";
|