@wheeparam/library 0.0.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.
@@ -0,0 +1,89 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/api/index.ts
21
+ var api_exports = {};
22
+ __export(api_exports, {
23
+ defineRoutes: () => defineRoutes,
24
+ matchRoute: () => matchRoute,
25
+ routeResponse: () => routeResponse
26
+ });
27
+ module.exports = __toCommonJS(api_exports);
28
+
29
+ // src/api/types.ts
30
+ function defineRoutes(routes) {
31
+ return routes;
32
+ }
33
+
34
+ // src/api/route.ts
35
+ function parseParamToken(segment) {
36
+ if (/^\[[^.[\]]+\]$/.test(segment)) return { kind: "single", key: segment.slice(1, -1) };
37
+ if (/^\[\.\.\.[^\]]+\]$/.test(segment)) return { kind: "catchAll", key: segment.slice(4, -1) };
38
+ if (/^\[\[\.\.\.[^\]]+\]\]$/.test(segment)) return { kind: "optionalCatchAll", key: segment.slice(5, -2) };
39
+ return null;
40
+ }
41
+ function matchRoute(path, slug) {
42
+ const parts = path.split("/").filter(Boolean);
43
+ const params = {};
44
+ let i = 0;
45
+ let j = 0;
46
+ while (i < parts.length) {
47
+ const seg = parts[i];
48
+ const token = parseParamToken(seg);
49
+ if (!token) {
50
+ if (j >= slug.length) return null;
51
+ if (seg !== slug[j]) return null;
52
+ i++;
53
+ j++;
54
+ continue;
55
+ }
56
+ if (token.kind === "single") {
57
+ if (j >= slug.length) return null;
58
+ params[token.key] = slug[j];
59
+ i++;
60
+ j++;
61
+ continue;
62
+ }
63
+ if (token.kind === "catchAll") {
64
+ if (j >= slug.length) return null;
65
+ params[token.key] = slug.slice(j);
66
+ return { params };
67
+ }
68
+ if (j >= slug.length) return { params };
69
+ params[token.key] = slug.slice(j);
70
+ return { params };
71
+ }
72
+ if (j !== slug.length) return null;
73
+ return { params };
74
+ }
75
+ async function routeResponse(slug, routes, request) {
76
+ for (const route of routes) {
77
+ const matched = matchRoute(route.path, slug);
78
+ if (!matched) continue;
79
+ const res = await route.handler(request, matched.params);
80
+ return res;
81
+ }
82
+ return Response.json({ error: "Not Found" }, { status: 404 });
83
+ }
84
+ // Annotate the CommonJS export names for ESM import in node:
85
+ 0 && (module.exports = {
86
+ defineRoutes,
87
+ matchRoute,
88
+ routeResponse
89
+ });
@@ -0,0 +1,124 @@
1
+ import { NextResponse, NextRequest } from 'next/server';
2
+
3
+ /**
4
+ * @packageDocumentation
5
+ * Next.js Route Handler 유틸에서 사용하는 타입/헬퍼 모음
6
+ *
7
+ * - path 문자열("users/[id]")로부터 params 타입을 추론하여 DX를 높인다.
8
+ * - defineRoutes()로 routes 배열의 path literal을 유지한다.
9
+ */
10
+
11
+ type Merge<A, B> = A & B;
12
+ /**
13
+ * 단일 path segment에서 params 타입을 추출한다.
14
+ *
15
+ * 지원 패턴:
16
+ * - [id] -> { id: string }
17
+ * - [...rest] -> { rest: string[] }
18
+ * - [[...rest]] -> { rest?: string[] }
19
+ */
20
+ type ExtractSegmentParam<S extends string> = S extends `[[...${infer K}]]` ? {
21
+ [P in K]?: string[];
22
+ } : S extends `[...${infer K}]` ? {
23
+ [P in K]: string[];
24
+ } : S extends `[${infer K}]` ? {
25
+ [P in K]: string;
26
+ } : {};
27
+ /**
28
+ * path 문자열로부터 params 타입을 재귀적으로 추론한다.
29
+ *
30
+ * @example
31
+ * type P1 = ParamsFromPath<"users/[id]"> // { id: string }
32
+ * type P2 = ParamsFromPath<"files/[...path]"> // { path: string[] }
33
+ * type P3 = ParamsFromPath<"docs/[[...slug]]"> // { slug?: string[] }
34
+ * type P4 = ParamsFromPath<"a/[id]/b/[postId]"> // { id: string; postId: string }
35
+ */
36
+ type ParamsFromPath<Path extends string> = Path extends `${infer Head}/${infer Tail}` ? Merge<ExtractSegmentParam<Head>, ParamsFromPath<Tail>> : ExtractSegmentParam<Path>;
37
+ /**
38
+ * Next.js Route Handler 타입
39
+ *
40
+ * - Request(표준) / NextRequest 모두 지원한다.
41
+ * - params는 path로부터 자동 추론된다.
42
+ *
43
+ * @example
44
+ * const r: Route<"users/[id]"> = {
45
+ * path: "users/[id]",
46
+ * handler: async (_req, params) => Response.json({ id: params.id })
47
+ * }
48
+ */
49
+ type RouteHandler<Path extends string> = ((request: Request, params: ParamsFromPath<Path>) => Promise<Response | NextResponse>) | ((request: NextRequest, params: ParamsFromPath<Path>) => Promise<Response | NextResponse>);
50
+ /**
51
+ * 라우팅 정의 객체
52
+ *
53
+ * @example
54
+ * const route: Route<"users/[id]"> = {
55
+ * path: "users/[id]",
56
+ * handler: async (_req, params) => Response.json({ id: params.id })
57
+ * }
58
+ */
59
+ type Route<Path extends string = string> = {
60
+ path: Path;
61
+ handler: RouteHandler<Path>;
62
+ };
63
+ /**
64
+ * routes 배열의 path literal을 유지하기 위한 identity helper
65
+ *
66
+ * TS가 배열 리터럴을 `string`으로 넓혀버리는 것을 방지하여,
67
+ * handler의 params 타입 추론이 끝까지 유지된다.
68
+ *
69
+ * @example
70
+ * const routes = defineRoutes([
71
+ * { path: "users/[id]", handler: async (_req, p) => Response.json({ id: p.id }) }
72
+ * ] as const)
73
+ */
74
+ declare function defineRoutes<const R extends readonly Route<string>[]>(routes: R): R;
75
+
76
+ /**
77
+ * @packageDocumentation
78
+ * slug 배열과 route 패턴을 매칭하여 handler를 호출하는 라우팅 유틸
79
+ *
80
+ * 지원 패턴:
81
+ * - 정적 경로: "health"
82
+ * - 단일 파라미터: "users/[id]"
83
+ * - catch-all: "files/[...path]"
84
+ * - optional catch-all: "docs/[[...slug]]"
85
+ */
86
+
87
+ type MatchResult = {
88
+ params: Record<string, string | string[]>;
89
+ };
90
+ /**
91
+ * 특정 route path 패턴이 slug와 매칭되는지 검사하고 params를 반환한다.
92
+ *
93
+ * @param path route 패턴 (예: "users/[id]", "docs/[[...slug]]")
94
+ * @param slug URL 경로 배열 (예: ["users","10"])
95
+ * @returns 매칭되면 params, 아니면 null
96
+ *
97
+ * @example
98
+ * matchRoute("users/[id]", ["users","10"]) // { params: { id: "10" } }
99
+ * matchRoute("docs/[[...slug]]", ["docs"]) // { params: {} }
100
+ * matchRoute("files/[...path]", ["files","a","b"]) // { params: { path: ["a","b"] } }
101
+ */
102
+ declare function matchRoute(path: string, slug: string[]): MatchResult | null;
103
+ /**
104
+ * 슬러그 기반 라우팅을 처리한다.
105
+ *
106
+ * 정의된 routes 목록에서 slug와 일치하는 handler를 찾아 실행한다.
107
+ * 매칭되는 route가 없으면 404 JSON 응답을 반환한다.
108
+ *
109
+ * @param slug URL 경로 배열
110
+ * @param routes 라우팅 정의 목록
111
+ * @param request Request 객체
112
+ * @returns handler가 반환한 Response (또는 404 Response)
113
+ *
114
+ * @example
115
+ * const routes = defineRoutes([
116
+ * { path: "health", handler: async () => Response.json({ ok: true }) },
117
+ * { path: "users/[id]", handler: async (_req, p) => Response.json({ id: p.id }) },
118
+ * ] as const)
119
+ *
120
+ * return routeResponse(slug, routes, request)
121
+ */
122
+ declare function routeResponse(slug: string[], routes: readonly Route<string>[], request: Request): Promise<Response>;
123
+
124
+ export { type ParamsFromPath, type Route, type RouteHandler, defineRoutes, matchRoute, routeResponse };
@@ -0,0 +1,124 @@
1
+ import { NextResponse, NextRequest } from 'next/server';
2
+
3
+ /**
4
+ * @packageDocumentation
5
+ * Next.js Route Handler 유틸에서 사용하는 타입/헬퍼 모음
6
+ *
7
+ * - path 문자열("users/[id]")로부터 params 타입을 추론하여 DX를 높인다.
8
+ * - defineRoutes()로 routes 배열의 path literal을 유지한다.
9
+ */
10
+
11
+ type Merge<A, B> = A & B;
12
+ /**
13
+ * 단일 path segment에서 params 타입을 추출한다.
14
+ *
15
+ * 지원 패턴:
16
+ * - [id] -> { id: string }
17
+ * - [...rest] -> { rest: string[] }
18
+ * - [[...rest]] -> { rest?: string[] }
19
+ */
20
+ type ExtractSegmentParam<S extends string> = S extends `[[...${infer K}]]` ? {
21
+ [P in K]?: string[];
22
+ } : S extends `[...${infer K}]` ? {
23
+ [P in K]: string[];
24
+ } : S extends `[${infer K}]` ? {
25
+ [P in K]: string;
26
+ } : {};
27
+ /**
28
+ * path 문자열로부터 params 타입을 재귀적으로 추론한다.
29
+ *
30
+ * @example
31
+ * type P1 = ParamsFromPath<"users/[id]"> // { id: string }
32
+ * type P2 = ParamsFromPath<"files/[...path]"> // { path: string[] }
33
+ * type P3 = ParamsFromPath<"docs/[[...slug]]"> // { slug?: string[] }
34
+ * type P4 = ParamsFromPath<"a/[id]/b/[postId]"> // { id: string; postId: string }
35
+ */
36
+ type ParamsFromPath<Path extends string> = Path extends `${infer Head}/${infer Tail}` ? Merge<ExtractSegmentParam<Head>, ParamsFromPath<Tail>> : ExtractSegmentParam<Path>;
37
+ /**
38
+ * Next.js Route Handler 타입
39
+ *
40
+ * - Request(표준) / NextRequest 모두 지원한다.
41
+ * - params는 path로부터 자동 추론된다.
42
+ *
43
+ * @example
44
+ * const r: Route<"users/[id]"> = {
45
+ * path: "users/[id]",
46
+ * handler: async (_req, params) => Response.json({ id: params.id })
47
+ * }
48
+ */
49
+ type RouteHandler<Path extends string> = ((request: Request, params: ParamsFromPath<Path>) => Promise<Response | NextResponse>) | ((request: NextRequest, params: ParamsFromPath<Path>) => Promise<Response | NextResponse>);
50
+ /**
51
+ * 라우팅 정의 객체
52
+ *
53
+ * @example
54
+ * const route: Route<"users/[id]"> = {
55
+ * path: "users/[id]",
56
+ * handler: async (_req, params) => Response.json({ id: params.id })
57
+ * }
58
+ */
59
+ type Route<Path extends string = string> = {
60
+ path: Path;
61
+ handler: RouteHandler<Path>;
62
+ };
63
+ /**
64
+ * routes 배열의 path literal을 유지하기 위한 identity helper
65
+ *
66
+ * TS가 배열 리터럴을 `string`으로 넓혀버리는 것을 방지하여,
67
+ * handler의 params 타입 추론이 끝까지 유지된다.
68
+ *
69
+ * @example
70
+ * const routes = defineRoutes([
71
+ * { path: "users/[id]", handler: async (_req, p) => Response.json({ id: p.id }) }
72
+ * ] as const)
73
+ */
74
+ declare function defineRoutes<const R extends readonly Route<string>[]>(routes: R): R;
75
+
76
+ /**
77
+ * @packageDocumentation
78
+ * slug 배열과 route 패턴을 매칭하여 handler를 호출하는 라우팅 유틸
79
+ *
80
+ * 지원 패턴:
81
+ * - 정적 경로: "health"
82
+ * - 단일 파라미터: "users/[id]"
83
+ * - catch-all: "files/[...path]"
84
+ * - optional catch-all: "docs/[[...slug]]"
85
+ */
86
+
87
+ type MatchResult = {
88
+ params: Record<string, string | string[]>;
89
+ };
90
+ /**
91
+ * 특정 route path 패턴이 slug와 매칭되는지 검사하고 params를 반환한다.
92
+ *
93
+ * @param path route 패턴 (예: "users/[id]", "docs/[[...slug]]")
94
+ * @param slug URL 경로 배열 (예: ["users","10"])
95
+ * @returns 매칭되면 params, 아니면 null
96
+ *
97
+ * @example
98
+ * matchRoute("users/[id]", ["users","10"]) // { params: { id: "10" } }
99
+ * matchRoute("docs/[[...slug]]", ["docs"]) // { params: {} }
100
+ * matchRoute("files/[...path]", ["files","a","b"]) // { params: { path: ["a","b"] } }
101
+ */
102
+ declare function matchRoute(path: string, slug: string[]): MatchResult | null;
103
+ /**
104
+ * 슬러그 기반 라우팅을 처리한다.
105
+ *
106
+ * 정의된 routes 목록에서 slug와 일치하는 handler를 찾아 실행한다.
107
+ * 매칭되는 route가 없으면 404 JSON 응답을 반환한다.
108
+ *
109
+ * @param slug URL 경로 배열
110
+ * @param routes 라우팅 정의 목록
111
+ * @param request Request 객체
112
+ * @returns handler가 반환한 Response (또는 404 Response)
113
+ *
114
+ * @example
115
+ * const routes = defineRoutes([
116
+ * { path: "health", handler: async () => Response.json({ ok: true }) },
117
+ * { path: "users/[id]", handler: async (_req, p) => Response.json({ id: p.id }) },
118
+ * ] as const)
119
+ *
120
+ * return routeResponse(slug, routes, request)
121
+ */
122
+ declare function routeResponse(slug: string[], routes: readonly Route<string>[], request: Request): Promise<Response>;
123
+
124
+ export { type ParamsFromPath, type Route, type RouteHandler, defineRoutes, matchRoute, routeResponse };
@@ -0,0 +1,60 @@
1
+ // src/api/types.ts
2
+ function defineRoutes(routes) {
3
+ return routes;
4
+ }
5
+
6
+ // src/api/route.ts
7
+ function parseParamToken(segment) {
8
+ if (/^\[[^.[\]]+\]$/.test(segment)) return { kind: "single", key: segment.slice(1, -1) };
9
+ if (/^\[\.\.\.[^\]]+\]$/.test(segment)) return { kind: "catchAll", key: segment.slice(4, -1) };
10
+ if (/^\[\[\.\.\.[^\]]+\]\]$/.test(segment)) return { kind: "optionalCatchAll", key: segment.slice(5, -2) };
11
+ return null;
12
+ }
13
+ function matchRoute(path, slug) {
14
+ const parts = path.split("/").filter(Boolean);
15
+ const params = {};
16
+ let i = 0;
17
+ let j = 0;
18
+ while (i < parts.length) {
19
+ const seg = parts[i];
20
+ const token = parseParamToken(seg);
21
+ if (!token) {
22
+ if (j >= slug.length) return null;
23
+ if (seg !== slug[j]) return null;
24
+ i++;
25
+ j++;
26
+ continue;
27
+ }
28
+ if (token.kind === "single") {
29
+ if (j >= slug.length) return null;
30
+ params[token.key] = slug[j];
31
+ i++;
32
+ j++;
33
+ continue;
34
+ }
35
+ if (token.kind === "catchAll") {
36
+ if (j >= slug.length) return null;
37
+ params[token.key] = slug.slice(j);
38
+ return { params };
39
+ }
40
+ if (j >= slug.length) return { params };
41
+ params[token.key] = slug.slice(j);
42
+ return { params };
43
+ }
44
+ if (j !== slug.length) return null;
45
+ return { params };
46
+ }
47
+ async function routeResponse(slug, routes, request) {
48
+ for (const route of routes) {
49
+ const matched = matchRoute(route.path, slug);
50
+ if (!matched) continue;
51
+ const res = await route.handler(request, matched.params);
52
+ return res;
53
+ }
54
+ return Response.json({ error: "Not Found" }, { status: 404 });
55
+ }
56
+ export {
57
+ defineRoutes,
58
+ matchRoute,
59
+ routeResponse
60
+ };
@@ -0,0 +1,205 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/client/index.ts
31
+ var client_exports = {};
32
+ __export(client_exports, {
33
+ createAxiosClient: () => createAxiosClient
34
+ });
35
+ module.exports = __toCommonJS(client_exports);
36
+
37
+ // src/client/axios.ts
38
+ var import_axios = __toESM(require("axios"), 1);
39
+ function createLocalStorageTokenAccess(keys) {
40
+ const accessTokenKey = keys?.accessTokenKey ?? "accessToken";
41
+ const refreshTokenKey = keys?.refreshTokenKey ?? "refreshToken";
42
+ return {
43
+ get() {
44
+ return {
45
+ accessToken: window.localStorage.getItem(accessTokenKey),
46
+ refreshToken: window.localStorage.getItem(refreshTokenKey)
47
+ };
48
+ },
49
+ set(data) {
50
+ if (data.accessToken !== void 0) {
51
+ window.localStorage.setItem(accessTokenKey, data.accessToken ?? "");
52
+ }
53
+ if (data.refreshToken !== void 0) {
54
+ window.localStorage.setItem(refreshTokenKey, data.refreshToken ?? "");
55
+ }
56
+ },
57
+ clear() {
58
+ window.localStorage.removeItem(accessTokenKey);
59
+ window.localStorage.removeItem(refreshTokenKey);
60
+ }
61
+ };
62
+ }
63
+ function createCookieModeTokenAccess(keys) {
64
+ const refreshTokenKey = keys?.refreshTokenKey ?? "refreshToken";
65
+ return {
66
+ get() {
67
+ return {
68
+ accessToken: null,
69
+ // 쿠키 기반이면 JS에서 accessToken을 직접 읽지 않는 전제를 둔다.
70
+ refreshToken: window.localStorage.getItem(refreshTokenKey)
71
+ };
72
+ },
73
+ set(data) {
74
+ if (data.refreshToken !== void 0) {
75
+ window.localStorage.setItem(refreshTokenKey, data.refreshToken ?? "");
76
+ }
77
+ },
78
+ clear() {
79
+ window.localStorage.removeItem(refreshTokenKey);
80
+ }
81
+ };
82
+ }
83
+ function createAxiosClient(options) {
84
+ const {
85
+ baseURL,
86
+ timeout = 1e4,
87
+ withCredentials = true,
88
+ refreshUrl,
89
+ storage = "localStorage",
90
+ storageKeys,
91
+ onAuthStateChange,
92
+ onError,
93
+ getErrorMessage
94
+ } = options;
95
+ const instance = import_axios.default.create({ baseURL, timeout, withCredentials });
96
+ const tokenAccess = storage === "localStorage" ? createLocalStorageTokenAccess(storageKeys) : createCookieModeTokenAccess({ refreshTokenKey: storageKeys?.refreshTokenKey });
97
+ let isRefreshing = false;
98
+ let subscribers = [];
99
+ const notifySubscribers = (token) => {
100
+ subscribers.forEach((cb) => cb(token));
101
+ subscribers = [];
102
+ };
103
+ const clearAuth = () => {
104
+ tokenAccess.clear();
105
+ onAuthStateChange?.("unauthenticated");
106
+ };
107
+ const requestRefresh = async (refreshToken) => {
108
+ const res = await fetch(refreshUrl, {
109
+ method: "POST",
110
+ headers: { "Content-Type": "application/json" },
111
+ body: JSON.stringify({ refreshToken }),
112
+ credentials: withCredentials ? "include" : "same-origin"
113
+ });
114
+ if (!res.ok) {
115
+ throw new Error("Token refresh failed");
116
+ }
117
+ return await res.json();
118
+ };
119
+ instance.interceptors.request.use(
120
+ (config) => {
121
+ const { accessToken } = tokenAccess.get();
122
+ if (accessToken) {
123
+ config.headers = config.headers ?? {};
124
+ config.headers.Authorization = `Bearer ${accessToken}`;
125
+ }
126
+ return config;
127
+ },
128
+ (e) => Promise.reject(e)
129
+ );
130
+ instance.interceptors.response.use(
131
+ (res) => res,
132
+ async (error) => {
133
+ const response = error.response;
134
+ const status = response?.status;
135
+ const originalRequest = error.config ?? {};
136
+ if (status !== 401) {
137
+ let message = getErrorMessage?.(error) ?? response?.data?.error ?? "";
138
+ if (!message && typeof status === "number") {
139
+ switch (status) {
140
+ case 0:
141
+ message = "REST API \uC11C\uBC84\uC5D0 \uC811\uADFC\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4\n\uC11C\uBC84 \uAD00\uB9AC\uC790\uC5D0\uAC8C \uBB38\uC758\uD558\uC138\uC694";
142
+ break;
143
+ case 400:
144
+ message = "\uC798\uBABB\uB41C \uC694\uCCAD\uC785\uB2C8\uB2E4.";
145
+ break;
146
+ case 404:
147
+ message = "[404] REST API \uC694\uCCAD\uC5D0 \uC2E4\uD328\uD558\uC600\uC2B5\uB2C8\uB2E4";
148
+ break;
149
+ case 500:
150
+ message = "\uC11C\uBC84\uC5D0\uC11C \uCC98\uB9AC \uC911 \uC624\uB958\uAC00 \uBC1C\uC0DD\uD558\uC600\uC2B5\uB2C8\uB2E4.";
151
+ break;
152
+ }
153
+ }
154
+ if (message) onError?.(message, error);
155
+ return Promise.reject(error);
156
+ }
157
+ if (originalRequest._retry) {
158
+ clearAuth();
159
+ return Promise.reject(error);
160
+ }
161
+ originalRequest._retry = true;
162
+ const { refreshToken } = tokenAccess.get();
163
+ if (!refreshToken) {
164
+ clearAuth();
165
+ return Promise.reject(error);
166
+ }
167
+ if (isRefreshing) {
168
+ return new Promise((resolve, reject) => {
169
+ subscribers.push((newToken) => {
170
+ if (!newToken) return reject(error);
171
+ originalRequest.headers = originalRequest.headers ?? {};
172
+ originalRequest.headers.Authorization = `Bearer ${newToken}`;
173
+ resolve(instance(originalRequest));
174
+ });
175
+ });
176
+ }
177
+ isRefreshing = true;
178
+ try {
179
+ const newTokens = await requestRefresh(refreshToken);
180
+ tokenAccess.set(newTokens);
181
+ onAuthStateChange?.("authenticated");
182
+ isRefreshing = false;
183
+ notifySubscribers(newTokens.accessToken);
184
+ originalRequest.headers = originalRequest.headers ?? {};
185
+ originalRequest.headers.Authorization = `Bearer ${newTokens.accessToken}`;
186
+ return instance(originalRequest);
187
+ } catch (e) {
188
+ isRefreshing = false;
189
+ notifySubscribers(null);
190
+ clearAuth();
191
+ return Promise.reject(error);
192
+ }
193
+ }
194
+ );
195
+ return {
196
+ axios: instance,
197
+ setToken: (data) => tokenAccess.set(data),
198
+ getToken: () => tokenAccess.get(),
199
+ clearToken: () => clearAuth()
200
+ };
201
+ }
202
+ // Annotate the CommonJS export names for ESM import in node:
203
+ 0 && (module.exports = {
204
+ createAxiosClient
205
+ });