@solapi/ui-kit 1.0.2 → 1.0.4

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,402 @@
1
+ import { useStore as M, create as T } from "zustand";
2
+ import { jsx as b } from "react/jsx-runtime";
3
+ import { createContext as C, useContext as A, useRef as p, useState as k, useEffect as F } from "react";
4
+ import { createStore as R } from "zustand/vanilla";
5
+ function H() {
6
+ return R((r, n) => ({
7
+ items: [],
8
+ showSnackbar: (e, t = "info", o, s) => {
9
+ const a = crypto.randomUUID?.() ?? String(Date.now() + Math.random()), c = o ?? 6e3, i = {
10
+ id: a,
11
+ message: e,
12
+ severity: t,
13
+ autoHideMs: c,
14
+ actions: s
15
+ };
16
+ if (c > 0) {
17
+ const d = window.setTimeout(() => n().hideSnackbar(a), c);
18
+ i.timer = d;
19
+ }
20
+ r({ items: [...n().items, i] });
21
+ },
22
+ hideSnackbar: (e) => {
23
+ const t = n().items.find((o) => o.id === e);
24
+ t?.timer && window.clearTimeout(t.timer), r({ items: n().items.filter((o) => o.id !== e) });
25
+ },
26
+ clear: () => {
27
+ n().items.forEach((e) => e.timer && window.clearTimeout(e.timer)), r({ items: [] });
28
+ }
29
+ }));
30
+ }
31
+ const x = () => `modal_${Date.now()}_${Math.random().toString(36).slice(2, 9)}`;
32
+ function L() {
33
+ return R((r, n) => ({
34
+ modals: [],
35
+ open: ({
36
+ content: e,
37
+ title: t,
38
+ maxWidth: o = "sm",
39
+ fullWidth: s,
40
+ fullHeight: a,
41
+ overrideButton: c,
42
+ customActions: i,
43
+ disableActions: d = !1,
44
+ disableBackdropClick: l = !1,
45
+ disableTransition: u = !1,
46
+ onBeforeClose: m
47
+ }) => new Promise((f, S) => {
48
+ const w = {
49
+ id: x(),
50
+ title: t || "",
51
+ content: e,
52
+ maxWidth: o,
53
+ fullWidth: !!s,
54
+ fullHeight: !!a,
55
+ overrideButton: c,
56
+ customActions: i,
57
+ disableActions: d,
58
+ disableBackdropClick: l,
59
+ disableTransition: u,
60
+ onBeforeClose: m,
61
+ resolve: f,
62
+ reject: S
63
+ };
64
+ r((U) => ({ modals: [...U.modals, w] }));
65
+ }),
66
+ close: (e, t) => {
67
+ const { modals: o } = n(), s = o.find((a) => a.id === e);
68
+ s && (s.resolve(t), r((a) => ({ modals: a.modals.filter((c) => c.id !== e) })));
69
+ },
70
+ closeAll: () => {
71
+ const { modals: e } = n();
72
+ e.forEach((t) => t.reject(new Error("Modal closed"))), r({ modals: [] });
73
+ }
74
+ }));
75
+ }
76
+ const D = () => `confirm_${Date.now()}_${Math.random().toString(36).slice(2, 9)}`;
77
+ function O() {
78
+ return R((r, n) => ({
79
+ confirms: [],
80
+ confirm: ({
81
+ title: e = "확인",
82
+ message: t,
83
+ confirmText: o = "확인",
84
+ cancelText: s = "취소",
85
+ alertMode: a = !1
86
+ }) => new Promise((c, i) => {
87
+ const l = {
88
+ id: D(),
89
+ title: e,
90
+ message: t,
91
+ confirmText: o,
92
+ cancelText: s,
93
+ alertMode: a,
94
+ resolve: c,
95
+ reject: i
96
+ };
97
+ r((u) => ({ confirms: [...u.confirms, l] }));
98
+ }),
99
+ close: (e, t) => {
100
+ const { confirms: o } = n(), s = o.find((a) => a.id === e);
101
+ s && (s.resolve(t), r((a) => ({ confirms: a.confirms.filter((c) => c.id !== e) })));
102
+ },
103
+ closeAll: () => {
104
+ const { confirms: e } = n();
105
+ e.forEach((t) => t.reject(new Error("Confirm closed"))), r({ confirms: [] });
106
+ }
107
+ }));
108
+ }
109
+ const K = {
110
+ mfaConfig: { enable: !0 }
111
+ }, B = () => {
112
+ const r = W(), [n, e] = k(null);
113
+ if (F(() => {
114
+ const o = () => {
115
+ const c = document.querySelector(
116
+ '[role="presentation"] [role="dialog"]'
117
+ )?.parentElement;
118
+ if (c?.closest('[role="presentation"]')) {
119
+ e(c);
120
+ return;
121
+ }
122
+ e(null);
123
+ };
124
+ o();
125
+ const s = new MutationObserver(o);
126
+ return s.observe(document.body, {
127
+ childList: !0,
128
+ subtree: !0,
129
+ attributes: !0,
130
+ attributeFilter: ["role"]
131
+ }), () => s.disconnect();
132
+ }, []), n) return n;
133
+ const t = r.portalContainer?.();
134
+ return t || document.body;
135
+ }, E = C(null), I = C(K);
136
+ let y = null;
137
+ const N = () => y, W = () => A(I), V = ({ children: r, config: n }) => {
138
+ const e = p(null);
139
+ e.current || (e.current = H(), y = e.current);
140
+ const t = p(null);
141
+ t.current || (t.current = L());
142
+ const o = p(null);
143
+ o.current || (o.current = O());
144
+ const s = {
145
+ mfaConfig: {
146
+ enable: n?.mfaConfig?.enable ?? !0,
147
+ popupWidth: n?.mfaConfig?.popupWidth,
148
+ redirectUrl: n?.mfaConfig?.redirectUrl,
149
+ hostWindow: n?.mfaConfig?.hostWindow
150
+ },
151
+ portalContainer: n?.portalContainer,
152
+ baseZIndex: n?.baseZIndex ?? 1300
153
+ };
154
+ return /* @__PURE__ */ b(I.Provider, { value: s, children: /* @__PURE__ */ b(
155
+ E.Provider,
156
+ {
157
+ value: {
158
+ snackbarStore: e.current,
159
+ modalStore: t.current,
160
+ confirmStore: o.current
161
+ },
162
+ children: r
163
+ }
164
+ ) });
165
+ }, q = () => {
166
+ const r = A(E);
167
+ if (!r)
168
+ throw new Error(
169
+ "useUI must be used within <UIProvider> or <GlobalUIProvider>"
170
+ );
171
+ return r;
172
+ }, X = (r) => {
173
+ const { snackbarStore: n } = q();
174
+ return M(n, r);
175
+ }, Y = (r) => {
176
+ const { modalStore: n } = q();
177
+ return M(n, r);
178
+ }, ee = (r) => {
179
+ const { confirmStore: n } = q();
180
+ return M(n, r);
181
+ }, v = T((r, n) => ({
182
+ queue: [],
183
+ isProcessing: !1,
184
+ lastAddedRequest: null,
185
+ lastRemovedRequestId: null,
186
+ enqueue: (e, t = {}) => {
187
+ const o = `req_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`, {
188
+ reason: s = "Unknown",
189
+ mfa: a,
190
+ isNewMfa: c,
191
+ then: i,
192
+ catch: d
193
+ } = t, l = {
194
+ id: o,
195
+ status: "pending",
196
+ config: e,
197
+ reason: s,
198
+ createdAt: Date.now(),
199
+ mfa: a,
200
+ isNewMfa: c,
201
+ then: i,
202
+ catch: d
203
+ };
204
+ return r((u) => ({
205
+ queue: [...u.queue, l],
206
+ lastAddedRequest: l
207
+ })), o;
208
+ },
209
+ dequeue: (e) => {
210
+ const t = n().queue.find((o) => o.id === e);
211
+ t && t.status === "pending" && t.catch?.(new Error("2차 인증이 중단되었습니다.")), r((o) => ({
212
+ queue: o.queue.filter((s) => s.id !== e),
213
+ lastRemovedRequestId: e
214
+ }));
215
+ },
216
+ clearQueue: () => {
217
+ r({ queue: [] });
218
+ },
219
+ updateQueue: (e, t) => {
220
+ r((o) => ({
221
+ queue: o.queue.map((s) => s.id === e ? { ...s, ...t } : s)
222
+ }));
223
+ },
224
+ resolve: (e, t) => {
225
+ const o = n().queue.find((s) => s.id === e);
226
+ o && (r((s) => ({
227
+ queue: s.queue.filter((a) => a.id !== e),
228
+ lastRemovedRequestId: e
229
+ })), o.then?.(t));
230
+ },
231
+ reject: (e, t) => {
232
+ const o = n().queue.find((s) => s.id === e);
233
+ o && (r((s) => ({
234
+ queue: s.queue.filter((a) => a.id !== e),
235
+ lastRemovedRequestId: e
236
+ })), o.catch?.(t));
237
+ },
238
+ getQueueStatus: () => {
239
+ const { queue: e } = n();
240
+ return {
241
+ total: e.length
242
+ };
243
+ },
244
+ getLastAddedRequest: () => {
245
+ const { lastAddedRequest: e } = n();
246
+ return e;
247
+ },
248
+ getLastRemovedRequestId: () => {
249
+ const { lastRemovedRequestId: e } = n();
250
+ return e;
251
+ }
252
+ }));
253
+ function _() {
254
+ const r = N();
255
+ if (!r) return;
256
+ const { showSnackbar: n } = r.getState();
257
+ return {
258
+ success: (e) => n(e, "success"),
259
+ error: (e) => n(e, "error")
260
+ };
261
+ }
262
+ let g = {
263
+ legacyMfaHeaderKey: "x-mfa-data",
264
+ newMfaHeaderKey: "x-auth-flow",
265
+ authTypeLabels: {
266
+ PASSWORD: "비밀번호",
267
+ "KR-ARS": "ARS",
268
+ SMS: "문자",
269
+ "EMAIL-OTP": "이메일",
270
+ HASH: "문자 해시",
271
+ ARS: "ARS",
272
+ "SELF-CERT": "본인인증",
273
+ "MULTI-CERT": "간편인증",
274
+ CERT: "본인인증"
275
+ },
276
+ authTypePriority: [
277
+ "PASSWORD",
278
+ "MULTI-CERT",
279
+ "SELF-CERT",
280
+ "EMAIL-OTP",
281
+ "KR-ARS",
282
+ "SMS",
283
+ "HASH",
284
+ "ARS",
285
+ "CERT"
286
+ ]
287
+ };
288
+ function te(r) {
289
+ g = { ...g, ...r };
290
+ }
291
+ function P() {
292
+ return { ...g };
293
+ }
294
+ function $(r) {
295
+ const e = P().newMfaHeaderKey || "x-auth-flow";
296
+ try {
297
+ const o = r?.response?.headers || {}, s = JSON.parse(o[e] || "{}"), a = s?.allowedAuthTypes || [], c = s.requiredFactors || [], i = s.completedFactors || [], d = c.find(
298
+ (f) => !i.includes(f)
299
+ ), l = {
300
+ ...s,
301
+ allowedAuthTypes: a,
302
+ requiredFactors: c,
303
+ completedFactors: i,
304
+ targetFactor: d
305
+ }, u = r.config, { enqueue: m } = v.getState();
306
+ return new Promise((f, S) => {
307
+ m(u, {
308
+ reason: "New MFA required",
309
+ isNewMfa: !0,
310
+ mfa: l,
311
+ then: f,
312
+ catch: S
313
+ });
314
+ });
315
+ } catch (t) {
316
+ console.error("신규 MFA 처리 실패:", t);
317
+ }
318
+ return !1;
319
+ }
320
+ function j(r) {
321
+ try {
322
+ const n = r?.response, e = n?.data || {}, t = String(n?.status), { mfa: o, errorCode: s } = e;
323
+ if (o && t === "401" && s === "Unauthorized") {
324
+ const a = r.config, { enqueue: c } = v.getState();
325
+ return new Promise((i, d) => {
326
+ c(a, {
327
+ reason: "Legacy MFA required",
328
+ isNewMfa: !1,
329
+ mfa: o,
330
+ then: i,
331
+ catch: d
332
+ });
333
+ });
334
+ }
335
+ } catch (n) {
336
+ console.error("기존 MFA 처리 실패:", n);
337
+ }
338
+ return !1;
339
+ }
340
+ function Q(r) {
341
+ const e = P().newMfaHeaderKey || "x-auth-flow";
342
+ try {
343
+ const t = r?.response, o = t?.headers || {}, s = t?.data?.errorCode, a = String(t?.status);
344
+ return o?.[e] && a === "401" && s === "Unauthorized" ? $(r) : j(r);
345
+ } catch (t) {
346
+ console.error("MFA 처리 실패:", t);
347
+ }
348
+ return !1;
349
+ }
350
+ function re(r = {}, n) {
351
+ const {
352
+ enableAlert: e = !0,
353
+ successMessage: t,
354
+ errorMessage: o,
355
+ onSuccess: s,
356
+ onError: a,
357
+ mutationFn: c,
358
+ snackbar: i,
359
+ ...d
360
+ } = r, l = n || i || _();
361
+ return {
362
+ ...d,
363
+ mutationFn: async (u, m) => {
364
+ const f = c || (() => Promise.resolve(void 0));
365
+ let S;
366
+ try {
367
+ S = await f(u, m);
368
+ } catch (h) {
369
+ const w = await Q(h);
370
+ if (w === !1)
371
+ throw h;
372
+ S = w;
373
+ }
374
+ return S;
375
+ },
376
+ onSuccess: async (u, m, f) => {
377
+ e && t && l && l.success(t), s && await s(u, m, f);
378
+ },
379
+ onError: async (u, m, f) => {
380
+ if (e && l) {
381
+ const S = u?.response?.data?.errorMessage, h = o || S || u?.message || "요청 처리 중 오류가 발생했습니다.";
382
+ l.error(h);
383
+ }
384
+ a && await a(u, m, f);
385
+ }
386
+ };
387
+ }
388
+ export {
389
+ V as U,
390
+ B as a,
391
+ Y as b,
392
+ W as c,
393
+ ee as d,
394
+ re as e,
395
+ te as f,
396
+ P as g,
397
+ Q as h,
398
+ v as i,
399
+ $ as j,
400
+ j as k,
401
+ X as u
402
+ };
@@ -0,0 +1 @@
1
+ "use strict";const g=require("zustand"),I=require("react/jsx-runtime"),h=require("react"),q=require("zustand/vanilla");function F(){return q.createStore((r,n)=>({items:[],showSnackbar:(e,t="info",o,s)=>{const a=crypto.randomUUID?.()??String(Date.now()+Math.random()),c=o??6e3,u={id:a,message:e,severity:t,autoHideMs:c,actions:s};if(c>0){const d=window.setTimeout(()=>n().hideSnackbar(a),c);u.timer=d}r({items:[...n().items,u]})},hideSnackbar:e=>{const t=n().items.find(o=>o.id===e);t?.timer&&window.clearTimeout(t.timer),r({items:n().items.filter(o=>o.id!==e)})},clear:()=>{n().items.forEach(e=>e.timer&&window.clearTimeout(e.timer)),r({items:[]})}}))}const x=()=>`modal_${Date.now()}_${Math.random().toString(36).slice(2,9)}`;function H(){return q.createStore((r,n)=>({modals:[],open:({content:e,title:t,maxWidth:o="sm",fullWidth:s,fullHeight:a,overrideButton:c,customActions:u,disableActions:d=!1,disableBackdropClick:l=!1,disableTransition:i=!1,onBeforeClose:m})=>new Promise((f,S)=>{const M={id:x(),title:t||"",content:e,maxWidth:o,fullWidth:!!s,fullHeight:!!a,overrideButton:c,customActions:u,disableActions:d,disableBackdropClick:l,disableTransition:i,onBeforeClose:m,resolve:f,reject:S};r(k=>({modals:[...k.modals,M]}))}),close:(e,t)=>{const{modals:o}=n(),s=o.find(a=>a.id===e);s&&(s.resolve(t),r(a=>({modals:a.modals.filter(c=>c.id!==e)})))},closeAll:()=>{const{modals:e}=n();e.forEach(t=>t.reject(new Error("Modal closed"))),r({modals:[]})}}))}const L=()=>`confirm_${Date.now()}_${Math.random().toString(36).slice(2,9)}`;function D(){return q.createStore((r,n)=>({confirms:[],confirm:({title:e="확인",message:t,confirmText:o="확인",cancelText:s="취소",alertMode:a=!1})=>new Promise((c,u)=>{const l={id:L(),title:e,message:t,confirmText:o,cancelText:s,alertMode:a,resolve:c,reject:u};r(i=>({confirms:[...i.confirms,l]}))}),close:(e,t)=>{const{confirms:o}=n(),s=o.find(a=>a.id===e);s&&(s.resolve(t),r(a=>({confirms:a.confirms.filter(c=>c.id!==e)})))},closeAll:()=>{const{confirms:e}=n();e.forEach(t=>t.reject(new Error("Confirm closed"))),r({confirms:[]})}}))}const N={mfaConfig:{enable:!0}},O=()=>{const r=v(),[n,e]=h.useState(null);if(h.useEffect(()=>{const o=()=>{const c=document.querySelector('[role="presentation"] [role="dialog"]')?.parentElement;if(c?.closest('[role="presentation"]')){e(c);return}e(null)};o();const s=new MutationObserver(o);return s.observe(document.body,{childList:!0,subtree:!0,attributes:!0,attributeFilter:["role"]}),()=>s.disconnect()},[]),n)return n;const t=r.portalContainer?.();return t||document.body},A=h.createContext(null),E=h.createContext(N);let y=null;const K=()=>y,v=()=>h.useContext(E),W=({children:r,config:n})=>{const e=h.useRef(null);e.current||(e.current=F(),y=e.current);const t=h.useRef(null);t.current||(t.current=H());const o=h.useRef(null);o.current||(o.current=D());const s={mfaConfig:{enable:n?.mfaConfig?.enable??!0,popupWidth:n?.mfaConfig?.popupWidth,redirectUrl:n?.mfaConfig?.redirectUrl,hostWindow:n?.mfaConfig?.hostWindow},portalContainer:n?.portalContainer,baseZIndex:n?.baseZIndex??1300};return I.jsx(E.Provider,{value:s,children:I.jsx(A.Provider,{value:{snackbarStore:e.current,modalStore:t.current,confirmStore:o.current},children:r})})},p=()=>{const r=h.useContext(A);if(!r)throw new Error("useUI must be used within <UIProvider> or <GlobalUIProvider>");return r},_=r=>{const{snackbarStore:n}=p();return g.useStore(n,r)},$=r=>{const{modalStore:n}=p();return g.useStore(n,r)},j=r=>{const{confirmStore:n}=p();return g.useStore(n,r)},C=g.create((r,n)=>({queue:[],isProcessing:!1,lastAddedRequest:null,lastRemovedRequestId:null,enqueue:(e,t={})=>{const o=`req_${Date.now()}_${Math.random().toString(36).substr(2,9)}`,{reason:s="Unknown",mfa:a,isNewMfa:c,then:u,catch:d}=t,l={id:o,status:"pending",config:e,reason:s,createdAt:Date.now(),mfa:a,isNewMfa:c,then:u,catch:d};return r(i=>({queue:[...i.queue,l],lastAddedRequest:l})),o},dequeue:e=>{const t=n().queue.find(o=>o.id===e);t&&t.status==="pending"&&t.catch?.(new Error("2차 인증이 중단되었습니다.")),r(o=>({queue:o.queue.filter(s=>s.id!==e),lastRemovedRequestId:e}))},clearQueue:()=>{r({queue:[]})},updateQueue:(e,t)=>{r(o=>({queue:o.queue.map(s=>s.id===e?{...s,...t}:s)}))},resolve:(e,t)=>{const o=n().queue.find(s=>s.id===e);o&&(r(s=>({queue:s.queue.filter(a=>a.id!==e),lastRemovedRequestId:e})),o.then?.(t))},reject:(e,t)=>{const o=n().queue.find(s=>s.id===e);o&&(r(s=>({queue:s.queue.filter(a=>a.id!==e),lastRemovedRequestId:e})),o.catch?.(t))},getQueueStatus:()=>{const{queue:e}=n();return{total:e.length}},getLastAddedRequest:()=>{const{lastAddedRequest:e}=n();return e},getLastRemovedRequestId:()=>{const{lastRemovedRequestId:e}=n();return e}}));function Q(){const r=K();if(!r)return;const{showSnackbar:n}=r.getState();return{success:e=>n(e,"success"),error:e=>n(e,"error")}}let R={legacyMfaHeaderKey:"x-mfa-data",newMfaHeaderKey:"x-auth-flow",authTypeLabels:{PASSWORD:"비밀번호","KR-ARS":"ARS",SMS:"문자","EMAIL-OTP":"이메일",HASH:"문자 해시",ARS:"ARS","SELF-CERT":"본인인증","MULTI-CERT":"간편인증",CERT:"본인인증"},authTypePriority:["PASSWORD","MULTI-CERT","SELF-CERT","EMAIL-OTP","KR-ARS","SMS","HASH","ARS","CERT"]};function z(r){R={...R,...r}}function b(){return{...R}}function P(r){const e=b().newMfaHeaderKey||"x-auth-flow";try{const o=r?.response?.headers||{},s=JSON.parse(o[e]||"{}"),a=s?.allowedAuthTypes||[],c=s.requiredFactors||[],u=s.completedFactors||[],d=c.find(f=>!u.includes(f)),l={...s,allowedAuthTypes:a,requiredFactors:c,completedFactors:u,targetFactor:d},i=r.config,{enqueue:m}=C.getState();return new Promise((f,S)=>{m(i,{reason:"New MFA required",isNewMfa:!0,mfa:l,then:f,catch:S})})}catch(t){console.error("신규 MFA 처리 실패:",t)}return!1}function U(r){try{const n=r?.response,e=n?.data||{},t=String(n?.status),{mfa:o,errorCode:s}=e;if(o&&t==="401"&&s==="Unauthorized"){const a=r.config,{enqueue:c}=C.getState();return new Promise((u,d)=>{c(a,{reason:"Legacy MFA required",isNewMfa:!1,mfa:o,then:u,catch:d})})}}catch(n){console.error("기존 MFA 처리 실패:",n)}return!1}function T(r){const e=b().newMfaHeaderKey||"x-auth-flow";try{const t=r?.response,o=t?.headers||{},s=t?.data?.errorCode,a=String(t?.status);return o?.[e]&&a==="401"&&s==="Unauthorized"?P(r):U(r)}catch(t){console.error("MFA 처리 실패:",t)}return!1}function Z(r={},n){const{enableAlert:e=!0,successMessage:t,errorMessage:o,onSuccess:s,onError:a,mutationFn:c,snackbar:u,...d}=r,l=n||u||Q();return{...d,mutationFn:async(i,m)=>{const f=c||(()=>Promise.resolve(void 0));let S;try{S=await f(i,m)}catch(w){const M=await T(w);if(M===!1)throw w;S=M}return S},onSuccess:async(i,m,f)=>{e&&t&&l&&l.success(t),s&&await s(i,m,f)},onError:async(i,m,f)=>{if(e&&l){const S=i?.response?.data?.errorMessage,w=o||S||i?.message||"요청 처리 중 오류가 발생했습니다.";l.error(w)}a&&await a(i,m,f)}}}exports.UIProvider=W;exports.configureMfa=z;exports.createMutationConfig=Z;exports.getMfaSettings=b;exports.handleLegacyMfa=U;exports.handleMfa=T;exports.handleNewMfa=P;exports.useConfirmSelector=j;exports.useModalSelector=$;exports.usePortalContainer=O;exports.useRequestQueueStore=C;exports.useSnackbarSelector=_;exports.useUIConfig=v;
@@ -1 +1 @@
1
- "use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const E=require("zustand"),R=E.create((a,r)=>({queue:[],isProcessing:!1,lastAddedRequest:null,lastRemovedRequestId:null,enqueue:(e,s={})=>{const n=`req_${Date.now()}_${Math.random().toString(36).substr(2,9)}`,{reason:t="Unknown",mfa:o,isNewMfa:c,then:f,catch:l}=s,i={id:n,status:"pending",config:e,reason:t,createdAt:Date.now(),mfa:o,isNewMfa:c,then:f,catch:l};return a(u=>({queue:[...u.queue,i],lastAddedRequest:i})),n},dequeue:e=>{const s=r().queue.find(n=>n.id===e);s&&s.status==="pending"&&s.catch?.(new Error("2차 인증이 중단되었습니다.")),a(n=>({queue:n.queue.filter(t=>t.id!==e),lastRemovedRequestId:e}))},clearQueue:()=>{a({queue:[]})},updateQueue:(e,s)=>{a(n=>({queue:n.queue.map(t=>t.id===e?{...t,...s}:t)}))},resolve:(e,s)=>{const n=r().queue.find(t=>t.id===e);n&&(a(t=>({queue:t.queue.filter(o=>o.id!==e),lastRemovedRequestId:e})),n.then?.(s))},reject:(e,s)=>{const n=r().queue.find(t=>t.id===e);n&&(a(t=>({queue:t.queue.filter(o=>o.id!==e),lastRemovedRequestId:e})),n.catch?.(s))},getQueueStatus:()=>{const{queue:e}=r();return{total:e.length}},getLastAddedRequest:()=>{const{lastAddedRequest:e}=r();return e},getLastRemovedRequestId:()=>{const{lastRemovedRequestId:e}=r();return e}}));let h={legacyMfaHeaderKey:"x-mfa-data",newMfaHeaderKey:"x-auth-flow",authTypeLabels:{PASSWORD:"비밀번호","KR-ARS":"ARS",SMS:"문자","EMAIL-OTP":"이메일",HASH:"문자 해시",ARS:"ARS","SELF-CERT":"본인인증","MULTI-CERT":"간편인증",CERT:"본인인증"},authTypePriority:["PASSWORD","MULTI-CERT","SELF-CERT","EMAIL-OTP","KR-ARS","SMS","HASH","ARS","CERT"]};function F(a){h={...h,...a}}function S(){return{...h}}function w(a){const e=S().newMfaHeaderKey||"x-auth-flow";try{const n=a?.response?.headers||{},t=JSON.parse(n[e]||"{}"),o=t?.allowedAuthTypes||[],c=t.requiredFactors||[],f=t.completedFactors||[],l=c.find(d=>!f.includes(d)),i={...t,allowedAuthTypes:o,requiredFactors:c,completedFactors:f,targetFactor:l},u=a.config,{enqueue:M}=R.getState();return new Promise((d,q)=>{M(u,{reason:"New MFA required",isNewMfa:!0,mfa:i,then:d,catch:q})})}catch(s){console.error("신규 MFA 처리 실패:",s)}return!1}function p(a){try{const r=a?.response,e=r?.data||{},s=String(r?.status),{mfa:n,errorCode:t}=e;if(n&&s==="401"&&t==="Unauthorized"){const o=a.config,{enqueue:c}=R.getState();return new Promise((f,l)=>{c(o,{reason:"Legacy MFA required",isNewMfa:!1,mfa:n,then:f,catch:l})})}}catch(r){console.error("기존 MFA 처리 실패:",r)}return!1}function A(a){const e=S().newMfaHeaderKey||"x-auth-flow";try{const s=a?.response,n=s?.headers||{},t=s?.data?.errorCode,o=String(s?.status);return n?.[e]&&o==="401"&&t==="Unauthorized"?w(a):p(a)}catch(s){console.error("MFA 처리 실패:",s)}return!1}function y(a={},r){const{enableAlert:e=!0,successMessage:s,errorMessage:n,onSuccess:t,onError:o,mutationFn:c,snackbar:f,...l}=a,i=r||f;return{...l,mutationFn:async(u,M)=>{const d=c||(()=>Promise.resolve(void 0));let q;try{q=await d(u,M)}catch(g){const m=await A(g);if(m===!1)throw g;q=m}return q},onSuccess:async(u,M,d)=>{e&&s&&i&&i.success(s),t&&await t(u,M,d)},onError:async(u,M,d)=>{if(e&&i){const q=u?.response?.data?.errorMessage,g=n||q||u?.message||"요청 처리 중 오류가 발생했습니다.";i.error(g)}o&&await o(u,M,d)}}}exports.configureMfa=F;exports.createMutationConfig=y;exports.default=y;exports.getMfaSettings=S;exports.handleLegacyMfa=p;exports.handleMfa=A;exports.handleNewMfa=w;exports.useRequestQueueStore=R;
1
+ "use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const e=require("./createMutationConfig-fwPFxVVI.cjs");exports.configureMfa=e.configureMfa;exports.createMutationConfig=e.createMutationConfig;exports.default=e.createMutationConfig;exports.getMfaSettings=e.getMfaSettings;exports.handleLegacyMfa=e.handleLegacyMfa;exports.handleMfa=e.handleMfa;exports.handleNewMfa=e.handleNewMfa;exports.useRequestQueueStore=e.useRequestQueueStore;
@@ -1,209 +1,11 @@
1
- import { create as w } from "zustand";
2
- const S = w((a, r) => ({
3
- queue: [],
4
- isProcessing: !1,
5
- lastAddedRequest: null,
6
- lastRemovedRequestId: null,
7
- enqueue: (e, s = {}) => {
8
- const n = `req_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`, {
9
- reason: t = "Unknown",
10
- mfa: o,
11
- isNewMfa: c,
12
- then: f,
13
- catch: l
14
- } = s, i = {
15
- id: n,
16
- status: "pending",
17
- config: e,
18
- reason: t,
19
- createdAt: Date.now(),
20
- mfa: o,
21
- isNewMfa: c,
22
- then: f,
23
- catch: l
24
- };
25
- return a((u) => ({
26
- queue: [...u.queue, i],
27
- lastAddedRequest: i
28
- })), n;
29
- },
30
- dequeue: (e) => {
31
- const s = r().queue.find((n) => n.id === e);
32
- s && s.status === "pending" && s.catch?.(new Error("2차 인증이 중단되었습니다.")), a((n) => ({
33
- queue: n.queue.filter((t) => t.id !== e),
34
- lastRemovedRequestId: e
35
- }));
36
- },
37
- clearQueue: () => {
38
- a({ queue: [] });
39
- },
40
- updateQueue: (e, s) => {
41
- a((n) => ({
42
- queue: n.queue.map((t) => t.id === e ? { ...t, ...s } : t)
43
- }));
44
- },
45
- resolve: (e, s) => {
46
- const n = r().queue.find((t) => t.id === e);
47
- n && (a((t) => ({
48
- queue: t.queue.filter((o) => o.id !== e),
49
- lastRemovedRequestId: e
50
- })), n.then?.(s));
51
- },
52
- reject: (e, s) => {
53
- const n = r().queue.find((t) => t.id === e);
54
- n && (a((t) => ({
55
- queue: t.queue.filter((o) => o.id !== e),
56
- lastRemovedRequestId: e
57
- })), n.catch?.(s));
58
- },
59
- getQueueStatus: () => {
60
- const { queue: e } = r();
61
- return {
62
- total: e.length
63
- };
64
- },
65
- getLastAddedRequest: () => {
66
- const { lastAddedRequest: e } = r();
67
- return e;
68
- },
69
- getLastRemovedRequestId: () => {
70
- const { lastRemovedRequestId: e } = r();
71
- return e;
72
- }
73
- }));
74
- let M = {
75
- legacyMfaHeaderKey: "x-mfa-data",
76
- newMfaHeaderKey: "x-auth-flow",
77
- authTypeLabels: {
78
- PASSWORD: "비밀번호",
79
- "KR-ARS": "ARS",
80
- SMS: "문자",
81
- "EMAIL-OTP": "이메일",
82
- HASH: "문자 해시",
83
- ARS: "ARS",
84
- "SELF-CERT": "본인인증",
85
- "MULTI-CERT": "간편인증",
86
- CERT: "본인인증"
87
- },
88
- authTypePriority: [
89
- "PASSWORD",
90
- "MULTI-CERT",
91
- "SELF-CERT",
92
- "EMAIL-OTP",
93
- "KR-ARS",
94
- "SMS",
95
- "HASH",
96
- "ARS",
97
- "CERT"
98
- ]
99
- };
100
- function F(a) {
101
- M = { ...M, ...a };
102
- }
103
- function g() {
104
- return { ...M };
105
- }
106
- function p(a) {
107
- const e = g().newMfaHeaderKey || "x-auth-flow";
108
- try {
109
- const n = a?.response?.headers || {}, t = JSON.parse(n[e] || "{}"), o = t?.allowedAuthTypes || [], c = t.requiredFactors || [], f = t.completedFactors || [], l = c.find(
110
- (d) => !f.includes(d)
111
- ), i = {
112
- ...t,
113
- allowedAuthTypes: o,
114
- requiredFactors: c,
115
- completedFactors: f,
116
- targetFactor: l
117
- }, u = a.config, { enqueue: q } = S.getState();
118
- return new Promise((d, R) => {
119
- q(u, {
120
- reason: "New MFA required",
121
- isNewMfa: !0,
122
- mfa: i,
123
- then: d,
124
- catch: R
125
- });
126
- });
127
- } catch (s) {
128
- console.error("신규 MFA 처리 실패:", s);
129
- }
130
- return !1;
131
- }
132
- function A(a) {
133
- try {
134
- const r = a?.response, e = r?.data || {}, s = String(r?.status), { mfa: n, errorCode: t } = e;
135
- if (n && s === "401" && t === "Unauthorized") {
136
- const o = a.config, { enqueue: c } = S.getState();
137
- return new Promise((f, l) => {
138
- c(o, {
139
- reason: "Legacy MFA required",
140
- isNewMfa: !1,
141
- mfa: n,
142
- then: f,
143
- catch: l
144
- });
145
- });
146
- }
147
- } catch (r) {
148
- console.error("기존 MFA 처리 실패:", r);
149
- }
150
- return !1;
151
- }
152
- function y(a) {
153
- const e = g().newMfaHeaderKey || "x-auth-flow";
154
- try {
155
- const s = a?.response, n = s?.headers || {}, t = s?.data?.errorCode, o = String(s?.status);
156
- return n?.[e] && o === "401" && t === "Unauthorized" ? p(a) : A(a);
157
- } catch (s) {
158
- console.error("MFA 처리 실패:", s);
159
- }
160
- return !1;
161
- }
162
- function T(a = {}, r) {
163
- const {
164
- enableAlert: e = !0,
165
- successMessage: s,
166
- errorMessage: n,
167
- onSuccess: t,
168
- onError: o,
169
- mutationFn: c,
170
- snackbar: f,
171
- ...l
172
- } = a, i = r || f;
173
- return {
174
- ...l,
175
- mutationFn: async (u, q) => {
176
- const d = c || (() => Promise.resolve(void 0));
177
- let R;
178
- try {
179
- R = await d(u, q);
180
- } catch (h) {
181
- const m = await y(h);
182
- if (m === !1)
183
- throw h;
184
- R = m;
185
- }
186
- return R;
187
- },
188
- onSuccess: async (u, q, d) => {
189
- e && s && i && i.success(s), t && await t(u, q, d);
190
- },
191
- onError: async (u, q, d) => {
192
- if (e && i) {
193
- const R = u?.response?.data?.errorMessage, h = n || R || u?.message || "요청 처리 중 오류가 발생했습니다.";
194
- i.error(h);
195
- }
196
- o && await o(u, q, d);
197
- }
198
- };
199
- }
1
+ import { f as s, e as f, e as t, g as n, k as u, h as g, j as o, i as M } from "./createMutationConfig-CwzGbAzV.js";
200
2
  export {
201
- F as configureMfa,
202
- T as createMutationConfig,
203
- T as default,
204
- g as getMfaSettings,
205
- A as handleLegacyMfa,
206
- y as handleMfa,
207
- p as handleNewMfa,
208
- S as useRequestQueueStore
3
+ s as configureMfa,
4
+ f as createMutationConfig,
5
+ t as default,
6
+ n as getMfaSettings,
7
+ u as handleLegacyMfa,
8
+ g as handleMfa,
9
+ o as handleNewMfa,
10
+ M as useRequestQueueStore
209
11
  };
