@withwiz/toolkit 0.4.1 → 0.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/auth/adapters/prisma/index.d.ts +20 -4
- package/dist/auth/adapters/prisma/index.js +51 -61
- package/dist/auth/core/jwt/cookie.d.ts +1 -0
- package/dist/auth/core/jwt/cookie.js +1 -1
- package/dist/auth/core/jwt/index.d.ts +1 -1
- package/dist/auth/core/jwt/index.js +1 -1
- package/dist/auth/core/jwt/types.js +5 -7
- package/dist/auth/core/oauth/index.d.ts +17 -27
- package/dist/auth/core/oauth/index.js +18 -5
- package/dist/auth/core/oauth/providers/github.d.ts +12 -0
- package/dist/auth/core/oauth/providers/github.js +8 -0
- package/dist/auth/core/oauth/providers/google.d.ts +12 -0
- package/dist/auth/core/oauth/providers/google.js +8 -0
- package/dist/auth/core/oauth/providers/index.d.ts +3 -0
- package/dist/auth/core/oauth/providers/index.js +17 -0
- package/dist/auth/core/oauth/providers/kakao.d.ts +12 -0
- package/dist/auth/core/oauth/providers/kakao.js +8 -0
- package/dist/auth/core/password/client-helper.js +1 -1
- package/dist/auth/core/password/index.js +1 -1
- package/dist/auth/index.d.ts +2 -3
- package/dist/auth/index.js +35 -24
- package/dist/auth/types/index.d.ts +31 -31
- package/dist/auth/types/index.js +5 -7
- package/dist/chunk-2QQNL4ND.js +62 -0
- package/dist/chunk-6PGZTY4N.js +30 -0
- package/dist/chunk-GBLNXNEH.js +64 -0
- package/dist/chunk-HZLJYEOO.js +92 -0
- package/dist/{chunk-N4D6OPPP.js → chunk-LLVIA4JX.js} +4 -2
- package/dist/{chunk-5WP57PJK.js → chunk-O3UR234Y.js} +4 -4
- package/dist/{chunk-6D3HHYER.js → chunk-QKC73SWB.js} +6 -12
- package/dist/chunk-RVL5ROWQ.js +62 -0
- package/dist/chunk-T4MDCVUQ.js +0 -0
- package/dist/{chunk-J5AISIJS.js → chunk-ZBXSEQ6W.js} +18 -14
- package/dist/config/registry.d.ts +42 -0
- package/dist/config/registry.js +12 -0
- package/dist/constants/index.js +6 -6
- package/dist/initialize.d.ts +2 -0
- package/dist/initialize.js +18 -10
- package/dist/middleware/auth.d.ts +1 -0
- package/dist/middleware/auth.js +4 -2
- package/dist/middleware/index.d.ts +1 -1
- package/dist/middleware/index.js +8 -6
- package/dist/middleware/rate-limit.d.ts +3 -7
- package/dist/middleware/types.d.ts +1 -1
- package/dist/middleware/wrappers.js +4 -4
- package/dist/types/geoip.d.ts +4 -4
- package/dist/types/qr-code.d.ts +20 -20
- package/dist/types/qr-code.js +4 -4
- package/package.json +6 -1
- package/dist/chunk-V5K5FYU7.js +0 -200
|
@@ -10,15 +10,11 @@ export interface Logger {
|
|
|
10
10
|
warn(message: string, meta?: any): void;
|
|
11
11
|
error(message: string, meta?: any): void;
|
|
12
12
|
}
|
|
13
|
-
export declare enum UserRole {
|
|
14
|
-
USER = "USER",
|
|
15
|
-
ADMIN = "ADMIN"
|
|
16
|
-
}
|
|
17
13
|
export interface JWTPayload {
|
|
18
14
|
id: string;
|
|
19
15
|
userId: string;
|
|
20
16
|
email: string;
|
|
21
|
-
role:
|
|
17
|
+
role: string;
|
|
22
18
|
emailVerified?: Date | null;
|
|
23
19
|
tokenType?: 'access' | 'refresh';
|
|
24
20
|
iat?: number;
|
|
@@ -34,10 +30,12 @@ export interface JWTConfig {
|
|
|
34
30
|
refreshTokenExpiry: string;
|
|
35
31
|
algorithm: 'HS256' | 'HS384' | 'HS512';
|
|
36
32
|
}
|
|
37
|
-
export declare
|
|
38
|
-
GOOGLE
|
|
39
|
-
GITHUB
|
|
40
|
-
|
|
33
|
+
export declare const OAUTH_PROVIDERS: {
|
|
34
|
+
readonly GOOGLE: "google";
|
|
35
|
+
readonly GITHUB: "github";
|
|
36
|
+
readonly KAKAO: "kakao";
|
|
37
|
+
};
|
|
38
|
+
export type OAuthProviderName = typeof OAUTH_PROVIDERS[keyof typeof OAUTH_PROVIDERS];
|
|
41
39
|
export interface OAuthUserInfo {
|
|
42
40
|
id: string;
|
|
43
41
|
email: string;
|
|
@@ -52,17 +50,19 @@ export interface OAuthTokenResponse {
|
|
|
52
50
|
refresh_token?: string;
|
|
53
51
|
scope?: string;
|
|
54
52
|
}
|
|
53
|
+
export interface OAuthProviderConfig {
|
|
54
|
+
clientId: string;
|
|
55
|
+
clientSecret: string;
|
|
56
|
+
redirectUri: string;
|
|
57
|
+
}
|
|
55
58
|
export interface OAuthConfig {
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
clientSecret: string;
|
|
64
|
-
redirectUri: string;
|
|
65
|
-
};
|
|
59
|
+
providers: Record<string, OAuthProviderConfig>;
|
|
60
|
+
}
|
|
61
|
+
export interface IOAuthProviderAdapter {
|
|
62
|
+
readonly name: string;
|
|
63
|
+
getLoginUrl(config: OAuthProviderConfig, state?: string): string;
|
|
64
|
+
exchangeCodeForToken(config: OAuthProviderConfig, code: string): Promise<OAuthTokenResponse>;
|
|
65
|
+
getUserInfo(accessToken: string): Promise<OAuthUserInfo>;
|
|
66
66
|
}
|
|
67
67
|
export declare enum PasswordStrength {
|
|
68
68
|
VERY_WEAK = "VERY_WEAK",
|
|
@@ -93,13 +93,13 @@ export declare enum TokenType {
|
|
|
93
93
|
export interface BaseUser {
|
|
94
94
|
id: string;
|
|
95
95
|
email: string;
|
|
96
|
-
name
|
|
97
|
-
role
|
|
98
|
-
emailVerified
|
|
99
|
-
isActive
|
|
100
|
-
image
|
|
101
|
-
createdAt
|
|
102
|
-
updatedAt
|
|
96
|
+
name?: string | null;
|
|
97
|
+
role?: string;
|
|
98
|
+
emailVerified?: Date | null;
|
|
99
|
+
isActive?: boolean;
|
|
100
|
+
image?: string | null;
|
|
101
|
+
createdAt?: Date;
|
|
102
|
+
updatedAt?: Date;
|
|
103
103
|
}
|
|
104
104
|
export interface UserRepository {
|
|
105
105
|
findById(id: string): Promise<BaseUser | null>;
|
|
@@ -114,7 +114,7 @@ export interface CreateUserData {
|
|
|
114
114
|
email: string;
|
|
115
115
|
password?: string | null;
|
|
116
116
|
name?: string | null;
|
|
117
|
-
role?:
|
|
117
|
+
role?: string;
|
|
118
118
|
emailVerified?: Date | null;
|
|
119
119
|
image?: string | null;
|
|
120
120
|
}
|
|
@@ -122,7 +122,7 @@ export interface UpdateUserData {
|
|
|
122
122
|
email?: string;
|
|
123
123
|
password?: string;
|
|
124
124
|
name?: string | null;
|
|
125
|
-
role?:
|
|
125
|
+
role?: string;
|
|
126
126
|
emailVerified?: Date | null;
|
|
127
127
|
isActive?: boolean;
|
|
128
128
|
image?: string | null;
|
|
@@ -130,7 +130,7 @@ export interface UpdateUserData {
|
|
|
130
130
|
export interface OAuthAccount {
|
|
131
131
|
id: string;
|
|
132
132
|
userId: string;
|
|
133
|
-
provider:
|
|
133
|
+
provider: string;
|
|
134
134
|
providerAccountId: string;
|
|
135
135
|
accessToken: string | null;
|
|
136
136
|
refreshToken: string | null;
|
|
@@ -141,7 +141,7 @@ export interface OAuthAccount {
|
|
|
141
141
|
updatedAt: Date;
|
|
142
142
|
}
|
|
143
143
|
export interface OAuthAccountRepository {
|
|
144
|
-
findByProvider(provider:
|
|
144
|
+
findByProvider(provider: string, providerAccountId: string): Promise<OAuthAccount | null>;
|
|
145
145
|
findByUserId(userId: string): Promise<OAuthAccount[]>;
|
|
146
146
|
create(data: CreateOAuthAccountData): Promise<OAuthAccount>;
|
|
147
147
|
update(id: string, data: UpdateOAuthAccountData): Promise<OAuthAccount>;
|
|
@@ -149,7 +149,7 @@ export interface OAuthAccountRepository {
|
|
|
149
149
|
}
|
|
150
150
|
export interface CreateOAuthAccountData {
|
|
151
151
|
userId: string;
|
|
152
|
-
provider:
|
|
152
|
+
provider: string;
|
|
153
153
|
providerAccountId: string;
|
|
154
154
|
accessToken?: string | null;
|
|
155
155
|
refreshToken?: string | null;
|
package/dist/auth/types/index.js
CHANGED
|
@@ -1,13 +1,11 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
2
|
+
OAUTH_PROVIDERS,
|
|
3
3
|
PasswordStrength,
|
|
4
|
-
TokenType
|
|
5
|
-
|
|
6
|
-
} from "../../chunk-6D3HHYER.js";
|
|
4
|
+
TokenType
|
|
5
|
+
} from "../../chunk-QKC73SWB.js";
|
|
7
6
|
import "../../chunk-ORMEWXMH.js";
|
|
8
7
|
export {
|
|
9
|
-
|
|
8
|
+
OAUTH_PROVIDERS,
|
|
10
9
|
PasswordStrength,
|
|
11
|
-
TokenType
|
|
12
|
-
UserRole
|
|
10
|
+
TokenType
|
|
13
11
|
};
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import {
|
|
2
|
+
OAuthError
|
|
3
|
+
} from "./chunk-AIH3F7JV.js";
|
|
4
|
+
|
|
5
|
+
// src/auth/core/oauth/providers/kakao.ts
|
|
6
|
+
var KakaoOAuthProvider = class {
|
|
7
|
+
constructor() {
|
|
8
|
+
this.name = "kakao";
|
|
9
|
+
}
|
|
10
|
+
getLoginUrl(config, state) {
|
|
11
|
+
const params = new URLSearchParams({
|
|
12
|
+
client_id: config.clientId,
|
|
13
|
+
redirect_uri: config.redirectUri,
|
|
14
|
+
response_type: "code",
|
|
15
|
+
scope: "profile_nickname profile_image account_email"
|
|
16
|
+
});
|
|
17
|
+
if (state) {
|
|
18
|
+
params.set("state", state);
|
|
19
|
+
}
|
|
20
|
+
return `https://kauth.kakao.com/oauth/authorize?${params.toString()}`;
|
|
21
|
+
}
|
|
22
|
+
async exchangeCodeForToken(config, code) {
|
|
23
|
+
const response = await fetch("https://kauth.kakao.com/oauth/token", {
|
|
24
|
+
method: "POST",
|
|
25
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
26
|
+
body: new URLSearchParams({
|
|
27
|
+
client_id: config.clientId,
|
|
28
|
+
client_secret: config.clientSecret,
|
|
29
|
+
code,
|
|
30
|
+
grant_type: "authorization_code",
|
|
31
|
+
redirect_uri: config.redirectUri
|
|
32
|
+
})
|
|
33
|
+
});
|
|
34
|
+
if (!response.ok) {
|
|
35
|
+
const errorData = await response.text();
|
|
36
|
+
throw new OAuthError(`Kakao token exchange failed: ${errorData}`, "TOKEN_EXCHANGE_FAILED");
|
|
37
|
+
}
|
|
38
|
+
return response.json();
|
|
39
|
+
}
|
|
40
|
+
async getUserInfo(accessToken) {
|
|
41
|
+
const response = await fetch("https://kapi.kakao.com/v2/user/me", {
|
|
42
|
+
headers: { Authorization: `Bearer ${accessToken}` }
|
|
43
|
+
});
|
|
44
|
+
if (!response.ok) {
|
|
45
|
+
throw new OAuthError("Failed to get Kakao user info", "USER_INFO_FAILED");
|
|
46
|
+
}
|
|
47
|
+
const data = await response.json();
|
|
48
|
+
const account = data.kakao_account || {};
|
|
49
|
+
const profile = account.profile || {};
|
|
50
|
+
return {
|
|
51
|
+
id: data.id.toString(),
|
|
52
|
+
email: account.email,
|
|
53
|
+
name: profile.nickname || null,
|
|
54
|
+
image: profile.profile_image_url || null,
|
|
55
|
+
emailVerified: account.is_email_verified || false
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
export {
|
|
61
|
+
KakaoOAuthProvider
|
|
62
|
+
};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ConfigurationError
|
|
3
|
+
} from "./chunk-2QH66EVQ.js";
|
|
4
|
+
|
|
5
|
+
// src/config/registry.ts
|
|
6
|
+
function initConfig(entries) {
|
|
7
|
+
if (globalThis.__withwiz_config) return;
|
|
8
|
+
globalThis.__withwiz_config = Object.freeze(entries);
|
|
9
|
+
}
|
|
10
|
+
var config = new Proxy({}, {
|
|
11
|
+
get(_target, prop, _receiver) {
|
|
12
|
+
const store = globalThis.__withwiz_config;
|
|
13
|
+
if (!store) {
|
|
14
|
+
throw new ConfigurationError("Config", "Not initialized. Call initConfig() first.");
|
|
15
|
+
}
|
|
16
|
+
return store[prop];
|
|
17
|
+
},
|
|
18
|
+
set() {
|
|
19
|
+
throw new TypeError("config is read-only");
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
function resetConfig() {
|
|
23
|
+
globalThis.__withwiz_config = void 0;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export {
|
|
27
|
+
initConfig,
|
|
28
|
+
config,
|
|
29
|
+
resetConfig
|
|
30
|
+
};
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import {
|
|
2
|
+
OAuthError
|
|
3
|
+
} from "./chunk-AIH3F7JV.js";
|
|
4
|
+
|
|
5
|
+
// src/auth/core/oauth/providers/github.ts
|
|
6
|
+
var GitHubOAuthProvider = class {
|
|
7
|
+
constructor() {
|
|
8
|
+
this.name = "github";
|
|
9
|
+
}
|
|
10
|
+
getLoginUrl(config, state) {
|
|
11
|
+
const params = new URLSearchParams({
|
|
12
|
+
client_id: config.clientId,
|
|
13
|
+
redirect_uri: config.redirectUri,
|
|
14
|
+
scope: "read:user user:email"
|
|
15
|
+
});
|
|
16
|
+
if (state) {
|
|
17
|
+
params.set("state", state);
|
|
18
|
+
}
|
|
19
|
+
return `https://github.com/login/oauth/authorize?${params.toString()}`;
|
|
20
|
+
}
|
|
21
|
+
async exchangeCodeForToken(config, code) {
|
|
22
|
+
const response = await fetch("https://github.com/login/oauth/access_token", {
|
|
23
|
+
method: "POST",
|
|
24
|
+
headers: {
|
|
25
|
+
"Content-Type": "application/json",
|
|
26
|
+
Accept: "application/json"
|
|
27
|
+
},
|
|
28
|
+
body: JSON.stringify({
|
|
29
|
+
client_id: config.clientId,
|
|
30
|
+
client_secret: config.clientSecret,
|
|
31
|
+
code,
|
|
32
|
+
redirect_uri: config.redirectUri
|
|
33
|
+
})
|
|
34
|
+
});
|
|
35
|
+
if (!response.ok) {
|
|
36
|
+
const errorData = await response.text();
|
|
37
|
+
throw new OAuthError(`GitHub token exchange failed: ${errorData}`, "TOKEN_EXCHANGE_FAILED");
|
|
38
|
+
}
|
|
39
|
+
return response.json();
|
|
40
|
+
}
|
|
41
|
+
async getUserInfo(accessToken) {
|
|
42
|
+
const response = await fetch("https://api.github.com/user", {
|
|
43
|
+
headers: {
|
|
44
|
+
Authorization: `Bearer ${accessToken}`,
|
|
45
|
+
"User-Agent": "Auth-Module"
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
if (!response.ok) {
|
|
49
|
+
throw new OAuthError("Failed to get GitHub user info", "USER_INFO_FAILED");
|
|
50
|
+
}
|
|
51
|
+
const data = await response.json();
|
|
52
|
+
return {
|
|
53
|
+
id: data.id.toString(),
|
|
54
|
+
email: data.email,
|
|
55
|
+
name: data.name || null,
|
|
56
|
+
image: data.avatar_url || null,
|
|
57
|
+
emailVerified: !!data.email
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
export {
|
|
63
|
+
GitHubOAuthProvider
|
|
64
|
+
};
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import {
|
|
2
|
+
KakaoOAuthProvider
|
|
3
|
+
} from "./chunk-2QQNL4ND.js";
|
|
4
|
+
import {
|
|
5
|
+
GitHubOAuthProvider
|
|
6
|
+
} from "./chunk-GBLNXNEH.js";
|
|
7
|
+
import {
|
|
8
|
+
GoogleOAuthProvider
|
|
9
|
+
} from "./chunk-RVL5ROWQ.js";
|
|
10
|
+
import {
|
|
11
|
+
OAuthError
|
|
12
|
+
} from "./chunk-AIH3F7JV.js";
|
|
13
|
+
|
|
14
|
+
// src/auth/core/oauth/index.ts
|
|
15
|
+
var OAuthManager = class {
|
|
16
|
+
constructor(config, logger) {
|
|
17
|
+
this.providers = /* @__PURE__ */ new Map();
|
|
18
|
+
this.config = config;
|
|
19
|
+
this.logger = logger;
|
|
20
|
+
this.registerProvider(new GoogleOAuthProvider());
|
|
21
|
+
this.registerProvider(new GitHubOAuthProvider());
|
|
22
|
+
this.registerProvider(new KakaoOAuthProvider());
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* 프로바이더 어댑터 등록
|
|
26
|
+
*/
|
|
27
|
+
registerProvider(provider) {
|
|
28
|
+
this.providers.set(provider.name, provider);
|
|
29
|
+
this.logger.debug(`OAuth provider registered: ${provider.name}`);
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* OAuth 로그인 URL 생성
|
|
33
|
+
*/
|
|
34
|
+
getLoginUrl(providerName, state) {
|
|
35
|
+
const provider = this.getProvider(providerName);
|
|
36
|
+
const config = this.getProviderConfig(providerName);
|
|
37
|
+
return provider.getLoginUrl(config, state);
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* 인증 코드를 액세스 토큰으로 교환
|
|
41
|
+
*/
|
|
42
|
+
async exchangeCodeForToken(providerName, code) {
|
|
43
|
+
const provider = this.getProvider(providerName);
|
|
44
|
+
const config = this.getProviderConfig(providerName);
|
|
45
|
+
try {
|
|
46
|
+
const tokenResponse = await provider.exchangeCodeForToken(config, code);
|
|
47
|
+
this.logger.debug(`${providerName} token exchange successful`);
|
|
48
|
+
return tokenResponse.access_token;
|
|
49
|
+
} catch (error) {
|
|
50
|
+
this.logger.error(`${providerName} token exchange error`, { error: error.message });
|
|
51
|
+
throw error instanceof OAuthError ? error : new OAuthError(`${providerName} token exchange failed`, "TOKEN_EXCHANGE_FAILED");
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* 사용자 정보 가져오기
|
|
56
|
+
*/
|
|
57
|
+
async getUserInfo(providerName, accessToken) {
|
|
58
|
+
const provider = this.getProvider(providerName);
|
|
59
|
+
try {
|
|
60
|
+
const userInfo = await provider.getUserInfo(accessToken);
|
|
61
|
+
this.logger.debug(`${providerName} user info retrieved`, { userId: userInfo.id, email: userInfo.email });
|
|
62
|
+
return userInfo;
|
|
63
|
+
} catch (error) {
|
|
64
|
+
this.logger.error(`${providerName} user info error`, { error: error.message });
|
|
65
|
+
throw error instanceof OAuthError ? error : new OAuthError(`Failed to retrieve ${providerName} user info`, "USER_INFO_FAILED");
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* 프로바이더 어댑터 조회
|
|
70
|
+
*/
|
|
71
|
+
getProvider(name) {
|
|
72
|
+
const provider = this.providers.get(name);
|
|
73
|
+
if (!provider) {
|
|
74
|
+
throw new OAuthError(`Unsupported OAuth provider: ${name}`, "UNSUPPORTED_PROVIDER");
|
|
75
|
+
}
|
|
76
|
+
return provider;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* 프로바이더 설정 조회
|
|
80
|
+
*/
|
|
81
|
+
getProviderConfig(providerName) {
|
|
82
|
+
const config = this.config.providers[providerName];
|
|
83
|
+
if (!config) {
|
|
84
|
+
throw new OAuthError(`${providerName} OAuth not configured`, `${providerName.toUpperCase()}_NOT_CONFIGURED`);
|
|
85
|
+
}
|
|
86
|
+
return config;
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
export {
|
|
91
|
+
OAuthManager
|
|
92
|
+
};
|
|
@@ -18,6 +18,7 @@ function getDefaultOptions() {
|
|
|
18
18
|
};
|
|
19
19
|
}
|
|
20
20
|
function setTokenCookies(response, tokenPair, options = {}) {
|
|
21
|
+
var _a;
|
|
21
22
|
const opts = __spreadValues(__spreadValues({}, getDefaultOptions()), options);
|
|
22
23
|
response.cookies.set("access_token", tokenPair.accessToken, {
|
|
23
24
|
httpOnly: true,
|
|
@@ -30,12 +31,13 @@ function setTokenCookies(response, tokenPair, options = {}) {
|
|
|
30
31
|
httpOnly: true,
|
|
31
32
|
secure: opts.secure,
|
|
32
33
|
sameSite: opts.sameSite,
|
|
33
|
-
path: "/api/auth",
|
|
34
|
+
path: (_a = opts.refreshTokenPath) != null ? _a : "/api/auth",
|
|
34
35
|
maxAge: 7 * 24 * 60 * 60
|
|
35
36
|
});
|
|
36
37
|
return response;
|
|
37
38
|
}
|
|
38
39
|
function clearTokenCookies(response, options = {}) {
|
|
40
|
+
var _a;
|
|
39
41
|
const opts = __spreadValues(__spreadValues({}, getDefaultOptions()), options);
|
|
40
42
|
response.cookies.set("access_token", "", {
|
|
41
43
|
httpOnly: true,
|
|
@@ -48,7 +50,7 @@ function clearTokenCookies(response, options = {}) {
|
|
|
48
50
|
httpOnly: true,
|
|
49
51
|
secure: opts.secure,
|
|
50
52
|
sameSite: opts.sameSite,
|
|
51
|
-
path: "/api/auth",
|
|
53
|
+
path: (_a = opts.refreshTokenPath) != null ? _a : "/api/auth",
|
|
52
54
|
maxAge: 0
|
|
53
55
|
});
|
|
54
56
|
return response;
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import {
|
|
2
|
+
initRequestMiddleware
|
|
3
|
+
} from "./chunk-62Q7DN5G.js";
|
|
1
4
|
import {
|
|
2
5
|
MiddlewareChain
|
|
3
6
|
} from "./chunk-FPESPW6P.js";
|
|
@@ -14,16 +17,13 @@ import {
|
|
|
14
17
|
adminMiddleware,
|
|
15
18
|
authMiddleware,
|
|
16
19
|
optionalAuthMiddleware
|
|
17
|
-
} from "./chunk-
|
|
20
|
+
} from "./chunk-ZBXSEQ6W.js";
|
|
18
21
|
import {
|
|
19
22
|
corsMiddleware
|
|
20
23
|
} from "./chunk-KGHWGLED.js";
|
|
21
24
|
import {
|
|
22
25
|
errorHandlerMiddleware
|
|
23
26
|
} from "./chunk-3YUKCYHI.js";
|
|
24
|
-
import {
|
|
25
|
-
initRequestMiddleware
|
|
26
|
-
} from "./chunk-62Q7DN5G.js";
|
|
27
27
|
|
|
28
28
|
// src/middleware/wrappers.ts
|
|
29
29
|
function withPublicApi(handler) {
|
|
@@ -1,14 +1,9 @@
|
|
|
1
1
|
// src/auth/types/index.ts
|
|
2
|
-
var
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
}
|
|
7
|
-
var OAuthProvider = /* @__PURE__ */ ((OAuthProvider2) => {
|
|
8
|
-
OAuthProvider2["GOOGLE"] = "google";
|
|
9
|
-
OAuthProvider2["GITHUB"] = "github";
|
|
10
|
-
return OAuthProvider2;
|
|
11
|
-
})(OAuthProvider || {});
|
|
2
|
+
var OAUTH_PROVIDERS = {
|
|
3
|
+
GOOGLE: "google",
|
|
4
|
+
GITHUB: "github",
|
|
5
|
+
KAKAO: "kakao"
|
|
6
|
+
};
|
|
12
7
|
var PasswordStrength = /* @__PURE__ */ ((PasswordStrength2) => {
|
|
13
8
|
PasswordStrength2["VERY_WEAK"] = "VERY_WEAK";
|
|
14
9
|
PasswordStrength2["WEAK"] = "WEAK";
|
|
@@ -25,8 +20,7 @@ var TokenType = /* @__PURE__ */ ((TokenType2) => {
|
|
|
25
20
|
})(TokenType || {});
|
|
26
21
|
|
|
27
22
|
export {
|
|
28
|
-
|
|
29
|
-
OAuthProvider,
|
|
23
|
+
OAUTH_PROVIDERS,
|
|
30
24
|
PasswordStrength,
|
|
31
25
|
TokenType
|
|
32
26
|
};
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import {
|
|
2
|
+
OAuthError
|
|
3
|
+
} from "./chunk-AIH3F7JV.js";
|
|
4
|
+
|
|
5
|
+
// src/auth/core/oauth/providers/google.ts
|
|
6
|
+
var GoogleOAuthProvider = class {
|
|
7
|
+
constructor() {
|
|
8
|
+
this.name = "google";
|
|
9
|
+
}
|
|
10
|
+
getLoginUrl(config, state) {
|
|
11
|
+
const params = new URLSearchParams({
|
|
12
|
+
client_id: config.clientId,
|
|
13
|
+
redirect_uri: config.redirectUri,
|
|
14
|
+
response_type: "code",
|
|
15
|
+
scope: "openid email profile",
|
|
16
|
+
access_type: "offline",
|
|
17
|
+
prompt: "select_account consent"
|
|
18
|
+
});
|
|
19
|
+
if (state) {
|
|
20
|
+
params.set("state", state);
|
|
21
|
+
}
|
|
22
|
+
return `https://accounts.google.com/o/oauth2/v2/auth?${params.toString()}`;
|
|
23
|
+
}
|
|
24
|
+
async exchangeCodeForToken(config, code) {
|
|
25
|
+
const response = await fetch("https://oauth2.googleapis.com/token", {
|
|
26
|
+
method: "POST",
|
|
27
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
28
|
+
body: new URLSearchParams({
|
|
29
|
+
client_id: config.clientId,
|
|
30
|
+
client_secret: config.clientSecret,
|
|
31
|
+
code,
|
|
32
|
+
grant_type: "authorization_code",
|
|
33
|
+
redirect_uri: config.redirectUri
|
|
34
|
+
})
|
|
35
|
+
});
|
|
36
|
+
if (!response.ok) {
|
|
37
|
+
const errorData = await response.text();
|
|
38
|
+
throw new OAuthError(`Google token exchange failed: ${errorData}`, "TOKEN_EXCHANGE_FAILED");
|
|
39
|
+
}
|
|
40
|
+
return response.json();
|
|
41
|
+
}
|
|
42
|
+
async getUserInfo(accessToken) {
|
|
43
|
+
const response = await fetch("https://www.googleapis.com/oauth2/v2/userinfo", {
|
|
44
|
+
headers: { Authorization: `Bearer ${accessToken}` }
|
|
45
|
+
});
|
|
46
|
+
if (!response.ok) {
|
|
47
|
+
throw new OAuthError("Failed to get Google user info", "USER_INFO_FAILED");
|
|
48
|
+
}
|
|
49
|
+
const data = await response.json();
|
|
50
|
+
return {
|
|
51
|
+
id: data.id,
|
|
52
|
+
email: data.email,
|
|
53
|
+
name: data.name || null,
|
|
54
|
+
image: data.picture || null,
|
|
55
|
+
emailVerified: data.verified_email || false
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
export {
|
|
61
|
+
GoogleOAuthProvider
|
|
62
|
+
};
|
|
File without changes
|
|
@@ -72,7 +72,7 @@ function initializeAuthMiddleware() {
|
|
|
72
72
|
return jwtManager !== null;
|
|
73
73
|
}
|
|
74
74
|
var authMiddleware = async (context, next) => {
|
|
75
|
-
var _a, _b, _c, _d;
|
|
75
|
+
var _a, _b, _c, _d, _e;
|
|
76
76
|
try {
|
|
77
77
|
const jwtManager = getJWTManager();
|
|
78
78
|
if (!jwtManager) {
|
|
@@ -111,13 +111,13 @@ var authMiddleware = async (context, next) => {
|
|
|
111
111
|
email: (_c = payload.email) != null ? _c : "",
|
|
112
112
|
name: void 0,
|
|
113
113
|
// 필요시 DB에서 조회
|
|
114
|
-
role: payload.role
|
|
114
|
+
role: (_d = payload.role) != null ? _d : "USER"
|
|
115
115
|
};
|
|
116
116
|
} catch (error) {
|
|
117
117
|
if (error instanceof AppError) {
|
|
118
118
|
throw error;
|
|
119
119
|
}
|
|
120
|
-
if (error.code === "TOKEN_EXPIRED" || ((
|
|
120
|
+
if (error.code === "TOKEN_EXPIRED" || ((_e = error.message) == null ? void 0 : _e.includes("expired"))) {
|
|
121
121
|
throw new AppError(ERROR_CODES.TOKEN_EXPIRED.code, error.message);
|
|
122
122
|
}
|
|
123
123
|
throw new AppError(
|
|
@@ -128,7 +128,7 @@ var authMiddleware = async (context, next) => {
|
|
|
128
128
|
return await next();
|
|
129
129
|
};
|
|
130
130
|
var optionalAuthMiddleware = async (context, next) => {
|
|
131
|
-
var _a, _b, _c;
|
|
131
|
+
var _a, _b, _c, _d;
|
|
132
132
|
try {
|
|
133
133
|
const jwtManager = getJWTManager();
|
|
134
134
|
if (jwtManager) {
|
|
@@ -149,7 +149,7 @@ var optionalAuthMiddleware = async (context, next) => {
|
|
|
149
149
|
id: payload.userId,
|
|
150
150
|
email: (_c = payload.email) != null ? _c : "",
|
|
151
151
|
name: void 0,
|
|
152
|
-
role: payload.role
|
|
152
|
+
role: (_d = payload.role) != null ? _d : "USER"
|
|
153
153
|
};
|
|
154
154
|
}
|
|
155
155
|
}
|
|
@@ -158,20 +158,24 @@ var optionalAuthMiddleware = async (context, next) => {
|
|
|
158
158
|
}
|
|
159
159
|
return await next();
|
|
160
160
|
};
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
161
|
+
function createRoleMiddleware(...allowedRoles) {
|
|
162
|
+
return async (context, next) => {
|
|
163
|
+
if (!context.user) {
|
|
164
|
+
throw new AppError(ERROR_CODES.UNAUTHORIZED.code);
|
|
165
|
+
}
|
|
166
|
+
if (!allowedRoles.includes(context.user.role)) {
|
|
167
|
+
throw new AppError(ERROR_CODES.FORBIDDEN.code);
|
|
168
|
+
}
|
|
169
|
+
return await next();
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
var adminMiddleware = createRoleMiddleware("ADMIN");
|
|
170
173
|
|
|
171
174
|
export {
|
|
172
175
|
setAccessTokenBlacklistChecker,
|
|
173
176
|
initializeAuthMiddleware,
|
|
174
177
|
authMiddleware,
|
|
175
178
|
optionalAuthMiddleware,
|
|
179
|
+
createRoleMiddleware,
|
|
176
180
|
adminMiddleware
|
|
177
181
|
};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unified Config Registry
|
|
3
|
+
*
|
|
4
|
+
* Single entry point for all withwiz configuration.
|
|
5
|
+
* Stores resolved configs in globalThis.__withwiz_config and exposes
|
|
6
|
+
* them via a read-only Proxy (`config`).
|
|
7
|
+
*/
|
|
8
|
+
import type { ResolvedCommonConfig } from './common';
|
|
9
|
+
import type { ResolvedAuthConfig } from '../auth/config';
|
|
10
|
+
import type { ResolvedLoggerConfig } from '../logger/config';
|
|
11
|
+
import type { ResolvedCacheConfig } from '../cache/config';
|
|
12
|
+
import type { ResolvedStorageConfig } from '../storage/config';
|
|
13
|
+
import type { ResolvedGeolocationConfig } from '../geolocation/config';
|
|
14
|
+
import type { ResolvedCorsConfig } from '../middleware/cors-config';
|
|
15
|
+
export interface ConfigRegistry {
|
|
16
|
+
common: ResolvedCommonConfig;
|
|
17
|
+
auth: ResolvedAuthConfig;
|
|
18
|
+
logger: ResolvedLoggerConfig;
|
|
19
|
+
cache?: ResolvedCacheConfig;
|
|
20
|
+
storage?: ResolvedStorageConfig;
|
|
21
|
+
geolocation?: ResolvedGeolocationConfig;
|
|
22
|
+
cors?: ResolvedCorsConfig;
|
|
23
|
+
}
|
|
24
|
+
declare global {
|
|
25
|
+
var __withwiz_config: ConfigRegistry | undefined;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Initialise the unified config registry.
|
|
29
|
+
* Idempotent — a second call is silently ignored.
|
|
30
|
+
* The stored object is frozen to prevent mutation.
|
|
31
|
+
*/
|
|
32
|
+
export declare function initConfig(entries: ConfigRegistry): void;
|
|
33
|
+
/**
|
|
34
|
+
* Read-only Proxy that delegates to `globalThis.__withwiz_config`.
|
|
35
|
+
* Throws `ConfigurationError` if accessed before `initConfig()`.
|
|
36
|
+
* Throws `TypeError` on any setter attempt.
|
|
37
|
+
*/
|
|
38
|
+
export declare const config: ConfigRegistry;
|
|
39
|
+
/**
|
|
40
|
+
* Reset the registry to uninitialised state. For test cleanup only.
|
|
41
|
+
*/
|
|
42
|
+
export declare function resetConfig(): void;
|