entity-client 1.0.21 → 1.0.22
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +362 -362
- package/dist/EntityAppServerApi.d.ts +16 -32
- package/dist/EntityAppServerApi.js.map +1 -1
- package/dist/EntityServerApi.d.ts +8 -16
- package/dist/EntityServerApi.js.map +1 -1
- package/dist/client/base.d.ts +1 -4
- package/dist/client/base.js +1 -1
- package/dist/client/base.js.map +3 -3
- package/dist/client/hmac.js.map +1 -1
- package/dist/client/packet.js.map +1 -1
- package/dist/client/request.js.map +1 -1
- package/dist/client/utils.js.map +1 -1
- package/dist/hooks/useEntityAppServer.js.map +1 -1
- package/dist/hooks/useEntityClient.js.map +1 -1
- package/dist/hooks/useEntityServer.js.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +3 -3
- package/dist/mixins/app/index.js.map +1 -1
- package/dist/mixins/app/plugins/alimtalk.d.ts +1 -2
- package/dist/mixins/app/plugins/alimtalk.js.map +1 -1
- package/dist/mixins/app/plugins/friendtalk.d.ts +1 -2
- package/dist/mixins/app/plugins/friendtalk.js.map +1 -1
- package/dist/mixins/app/plugins/holidays.d.ts +1 -2
- package/dist/mixins/app/plugins/holidays.js.map +1 -1
- package/dist/mixins/app/plugins/identity.d.ts +1 -2
- package/dist/mixins/app/plugins/identity.js.map +1 -1
- package/dist/mixins/app/plugins/index.js.map +1 -1
- package/dist/mixins/app/plugins/llm.d.ts +1 -2
- package/dist/mixins/app/plugins/llm.js.map +1 -1
- package/dist/mixins/app/plugins/ocr.d.ts +1 -2
- package/dist/mixins/app/plugins/ocr.js.map +1 -1
- package/dist/mixins/app/plugins/pg.d.ts +1 -2
- package/dist/mixins/app/plugins/pg.js.map +1 -1
- package/dist/mixins/app/plugins/push.d.ts +1 -2
- package/dist/mixins/app/plugins/push.js.map +1 -1
- package/dist/mixins/app/plugins/sms.d.ts +1 -2
- package/dist/mixins/app/plugins/sms.js.map +1 -1
- package/dist/mixins/app/plugins/taxinvoice.d.ts +1 -2
- package/dist/mixins/app/plugins/taxinvoice.js.map +1 -1
- package/dist/mixins/app/routes/account.d.ts +1 -2
- package/dist/mixins/app/routes/account.js.map +1 -1
- package/dist/mixins/app/routes/board.d.ts +1 -2
- package/dist/mixins/app/routes/board.js.map +1 -1
- package/dist/mixins/app/routes/email-verify.d.ts +1 -2
- package/dist/mixins/app/routes/email-verify.js.map +1 -1
- package/dist/mixins/app/routes/oauth.d.ts +1 -2
- package/dist/mixins/app/routes/oauth.js.map +1 -1
- package/dist/mixins/app/routes/password-reset.d.ts +1 -2
- package/dist/mixins/app/routes/password-reset.js.map +1 -1
- package/dist/mixins/app/routes/two-factor.d.ts +1 -2
- package/dist/mixins/app/routes/two-factor.js.map +1 -1
- package/dist/mixins/server/admin.d.ts +1 -2
- package/dist/mixins/server/admin.js.map +1 -1
- package/dist/mixins/server/auth.d.ts +1 -3
- package/dist/mixins/server/auth.js +1 -1
- package/dist/mixins/server/auth.js.map +3 -3
- package/dist/mixins/server/entity.d.ts +1 -2
- package/dist/mixins/server/entity.js.map +1 -1
- package/dist/mixins/server/file.d.ts +1 -2
- package/dist/mixins/server/file.js.map +1 -1
- package/dist/mixins/server/index.js.map +1 -1
- package/dist/mixins/server/push.d.ts +1 -2
- package/dist/mixins/server/push.js.map +1 -1
- package/dist/mixins/server/smtp.d.ts +1 -2
- package/dist/mixins/server/smtp.js.map +1 -1
- package/dist/mixins/server/transaction.d.ts +1 -2
- package/dist/mixins/server/transaction.js.map +1 -1
- package/dist/mixins/server/utils.d.ts +1 -2
- package/dist/mixins/server/utils.js.map +1 -1
- package/dist/packet.js.map +1 -1
- package/dist/react.js +1 -1
- package/dist/react.js.map +3 -3
- package/package.json +57 -57
package/dist/client/base.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/client/base.ts"],
|
|
4
|
-
"sourcesContent": ["import type {\r\n EntityServerClientOptions,\r\n RealtimeClientOptions,\r\n RealtimeConnectionStatus,\r\n RealtimeEnvelope,\r\n RealtimeMessageListener,\r\n RealtimeStatusListener,\r\n} from \"../types.js\";\r\nimport { readEnv } from \"./utils.js\";\r\nimport { derivePacketKey, parseRequestBody } from \"./packet.js\";\r\nimport {\r\n entityRequest,\r\n type EntityRequestConfig,\r\n type RequestOptions,\r\n} from \"./request.js\";\r\n\r\nconst REALTIME_DEFAULT_PATH = \"/v1/realtime\";\r\n\r\n// mixin \uD5EC\uD37C \uD0C0\uC785\r\nexport type GConstructor<T = object> = new (...args: any[]) => T;\r\n\r\nexport class EntityServerClientBase {\r\n baseUrl: string;\r\n token: string;\r\n anonymousPacketToken: string;\r\n apiKey: string;\r\n hmacSecret: string;\r\n encryptRequests: boolean;\r\n csrfEnabled: boolean;\r\n csrfHeaderName: string;\r\n csrfCookieName: string;\r\n /** @internal health \uC7AC\uD638\uCD9C\uB85C CSRF \uCFE0\uD0A4 \uAC31\uC2E0 (AuthMixin\uC5D0\uC11C \uC124\uC815) */\r\n csrfRefresher: (() => Promise<void>) | null = null;\r\n activeTxId: string | null = null;\r\n\r\n // \uC138\uC158 \uC720\uC9C0 \uAD00\uB828\r\n keepSession: boolean;\r\n refreshBuffer: number;\r\n onTokenRefreshed?: (accessToken: string, expiresIn: number) => void;\r\n onSessionExpired?: (error: Error) => void;\r\n onHealthChange?: (online: boolean) => void;\r\n sessionRefreshToken: string | null = null;\r\n refreshTimer: ReturnType<typeof setTimeout> | null = null;\r\n healthTickTimer: ReturnType<typeof setInterval> | null = null;\r\n healthTickPromise: Promise<unknown> | null = null;\r\n realtimeEnabled: boolean;\r\n realtimePath: string;\r\n realtimeAutoConnect: boolean;\r\n realtimeAutoReconnect: boolean;\r\n realtimeReconnectDelayMs: number;\r\n realtimeStatus: RealtimeConnectionStatus;\r\n realtimeSocket: WebSocket | null = null;\r\n realtimeConnectPromise: Promise<void> | null = null;\r\n realtimeReconnectTimer: ReturnType<typeof setTimeout> | null = null;\r\n realtimeShouldReconnect = false;\r\n realtimeMessageListeners = new Set<RealtimeMessageListener>();\r\n realtimeStatusListeners = new Set<RealtimeStatusListener>();\r\n realtimeEventListeners = new Map<string, Set<RealtimeMessageListener>>();\r\n // \u2500\u2500\u2500 \uCD08\uAE30\uD654 & \uC124\uC815 \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\r\n\r\n /**\r\n * EntityServerClient \uC778\uC2A4\uD134\uC2A4\uB97C \uC0DD\uC131\uD569\uB2C8\uB2E4.\r\n *\r\n * \uAE30\uBCF8\uAC12:\r\n * - `baseUrl`: `VITE_ENTITY_SERVER_URL` \uB610\uB294 \uC0C1\uB300 \uACBD\uB85C(`\"\"`)\r\n */\r\n constructor(options: EntityServerClientOptions = {}) {\r\n const envBaseUrl = readEnv(\"VITE_ENTITY_SERVER_URL\");\r\n\r\n this.baseUrl = (options.baseUrl ?? envBaseUrl ?? \"\").replace(/\\/$/, \"\");\r\n this.token = options.token ?? \"\";\r\n this.anonymousPacketToken = options.anonymousPacketToken ?? \"\";\r\n this.apiKey = options.apiKey ?? \"\";\r\n this.hmacSecret = options.hmacSecret ?? \"\";\r\n this.encryptRequests = options.encryptRequests ?? false;\r\n this.csrfEnabled = options.csrfEnabled ?? false;\r\n this.csrfHeaderName = options.csrfHeaderName ?? \"x-csrf-token\";\r\n this.csrfCookieName = options.csrfCookieName ?? \"_csrf\";\r\n this.keepSession = options.keepSession ?? false;\r\n this.refreshBuffer = options.refreshBuffer ?? 60;\r\n this.onTokenRefreshed = options.onTokenRefreshed;\r\n this.onSessionExpired = options.onSessionExpired;\r\n this.onHealthChange = options.onHealthChange;\r\n this.realtimeEnabled = false;\r\n this.realtimePath = REALTIME_DEFAULT_PATH;\r\n this.realtimeAutoConnect = true;\r\n this.realtimeAutoReconnect = true;\r\n this.realtimeReconnectDelayMs = 3000;\r\n this.realtimeStatus = \"idle\";\r\n this.applyRealtimeOptions(options.realtime);\r\n if (\r\n typeof options.healthTickInterval === \"number\" &&\r\n options.healthTickInterval > 0\r\n ) {\r\n // csrfRefresher\uB294 AuthMixin\uC5D0\uC11C \uC124\uC815\uB418\uBBC0\uB85C \uB2E4\uC74C tick\uC5D0 \uC2DC\uC791\r\n Promise.resolve().then(() =>\r\n this.startHealthTick(options.healthTickInterval, false),\r\n );\r\n }\r\n }\r\n\r\n /** baseUrl, token, encryptRequests \uAC12\uC744 \uB7F0\uD0C0\uC784\uC5D0 \uAC31\uC2E0\uD569\uB2C8\uB2E4. */\r\n configure(options: Partial<EntityServerClientOptions>): void {\r\n if (typeof options.baseUrl === \"string\") {\r\n this.baseUrl = options.baseUrl.replace(/\\/$/, \"\");\r\n }\r\n if (typeof options.token === \"string\") this.token = options.token;\r\n if (typeof options.anonymousPacketToken === \"string\") {\r\n this.anonymousPacketToken = options.anonymousPacketToken;\r\n }\r\n if (typeof options.encryptRequests === \"boolean\")\r\n this.encryptRequests = options.encryptRequests;\r\n if (typeof options.csrfEnabled === \"boolean\") {\r\n this.csrfEnabled = options.csrfEnabled;\r\n }\r\n if (typeof options.csrfHeaderName === \"string\") {\r\n this.csrfHeaderName = options.csrfHeaderName;\r\n }\r\n if (typeof options.csrfCookieName === \"string\") {\r\n this.csrfCookieName = options.csrfCookieName;\r\n }\r\n if (typeof options.apiKey === \"string\") this.apiKey = options.apiKey;\r\n if (typeof options.hmacSecret === \"string\")\r\n this.hmacSecret = options.hmacSecret;\r\n if (typeof options.keepSession === \"boolean\")\r\n this.keepSession = options.keepSession;\r\n if (typeof options.refreshBuffer === \"number\")\r\n this.refreshBuffer = options.refreshBuffer;\r\n if (options.onTokenRefreshed)\r\n this.onTokenRefreshed = options.onTokenRefreshed;\r\n if (options.onSessionExpired)\r\n this.onSessionExpired = options.onSessionExpired;\r\n if (options.onHealthChange)\r\n this.onHealthChange = options.onHealthChange;\r\n if (typeof options.realtime !== \"undefined\") {\r\n this.applyRealtimeOptions(options.realtime);\r\n }\r\n if (\r\n typeof options.healthTickInterval === \"number\" &&\r\n options.healthTickInterval > 0\r\n ) {\r\n Promise.resolve().then(() =>\r\n this.startHealthTick(options.healthTickInterval, false),\r\n );\r\n }\r\n }\r\n\r\n /** \uC778\uC99D \uC694\uCCAD\uC5D0 \uC0AC\uC6A9\uD560 JWT Access Token\uC744 \uC124\uC815\uD569\uB2C8\uB2E4. */\r\n setToken(token: string): void {\r\n this.token = token;\r\n if (!token) {\r\n this.disconnectRealtime(\"token_cleared\");\r\n return;\r\n }\r\n if (this.realtimeEnabled && this.realtimeAutoConnect) {\r\n void this.connectRealtime().catch(() => {});\r\n }\r\n }\r\n\r\n /** \uC751\uB2F5 \uD5E4\uB354\uB85C \uBC1B\uC740 access token \uAC31\uC2E0\uC744 \uBC18\uC601\uD55C\uB2E4. */\r\n setAccessTokenFromResponse(token: string): void {\r\n this.token = token;\r\n }\r\n\r\n /** \uC775\uBA85 \uD328\uD0B7 \uC554\uD638\uD654\uC6A9 \uD1A0\uD070\uC744 \uC124\uC815\uD569\uB2C8\uB2E4. */\r\n setAnonymousPacketToken(token: string): void {\r\n this.anonymousPacketToken = token;\r\n }\r\n\r\n /** HMAC \uC778\uC99D\uC6A9 API Key\uB97C \uC124\uC815\uD569\uB2C8\uB2E4. */\r\n setApiKey(apiKey: string): void {\r\n this.apiKey = apiKey;\r\n }\r\n\r\n /** HMAC \uC778\uC99D\uC6A9 \uC2DC\uD06C\uB9BF\uC744 \uC124\uC815\uD569\uB2C8\uB2E4. */\r\n setHmacSecret(secret: string): void {\r\n this.hmacSecret = secret;\r\n }\r\n\r\n /** \uC554\uD638\uD654 \uC694\uCCAD \uD65C\uC131\uD654 \uC5EC\uBD80\uB97C \uC124\uC815\uD569\uB2C8\uB2E4. */\r\n setEncryptRequests(value: boolean): void {\r\n this.encryptRequests = value;\r\n }\r\n\r\n setCsrfEnabled(enabled: boolean): void {\r\n this.csrfEnabled = enabled;\r\n }\r\n\r\n addRealtimeListener(listener: RealtimeMessageListener): void {\r\n this.realtimeMessageListeners.add(listener);\r\n }\r\n\r\n removeRealtimeListener(listener: RealtimeMessageListener): void {\r\n this.realtimeMessageListeners.delete(listener);\r\n }\r\n\r\n addRealtimeStatusListener(listener: RealtimeStatusListener): void {\r\n this.realtimeStatusListeners.add(listener);\r\n }\r\n\r\n removeRealtimeStatusListener(listener: RealtimeStatusListener): void {\r\n this.realtimeStatusListeners.delete(listener);\r\n }\r\n\r\n addRealtimeEventListener(\r\n eventName: string,\r\n listener: RealtimeMessageListener,\r\n ): void {\r\n const key = String(eventName).trim();\r\n if (!key) {\r\n return;\r\n }\r\n if (!this.realtimeEventListeners.has(key)) {\r\n this.realtimeEventListeners.set(key, new Set());\r\n }\r\n this.realtimeEventListeners.get(key)!.add(listener);\r\n }\r\n\r\n removeRealtimeEventListener(\r\n eventName: string,\r\n listener: RealtimeMessageListener,\r\n ): void {\r\n const key = String(eventName).trim();\r\n if (!key) {\r\n return;\r\n }\r\n const listeners = this.realtimeEventListeners.get(key);\r\n if (!listeners) {\r\n return;\r\n }\r\n listeners.delete(listener);\r\n if (listeners.size === 0) {\r\n this.realtimeEventListeners.delete(key);\r\n }\r\n }\r\n\r\n async connectRealtime(): Promise<void> {\r\n if (!this.realtimeEnabled) {\r\n this.setRealtimeStatus(\"disabled\", \"realtime_disabled\");\r\n return;\r\n }\r\n\r\n if (!this.token) {\r\n throw new Error(\r\n \"Cannot open realtime connection without access token.\",\r\n );\r\n }\r\n\r\n if (typeof WebSocket === \"undefined\") {\r\n throw new Error(\"WebSocket is not available in this environment.\");\r\n }\r\n\r\n if (\r\n this.realtimeSocket &&\r\n this.realtimeSocket.readyState === WebSocket.OPEN\r\n ) {\r\n return;\r\n }\r\n\r\n if (\r\n this.realtimeSocket &&\r\n this.realtimeSocket.readyState === WebSocket.CONNECTING &&\r\n this.realtimeConnectPromise\r\n ) {\r\n return this.realtimeConnectPromise;\r\n }\r\n\r\n this.clearRealtimeReconnectTimer();\r\n this.realtimeShouldReconnect = this.realtimeAutoReconnect;\r\n this.setRealtimeStatus(\"connecting\", \"connect_requested\");\r\n\r\n const socket = new WebSocket(this.buildRealtimeUrl());\r\n this.realtimeSocket = socket;\r\n\r\n this.realtimeConnectPromise = new Promise<void>((resolve, reject) => {\r\n let settled = false;\r\n\r\n const finalizeResolve = () => {\r\n if (settled) {\r\n return;\r\n }\r\n settled = true;\r\n this.realtimeConnectPromise = null;\r\n resolve();\r\n };\r\n\r\n const finalizeReject = (error: Error) => {\r\n if (settled) {\r\n return;\r\n }\r\n settled = true;\r\n this.realtimeConnectPromise = null;\r\n reject(error);\r\n };\r\n\r\n socket.addEventListener(\"open\", () => {\r\n this.setRealtimeStatus(\"open\", \"socket_open\");\r\n finalizeResolve();\r\n });\r\n\r\n socket.addEventListener(\"message\", (event) => {\r\n this.handleRealtimeMessage(event.data);\r\n });\r\n\r\n socket.addEventListener(\"error\", () => {\r\n this.setRealtimeStatus(\r\n \"closed\",\r\n \"socket_error\",\r\n new Error(\"Realtime socket error.\"),\r\n );\r\n });\r\n\r\n socket.addEventListener(\"close\", (event) => {\r\n if (this.realtimeSocket === socket) {\r\n this.realtimeSocket = null;\r\n }\r\n\r\n const reason = event.reason || \"socket_closed\";\r\n const error = new Error(\r\n `Realtime socket closed (${event.code}${event.reason ? `: ${event.reason}` : \"\"}).`,\r\n );\r\n\r\n this.setRealtimeStatus(\"closed\", reason, error);\r\n if (!settled) {\r\n finalizeReject(error);\r\n }\r\n\r\n if (\r\n this.realtimeShouldReconnect &&\r\n this.realtimeEnabled &&\r\n this.realtimeAutoReconnect &&\r\n this.token\r\n ) {\r\n this.scheduleRealtimeReconnect(reason);\r\n }\r\n });\r\n });\r\n\r\n return this.realtimeConnectPromise;\r\n }\r\n\r\n disconnectRealtime(reason = \"client_disconnect\"): void {\r\n this.realtimeShouldReconnect = false;\r\n this.clearRealtimeReconnectTimer();\r\n\r\n if (this.realtimeSocket) {\r\n const socket = this.realtimeSocket;\r\n this.realtimeSocket = null;\r\n try {\r\n if (\r\n socket.readyState === WebSocket.OPEN ||\r\n socket.readyState === WebSocket.CONNECTING\r\n ) {\r\n socket.close(1000, reason);\r\n }\r\n } catch {\r\n // ignore close errors\r\n }\r\n }\r\n\r\n this.realtimeConnectPromise = null;\r\n this.setRealtimeStatus(\r\n this.realtimeEnabled ? \"idle\" : \"disabled\",\r\n reason,\r\n );\r\n }\r\n\r\n sendRealtime(message: RealtimeEnvelope | Record<string, unknown>): boolean {\r\n if (\r\n !this.realtimeSocket ||\r\n this.realtimeSocket.readyState !== WebSocket.OPEN\r\n ) {\r\n return false;\r\n }\r\n\r\n this.realtimeSocket.send(JSON.stringify(message));\r\n return true;\r\n }\r\n\r\n subscribeRealtime(subscriptions: string[]): boolean {\r\n return this.sendRealtime({\r\n type: \"subscribe\",\r\n channel: \"session\",\r\n event: \"session.subscribe\",\r\n data: { subscriptions },\r\n });\r\n }\r\n\r\n unsubscribeRealtime(subscriptions: string[]): boolean {\r\n return this.sendRealtime({\r\n type: \"unsubscribe\",\r\n channel: \"session\",\r\n event: \"session.unsubscribe\",\r\n data: { subscriptions },\r\n });\r\n }\r\n\r\n /**\r\n * \uC8FC\uAE30\uC801\uC73C\uB85C health \uCCB4\uD06C\uB97C \uC2E4\uD589\uD569\uB2C8\uB2E4.\r\n * CSRF \uCFE0\uD0A4 \uAC31\uC2E0\uACFC \uC11C\uBC84 \uC0C1\uD0DC \uD655\uC778\uC744 \uC790\uB3D9\uD654\uD569\uB2C8\uB2E4.\r\n * keepSession=true \uC774\uBA74 \uAC01 tick\uC5D0\uC11C \uC138\uC158 \uBD80\uD2B8\uC2A4\uD2B8\uB7A9\uB3C4 \uD568\uAED8 \uC2DC\uB3C4\uD569\uB2C8\uB2E4.\r\n *\r\n * @param intervalMs \uD638\uCD9C \uC8FC\uAE30(ms). \uAE30\uBCF8\uAC12: 5\uBD84\r\n * @param runImmediately true\uBA74 \uC2DC\uC791 \uC9C1\uD6C4 \uCCAB tick\uC744 \uC989\uC2DC \uC2E4\uD589\uD569\uB2C8\uB2E4.\r\n */\r\n startHealthTick(\r\n intervalMs: number = 5 * 60 * 1000,\r\n runImmediately = true,\r\n ): void {\r\n this.stopHealthTick();\r\n const tick = (): void => {\r\n if (this.healthTickPromise) return;\r\n this.healthTickPromise = (\r\n this.csrfRefresher ? this.csrfRefresher() : Promise.resolve()\r\n )\r\n .then(() => {\r\n this.onHealthChange?.(true);\r\n })\r\n .catch(() => {\r\n this.onHealthChange?.(false);\r\n })\r\n .finally(() => {\r\n this.healthTickPromise = null;\r\n });\r\n };\r\n if (runImmediately) {\r\n tick();\r\n }\r\n this.healthTickTimer = setInterval(tick, intervalMs);\r\n }\r\n\r\n /** health tick \uD0C0\uC774\uBA38\uB97C \uC911\uC9C0\uD569\uB2C8\uB2E4. */\r\n stopHealthTick(): void {\r\n if (this.healthTickTimer !== null) {\r\n clearInterval(this.healthTickTimer);\r\n this.healthTickTimer = null;\r\n }\r\n this.healthTickPromise = null;\r\n }\r\n\r\n // \u2500\u2500\u2500 \uC138\uC158 \uC720\uC9C0 \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\r\n\r\n /** @deprecated \uC138\uC158 \uC5F0\uC7A5\uC740 health tick \uAE30\uBC18 \uBD80\uD2B8\uC2A4\uD2B8\uB7A9\uC73C\uB85C \uB300\uCCB4\uB418\uC5C8\uC2B5\uB2C8\uB2E4. */\r\n scheduleKeepSession(\r\n refreshToken: string,\r\n expiresIn: number,\r\n refreshFn: (\r\n rt: string,\r\n ) => Promise<{ access_token: string; expires_in: number }>,\r\n ): void {\r\n this.clearRefreshTimer();\r\n this.sessionRefreshToken = refreshToken;\r\n const delayMs = Math.max((expiresIn - this.refreshBuffer) * 1000, 0);\r\n this.refreshTimer = setTimeout(async () => {\r\n if (!this.sessionRefreshToken) return;\r\n try {\r\n const result = await refreshFn(this.sessionRefreshToken);\r\n this.onTokenRefreshed?.(result.access_token, result.expires_in);\r\n this.scheduleKeepSession(\r\n this.sessionRefreshToken,\r\n result.expires_in,\r\n refreshFn,\r\n );\r\n } catch (err) {\r\n this.clearRefreshTimer();\r\n this.onSessionExpired?.(\r\n err instanceof Error ? err : new Error(String(err)),\r\n );\r\n }\r\n }, delayMs);\r\n }\r\n\r\n /** @deprecated \uC138\uC158 \uC5F0\uC7A5\uC740 health tick \uAE30\uBC18 \uBD80\uD2B8\uC2A4\uD2B8\uB7A9\uC73C\uB85C \uB300\uCCB4\uB418\uC5C8\uC2B5\uB2C8\uB2E4. */\r\n clearRefreshTimer(): void {\r\n if (this.refreshTimer !== null) {\r\n clearTimeout(this.refreshTimer);\r\n this.refreshTimer = null;\r\n }\r\n }\r\n\r\n /**\r\n * \uC138\uC158 \uC790\uB3D9 \uC5F0\uC7A5\uC744 \uC911\uC9C0\uD569\uB2C8\uB2E4.\r\n * `logout()` \uD638\uCD9C \uC2DC \uC790\uB3D9\uC73C\uB85C \uC911\uC9C0\uB418\uBA70, \uC9C1\uC811 \uD638\uCD9C\uC774 \uD544\uC694\uD55C \uACBD\uC6B0\uB294 \uB4DC\uBB45\uB2C8\uB2E4.\r\n */\r\n stopKeepSession(): void {\r\n this.clearRefreshTimer();\r\n this.sessionRefreshToken = null;\r\n }\r\n\r\n applyRealtimeOptions(options?: boolean | RealtimeClientOptions): void {\r\n const normalized: RealtimeClientOptions =\r\n typeof options === \"boolean\"\r\n ? { enabled: options }\r\n : (options ?? {});\r\n\r\n this.realtimeEnabled = normalized.enabled ?? false;\r\n this.realtimePath =\r\n String(normalized.path ?? REALTIME_DEFAULT_PATH).trim() ||\r\n REALTIME_DEFAULT_PATH;\r\n this.realtimeAutoConnect = normalized.autoConnect ?? true;\r\n this.realtimeAutoReconnect = normalized.autoReconnect ?? true;\r\n this.realtimeReconnectDelayMs = Math.max(\r\n 250,\r\n normalized.reconnectDelayMs ?? 3000,\r\n );\r\n\r\n if (!this.realtimeEnabled) {\r\n this.disconnectRealtime(\"realtime_disabled\");\r\n return;\r\n }\r\n\r\n this.setRealtimeStatus(\"idle\", \"realtime_enabled\");\r\n if (this.token && this.realtimeAutoConnect) {\r\n void this.connectRealtime().catch(() => {});\r\n }\r\n }\r\n\r\n buildRealtimeUrl(): string {\r\n const rawBaseUrl =\r\n this.baseUrl || readEnv(\"VITE_ENTITY_SERVER_URL\") || \"\";\r\n const baseUrl =\r\n rawBaseUrl ||\r\n (typeof window !== \"undefined\" ? window.location.origin : \"\");\r\n\r\n if (!baseUrl) {\r\n throw new Error(\"Realtime connection requires baseUrl.\");\r\n }\r\n\r\n const url = new URL(this.realtimePath, baseUrl);\r\n url.protocol = url.protocol === \"https:\" ? \"wss:\" : \"ws:\";\r\n url.searchParams.set(\"access_token\", this.token);\r\n return url.toString();\r\n }\r\n\r\n handleRealtimeMessage(payload: unknown): void {\r\n if (typeof payload !== \"string\") {\r\n return;\r\n }\r\n\r\n let envelope: RealtimeEnvelope;\r\n try {\r\n envelope = JSON.parse(payload) as RealtimeEnvelope;\r\n } catch {\r\n return;\r\n }\r\n\r\n for (const listener of this.realtimeMessageListeners) {\r\n listener(envelope);\r\n }\r\n\r\n const listeners = this.realtimeEventListeners.get(envelope.event);\r\n if (listeners) {\r\n for (const listener of listeners) {\r\n listener(envelope);\r\n }\r\n }\r\n }\r\n\r\n scheduleRealtimeReconnect(reason: string): void {\r\n this.clearRealtimeReconnectTimer();\r\n this.realtimeReconnectTimer = setTimeout(() => {\r\n this.realtimeReconnectTimer = null;\r\n if (!this.realtimeEnabled || !this.token) {\r\n return;\r\n }\r\n this.setRealtimeStatus(\"connecting\", `${reason}:reconnect`);\r\n void this.connectRealtime().catch(() => {});\r\n }, this.realtimeReconnectDelayMs);\r\n }\r\n\r\n clearRealtimeReconnectTimer(): void {\r\n if (this.realtimeReconnectTimer !== null) {\r\n clearTimeout(this.realtimeReconnectTimer);\r\n this.realtimeReconnectTimer = null;\r\n }\r\n }\r\n\r\n setRealtimeStatus(\r\n status: RealtimeConnectionStatus,\r\n reason?: string,\r\n error?: Error,\r\n ): void {\r\n const previousStatus = this.realtimeStatus;\r\n if (\r\n previousStatus === status &&\r\n typeof reason === \"undefined\" &&\r\n typeof error === \"undefined\"\r\n ) {\r\n return;\r\n }\r\n\r\n this.realtimeStatus = status;\r\n for (const listener of this.realtimeStatusListeners) {\r\n listener({\r\n status,\r\n previousStatus,\r\n ...(reason ? { reason } : {}),\r\n ...(error ? { error } : {}),\r\n });\r\n }\r\n }\r\n\r\n applyCsrfHealth(): void {\r\n if (typeof document === \"undefined\") return;\r\n for (const chunk of document.cookie.split(\";\")) {\r\n const idx = chunk.indexOf(\"=\");\r\n if (idx < 0) continue;\r\n if (chunk.substring(0, idx).trim() === this.csrfCookieName) {\r\n this.csrfEnabled = !!chunk.substring(idx + 1).trim();\r\n return;\r\n }\r\n }\r\n this.csrfEnabled = false;\r\n }\r\n\r\n // \u2500\u2500\u2500 \uC694\uCCAD \uBCF8\uBB38 \uD30C\uC2F1 \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\r\n\r\n /**\r\n * \uC694\uCCAD \uBC14\uB514\uB97C \uD30C\uC2F1\uD569\uB2C8\uB2E4.\r\n * `application/octet-stream`\uC774\uBA74 XChaCha20-Poly1305 \uBCF5\uD638\uD654, \uADF8 \uC678\uB294 JSON \uD30C\uC2F1\uD569\uB2C8\uB2E4.\r\n *\r\n * @param requireEncrypted `true`\uC774\uBA74 \uC554\uD638\uD654\uB41C \uC694\uCCAD\uB9CC \uD5C8\uC6A9\uD569\uB2C8\uB2E4.\r\n */\r\n readRequestBody<T = Record<string, unknown>>(\r\n body: ArrayBuffer | Uint8Array | string | T | null | undefined,\r\n contentType = \"application/json\",\r\n requireEncrypted = false,\r\n ): T {\r\n const key = derivePacketKey(\r\n this.hmacSecret,\r\n this.token || this.anonymousPacketToken,\r\n );\r\n return parseRequestBody<T>(body, contentType, requireEncrypted, key);\r\n }\r\n\r\n // \u2500\u2500\u2500 \uB0B4\uBD80 \uD5EC\uD37C \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\r\n\r\n get reqOpts(): RequestOptions {\r\n return {\r\n baseUrl: this.baseUrl,\r\n token: this.token,\r\n anonymousPacketToken: this.anonymousPacketToken,\r\n apiKey: this.apiKey,\r\n hmacSecret: this.hmacSecret,\r\n encryptRequests: this.encryptRequests,\r\n csrfEnabled: this.csrfEnabled,\r\n csrfHeaderName: this.csrfHeaderName,\r\n csrfCookieName: this.csrfCookieName,\r\n refreshCsrfCookie: this.csrfEnabled ? this.csrfRefresher : null,\r\n onAccessToken: (token) => {\r\n this.setAccessTokenFromResponse(token);\r\n },\r\n };\r\n }\r\n\r\n // \uC778\uC99D \uC694\uCCAD \uC804\uC5D0 \uD544\uC694\uD55C \uD074\uB77C\uC774\uC5B8\uD2B8 \uC900\uBE44 \uC791\uC5C5\uC744 \uC218\uD589\uD569\uB2C8\uB2E4.\r\n prepareRequest(_withAuth: boolean): Promise<void> {\r\n return Promise.resolve();\r\n }\r\n\r\n /**\r\n * \uCEE4\uC2A4\uD140 \uB77C\uC6B0\uD2B8 \uC9C1\uC811 \uD638\uCD9C\uC6A9 HTTP \uB124\uC784\uC2A4\uD398\uC774\uC2A4.\r\n * \uC778\uC99D\u00B7\uC554\uD638\uD654\u00B7HMAC \uB4F1 SDK \uC635\uC158\uC774 \uADF8\uB300\uB85C \uC801\uC6A9\uB429\uB2C8\uB2E4.\r\n *\r\n * @example\r\n * const res = await client.http.get<{ version: string }>(\"/api/v1/status\", false);\r\n * const res = await client.http.post<MyResponse>(\"/api/v1/custom\", { key: \"value\" });\r\n */\r\n get http() {\r\n // eslint-disable-next-line @typescript-eslint/no-this-alias\r\n const self = this;\r\n return {\r\n get<T>(\r\n path: string,\r\n withAuth = true,\r\n extraHeaders?: Record<string, string>,\r\n requestConfig?: EntityRequestConfig,\r\n ): Promise<T> {\r\n return self\r\n .prepareRequest(withAuth)\r\n .then(() =>\r\n entityRequest<T>(\r\n self.reqOpts,\r\n \"GET\",\r\n path,\r\n undefined,\r\n withAuth,\r\n extraHeaders,\r\n requestConfig ?? true,\r\n ),\r\n );\r\n },\r\n post<T>(\r\n path: string,\r\n body?: unknown,\r\n withAuth = true,\r\n extraHeaders?: Record<string, string>,\r\n requestConfig?: EntityRequestConfig,\r\n ): Promise<T> {\r\n return self\r\n .prepareRequest(withAuth)\r\n .then(() =>\r\n entityRequest<T>(\r\n self.reqOpts,\r\n \"POST\",\r\n path,\r\n body,\r\n withAuth,\r\n extraHeaders,\r\n requestConfig ?? true,\r\n ),\r\n );\r\n },\r\n put<T>(\r\n path: string,\r\n body?: unknown,\r\n withAuth = true,\r\n extraHeaders?: Record<string, string>,\r\n requestConfig?: EntityRequestConfig,\r\n ): Promise<T> {\r\n return self\r\n .prepareRequest(withAuth)\r\n .then(() =>\r\n entityRequest<T>(\r\n self.reqOpts,\r\n \"PUT\",\r\n path,\r\n body,\r\n withAuth,\r\n extraHeaders,\r\n requestConfig ?? true,\r\n ),\r\n );\r\n },\r\n patch<T>(\r\n path: string,\r\n body?: unknown,\r\n withAuth = true,\r\n extraHeaders?: Record<string, string>,\r\n requestConfig?: EntityRequestConfig,\r\n ): Promise<T> {\r\n return self\r\n .prepareRequest(withAuth)\r\n .then(() =>\r\n entityRequest<T>(\r\n self.reqOpts,\r\n \"PATCH\",\r\n path,\r\n body,\r\n withAuth,\r\n extraHeaders,\r\n requestConfig ?? true,\r\n ),\r\n );\r\n },\r\n delete<T>(\r\n path: string,\r\n body?: unknown,\r\n withAuth = true,\r\n extraHeaders?: Record<string, string>,\r\n requestConfig?: EntityRequestConfig,\r\n ): Promise<T> {\r\n return self\r\n .prepareRequest(withAuth)\r\n .then(() =>\r\n entityRequest<T>(\r\n self.reqOpts,\r\n \"DELETE\",\r\n path,\r\n body,\r\n withAuth,\r\n extraHeaders,\r\n requestConfig ?? true,\r\n ),\r\n );\r\n },\r\n };\r\n }\r\n\r\n request<T>(\r\n method: string,\r\n path: string,\r\n body?: unknown,\r\n withAuth = true,\r\n extraHeaders?: Record<string, string>,\r\n requestConfig?: EntityRequestConfig,\r\n ): Promise<T> {\r\n return this.prepareRequest(withAuth).then(() =>\r\n entityRequest<T>(\r\n this.reqOpts,\r\n method,\r\n path,\r\n body,\r\n withAuth,\r\n extraHeaders,\r\n requestConfig ?? true,\r\n ),\r\n );\r\n }\r\n\r\n /** PNG/\uBC14\uC774\uB108\uB9AC \uC751\uB2F5\uC744 ArrayBuffer\uB85C \uBC18\uD658\uD569\uB2C8\uB2E4. (QR, \uBC14\uCF54\uB4DC \uB4F1) */\r\n async requestBinary(\r\n method: string,\r\n path: string,\r\n body?: unknown,\r\n withAuth = true,\r\n ): Promise<ArrayBuffer> {\r\n await this.prepareRequest(withAuth);\r\n\r\n const headers: Record<string, string> = {\r\n \"Content-Type\": \"application/json\",\r\n };\r\n if (withAuth && this.token)\r\n headers[\"Authorization\"] = `Bearer ${this.token}`;\r\n if (this.apiKey) headers[\"X-API-Key\"] = this.apiKey;\r\n\r\n const res = await fetch(this.baseUrl + path, {\r\n method,\r\n headers,\r\n ...(body != null ? { body: JSON.stringify(body) } : {}),\r\n credentials: \"include\",\r\n });\r\n\r\n if (!res.ok) {\r\n const text = await res.text();\r\n const err = new Error(`HTTP ${res.status}: ${text}`);\r\n (err as { status?: number }).status = res.status;\r\n throw err;\r\n }\r\n\r\n return res.arrayBuffer();\r\n }\r\n\r\n /** multipart/form-data \uC694\uCCAD\uC744 \uBCF4\uB0C5\uB2C8\uB2E4. (\uD30C\uC77C \uC5C5\uB85C\uB4DC \uB4F1) */\r\n async requestForm<T>(\r\n method: string,\r\n path: string,\r\n form: FormData,\r\n withAuth = true,\r\n ): Promise<T> {\r\n const headers: Record<string, string> = {};\r\n if (withAuth && this.token)\r\n headers[\"Authorization\"] = `Bearer ${this.token}`;\r\n if (this.apiKey) headers[\"X-API-Key\"] = this.apiKey;\r\n\r\n const res = await fetch(this.baseUrl + path, {\r\n method,\r\n headers,\r\n body: form,\r\n credentials: \"include\",\r\n });\r\n\r\n const data = (await res.json()) as { ok?: boolean; message?: string };\r\n if (!data.ok) {\r\n const err = new Error(\r\n data.message ?? `EntityServer error (HTTP ${res.status})`,\r\n );\r\n (err as { status?: number }).status = res.status;\r\n throw err;\r\n }\r\n return data as T;\r\n }\r\n\r\n /** multipart/form-data \uC694\uCCAD\uC744 \uBCF4\uB0B4\uACE0 \uBC14\uC774\uB108\uB9AC(ArrayBuffer)\uB97C \uBC18\uD658\uD569\uB2C8\uB2E4. */\r\n async requestFormBinary(\r\n method: string,\r\n path: string,\r\n form: FormData,\r\n withAuth = true,\r\n ): Promise<ArrayBuffer> {\r\n const headers: Record<string, string> = {};\r\n if (withAuth && this.token)\r\n headers[\"Authorization\"] = `Bearer ${this.token}`;\r\n if (this.apiKey) headers[\"X-API-Key\"] = this.apiKey;\r\n\r\n const res = await fetch(this.baseUrl + path, {\r\n method,\r\n headers,\r\n body: form,\r\n credentials: \"include\",\r\n });\r\n\r\n if (!res.ok) {\r\n const text = await res.text();\r\n const err = new Error(`HTTP ${res.status}: ${text}`);\r\n (err as { status?: number }).status = res.status;\r\n throw err;\r\n }\r\n\r\n return res.arrayBuffer();\r\n }\r\n}\r\n"],
|
|
5
|
-
"mappings": "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",
|
|
6
|
-
"names": ["readEnv", "derivePacketKey", "parseRequestBody", "entityRequest", "REALTIME_DEFAULT_PATH", "EntityServerClientBase", "options", "envBaseUrl", "token", "apiKey", "secret", "value", "enabled", "listener", "eventName", "key", "listeners", "socket", "resolve", "reject", "settled", "finalizeResolve", "finalizeReject", "error", "event", "reason", "message", "subscriptions", "intervalMs", "
|
|
4
|
+
"sourcesContent": ["import type {\n EntityServerClientOptions,\n RealtimeClientOptions,\n RealtimeConnectionStatus,\n RealtimeEnvelope,\n RealtimeMessageListener,\n RealtimeStatusListener,\n} from \"../types.js\";\nimport { readEnv } from \"./utils.js\";\nimport { derivePacketKey, parseRequestBody } from \"./packet.js\";\nimport {\n entityRequest,\n type EntityRequestConfig,\n type RequestOptions,\n} from \"./request.js\";\n\nconst REALTIME_DEFAULT_PATH = \"/v1/realtime\";\n\n// mixin \uD5EC\uD37C \uD0C0\uC785\nexport type GConstructor<T = object> = new (...args: any[]) => T;\n\nexport class EntityServerClientBase {\n baseUrl: string;\n token: string;\n anonymousPacketToken: string;\n apiKey: string;\n hmacSecret: string;\n encryptRequests: boolean;\n csrfEnabled: boolean;\n csrfHeaderName: string;\n csrfCookieName: string;\n /** @internal health \uC7AC\uD638\uCD9C\uB85C CSRF \uCFE0\uD0A4 \uAC31\uC2E0 (AuthMixin\uC5D0\uC11C \uC124\uC815) */\n csrfRefresher: (() => Promise<void>) | null = null;\n activeTxId: string | null = null;\n\n // \uC138\uC158 \uC720\uC9C0 \uAD00\uB828\n keepSession: boolean;\n refreshBuffer: number;\n onTokenRefreshed?: (accessToken: string, expiresIn: number) => void;\n onSessionExpired?: (error: Error) => void;\n onHealthChange?: (online: boolean) => void;\n sessionRefreshToken: string | null = null;\n refreshTimer: ReturnType<typeof setTimeout> | null = null;\n healthTickTimer: ReturnType<typeof setInterval> | null = null;\n healthTickPromise: Promise<unknown> | null = null;\n realtimeEnabled: boolean;\n realtimePath: string;\n realtimeAutoConnect: boolean;\n realtimeAutoReconnect: boolean;\n realtimeReconnectDelayMs: number;\n realtimeStatus: RealtimeConnectionStatus;\n realtimeSocket: WebSocket | null = null;\n realtimeConnectPromise: Promise<void> | null = null;\n realtimeReconnectTimer: ReturnType<typeof setTimeout> | null = null;\n realtimeShouldReconnect = false;\n realtimeMessageListeners = new Set<RealtimeMessageListener>();\n realtimeStatusListeners = new Set<RealtimeStatusListener>();\n realtimeEventListeners = new Map<string, Set<RealtimeMessageListener>>();\n // \u2500\u2500\u2500 \uCD08\uAE30\uD654 & \uC124\uC815 \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n /**\n * EntityServerClient \uC778\uC2A4\uD134\uC2A4\uB97C \uC0DD\uC131\uD569\uB2C8\uB2E4.\n *\n * \uAE30\uBCF8\uAC12:\n * - `baseUrl`: `VITE_ENTITY_SERVER_URL` \uB610\uB294 \uC0C1\uB300 \uACBD\uB85C(`\"\"`)\n */\n constructor(options: EntityServerClientOptions = {}) {\n const envBaseUrl = readEnv(\"VITE_ENTITY_SERVER_URL\");\n\n this.baseUrl = (options.baseUrl ?? envBaseUrl ?? \"\").replace(/\\/$/, \"\");\n this.token = options.token ?? \"\";\n this.anonymousPacketToken = options.anonymousPacketToken ?? \"\";\n this.apiKey = options.apiKey ?? \"\";\n this.hmacSecret = options.hmacSecret ?? \"\";\n this.encryptRequests = options.encryptRequests ?? false;\n this.csrfEnabled = options.csrfEnabled ?? false;\n this.csrfHeaderName = options.csrfHeaderName ?? \"x-csrf-token\";\n this.csrfCookieName = options.csrfCookieName ?? \"_csrf\";\n this.keepSession = options.keepSession ?? false;\n this.refreshBuffer = options.refreshBuffer ?? 60;\n this.onTokenRefreshed = options.onTokenRefreshed;\n this.onSessionExpired = options.onSessionExpired;\n this.onHealthChange = options.onHealthChange;\n this.realtimeEnabled = false;\n this.realtimePath = REALTIME_DEFAULT_PATH;\n this.realtimeAutoConnect = true;\n this.realtimeAutoReconnect = true;\n this.realtimeReconnectDelayMs = 3000;\n this.realtimeStatus = \"idle\";\n this.applyRealtimeOptions(options.realtime);\n if (\n typeof options.healthTickInterval === \"number\" &&\n options.healthTickInterval > 0\n ) {\n // csrfRefresher\uB294 AuthMixin\uC5D0\uC11C \uC124\uC815\uB418\uBBC0\uB85C \uB2E4\uC74C tick\uC5D0 \uC2DC\uC791\n Promise.resolve().then(() =>\n this.startHealthTick(options.healthTickInterval),\n );\n }\n }\n\n /** baseUrl, token, encryptRequests \uAC12\uC744 \uB7F0\uD0C0\uC784\uC5D0 \uAC31\uC2E0\uD569\uB2C8\uB2E4. */\n configure(options: Partial<EntityServerClientOptions>): void {\n if (typeof options.baseUrl === \"string\") {\n this.baseUrl = options.baseUrl.replace(/\\/$/, \"\");\n }\n if (typeof options.token === \"string\") this.token = options.token;\n if (typeof options.anonymousPacketToken === \"string\") {\n this.anonymousPacketToken = options.anonymousPacketToken;\n }\n if (typeof options.encryptRequests === \"boolean\")\n this.encryptRequests = options.encryptRequests;\n if (typeof options.csrfEnabled === \"boolean\") {\n this.csrfEnabled = options.csrfEnabled;\n }\n if (typeof options.csrfHeaderName === \"string\") {\n this.csrfHeaderName = options.csrfHeaderName;\n }\n if (typeof options.csrfCookieName === \"string\") {\n this.csrfCookieName = options.csrfCookieName;\n }\n if (typeof options.apiKey === \"string\") this.apiKey = options.apiKey;\n if (typeof options.hmacSecret === \"string\")\n this.hmacSecret = options.hmacSecret;\n if (typeof options.keepSession === \"boolean\")\n this.keepSession = options.keepSession;\n if (typeof options.refreshBuffer === \"number\")\n this.refreshBuffer = options.refreshBuffer;\n if (options.onTokenRefreshed)\n this.onTokenRefreshed = options.onTokenRefreshed;\n if (options.onSessionExpired)\n this.onSessionExpired = options.onSessionExpired;\n if (options.onHealthChange)\n this.onHealthChange = options.onHealthChange;\n if (typeof options.realtime !== \"undefined\") {\n this.applyRealtimeOptions(options.realtime);\n }\n if (\n typeof options.healthTickInterval === \"number\" &&\n options.healthTickInterval > 0\n ) {\n Promise.resolve().then(() =>\n this.startHealthTick(options.healthTickInterval),\n );\n }\n }\n\n /** \uC778\uC99D \uC694\uCCAD\uC5D0 \uC0AC\uC6A9\uD560 JWT Access Token\uC744 \uC124\uC815\uD569\uB2C8\uB2E4. */\n setToken(token: string): void {\n this.token = token;\n if (!token) {\n this.disconnectRealtime(\"token_cleared\");\n return;\n }\n if (this.realtimeEnabled && this.realtimeAutoConnect) {\n void this.connectRealtime().catch(() => {});\n }\n }\n\n /** \uC775\uBA85 \uD328\uD0B7 \uC554\uD638\uD654\uC6A9 \uD1A0\uD070\uC744 \uC124\uC815\uD569\uB2C8\uB2E4. */\n setAnonymousPacketToken(token: string): void {\n this.anonymousPacketToken = token;\n }\n\n /** HMAC \uC778\uC99D\uC6A9 API Key\uB97C \uC124\uC815\uD569\uB2C8\uB2E4. */\n setApiKey(apiKey: string): void {\n this.apiKey = apiKey;\n }\n\n /** HMAC \uC778\uC99D\uC6A9 \uC2DC\uD06C\uB9BF\uC744 \uC124\uC815\uD569\uB2C8\uB2E4. */\n setHmacSecret(secret: string): void {\n this.hmacSecret = secret;\n }\n\n /** \uC554\uD638\uD654 \uC694\uCCAD \uD65C\uC131\uD654 \uC5EC\uBD80\uB97C \uC124\uC815\uD569\uB2C8\uB2E4. */\n setEncryptRequests(value: boolean): void {\n this.encryptRequests = value;\n }\n\n setCsrfEnabled(enabled: boolean): void {\n this.csrfEnabled = enabled;\n }\n\n addRealtimeListener(listener: RealtimeMessageListener): void {\n this.realtimeMessageListeners.add(listener);\n }\n\n removeRealtimeListener(listener: RealtimeMessageListener): void {\n this.realtimeMessageListeners.delete(listener);\n }\n\n addRealtimeStatusListener(listener: RealtimeStatusListener): void {\n this.realtimeStatusListeners.add(listener);\n }\n\n removeRealtimeStatusListener(listener: RealtimeStatusListener): void {\n this.realtimeStatusListeners.delete(listener);\n }\n\n addRealtimeEventListener(\n eventName: string,\n listener: RealtimeMessageListener,\n ): void {\n const key = String(eventName).trim();\n if (!key) {\n return;\n }\n if (!this.realtimeEventListeners.has(key)) {\n this.realtimeEventListeners.set(key, new Set());\n }\n this.realtimeEventListeners.get(key)!.add(listener);\n }\n\n removeRealtimeEventListener(\n eventName: string,\n listener: RealtimeMessageListener,\n ): void {\n const key = String(eventName).trim();\n if (!key) {\n return;\n }\n const listeners = this.realtimeEventListeners.get(key);\n if (!listeners) {\n return;\n }\n listeners.delete(listener);\n if (listeners.size === 0) {\n this.realtimeEventListeners.delete(key);\n }\n }\n\n async connectRealtime(): Promise<void> {\n if (!this.realtimeEnabled) {\n this.setRealtimeStatus(\"disabled\", \"realtime_disabled\");\n return;\n }\n\n if (!this.token) {\n throw new Error(\n \"Cannot open realtime connection without access token.\",\n );\n }\n\n if (typeof WebSocket === \"undefined\") {\n throw new Error(\"WebSocket is not available in this environment.\");\n }\n\n if (\n this.realtimeSocket &&\n this.realtimeSocket.readyState === WebSocket.OPEN\n ) {\n return;\n }\n\n if (\n this.realtimeSocket &&\n this.realtimeSocket.readyState === WebSocket.CONNECTING &&\n this.realtimeConnectPromise\n ) {\n return this.realtimeConnectPromise;\n }\n\n this.clearRealtimeReconnectTimer();\n this.realtimeShouldReconnect = this.realtimeAutoReconnect;\n this.setRealtimeStatus(\"connecting\", \"connect_requested\");\n\n const socket = new WebSocket(this.buildRealtimeUrl());\n this.realtimeSocket = socket;\n\n this.realtimeConnectPromise = new Promise<void>((resolve, reject) => {\n let settled = false;\n\n const finalizeResolve = () => {\n if (settled) {\n return;\n }\n settled = true;\n this.realtimeConnectPromise = null;\n resolve();\n };\n\n const finalizeReject = (error: Error) => {\n if (settled) {\n return;\n }\n settled = true;\n this.realtimeConnectPromise = null;\n reject(error);\n };\n\n socket.addEventListener(\"open\", () => {\n this.setRealtimeStatus(\"open\", \"socket_open\");\n finalizeResolve();\n });\n\n socket.addEventListener(\"message\", (event) => {\n this.handleRealtimeMessage(event.data);\n });\n\n socket.addEventListener(\"error\", () => {\n this.setRealtimeStatus(\n \"closed\",\n \"socket_error\",\n new Error(\"Realtime socket error.\"),\n );\n });\n\n socket.addEventListener(\"close\", (event) => {\n if (this.realtimeSocket === socket) {\n this.realtimeSocket = null;\n }\n\n const reason = event.reason || \"socket_closed\";\n const error = new Error(\n `Realtime socket closed (${event.code}${event.reason ? `: ${event.reason}` : \"\"}).`,\n );\n\n this.setRealtimeStatus(\"closed\", reason, error);\n if (!settled) {\n finalizeReject(error);\n }\n\n if (\n this.realtimeShouldReconnect &&\n this.realtimeEnabled &&\n this.realtimeAutoReconnect &&\n this.token\n ) {\n this.scheduleRealtimeReconnect(reason);\n }\n });\n });\n\n return this.realtimeConnectPromise;\n }\n\n disconnectRealtime(reason = \"client_disconnect\"): void {\n this.realtimeShouldReconnect = false;\n this.clearRealtimeReconnectTimer();\n\n if (this.realtimeSocket) {\n const socket = this.realtimeSocket;\n this.realtimeSocket = null;\n try {\n if (\n socket.readyState === WebSocket.OPEN ||\n socket.readyState === WebSocket.CONNECTING\n ) {\n socket.close(1000, reason);\n }\n } catch {\n // ignore close errors\n }\n }\n\n this.realtimeConnectPromise = null;\n this.setRealtimeStatus(\n this.realtimeEnabled ? \"idle\" : \"disabled\",\n reason,\n );\n }\n\n sendRealtime(message: RealtimeEnvelope | Record<string, unknown>): boolean {\n if (\n !this.realtimeSocket ||\n this.realtimeSocket.readyState !== WebSocket.OPEN\n ) {\n return false;\n }\n\n this.realtimeSocket.send(JSON.stringify(message));\n return true;\n }\n\n subscribeRealtime(subscriptions: string[]): boolean {\n return this.sendRealtime({\n type: \"subscribe\",\n channel: \"session\",\n event: \"session.subscribe\",\n data: { subscriptions },\n });\n }\n\n unsubscribeRealtime(subscriptions: string[]): boolean {\n return this.sendRealtime({\n type: \"unsubscribe\",\n channel: \"session\",\n event: \"session.unsubscribe\",\n data: { subscriptions },\n });\n }\n\n /**\n * \uC8FC\uAE30\uC801\uC73C\uB85C health \uCCB4\uD06C\uB97C \uC2E4\uD589\uD569\uB2C8\uB2E4.\n * CSRF \uCFE0\uD0A4 \uAC31\uC2E0\uACFC \uC11C\uBC84 \uC0C1\uD0DC \uD655\uC778\uC744 \uC790\uB3D9\uD654\uD569\uB2C8\uB2E4.\n * keepSession=true \uC774\uBA74 \uAC01 tick\uC5D0\uC11C \uC138\uC158 \uBD80\uD2B8\uC2A4\uD2B8\uB7A9\uB3C4 \uD568\uAED8 \uC2DC\uB3C4\uD569\uB2C8\uB2E4.\n *\n * @param intervalMs \uD638\uCD9C \uC8FC\uAE30(ms). \uAE30\uBCF8\uAC12: 5\uBD84\n */\n startHealthTick(intervalMs: number = 5 * 60 * 1000): void {\n this.stopHealthTick();\n const tick = (): void => {\n if (this.healthTickPromise) return;\n this.healthTickPromise = (\n this.csrfRefresher ? this.csrfRefresher() : Promise.resolve()\n )\n .then(() => {\n this.onHealthChange?.(true);\n })\n .catch(() => {\n this.onHealthChange?.(false);\n })\n .finally(() => {\n this.healthTickPromise = null;\n });\n };\n tick(); // \uC989\uC2DC 1\uD68C \uC2E4\uD589\n this.healthTickTimer = setInterval(tick, intervalMs);\n }\n\n /** health tick \uD0C0\uC774\uBA38\uB97C \uC911\uC9C0\uD569\uB2C8\uB2E4. */\n stopHealthTick(): void {\n if (this.healthTickTimer !== null) {\n clearInterval(this.healthTickTimer);\n this.healthTickTimer = null;\n }\n this.healthTickPromise = null;\n }\n\n // \u2500\u2500\u2500 \uC138\uC158 \uC720\uC9C0 \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n /** @deprecated \uC138\uC158 \uC5F0\uC7A5\uC740 health tick \uAE30\uBC18 \uBD80\uD2B8\uC2A4\uD2B8\uB7A9\uC73C\uB85C \uB300\uCCB4\uB418\uC5C8\uC2B5\uB2C8\uB2E4. */\n scheduleKeepSession(\n refreshToken: string,\n expiresIn: number,\n refreshFn: (\n rt: string,\n ) => Promise<{ access_token: string; expires_in: number }>,\n ): void {\n this.clearRefreshTimer();\n this.sessionRefreshToken = refreshToken;\n const delayMs = Math.max((expiresIn - this.refreshBuffer) * 1000, 0);\n this.refreshTimer = setTimeout(async () => {\n if (!this.sessionRefreshToken) return;\n try {\n const result = await refreshFn(this.sessionRefreshToken);\n this.onTokenRefreshed?.(result.access_token, result.expires_in);\n this.scheduleKeepSession(\n this.sessionRefreshToken,\n result.expires_in,\n refreshFn,\n );\n } catch (err) {\n this.clearRefreshTimer();\n this.onSessionExpired?.(\n err instanceof Error ? err : new Error(String(err)),\n );\n }\n }, delayMs);\n }\n\n /** @deprecated \uC138\uC158 \uC5F0\uC7A5\uC740 health tick \uAE30\uBC18 \uBD80\uD2B8\uC2A4\uD2B8\uB7A9\uC73C\uB85C \uB300\uCCB4\uB418\uC5C8\uC2B5\uB2C8\uB2E4. */\n clearRefreshTimer(): void {\n if (this.refreshTimer !== null) {\n clearTimeout(this.refreshTimer);\n this.refreshTimer = null;\n }\n }\n\n /**\n * \uC138\uC158 \uC790\uB3D9 \uC5F0\uC7A5\uC744 \uC911\uC9C0\uD569\uB2C8\uB2E4.\n * `logout()` \uD638\uCD9C \uC2DC \uC790\uB3D9\uC73C\uB85C \uC911\uC9C0\uB418\uBA70, \uC9C1\uC811 \uD638\uCD9C\uC774 \uD544\uC694\uD55C \uACBD\uC6B0\uB294 \uB4DC\uBB45\uB2C8\uB2E4.\n */\n stopKeepSession(): void {\n this.clearRefreshTimer();\n this.sessionRefreshToken = null;\n }\n\n applyRealtimeOptions(options?: boolean | RealtimeClientOptions): void {\n const normalized: RealtimeClientOptions =\n typeof options === \"boolean\"\n ? { enabled: options }\n : (options ?? {});\n\n this.realtimeEnabled = normalized.enabled ?? false;\n this.realtimePath =\n String(normalized.path ?? REALTIME_DEFAULT_PATH).trim() ||\n REALTIME_DEFAULT_PATH;\n this.realtimeAutoConnect = normalized.autoConnect ?? true;\n this.realtimeAutoReconnect = normalized.autoReconnect ?? true;\n this.realtimeReconnectDelayMs = Math.max(\n 250,\n normalized.reconnectDelayMs ?? 3000,\n );\n\n if (!this.realtimeEnabled) {\n this.disconnectRealtime(\"realtime_disabled\");\n return;\n }\n\n this.setRealtimeStatus(\"idle\", \"realtime_enabled\");\n if (this.token && this.realtimeAutoConnect) {\n void this.connectRealtime().catch(() => {});\n }\n }\n\n buildRealtimeUrl(): string {\n const rawBaseUrl =\n this.baseUrl || readEnv(\"VITE_ENTITY_SERVER_URL\") || \"\";\n const origin =\n typeof window !== \"undefined\" ? window.location.origin : \"\";\n const baseUrl = rawBaseUrl || origin;\n\n if (!baseUrl) {\n throw new Error(\"Realtime connection requires baseUrl.\");\n }\n\n const url = new URL(baseUrl, origin || undefined);\n const basePath =\n url.pathname === \"/\" ? \"\" : url.pathname.replace(/\\/+$/, \"\");\n const realtimePath = `/${this.realtimePath.replace(/^\\/+/, \"\")}`;\n\n url.pathname = `${basePath}${realtimePath}` || realtimePath;\n url.search = \"\";\n url.hash = \"\";\n url.protocol = url.protocol === \"https:\" ? \"wss:\" : \"ws:\";\n url.searchParams.set(\"access_token\", this.token);\n return url.toString();\n }\n\n handleRealtimeMessage(payload: unknown): void {\n if (typeof payload !== \"string\") {\n return;\n }\n\n let envelope: RealtimeEnvelope;\n try {\n envelope = JSON.parse(payload) as RealtimeEnvelope;\n } catch {\n return;\n }\n\n for (const listener of this.realtimeMessageListeners) {\n listener(envelope);\n }\n\n const listeners = this.realtimeEventListeners.get(envelope.event);\n if (listeners) {\n for (const listener of listeners) {\n listener(envelope);\n }\n }\n }\n\n scheduleRealtimeReconnect(reason: string): void {\n this.clearRealtimeReconnectTimer();\n this.realtimeReconnectTimer = setTimeout(() => {\n this.realtimeReconnectTimer = null;\n if (!this.realtimeEnabled || !this.token) {\n return;\n }\n this.setRealtimeStatus(\"connecting\", `${reason}:reconnect`);\n void this.connectRealtime().catch(() => {});\n }, this.realtimeReconnectDelayMs);\n }\n\n clearRealtimeReconnectTimer(): void {\n if (this.realtimeReconnectTimer !== null) {\n clearTimeout(this.realtimeReconnectTimer);\n this.realtimeReconnectTimer = null;\n }\n }\n\n setRealtimeStatus(\n status: RealtimeConnectionStatus,\n reason?: string,\n error?: Error,\n ): void {\n const previousStatus = this.realtimeStatus;\n if (\n previousStatus === status &&\n typeof reason === \"undefined\" &&\n typeof error === \"undefined\"\n ) {\n return;\n }\n\n this.realtimeStatus = status;\n for (const listener of this.realtimeStatusListeners) {\n listener({\n status,\n previousStatus,\n ...(reason ? { reason } : {}),\n ...(error ? { error } : {}),\n });\n }\n }\n\n applyCsrfHealth(): void {\n if (typeof document === \"undefined\") return;\n for (const chunk of document.cookie.split(\";\")) {\n const idx = chunk.indexOf(\"=\");\n if (idx < 0) continue;\n if (chunk.substring(0, idx).trim() === this.csrfCookieName) {\n this.csrfEnabled = !!chunk.substring(idx + 1).trim();\n return;\n }\n }\n this.csrfEnabled = false;\n }\n\n // \u2500\u2500\u2500 \uC694\uCCAD \uBCF8\uBB38 \uD30C\uC2F1 \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n /**\n * \uC694\uCCAD \uBC14\uB514\uB97C \uD30C\uC2F1\uD569\uB2C8\uB2E4.\n * `application/octet-stream`\uC774\uBA74 XChaCha20-Poly1305 \uBCF5\uD638\uD654, \uADF8 \uC678\uB294 JSON \uD30C\uC2F1\uD569\uB2C8\uB2E4.\n *\n * @param requireEncrypted `true`\uC774\uBA74 \uC554\uD638\uD654\uB41C \uC694\uCCAD\uB9CC \uD5C8\uC6A9\uD569\uB2C8\uB2E4.\n */\n readRequestBody<T = Record<string, unknown>>(\n body: ArrayBuffer | Uint8Array | string | T | null | undefined,\n contentType = \"application/json\",\n requireEncrypted = false,\n ): T {\n const key = derivePacketKey(\n this.hmacSecret,\n this.token || this.anonymousPacketToken,\n );\n return parseRequestBody<T>(body, contentType, requireEncrypted, key);\n }\n\n // \u2500\u2500\u2500 \uB0B4\uBD80 \uD5EC\uD37C \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n get reqOpts(): RequestOptions {\n return {\n baseUrl: this.baseUrl,\n token: this.token,\n anonymousPacketToken: this.anonymousPacketToken,\n apiKey: this.apiKey,\n hmacSecret: this.hmacSecret,\n encryptRequests: this.encryptRequests,\n csrfEnabled: this.csrfEnabled,\n csrfHeaderName: this.csrfHeaderName,\n csrfCookieName: this.csrfCookieName,\n refreshCsrfCookie: this.csrfEnabled ? this.csrfRefresher : null,\n onAccessToken: (token) => {\n this.token = token;\n },\n };\n }\n\n // \uC778\uC99D \uC694\uCCAD \uC804\uC5D0 \uD544\uC694\uD55C \uD074\uB77C\uC774\uC5B8\uD2B8 \uC900\uBE44 \uC791\uC5C5\uC744 \uC218\uD589\uD569\uB2C8\uB2E4.\n prepareRequest(_withAuth: boolean): Promise<void> {\n return Promise.resolve();\n }\n\n /**\n * \uCEE4\uC2A4\uD140 \uB77C\uC6B0\uD2B8 \uC9C1\uC811 \uD638\uCD9C\uC6A9 HTTP \uB124\uC784\uC2A4\uD398\uC774\uC2A4.\n * \uC778\uC99D\u00B7\uC554\uD638\uD654\u00B7HMAC \uB4F1 SDK \uC635\uC158\uC774 \uADF8\uB300\uB85C \uC801\uC6A9\uB429\uB2C8\uB2E4.\n *\n * @example\n * const res = await client.http.get<{ version: string }>(\"/api/v1/status\", false);\n * const res = await client.http.post<MyResponse>(\"/api/v1/custom\", { key: \"value\" });\n */\n get http() {\n // eslint-disable-next-line @typescript-eslint/no-this-alias\n const self = this;\n return {\n get<T>(\n path: string,\n withAuth = true,\n extraHeaders?: Record<string, string>,\n requestConfig?: EntityRequestConfig,\n ): Promise<T> {\n return self\n .prepareRequest(withAuth)\n .then(() =>\n entityRequest<T>(\n self.reqOpts,\n \"GET\",\n path,\n undefined,\n withAuth,\n extraHeaders,\n requestConfig ?? true,\n ),\n );\n },\n post<T>(\n path: string,\n body?: unknown,\n withAuth = true,\n extraHeaders?: Record<string, string>,\n requestConfig?: EntityRequestConfig,\n ): Promise<T> {\n return self\n .prepareRequest(withAuth)\n .then(() =>\n entityRequest<T>(\n self.reqOpts,\n \"POST\",\n path,\n body,\n withAuth,\n extraHeaders,\n requestConfig ?? true,\n ),\n );\n },\n put<T>(\n path: string,\n body?: unknown,\n withAuth = true,\n extraHeaders?: Record<string, string>,\n requestConfig?: EntityRequestConfig,\n ): Promise<T> {\n return self\n .prepareRequest(withAuth)\n .then(() =>\n entityRequest<T>(\n self.reqOpts,\n \"PUT\",\n path,\n body,\n withAuth,\n extraHeaders,\n requestConfig ?? true,\n ),\n );\n },\n patch<T>(\n path: string,\n body?: unknown,\n withAuth = true,\n extraHeaders?: Record<string, string>,\n requestConfig?: EntityRequestConfig,\n ): Promise<T> {\n return self\n .prepareRequest(withAuth)\n .then(() =>\n entityRequest<T>(\n self.reqOpts,\n \"PATCH\",\n path,\n body,\n withAuth,\n extraHeaders,\n requestConfig ?? true,\n ),\n );\n },\n delete<T>(\n path: string,\n body?: unknown,\n withAuth = true,\n extraHeaders?: Record<string, string>,\n requestConfig?: EntityRequestConfig,\n ): Promise<T> {\n return self\n .prepareRequest(withAuth)\n .then(() =>\n entityRequest<T>(\n self.reqOpts,\n \"DELETE\",\n path,\n body,\n withAuth,\n extraHeaders,\n requestConfig ?? true,\n ),\n );\n },\n };\n }\n\n request<T>(\n method: string,\n path: string,\n body?: unknown,\n withAuth = true,\n extraHeaders?: Record<string, string>,\n requestConfig?: EntityRequestConfig,\n ): Promise<T> {\n return this.prepareRequest(withAuth).then(() =>\n entityRequest<T>(\n this.reqOpts,\n method,\n path,\n body,\n withAuth,\n extraHeaders,\n requestConfig ?? true,\n ),\n );\n }\n\n /** PNG/\uBC14\uC774\uB108\uB9AC \uC751\uB2F5\uC744 ArrayBuffer\uB85C \uBC18\uD658\uD569\uB2C8\uB2E4. (QR, \uBC14\uCF54\uB4DC \uB4F1) */\n async requestBinary(\n method: string,\n path: string,\n body?: unknown,\n withAuth = true,\n ): Promise<ArrayBuffer> {\n await this.prepareRequest(withAuth);\n\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n };\n if (withAuth && this.token)\n headers[\"Authorization\"] = `Bearer ${this.token}`;\n if (this.apiKey) headers[\"X-API-Key\"] = this.apiKey;\n\n const res = await fetch(this.baseUrl + path, {\n method,\n headers,\n ...(body != null ? { body: JSON.stringify(body) } : {}),\n credentials: \"include\",\n });\n\n if (!res.ok) {\n const text = await res.text();\n const err = new Error(`HTTP ${res.status}: ${text}`);\n (err as { status?: number }).status = res.status;\n throw err;\n }\n\n return res.arrayBuffer();\n }\n\n /** multipart/form-data \uC694\uCCAD\uC744 \uBCF4\uB0C5\uB2C8\uB2E4. (\uD30C\uC77C \uC5C5\uB85C\uB4DC \uB4F1) */\n async requestForm<T>(\n method: string,\n path: string,\n form: FormData,\n withAuth = true,\n ): Promise<T> {\n const headers: Record<string, string> = {};\n if (withAuth && this.token)\n headers[\"Authorization\"] = `Bearer ${this.token}`;\n if (this.apiKey) headers[\"X-API-Key\"] = this.apiKey;\n\n const res = await fetch(this.baseUrl + path, {\n method,\n headers,\n body: form,\n credentials: \"include\",\n });\n\n const data = (await res.json()) as { ok?: boolean; message?: string };\n if (!data.ok) {\n const err = new Error(\n data.message ?? `EntityServer error (HTTP ${res.status})`,\n );\n (err as { status?: number }).status = res.status;\n throw err;\n }\n return data as T;\n }\n\n /** multipart/form-data \uC694\uCCAD\uC744 \uBCF4\uB0B4\uACE0 \uBC14\uC774\uB108\uB9AC(ArrayBuffer)\uB97C \uBC18\uD658\uD569\uB2C8\uB2E4. */\n async requestFormBinary(\n method: string,\n path: string,\n form: FormData,\n withAuth = true,\n ): Promise<ArrayBuffer> {\n const headers: Record<string, string> = {};\n if (withAuth && this.token)\n headers[\"Authorization\"] = `Bearer ${this.token}`;\n if (this.apiKey) headers[\"X-API-Key\"] = this.apiKey;\n\n const res = await fetch(this.baseUrl + path, {\n method,\n headers,\n body: form,\n credentials: \"include\",\n });\n\n if (!res.ok) {\n const text = await res.text();\n const err = new Error(`HTTP ${res.status}: ${text}`);\n (err as { status?: number }).status = res.status;\n throw err;\n }\n\n return res.arrayBuffer();\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["readEnv", "derivePacketKey", "parseRequestBody", "entityRequest", "REALTIME_DEFAULT_PATH", "EntityServerClientBase", "options", "envBaseUrl", "token", "apiKey", "secret", "value", "enabled", "listener", "eventName", "key", "listeners", "socket", "resolve", "reject", "settled", "finalizeResolve", "finalizeReject", "error", "event", "reason", "message", "subscriptions", "intervalMs", "tick", "refreshToken", "expiresIn", "refreshFn", "delayMs", "result", "err", "normalized", "rawBaseUrl", "origin", "baseUrl", "url", "basePath", "realtimePath", "payload", "envelope", "status", "previousStatus", "chunk", "idx", "body", "contentType", "requireEncrypted", "_withAuth", "self", "path", "withAuth", "extraHeaders", "requestConfig", "method", "headers", "res", "text", "form", "data"]
|
|
7
7
|
}
|
package/dist/client/hmac.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/client/hmac.ts"],
|
|
4
|
-
"sourcesContent": ["// @ts-ignore\
|
|
4
|
+
"sourcesContent": ["// @ts-ignore\nimport { sha256 } from \"@noble/hashes/sha2\";\n// @ts-ignore\nimport { hmac } from \"@noble/hashes/hmac\";\n\n/**\n * HMAC-SHA256 \uC11C\uBA85 \uD5E4\uB354\uB97C \uC0DD\uC131\uD569\uB2C8\uB2E4.\n *\n * \uC11C\uBA85 \uB300\uC0C1: `METHOD|PATH|TIMESTAMP|NONCE|BODY`\n *\n * @returns `X-API-Key`, `X-Timestamp`, `X-Nonce`, `X-Signature` \uD5E4\uB354 \uAC1D\uCCB4\n */\nexport function buildHmacHeaders(\n method: string,\n path: string,\n bodyBytes: Uint8Array,\n apiKey: string,\n hmacSecret: string,\n): Record<string, string> {\n const timestamp = String(Math.floor(Date.now() / 1000));\n const nonce = crypto.randomUUID();\n\n const prefix = new TextEncoder().encode(\n `${method}|${path}|${timestamp}|${nonce}|`,\n );\n const payload = new Uint8Array(prefix.length + bodyBytes.length);\n payload.set(prefix, 0);\n payload.set(bodyBytes, prefix.length);\n\n const sig = hmac(sha256, new TextEncoder().encode(hmacSecret), payload);\n const signature = [...sig]\n .map((b) => b.toString(16).padStart(2, \"0\"))\n .join(\"\");\n\n return {\n \"X-API-Key\": apiKey,\n \"X-Timestamp\": timestamp,\n \"X-Nonce\": nonce,\n \"X-Signature\": signature,\n };\n}\n"],
|
|
5
5
|
"mappings": "AACA,OAAS,UAAAA,MAAc,qBAEvB,OAAS,QAAAC,MAAY,qBASd,SAASC,EACZC,EACAC,EACAC,EACAC,EACAC,EACsB,CACtB,MAAMC,EAAY,OAAO,KAAK,MAAM,KAAK,IAAI,EAAI,GAAI,CAAC,EAChDC,EAAQ,OAAO,WAAW,EAE1BC,EAAS,IAAI,YAAY,EAAE,OAC7B,GAAGP,CAAM,IAAIC,CAAI,IAAII,CAAS,IAAIC,CAAK,GAC3C,EACME,EAAU,IAAI,WAAWD,EAAO,OAASL,EAAU,MAAM,EAC/DM,EAAQ,IAAID,EAAQ,CAAC,EACrBC,EAAQ,IAAIN,EAAWK,EAAO,MAAM,EAGpC,MAAME,EAAY,CAAC,GADPX,EAAKD,EAAQ,IAAI,YAAY,EAAE,OAAOO,CAAU,EAAGI,CAAO,CAC7C,EACpB,IAAKE,GAAMA,EAAE,SAAS,EAAE,EAAE,SAAS,EAAG,GAAG,CAAC,EAC1C,KAAK,EAAE,EAEZ,MAAO,CACH,YAAaP,EACb,cAAeE,EACf,UAAWC,EACX,cAAeG,CACnB,CACJ",
|
|
6
6
|
"names": ["sha256", "hmac", "buildHmacHeaders", "method", "path", "bodyBytes", "apiKey", "hmacSecret", "timestamp", "nonce", "prefix", "payload", "signature", "b"]
|
|
7
7
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/client/packet.ts"],
|
|
4
|
-
"sourcesContent": ["import {\
|
|
4
|
+
"sourcesContent": ["import {\n derivePacketKey as derivePacketKeyCore,\n encryptPacket as encryptPacketCore,\n decryptPacket as decryptPacketCore,\n} from \"../packet.js\";\n\n/**\n * \uD328\uD0B7 \uC554\uD638\uD654 \uD0A4\uB97C \uC720\uB3C4\uD569\uB2C8\uB2E4.\n * - HMAC \uBAA8\uB4DC (`hmacSecret` \uC720\uD6A8 \uC2DC): HKDF-SHA256(hmac_secret, \"entity-server:packet-encryption\")\n * - JWT \uBAA8\uB4DC: HKDF-SHA256(jwt_token, \"entity-server:packet-encryption\")\n */\nexport function derivePacketKey(hmacSecret: string, token: string): Uint8Array {\n return derivePacketKeyCore(hmacSecret || token);\n}\n\n/**\n * \uD3C9\uBB38 \uBC14\uC774\uD2B8\uB97C XChaCha20-Poly1305\uB85C \uC554\uD638\uD654\uD569\uB2C8\uB2E4.\n * \uD3EC\uB9F7: [random_magic:K][random_nonce:24][ciphertext+tag]\n * K = 2 + key[31] % 14 (\uD328\uD0B7 \uD0A4\uC5D0\uC11C \uC790\uB3D9 \uD30C\uC0DD)\n */\nexport function encryptPacket(\n plaintext: Uint8Array,\n key: Uint8Array,\n): Uint8Array {\n return encryptPacketCore(plaintext, key);\n}\n\n/**\n * XChaCha20-Poly1305 \uD328\uD0B7\uC744 \uBCF5\uD638\uD654\uD574 JSON \uAC1D\uCCB4\uB85C \uBCC0\uD658\uD569\uB2C8\uB2E4.\n * \uD3EC\uB9F7: [magic:K][nonce:24][ciphertext+tag]\n * K = 2 + key[31] % 14 (\uD328\uD0B7 \uD0A4\uC5D0\uC11C \uC790\uB3D9 \uD30C\uC0DD)\n */\nexport function decryptPacket<T>(buffer: ArrayBuffer, key: Uint8Array): T {\n const plaintext = decryptPacketCore(buffer, key);\n return JSON.parse(new TextDecoder().decode(plaintext)) as T;\n}\n\n/**\n * \uC694\uCCAD \uBC14\uB514\uB97C \uD30C\uC2F1\uD569\uB2C8\uB2E4. `application/octet-stream`\uC774\uBA74 \uBCF5\uD638\uD654, \uADF8 \uC678\uB294 JSON \uD30C\uC2F1\uD569\uB2C8\uB2E4.\n *\n * @param requireEncrypted `true`\uC774\uBA74 \uC554\uD638\uD654\uB41C \uC694\uCCAD\uB9CC \uD5C8\uC6A9\uD569\uB2C8\uB2E4.\n */\nexport function parseRequestBody<T>(\n body: ArrayBuffer | Uint8Array | string | T | null | undefined,\n contentType: string,\n requireEncrypted: boolean,\n key: Uint8Array,\n): T {\n const isEncrypted = contentType\n .toLowerCase()\n .includes(\"application/octet-stream\");\n\n if (requireEncrypted && !isEncrypted) {\n throw new Error(\n \"Encrypted request required: Content-Type must be application/octet-stream\",\n );\n }\n\n if (isEncrypted) {\n if (body == null) throw new Error(\"Encrypted request body is empty\");\n if (body instanceof ArrayBuffer) return decryptPacket<T>(body, key);\n if (body instanceof Uint8Array) {\n const sliced = body.buffer.slice(\n body.byteOffset,\n body.byteOffset + body.byteLength,\n );\n return decryptPacket<T>(sliced as ArrayBuffer, key);\n }\n throw new Error(\n \"Encrypted request body must be ArrayBuffer or Uint8Array\",\n );\n }\n\n if (body == null || body === \"\") return {} as T;\n if (typeof body === \"string\") return JSON.parse(body) as T;\n return body as T;\n}\n"],
|
|
5
5
|
"mappings": "AAAA,OACI,mBAAmBA,EACnB,iBAAiBC,EACjB,iBAAiBC,MACd,eAOA,SAASC,EAAgBC,EAAoBC,EAA2B,CAC3E,OAAOL,EAAoBI,GAAcC,CAAK,CAClD,CAOO,SAASC,EACZC,EACAC,EACU,CACV,OAAOP,EAAkBM,EAAWC,CAAG,CAC3C,CAOO,SAASC,EAAiBC,EAAqBF,EAAoB,CACtE,MAAMD,EAAYL,EAAkBQ,EAAQF,CAAG,EAC/C,OAAO,KAAK,MAAM,IAAI,YAAY,EAAE,OAAOD,CAAS,CAAC,CACzD,CAOO,SAASI,EACZC,EACAC,EACAC,EACAN,EACC,CACD,MAAMO,EAAcF,EACf,YAAY,EACZ,SAAS,0BAA0B,EAExC,GAAIC,GAAoB,CAACC,EACrB,MAAM,IAAI,MACN,2EACJ,EAGJ,GAAIA,EAAa,CACb,GAAIH,GAAQ,KAAM,MAAM,IAAI,MAAM,iCAAiC,EACnE,GAAIA,aAAgB,YAAa,OAAOH,EAAiBG,EAAMJ,CAAG,EAClE,GAAII,aAAgB,WAAY,CAC5B,MAAMI,EAASJ,EAAK,OAAO,MACvBA,EAAK,WACLA,EAAK,WAAaA,EAAK,UAC3B,EACA,OAAOH,EAAiBO,EAAuBR,CAAG,CACtD,CACA,MAAM,IAAI,MACN,0DACJ,CACJ,CAEA,OAAII,GAAQ,MAAQA,IAAS,GAAW,CAAC,EACrC,OAAOA,GAAS,SAAiB,KAAK,MAAMA,CAAI,EAC7CA,CACX",
|
|
6
6
|
"names": ["derivePacketKeyCore", "encryptPacketCore", "decryptPacketCore", "derivePacketKey", "hmacSecret", "token", "encryptPacket", "plaintext", "key", "decryptPacket", "buffer", "parseRequestBody", "body", "contentType", "requireEncrypted", "isEncrypted", "sliced"]
|
|
7
7
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/client/request.ts"],
|
|
4
|
-
"sourcesContent": ["import { derivePacketKey, encryptPacket, decryptPacket } from \"./packet.js\";\r\nimport { buildHmacHeaders } from \"./hmac.js\";\r\n\r\nexport interface RequestOptions {\r\n baseUrl: string;\r\n token: string;\r\n anonymousPacketToken: string;\r\n apiKey: string;\r\n hmacSecret: string;\r\n encryptRequests: boolean;\r\n csrfEnabled: boolean;\r\n csrfHeaderName: string;\r\n csrfCookieName: string;\r\n refreshCsrfCookie: (() => Promise<void>) | null;\r\n onAccessToken?: (token: string) => void;\r\n}\r\n\r\nexport interface EntityRequestConfig {\r\n requireOkShape?: boolean;\r\n allowStatuses?: number[];\r\n signal?: AbortSignal;\r\n}\r\n\r\nfunction resolvePacketSource(opts: RequestOptions): string {\r\n return opts.hmacSecret || opts.token || opts.anonymousPacketToken;\r\n}\r\n\r\nfunction resolveResponsePacketSource(\r\n opts: RequestOptions,\r\n withAuth: boolean,\r\n anonymousPacketToken: string,\r\n): string {\r\n if (opts.hmacSecret) {\r\n return opts.hmacSecret;\r\n }\r\n\r\n if (!withAuth) {\r\n return anonymousPacketToken;\r\n }\r\n\r\n return opts.token || anonymousPacketToken;\r\n}\r\n\r\nfunction maskPacketSource(value: string): string {\r\n if (!value) {\r\n return \"\";\r\n }\r\n\r\n if (value.length <= 8) {\r\n return `${value.slice(0, 2)}...${value.slice(-2)}`;\r\n }\r\n\r\n return `${value.slice(0, 4)}...${value.slice(-4)}`;\r\n}\r\n\r\nfunction logPacketDecryptError(details: {\r\n method: string;\r\n path: string;\r\n withAuth: boolean;\r\n status: number;\r\n contentType: string;\r\n responsePacketSource: string;\r\n tokenPresent: boolean;\r\n anonymousPacketTokenPresent: boolean;\r\n hmacEnabled: boolean;\r\n error: unknown;\r\n}): void {\r\n if (typeof console === \"undefined\" || typeof console.error !== \"function\") {\r\n return;\r\n }\r\n\r\n console.error(\"[entity-client] packet decrypt failed\", {\r\n method: details.method,\r\n path: details.path,\r\n withAuth: details.withAuth,\r\n status: details.status,\r\n contentType: details.contentType,\r\n responsePacketSource: maskPacketSource(details.responsePacketSource),\r\n tokenPresent: details.tokenPresent,\r\n anonymousPacketTokenPresent: details.anonymousPacketTokenPresent,\r\n hmacEnabled: details.hmacEnabled,\r\n error:\r\n details.error instanceof Error\r\n ? {\r\n name: details.error.name,\r\n message: details.error.message,\r\n stack: details.error.stack,\r\n }\r\n : details.error,\r\n });\r\n}\r\n\r\nfunction requiresCsrf(method: string): boolean {\r\n return method !== \"GET\" && method !== \"HEAD\" && method !== \"OPTIONS\";\r\n}\r\n\r\nfunction readCsrfCookie(name: string): string {\r\n if (typeof document === \"undefined\") return \"\";\r\n for (const chunk of document.cookie.split(\";\")) {\r\n const idx = chunk.indexOf(\"=\");\r\n if (idx < 0) continue;\r\n if (chunk.substring(0, idx).trim() === name) {\r\n return decodeURIComponent(chunk.substring(idx + 1).trim());\r\n }\r\n }\r\n return \"\";\r\n}\r\n\r\nfunction isCsrfError(status: number, message: string): boolean {\r\n if (status === 403 && /csrf/i.test(message)) {\r\n return true;\r\n }\r\n\r\n return (\r\n /csrf/i.test(message) &&\r\n /expired|token validation failed/i.test(message)\r\n );\r\n}\r\n\r\nasync function readErrorMessage(res: Response): Promise<string> {\r\n const contentType = res.headers.get(\"Content-Type\") ?? \"\";\r\n if (contentType.includes(\"application/json\")) {\r\n const data = (await res.json().catch(() => null)) as {\r\n error?: string;\r\n message?: string;\r\n } | null;\r\n if (data?.error) return data.error;\r\n if (data?.message) return data.message;\r\n }\r\n\r\n const text = await res.text().catch(() => \"\");\r\n return text || `HTTP ${res.status}`;\r\n}\r\n\r\n/**\r\n * Entity Server\uC5D0 HTTP \uC694\uCCAD\uC744 \uBCF4\uB0C5\uB2C8\uB2E4.\r\n *\r\n * - `encryptRequests` \uD65C\uC131\uD654 \uC2DC \uC778\uC99D\uB41C POST \uBC14\uB514\uB97C \uC790\uB3D9 \uC554\uD638\uD654\uD569\uB2C8\uB2E4.\r\n * - \uC751\uB2F5\uC774 `application/octet-stream`\uC774\uBA74 \uC790\uB3D9 \uBCF5\uD638\uD654\uD569\uB2C8\uB2E4.\r\n * - JSON \uC751\uB2F5\uC758 `ok`\uAC00 false\uC774\uBA74 \uC5D0\uB7EC\uB97C \uB358\uC9D1\uB2C8\uB2E4.\r\n */\r\nexport async function entityRequest<T>(\r\n opts: RequestOptions,\r\n method: string,\r\n path: string,\r\n body?: unknown,\r\n withAuth = true,\r\n extraHeaders: Record<string, string> = {},\r\n config: boolean | EntityRequestConfig = true,\r\n): Promise<T> {\r\n const requestConfig: EntityRequestConfig =\r\n typeof config === \"boolean\" ? { requireOkShape: config } : config;\r\n const requireOkShape = requestConfig.requireOkShape ?? true;\r\n const allowStatuses = new Set(requestConfig.allowStatuses ?? []);\r\n const signal = requestConfig.signal;\r\n\r\n const {\r\n baseUrl,\r\n token,\r\n apiKey,\r\n hmacSecret,\r\n encryptRequests,\r\n csrfEnabled,\r\n csrfHeaderName,\r\n csrfCookieName,\r\n refreshCsrfCookie,\r\n onAccessToken,\r\n } = opts;\r\n // checkHealth()\uAC00 \uC644\uB8CC\uB418\uAE30 \uC804 race condition\uC744 \uB9C9\uAE30 \uC704\uD574 anon_token \uCFE0\uD0A4\uB97C \uC9C1\uC811 fallback\uC73C\uB85C \uC77D\uC74C\r\n const anonymousPacketToken =\r\n opts.anonymousPacketToken || readCsrfCookie(\"anon_token\");\r\n const isHmacMode = withAuth && !!(apiKey && hmacSecret);\r\n const packetSource = resolvePacketSource(opts);\r\n const responsePacketSource = resolveResponsePacketSource(\r\n opts,\r\n withAuth,\r\n anonymousPacketToken,\r\n );\r\n const shouldUseCsrf = csrfEnabled && requiresCsrf(method) && !isHmacMode;\r\n let csrfToken = shouldUseCsrf ? readCsrfCookie(csrfCookieName) : \"\";\r\n let requestContentType = \"application/json\";\r\n const includeAnonymousPacketHeader = !isHmacMode && !!anonymousPacketToken;\r\n\r\n let fetchBody: string | Uint8Array | null = null;\r\n if (body != null) {\r\n const shouldEncrypt =\r\n encryptRequests &&\r\n !!packetSource &&\r\n withAuth &&\r\n method !== \"GET\" &&\r\n method !== \"HEAD\";\r\n\r\n if (shouldEncrypt) {\r\n const key = derivePacketKey(\r\n hmacSecret,\r\n token || anonymousPacketToken,\r\n );\r\n fetchBody = encryptPacket(\r\n new TextEncoder().encode(JSON.stringify(body)),\r\n key,\r\n );\r\n requestContentType = \"application/octet-stream\";\r\n } else {\r\n fetchBody = JSON.stringify(body);\r\n }\r\n }\r\n\r\n const buildHeaders = (\r\n resolvedCsrfToken: string,\r\n ): Record<string, string> => {\r\n const headers: Record<string, string> = { ...extraHeaders };\r\n const hasExplicitContentType = Object.keys(headers).some(\r\n (key) => key.toLowerCase() === \"content-type\",\r\n );\r\n if (fetchBody != null && !hasExplicitContentType) {\r\n headers[\"Content-Type\"] = requestContentType;\r\n }\r\n if (!isHmacMode && withAuth && token) {\r\n headers.Authorization = `Bearer ${token}`;\r\n }\r\n if (includeAnonymousPacketHeader) {\r\n headers[\"X-Packet-Token\"] = anonymousPacketToken;\r\n }\r\n if (shouldUseCsrf && resolvedCsrfToken) {\r\n headers[csrfHeaderName] = resolvedCsrfToken;\r\n }\r\n if (isHmacMode) {\r\n const bodyBytes =\r\n fetchBody instanceof Uint8Array\r\n ? fetchBody\r\n : typeof fetchBody === \"string\"\r\n ? new TextEncoder().encode(fetchBody)\r\n : new Uint8Array(0);\r\n Object.assign(\r\n headers,\r\n buildHmacHeaders(method, path, bodyBytes, apiKey, hmacSecret),\r\n );\r\n }\r\n return headers;\r\n };\r\n\r\n if (shouldUseCsrf && !csrfToken && refreshCsrfCookie) {\r\n await refreshCsrfCookie();\r\n csrfToken = readCsrfCookie(csrfCookieName);\r\n }\r\n\r\n const executeRequest = (resolvedCsrfToken: string): Promise<Response> =>\r\n fetch(baseUrl + path, {\r\n method,\r\n headers: buildHeaders(resolvedCsrfToken),\r\n ...(fetchBody != null\r\n ? { body: fetchBody as RequestInit[\"body\"] }\r\n : {}),\r\n credentials: \"include\",\r\n signal,\r\n });\r\n\r\n let res = await executeRequest(csrfToken);\r\n\r\n if (!res.ok) {\r\n const message = await readErrorMessage(res.clone());\r\n if (\r\n shouldUseCsrf &&\r\n refreshCsrfCookie &&\r\n isCsrfError(res.status, message)\r\n ) {\r\n await refreshCsrfCookie();\r\n csrfToken = readCsrfCookie(csrfCookieName);\r\n res = await executeRequest(csrfToken);\r\n } else if (!allowStatuses.has(res.status)) {\r\n const err = new Error(message);\r\n (err as { status?: number }).status = res.status;\r\n throw err;\r\n } else {\r\n // \uD5C8\uC6A9\uB41C \uBE44\uC815\uC0C1 \uC0C1\uD0DC\uB294 \uBCF8\uBB38\uC744 \uADF8\uB300\uB85C \uD30C\uC2F1\uD574 \uD638\uCD9C\uC790\uC5D0\uAC8C \uB118\uAE41\uB2C8\uB2E4.\r\n }\r\n }\r\n\r\n if (!res.ok && !allowStatuses.has(res.status)) {\r\n const err = new Error(await readErrorMessage(res));\r\n (err as { status?: number }).status = res.status;\r\n throw err;\r\n }\r\n\r\n const accessTokenHeader = res.headers.get(\"X-Access-Token\")?.trim() ?? \"\";\r\n\r\n const contentType = res.headers.get(\"Content-Type\") ?? \"\";\r\n if (contentType.includes(\"application/octet-stream\")) {\r\n const key = derivePacketKey(hmacSecret, responsePacketSource);\r\n const encryptedBody = await res.arrayBuffer();\r\n let decrypted: T;\r\n\r\n try {\r\n decrypted = decryptPacket<T>(encryptedBody, key);\r\n } catch (error) {\r\n logPacketDecryptError({\r\n method,\r\n path,\r\n withAuth,\r\n status: res.status,\r\n contentType,\r\n responsePacketSource,\r\n tokenPresent: !!token,\r\n anonymousPacketTokenPresent: !!anonymousPacketToken,\r\n hmacEnabled: !!hmacSecret,\r\n error,\r\n });\r\n throw error;\r\n }\r\n\r\n if (accessTokenHeader) {\r\n onAccessToken?.(accessTokenHeader);\r\n }\r\n return decrypted;\r\n }\r\n\r\n if (accessTokenHeader) {\r\n onAccessToken?.(accessTokenHeader);\r\n }\r\n\r\n if (!contentType.includes(\"application/json\")) {\r\n return (await res.text()) as T;\r\n }\r\n\r\n const data = (await res.json()) as { ok?: boolean; message?: string };\r\n if (requireOkShape && !data.ok && !allowStatuses.has(res.status)) {\r\n const err = new Error(\r\n data.message ?? `EntityServer error (HTTP ${res.status})`,\r\n );\r\n (err as { status?: number }).status = res.status;\r\n throw err;\r\n }\r\n\r\n return data as T;\r\n}\r\n"],
|
|
4
|
+
"sourcesContent": ["import { derivePacketKey, encryptPacket, decryptPacket } from \"./packet.js\";\nimport { buildHmacHeaders } from \"./hmac.js\";\n\nexport interface RequestOptions {\n baseUrl: string;\n token: string;\n anonymousPacketToken: string;\n apiKey: string;\n hmacSecret: string;\n encryptRequests: boolean;\n csrfEnabled: boolean;\n csrfHeaderName: string;\n csrfCookieName: string;\n refreshCsrfCookie: (() => Promise<void>) | null;\n onAccessToken?: (token: string) => void;\n}\n\nexport interface EntityRequestConfig {\n requireOkShape?: boolean;\n allowStatuses?: number[];\n signal?: AbortSignal;\n}\n\nfunction resolvePacketSource(opts: RequestOptions): string {\n return opts.hmacSecret || opts.token || opts.anonymousPacketToken;\n}\n\nfunction resolveResponsePacketSource(\n opts: RequestOptions,\n withAuth: boolean,\n anonymousPacketToken: string,\n): string {\n if (opts.hmacSecret) {\n return opts.hmacSecret;\n }\n\n if (!withAuth) {\n return anonymousPacketToken;\n }\n\n return opts.token || anonymousPacketToken;\n}\n\nfunction maskPacketSource(value: string): string {\n if (!value) {\n return \"\";\n }\n\n if (value.length <= 8) {\n return `${value.slice(0, 2)}...${value.slice(-2)}`;\n }\n\n return `${value.slice(0, 4)}...${value.slice(-4)}`;\n}\n\nfunction logPacketDecryptError(details: {\n method: string;\n path: string;\n withAuth: boolean;\n status: number;\n contentType: string;\n responsePacketSource: string;\n tokenPresent: boolean;\n anonymousPacketTokenPresent: boolean;\n hmacEnabled: boolean;\n error: unknown;\n}): void {\n if (typeof console === \"undefined\" || typeof console.error !== \"function\") {\n return;\n }\n\n console.error(\"[entity-client] packet decrypt failed\", {\n method: details.method,\n path: details.path,\n withAuth: details.withAuth,\n status: details.status,\n contentType: details.contentType,\n responsePacketSource: maskPacketSource(details.responsePacketSource),\n tokenPresent: details.tokenPresent,\n anonymousPacketTokenPresent: details.anonymousPacketTokenPresent,\n hmacEnabled: details.hmacEnabled,\n error:\n details.error instanceof Error\n ? {\n name: details.error.name,\n message: details.error.message,\n stack: details.error.stack,\n }\n : details.error,\n });\n}\n\nfunction requiresCsrf(method: string): boolean {\n return method !== \"GET\" && method !== \"HEAD\" && method !== \"OPTIONS\";\n}\n\nfunction readCsrfCookie(name: string): string {\n if (typeof document === \"undefined\") return \"\";\n for (const chunk of document.cookie.split(\";\")) {\n const idx = chunk.indexOf(\"=\");\n if (idx < 0) continue;\n if (chunk.substring(0, idx).trim() === name) {\n return decodeURIComponent(chunk.substring(idx + 1).trim());\n }\n }\n return \"\";\n}\n\nfunction isCsrfError(status: number, message: string): boolean {\n if (status === 403 && /csrf/i.test(message)) {\n return true;\n }\n\n return (\n /csrf/i.test(message) &&\n /expired|token validation failed/i.test(message)\n );\n}\n\nasync function readErrorMessage(res: Response): Promise<string> {\n const contentType = res.headers.get(\"Content-Type\") ?? \"\";\n if (contentType.includes(\"application/json\")) {\n const data = (await res.json().catch(() => null)) as {\n error?: string;\n message?: string;\n } | null;\n if (data?.error) return data.error;\n if (data?.message) return data.message;\n }\n\n const text = await res.text().catch(() => \"\");\n return text || `HTTP ${res.status}`;\n}\n\n/**\n * Entity Server\uC5D0 HTTP \uC694\uCCAD\uC744 \uBCF4\uB0C5\uB2C8\uB2E4.\n *\n * - `encryptRequests` \uD65C\uC131\uD654 \uC2DC \uC778\uC99D\uB41C POST \uBC14\uB514\uB97C \uC790\uB3D9 \uC554\uD638\uD654\uD569\uB2C8\uB2E4.\n * - \uC751\uB2F5\uC774 `application/octet-stream`\uC774\uBA74 \uC790\uB3D9 \uBCF5\uD638\uD654\uD569\uB2C8\uB2E4.\n * - JSON \uC751\uB2F5\uC758 `ok`\uAC00 false\uC774\uBA74 \uC5D0\uB7EC\uB97C \uB358\uC9D1\uB2C8\uB2E4.\n */\nexport async function entityRequest<T>(\n opts: RequestOptions,\n method: string,\n path: string,\n body?: unknown,\n withAuth = true,\n extraHeaders: Record<string, string> = {},\n config: boolean | EntityRequestConfig = true,\n): Promise<T> {\n const requestConfig: EntityRequestConfig =\n typeof config === \"boolean\" ? { requireOkShape: config } : config;\n const requireOkShape = requestConfig.requireOkShape ?? true;\n const allowStatuses = new Set(requestConfig.allowStatuses ?? []);\n const signal = requestConfig.signal;\n\n const {\n baseUrl,\n token,\n apiKey,\n hmacSecret,\n encryptRequests,\n csrfEnabled,\n csrfHeaderName,\n csrfCookieName,\n refreshCsrfCookie,\n onAccessToken,\n } = opts;\n // checkHealth()\uAC00 \uC644\uB8CC\uB418\uAE30 \uC804 race condition\uC744 \uB9C9\uAE30 \uC704\uD574 anon_token \uCFE0\uD0A4\uB97C \uC9C1\uC811 fallback\uC73C\uB85C \uC77D\uC74C\n const anonymousPacketToken =\n opts.anonymousPacketToken || readCsrfCookie(\"anon_token\");\n const isHmacMode = withAuth && !!(apiKey && hmacSecret);\n const packetSource = resolvePacketSource(opts);\n const responsePacketSource = resolveResponsePacketSource(\n opts,\n withAuth,\n anonymousPacketToken,\n );\n const shouldUseCsrf = csrfEnabled && requiresCsrf(method) && !isHmacMode;\n let csrfToken = shouldUseCsrf ? readCsrfCookie(csrfCookieName) : \"\";\n let requestContentType = \"application/json\";\n const includeAnonymousPacketHeader = !isHmacMode && !!anonymousPacketToken;\n\n let fetchBody: string | Uint8Array | null = null;\n if (body != null) {\n const shouldEncrypt =\n encryptRequests &&\n !!packetSource &&\n withAuth &&\n method !== \"GET\" &&\n method !== \"HEAD\";\n\n if (shouldEncrypt) {\n const key = derivePacketKey(\n hmacSecret,\n token || anonymousPacketToken,\n );\n fetchBody = encryptPacket(\n new TextEncoder().encode(JSON.stringify(body)),\n key,\n );\n requestContentType = \"application/octet-stream\";\n } else {\n fetchBody = JSON.stringify(body);\n }\n }\n\n const buildHeaders = (\n resolvedCsrfToken: string,\n ): Record<string, string> => {\n const headers: Record<string, string> = { ...extraHeaders };\n const hasExplicitContentType = Object.keys(headers).some(\n (key) => key.toLowerCase() === \"content-type\",\n );\n if (fetchBody != null && !hasExplicitContentType) {\n headers[\"Content-Type\"] = requestContentType;\n }\n if (!isHmacMode && withAuth && token) {\n headers.Authorization = `Bearer ${token}`;\n }\n if (includeAnonymousPacketHeader) {\n headers[\"X-Packet-Token\"] = anonymousPacketToken;\n }\n if (shouldUseCsrf && resolvedCsrfToken) {\n headers[csrfHeaderName] = resolvedCsrfToken;\n }\n if (isHmacMode) {\n const bodyBytes =\n fetchBody instanceof Uint8Array\n ? fetchBody\n : typeof fetchBody === \"string\"\n ? new TextEncoder().encode(fetchBody)\n : new Uint8Array(0);\n Object.assign(\n headers,\n buildHmacHeaders(method, path, bodyBytes, apiKey, hmacSecret),\n );\n }\n return headers;\n };\n\n if (shouldUseCsrf && !csrfToken && refreshCsrfCookie) {\n await refreshCsrfCookie();\n csrfToken = readCsrfCookie(csrfCookieName);\n }\n\n const executeRequest = (resolvedCsrfToken: string): Promise<Response> =>\n fetch(baseUrl + path, {\n method,\n headers: buildHeaders(resolvedCsrfToken),\n ...(fetchBody != null\n ? { body: fetchBody as RequestInit[\"body\"] }\n : {}),\n credentials: \"include\",\n signal,\n });\n\n let res = await executeRequest(csrfToken);\n\n if (!res.ok) {\n const message = await readErrorMessage(res.clone());\n if (\n shouldUseCsrf &&\n refreshCsrfCookie &&\n isCsrfError(res.status, message)\n ) {\n await refreshCsrfCookie();\n csrfToken = readCsrfCookie(csrfCookieName);\n res = await executeRequest(csrfToken);\n } else if (!allowStatuses.has(res.status)) {\n const err = new Error(message);\n (err as { status?: number }).status = res.status;\n throw err;\n } else {\n // \uD5C8\uC6A9\uB41C \uBE44\uC815\uC0C1 \uC0C1\uD0DC\uB294 \uBCF8\uBB38\uC744 \uADF8\uB300\uB85C \uD30C\uC2F1\uD574 \uD638\uCD9C\uC790\uC5D0\uAC8C \uB118\uAE41\uB2C8\uB2E4.\n }\n }\n\n if (!res.ok && !allowStatuses.has(res.status)) {\n const err = new Error(await readErrorMessage(res));\n (err as { status?: number }).status = res.status;\n throw err;\n }\n\n const accessTokenHeader = res.headers.get(\"X-Access-Token\")?.trim() ?? \"\";\n\n const contentType = res.headers.get(\"Content-Type\") ?? \"\";\n if (contentType.includes(\"application/octet-stream\")) {\n const key = derivePacketKey(hmacSecret, responsePacketSource);\n const encryptedBody = await res.arrayBuffer();\n let decrypted: T;\n\n try {\n decrypted = decryptPacket<T>(encryptedBody, key);\n } catch (error) {\n logPacketDecryptError({\n method,\n path,\n withAuth,\n status: res.status,\n contentType,\n responsePacketSource,\n tokenPresent: !!token,\n anonymousPacketTokenPresent: !!anonymousPacketToken,\n hmacEnabled: !!hmacSecret,\n error,\n });\n throw error;\n }\n\n if (accessTokenHeader) {\n onAccessToken?.(accessTokenHeader);\n }\n return decrypted;\n }\n\n if (accessTokenHeader) {\n onAccessToken?.(accessTokenHeader);\n }\n\n if (!contentType.includes(\"application/json\")) {\n return (await res.text()) as T;\n }\n\n const data = (await res.json()) as { ok?: boolean; message?: string };\n if (requireOkShape && !data.ok && !allowStatuses.has(res.status)) {\n const err = new Error(\n data.message ?? `EntityServer error (HTTP ${res.status})`,\n );\n (err as { status?: number }).status = res.status;\n throw err;\n }\n\n return data as T;\n}\n"],
|
|
5
5
|
"mappings": "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",
|
|
6
6
|
"names": ["derivePacketKey", "encryptPacket", "decryptPacket", "buildHmacHeaders", "resolvePacketSource", "opts", "resolveResponsePacketSource", "withAuth", "anonymousPacketToken", "maskPacketSource", "value", "logPacketDecryptError", "details", "requiresCsrf", "method", "readCsrfCookie", "name", "chunk", "idx", "isCsrfError", "status", "message", "readErrorMessage", "res", "data", "entityRequest", "path", "body", "extraHeaders", "config", "requestConfig", "requireOkShape", "allowStatuses", "signal", "baseUrl", "token", "apiKey", "hmacSecret", "encryptRequests", "csrfEnabled", "csrfHeaderName", "csrfCookieName", "refreshCsrfCookie", "onAccessToken", "isHmacMode", "packetSource", "responsePacketSource", "shouldUseCsrf", "csrfToken", "requestContentType", "includeAnonymousPacketHeader", "fetchBody", "key", "buildHeaders", "resolvedCsrfToken", "headers", "hasExplicitContentType", "bodyBytes", "executeRequest", "err", "accessTokenHeader", "contentType", "encryptedBody", "decrypted", "error"]
|
|
7
7
|
}
|
package/dist/client/utils.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/client/utils.ts"],
|
|
4
|
-
"sourcesContent": ["/**\
|
|
4
|
+
"sourcesContent": ["/**\n * \uD658\uACBD\uBCC0\uC218\uB97C \uC77D\uC2B5\uB2C8\uB2E4.\n * - \uBE0C\uB77C\uC6B0\uC800/Vite: `import.meta.env`\n * - Node.js: `process.env`\n */\nexport function readEnv(name: string): string | undefined {\n // Vite / \uAE30\uD0C0 \uBC88\uB4E4\uB7EC (import.meta.env)\n const meta = import.meta as unknown as {\n env?: Record<string, string | undefined>;\n };\n if (meta?.env?.[name] != null) return meta.env[name];\n\n // Node.js (process.env)\n const _proc = (\n globalThis as { process?: { env?: Record<string, string | undefined> } }\n ).process;\n if (_proc?.env?.[name] != null) {\n return _proc.env[name];\n }\n\n return undefined;\n}\n\n/** \uCFFC\uB9AC \uD30C\uB77C\uBBF8\uD130 \uAC1D\uCCB4\uB97C URL \uCFFC\uB9AC \uBB38\uC790\uC5F4\uB85C \uBCC0\uD658\uD569\uB2C8\uB2E4. `orderBy` \uD0A4\uB294 `order_by`\uB85C \uBCC0\uD658\uB429\uB2C8\uB2E4. */\nexport function buildQuery(params: Record<string, unknown>): string {\n return Object.entries(params)\n .filter(([, value]) => value != null)\n .map(\n ([key, value]) =>\n `${encodeURIComponent(key === \"orderBy\" ? \"order_by\" : key)}=${encodeURIComponent(String(value))}`,\n )\n .join(\"&\");\n}\n"],
|
|
5
5
|
"mappings": "AAKO,SAASA,EAAQC,EAAkC,CAEtD,MAAMC,EAAO,YAGb,GAAIA,GAAM,MAAMD,CAAI,GAAK,KAAM,OAAOC,EAAK,IAAID,CAAI,EAGnD,MAAME,EACF,WACF,QACF,GAAIA,GAAO,MAAMF,CAAI,GAAK,KACtB,OAAOE,EAAM,IAAIF,CAAI,CAI7B,CAGO,SAASG,EAAWC,EAAyC,CAChE,OAAO,OAAO,QAAQA,CAAM,EACvB,OAAO,CAAC,CAAC,CAAEC,CAAK,IAAMA,GAAS,IAAI,EACnC,IACG,CAAC,CAACC,EAAKD,CAAK,IACR,GAAG,mBAAmBC,IAAQ,UAAY,WAAaA,CAAG,CAAC,IAAI,mBAAmB,OAAOD,CAAK,CAAC,CAAC,EACxG,EACC,KAAK,GAAG,CACjB",
|
|
6
6
|
"names": ["readEnv", "name", "meta", "_proc", "buildQuery", "params", "value", "key"]
|
|
7
7
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/hooks/useEntityAppServer.ts"],
|
|
4
|
-
"sourcesContent": ["import { EntityAppServerApi, entityAppServer } from \"../index.js\";\
|
|
4
|
+
"sourcesContent": ["import { EntityAppServerApi, entityAppServer } from \"../index.js\";\nimport {\n useEntityClient,\n type UseEntityClientResult,\n type UseEntityServerOptions,\n} from \"./useEntityClient.js\";\n\nexport interface UseEntityAppServerOptions extends UseEntityServerOptions {}\n\nexport interface UseEntityAppServerResult extends UseEntityClientResult<EntityAppServerApi> {}\n\n/**\n * React \uD658\uACBD\uC5D0\uC11C EntityAppServerApi \uC778\uC2A4\uD134\uC2A4\uC640 mutation \uC0C1\uD0DC\uB97C \uBC18\uD658\uD569\uB2C8\uB2E4.\n *\n * - `singleton=true`(\uAE30\uBCF8): \uD328\uD0A4\uC9C0 \uC804\uC5ED `entityAppServer` \uC778\uC2A4\uD134\uC2A4\uB97C \uC0AC\uC6A9\uD569\uB2C8\uB2E4.\n * - `singleton=false`: \uCEF4\uD3EC\uB10C\uD2B8 \uC2A4\uCF54\uD504\uC758 \uC0C8 \uC778\uC2A4\uD134\uC2A4\uB97C \uC0DD\uC131\uD569\uB2C8\uB2E4.\n *\n * @example\n * ```tsx\n * const { submit, del, isPending, error } = useEntityAppServer();\n * ```\n */\nexport function useEntityAppServer(\n options: UseEntityAppServerOptions = {},\n): UseEntityAppServerResult {\n return useEntityClient(options, {\n singletonInstance: entityAppServer,\n ClientClass: EntityAppServerApi,\n });\n}\n"],
|
|
5
5
|
"mappings": "AAAA,OAAS,sBAAAA,EAAoB,mBAAAC,MAAuB,cACpD,OACI,mBAAAC,MAGG,uBAiBA,SAASC,EACZC,EAAqC,CAAC,EACd,CACxB,OAAOF,EAAgBE,EAAS,CAC5B,kBAAmBH,EACnB,YAAaD,CACjB,CAAC,CACL",
|
|
6
6
|
"names": ["EntityAppServerApi", "entityAppServer", "useEntityClient", "useEntityAppServer", "options"]
|
|
7
7
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/hooks/useEntityClient.ts"],
|
|
4
|
-
"sourcesContent": ["import { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\
|
|
4
|
+
"sourcesContent": ["import { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport {\n type EntityQueryRequest,\n type EntityServerClientOptions,\n} from \"../index.js\";\n\nexport interface UseEntityServerOptions extends EntityServerClientOptions {\n singleton?: boolean;\n tokenResolver?: () => string | undefined | null;\n /**\n * \uD398\uC774\uC9C0 \uC0C8\uB85C\uACE0\uCE68 \uD6C4 \uB85C\uADF8\uC778 \uC0C1\uD0DC\uB97C \uBCF5\uC6D0\uD560 \uB54C \uC0AC\uC6A9\uD569\uB2C8\uB2E4.\n * \uAC12 \uC790\uCCB4\uB294 \uB354 \uC774\uC0C1 \uC0AC\uC6A9\uD558\uC9C0 \uC54A\uACE0, \uAC12\uC774 \uC788\uC73C\uBA74 \uB9C8\uC6B4\uD2B8 \uC2DC `client.checkHealth(true)`\uB85C\n * refresh \uCFE0\uD0A4 \uAE30\uBC18 \uC138\uC158 \uBD80\uD2B8\uC2A4\uD2B8\uB7A9\uC744 \uC2DC\uB3C4\uD569\uB2C8\uB2E4.\n */\n resumeSession?: string;\n}\n\n/** useEntityClient\uAC00 \uC694\uAD6C\uD558\uB294 \uCD5C\uC18C \uD074\uB77C\uC774\uC5B8\uD2B8 \uC778\uD130\uD398\uC774\uC2A4 */\nexport interface EntityClientShape {\n configure(options: Partial<EntityServerClientOptions>): void;\n setToken(token: string): void;\n checkHealth?: (bootstrapAuth?: boolean) => Promise<unknown>;\n refreshToken(refreshToken?: string): Promise<unknown>;\n submit(\n entity: string,\n data: Record<string, unknown>,\n opts?: { transactionId?: string; skipHooks?: boolean },\n ): Promise<{ ok: boolean; seq: number }>;\n delete(\n entity: string,\n seq: number,\n opts?: { transactionId?: string; hard?: boolean; skipHooks?: boolean },\n ): Promise<{ ok: boolean; deleted: number }>;\n query<T = unknown>(\n entity: string,\n req: EntityQueryRequest,\n ): Promise<{ ok: boolean; data: { items: T[]; count: number } }>;\n}\n\ntype ClientConstructor<TClient extends EntityClientShape> = new (\n options?: EntityServerClientOptions,\n) => TClient;\n\nexport interface UseEntityClientResult<TClient extends EntityClientShape> {\n client: TClient;\n isPending: boolean;\n error: Error | null;\n reset: () => void;\n submit: (\n entity: string,\n data: Record<string, unknown>,\n opts?: { transactionId?: string; skipHooks?: boolean },\n ) => Promise<{ ok: boolean; seq: number }>;\n del: (\n entity: string,\n seq: number,\n opts?: { transactionId?: string; hard?: boolean; skipHooks?: boolean },\n ) => Promise<{ ok: boolean; deleted: number }>;\n query: <T = unknown>(\n entity: string,\n req: EntityQueryRequest,\n ) => Promise<{ ok: boolean; data: { items: T[]; count: number } }>;\n}\n\nexport function useEntityClient<TClient extends EntityClientShape>(\n options: UseEntityServerOptions,\n config: {\n singletonInstance: TClient;\n ClientClass: ClientConstructor<TClient>;\n },\n): UseEntityClientResult<TClient> {\n const {\n singleton = true,\n tokenResolver,\n baseUrl,\n token,\n resumeSession,\n } = options;\n\n const [isPending, setIsPending] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n\n const mountedRef = useRef(true);\n useEffect(() => {\n mountedRef.current = true;\n return () => {\n mountedRef.current = false;\n };\n }, []);\n\n const client = useMemo(() => {\n const instance = singleton\n ? config.singletonInstance\n : new config.ClientClass({ baseUrl, token });\n\n if (singleton) {\n instance.configure({ baseUrl, token });\n }\n\n const resolvedToken = tokenResolver?.();\n if (typeof resolvedToken === \"string\") {\n instance.setToken(resolvedToken);\n }\n\n return instance;\n }, [\n singleton,\n tokenResolver,\n baseUrl,\n token,\n config.ClientClass,\n config.singletonInstance,\n ]);\n\n const resumeTokenRef = useRef(resumeSession);\n useEffect(() => {\n if (!resumeTokenRef.current) return;\n if (client.checkHealth) {\n client.checkHealth(true).catch(() => {\n // refresh cookie \uB9CC\uB8CC \uB4F1 \u2014 onSessionExpired \uCF5C\uBC31\uC5D0\uC11C \uCC98\uB9AC \uAC00\uB2A5\n });\n return;\n }\n\n client.refreshToken(resumeTokenRef.current).catch(() => {\n // \uD558\uC704 \uD638\uD658 fallback\n });\n }, [client]);\n\n const run = useCallback(async <T>(fn: () => Promise<T>): Promise<T> => {\n if (mountedRef.current) {\n setIsPending(true);\n setError(null);\n }\n try {\n const result = await fn();\n return result;\n } catch (err) {\n const wrapped = err instanceof Error ? err : new Error(String(err));\n if (mountedRef.current) setError(wrapped);\n throw wrapped;\n } finally {\n if (mountedRef.current) setIsPending(false);\n }\n }, []);\n\n const submit = useCallback<UseEntityClientResult<TClient>[\"submit\"]>(\n (entity, data, opts) => run(() => client.submit(entity, data, opts)),\n [client, run],\n );\n\n const del = useCallback<UseEntityClientResult<TClient>[\"del\"]>(\n (entity, seq, opts) => run(() => client.delete(entity, seq, opts)),\n [client, run],\n );\n\n const query = useCallback<UseEntityClientResult<TClient>[\"query\"]>(\n (entity, req) => run(() => client.query(entity, req)),\n [client, run],\n );\n\n const reset = useCallback(() => {\n setIsPending(false);\n setError(null);\n }, []);\n\n return { client, isPending, error, reset, submit, del, query };\n}\n"],
|
|
5
5
|
"mappings": "AAAA,OAAS,eAAAA,EAAa,aAAAC,EAAW,WAAAC,EAAS,UAAAC,EAAQ,YAAAC,MAAgB,QAgE3D,SAASC,EACZC,EACAC,EAI8B,CAC9B,KAAM,CACF,UAAAC,EAAY,GACZ,cAAAC,EACA,QAAAC,EACA,MAAAC,EACA,cAAAC,CACJ,EAAIN,EAEE,CAACO,EAAWC,CAAY,EAAIV,EAAS,EAAK,EAC1C,CAACW,EAAOC,CAAQ,EAAIZ,EAAuB,IAAI,EAE/Ca,EAAad,EAAO,EAAI,EAC9BF,EAAU,KACNgB,EAAW,QAAU,GACd,IAAM,CACTA,EAAW,QAAU,EACzB,GACD,CAAC,CAAC,EAEL,MAAMC,EAAShB,EAAQ,IAAM,CACzB,MAAMiB,EAAWX,EACXD,EAAO,kBACP,IAAIA,EAAO,YAAY,CAAE,QAAAG,EAAS,MAAAC,CAAM,CAAC,EAE3CH,GACAW,EAAS,UAAU,CAAE,QAAAT,EAAS,MAAAC,CAAM,CAAC,EAGzC,MAAMS,EAAgBX,IAAgB,EACtC,OAAI,OAAOW,GAAkB,UACzBD,EAAS,SAASC,CAAa,EAG5BD,CACX,EAAG,CACCX,EACAC,EACAC,EACAC,EACAJ,EAAO,YACPA,EAAO,iBACX,CAAC,EAEKc,EAAiBlB,EAAOS,CAAa,EAC3CX,EAAU,IAAM,CACZ,GAAKoB,EAAe,QACpB,IAAIH,EAAO,YAAa,CACpBA,EAAO,YAAY,EAAI,EAAE,MAAM,IAAM,CAErC,CAAC,EACD,MACJ,CAEAA,EAAO,aAAaG,EAAe,OAAO,EAAE,MAAM,IAAM,CAExD,CAAC,EACL,EAAG,CAACH,CAAM,CAAC,EAEX,MAAMI,EAAMtB,EAAY,MAAUuB,GAAqC,CAC/DN,EAAW,UACXH,EAAa,EAAI,EACjBE,EAAS,IAAI,GAEjB,GAAI,CAEA,OADe,MAAMO,EAAG,CAE5B,OAASC,EAAK,CACV,MAAMC,EAAUD,aAAe,MAAQA,EAAM,IAAI,MAAM,OAAOA,CAAG,CAAC,EAClE,MAAIP,EAAW,SAASD,EAASS,CAAO,EAClCA,CACV,QAAE,CACMR,EAAW,SAASH,EAAa,EAAK,CAC9C,CACJ,EAAG,CAAC,CAAC,EAECY,EAAS1B,EACX,CAAC2B,EAAQC,EAAMC,IAASP,EAAI,IAAMJ,EAAO,OAAOS,EAAQC,EAAMC,CAAI,CAAC,EACnE,CAACX,EAAQI,CAAG,CAChB,EAEMQ,EAAM9B,EACR,CAAC2B,EAAQI,EAAKF,IAASP,EAAI,IAAMJ,EAAO,OAAOS,EAAQI,EAAKF,CAAI,CAAC,EACjE,CAACX,EAAQI,CAAG,CAChB,EAEMU,EAAQhC,EACV,CAAC2B,EAAQM,IAAQX,EAAI,IAAMJ,EAAO,MAAMS,EAAQM,CAAG,CAAC,EACpD,CAACf,EAAQI,CAAG,CAChB,EAEMY,EAAQlC,EAAY,IAAM,CAC5Bc,EAAa,EAAK,EAClBE,EAAS,IAAI,CACjB,EAAG,CAAC,CAAC,EAEL,MAAO,CAAE,OAAAE,EAAQ,UAAAL,EAAW,MAAAE,EAAO,MAAAmB,EAAO,OAAAR,EAAQ,IAAAI,EAAK,MAAAE,CAAM,CACjE",
|
|
6
6
|
"names": ["useCallback", "useEffect", "useMemo", "useRef", "useState", "useEntityClient", "options", "config", "singleton", "tokenResolver", "baseUrl", "token", "resumeSession", "isPending", "setIsPending", "error", "setError", "mountedRef", "client", "instance", "resolvedToken", "resumeTokenRef", "run", "fn", "err", "wrapped", "submit", "entity", "data", "opts", "del", "seq", "query", "req", "reset"]
|
|
7
7
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/hooks/useEntityServer.ts"],
|
|
4
|
-
"sourcesContent": ["import { EntityServerApi, entityServer } from \"../index.js\";\
|
|
4
|
+
"sourcesContent": ["import { EntityServerApi, entityServer } from \"../index.js\";\nimport {\n useEntityClient,\n type UseEntityClientResult,\n type UseEntityServerOptions,\n} from \"./useEntityClient.js\";\n\nexport type { UseEntityServerOptions };\n\nexport interface UseEntityServerResult extends UseEntityClientResult<EntityServerApi> {}\n\n/**\n * React \uD658\uACBD\uC5D0\uC11C EntityServerApi \uC778\uC2A4\uD134\uC2A4\uC640 mutation \uC0C1\uD0DC\uB97C \uBC18\uD658\uD569\uB2C8\uB2E4.\n *\n * - `singleton=true`(\uAE30\uBCF8): \uD328\uD0A4\uC9C0 \uC804\uC5ED `entityServer` \uC778\uC2A4\uD134\uC2A4\uB97C \uC0AC\uC6A9\uD569\uB2C8\uB2E4.\n * - `singleton=false`: \uCEF4\uD3EC\uB10C\uD2B8 \uC2A4\uCF54\uD504\uC758 \uC0C8 \uC778\uC2A4\uD134\uC2A4\uB97C \uC0DD\uC131\uD569\uB2C8\uB2E4.\n *\n * @example\n * ```tsx\n * const { submit, del, isPending, error, reset } = useEntityServer();\n *\n * const handleSave = async () => {\n * await submit(\"account\", { name: \"\uD64D\uAE38\uB3D9\" });\n * };\n * ```\n */\nexport function useEntityServer(\n options: UseEntityServerOptions = {},\n): UseEntityServerResult {\n return useEntityClient(options, {\n singletonInstance: entityServer,\n ClientClass: EntityServerApi,\n });\n}\n"],
|
|
5
5
|
"mappings": "AAAA,OAAS,mBAAAA,EAAiB,gBAAAC,MAAoB,cAC9C,OACI,mBAAAC,MAGG,uBAqBA,SAASC,EACZC,EAAkC,CAAC,EACd,CACrB,OAAOF,EAAgBE,EAAS,CAC5B,kBAAmBH,EACnB,YAAaD,CACjB,CAAC,CACL",
|
|
6
6
|
"names": ["EntityServerApi", "entityServer", "useEntityClient", "useEntityServer", "options"]
|
|
7
7
|
}
|