@@ -28,6 +28,7 @@ export type UIConfig = {
28
28
  * 그 안에 렌더링하여 focus 호환성을 확보
29
29
  */
30
30
  export declare const usePortalContainer: () => HTMLElement;
31
+ export declare const getSnackbarStore: () => StoreApi<SnackbarState> | null;
31
32
  export declare const useUIConfig: () => UIConfig;
32
33
  interface UIProviderProps {
33
34
  children: React.ReactNode;
@@ -10,5 +10,5 @@ export { default as ListFilter } from 'components/ListFilter';
10
10
  export { default as TextInput } from 'components/TextInput';
11
11
  export { DatePicker } from 'components/DatePicker';
12
12
  export { type Theme, type ThemeMode, type ThemeConfig, type ThemeColors, type ThemeSpacing, type ThemeTypography, type ThemeBorderRadius, type ThemeShadows, type ThemeTransition, type ThemeBreakpoints, defaultTheme, lightColors, darkColors, ThemeProvider, useTheme, useThemeOptional, getCSSVariable, setCSSVariable, getThemeColor, getThemeSpacing, getThemeFontSize, getThemeBorderRadius, getThemeShadow, createTransition, mediaQuery, withAlpha, spacing } from 'theme/index';
13
- export { default as createMutationConfig } from 'lib/createMutationConfig';
13
+ export { default as createMutationConfig, configureMfa, getMfaSettings, useRequestQueueStore } from 'lib/createMutationConfig';
14
14
  export { Box, Stack, Grid, Typography, Button, Divider, Collapse, Paper, IconButton } from 'components/common';