entity-server-client 0.2.3 → 0.2.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/EntityServerClient.d.ts +203 -0
- package/dist/client/hmac.d.ts +8 -0
- package/dist/client/packet.d.ts +22 -0
- package/dist/client/request.d.ts +16 -0
- package/dist/client/utils.d.ts +4 -0
- package/dist/index.d.ts +3 -366
- package/dist/index.js +1 -1
- package/dist/index.js.map +4 -4
- package/dist/react.js +1 -1
- package/dist/react.js.map +4 -4
- package/dist/types.d.ts +165 -0
- package/docs/apis.md +13 -6
- package/package.json +1 -1
- package/src/EntityServerClient.ts +546 -0
- package/src/client/hmac.ts +41 -0
- package/src/client/packet.ts +113 -0
- package/src/client/request.ts +102 -0
- package/src/client/utils.ts +18 -0
- package/src/index.ts +3 -824
- package/src/types.ts +186 -0
package/dist/index.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
|
-
"sources": ["../src/index.ts"],
|
|
4
|
-
"sourcesContent": ["// @ts-ignore\nimport { xchacha20poly1305 } from \"@noble/ciphers/chacha\";\n// @ts-ignore\nimport { sha256 } from \"@noble/hashes/sha2\";\n\n/**\n * \uC5D4\uD2F0\uD2F0 \uBAA9\uB85D \uC870\uD68C \uD30C\uB77C\uBBF8\uD130\uC785\uB2C8\uB2E4.\n *\n * ```ts\n * client.list(\"post\", {\n * page: 1, limit: 10,\n * orderBy: \"created_time\", orderDir: \"DESC\",\n * fields: [\"seq\", \"title\", \"created_time\"],\n * conditions: { status: \"active\" },\n * });\n * ```\n */\nexport interface EntityListParams {\n /** \uC870\uD68C \uD398\uC774\uC9C0 \uBC88\uD638. \uAE30\uBCF8\uAC12: `1` */\n page?: number;\n /** \uD398\uC774\uC9C0\uB2F9 \uB808\uCF54\uB4DC \uC218. \uAE30\uBCF8\uAC12: `20` */\n limit?: number;\n /** \uC815\uB82C \uAE30\uC900 \uD544\uB4DC\uBA85 */\n orderBy?: string;\n /** \uC815\uB82C \uBC29\uD5A5. \uAE30\uBCF8\uAC12: `\"ASC\"` */\n orderDir?: \"ASC\" | \"DESC\";\n /**\n * \uBC18\uD658\uD560 \uD544\uB4DC \uBAA9\uB85D.\n *\n * - **\uBBF8\uC9C0\uC815 (\uAE30\uBCF8\uAC12)**: \uC5D4\uD2F0\uD2F0\uC758 \uC778\uB371\uC2A4 \uD544\uB4DC\uB9CC \uBC18\uD658\uD569\uB2C8\uB2E4.\n * \uBCF5\uD638\uD654\uB97C \uAC74\uB108\uB6F0\uAE30 \uB54C\uBB38\uC5D0 **\uAC00\uC7A5 \uBE60\uB985\uB2C8\uB2E4**.\n * - `[\"*\"]`: \uC804\uCCB4 \uD544\uB4DC \uBC18\uD658 (\uBCF5\uD638\uD654 \uC218\uD589).\n * - \uD544\uB4DC\uBA85 \uBAA9\uB85D: \uD574\uB2F9 \uD544\uB4DC\uB9CC \uBC18\uD658\uD569\uB2C8\uB2E4.\n * \uC5D4\uD2F0\uD2F0 \uC124\uC815\uC5D0 `index`\uB85C \uC120\uC5B8\uB41C \uD544\uB4DC\uB9CC \uC9C0\uC815 \uAC00\uB2A5\uD569\uB2C8\uB2E4.\n * \uC874\uC7AC\uD558\uC9C0 \uC54A\uB294 \uD544\uB4DC\uBA85\uC744 \uC9C0\uC815\uD558\uBA74 \uC11C\uBC84 \uC5D0\uB7EC\uAC00 \uBC1C\uC0DD\uD569\uB2C8\uB2E4.\n * - `seq`, `created_time`, `updated_time`, `license_seq`\uB294 \uD544\uB4DC\uC5D0 \uAD00\uACC4\uC5C6\uC774 \uD56D\uC0C1 \uD3EC\uD568\uB429\uB2C8\uB2E4.\n *\n * ```ts\n * // \uAE30\uBCF8\uAC12 (\uC778\uB371\uC2A4 \uD544\uB4DC\uB9CC, \uAC00\uC7A5 \uBE60\uB984)\n * client.list(\"account\")\n * // \uC804\uCCB4 \uD544\uB4DC\n * client.list(\"account\", { fields: [\"*\"] })\n * // seq, name, email\uB9CC\n * client.list(\"account\", { fields: [\"seq\", \"name\", \"email\"] })\n * ```\n */\n fields?: string[];\n /** \uD544\uD130 \uC870\uAC74. POST body\uB85C \uC804\uB2EC\uB429\uB2C8\uB2E4. (\uC608: `{ status: \"active\" }`) */\n conditions?: Record<string, unknown>;\n}\n\n/**\n * `query()` \uBA54\uC11C\uB4DC\uC5D0 \uC804\uB2EC\uD558\uB294 SQL \uCFFC\uB9AC \uC694\uCCAD\uC785\uB2C8\uB2E4.\n *\n * - `sql`: SELECT \uC804\uC6A9 SQL. \uC778\uB371\uC2A4 \uD14C\uC774\uBE14\uB9CC \uC870\uD68C \uAC00\uB2A5\uD558\uBA70 JOIN \uC9C0\uC6D0.\n * - `params`: SQL \uBC14\uC778\uB529 \uD30C\uB77C\uBBF8\uD130 (`?` \uD50C\uB808\uC774\uC2A4\uD640\uB354 \uB300\uC751).\n * - `limit`: \uCD5C\uB300 \uBC18\uD658 \uAC74\uC218 (\uCD5C\uB300 1000. \uBBF8\uC9C0\uC815 \uC2DC \uC11C\uBC84 \uAE30\uBCF8\uAC12 \uC801\uC6A9).\n *\n * ```ts\n * client.query(\"order\", {\n * sql: `SELECT o.seq, o.status, u.name\n * FROM order o\n * JOIN account u ON u.data_seq = o.account_seq\n * WHERE o.status = ?`,\n * params: [\"pending\"],\n * limit: 100,\n * });\n * ```\n */\nexport interface EntityQueryRequest {\n sql: string;\n params?: unknown[];\n limit?: number;\n}\n\nexport interface RegisterPushDeviceOptions {\n platform?: string;\n deviceType?: string;\n browser?: string;\n browserVersion?: string;\n pushEnabled?: boolean;\n transactionId?: string;\n}\n\n/** EntityServerClient \uC0DD\uC131/\uC124\uC815 \uC635\uC158\uC785\uB2C8\uB2E4. */\nexport interface EntityServerClientOptions {\n baseUrl?: string;\n token?: string;\n packetMagicLen?: number;\n /**\n * `true`\uC774\uBA74 \uC778\uC99D\uB41C POST/PUT \uC694\uCCAD \uBC14\uB514\uB97C XChaCha20-Poly1305\uB85C \uC554\uD638\uD654\uD569\uB2C8\uB2E4.\n *\n * \uC11C\uBC84\uC758 `EnablePacketEncryption`\uC774 \uD65C\uC131\uD654\uB41C \uACBD\uC6B0 \uD544\uC218\uB85C \uC124\uC815\uD574\uC57C \uD569\uB2C8\uB2E4.\n * \uB85C\uADF8\uC778(`login()`)\u00B7\uD1A0\uD070 \uAC31\uC2E0(`refreshToken()`)\uC740 \uC778\uC99D \uC804 \uC694\uCCAD\uC774\uBBC0\uB85C \uC790\uB3D9\uC73C\uB85C \uAC74\uB108\uB701\uB2C8\uB2E4.\n *\n * \uAE30\uBCF8\uAC12: `false`\n */\n encryptRequests?: boolean;\n /**\n * `true`\uC774\uBA74 `login()` \uC131\uACF5 \uD6C4 Access Token \uB9CC\uB8CC \uC804\uC5D0 \uC790\uB3D9\uC73C\uB85C \uAC31\uC2E0(silent refresh)\uD569\uB2C8\uB2E4.\n * \uAC31\uC2E0 \uC2DC\uC810\uC740 `expires_in - refreshBuffer` \uCD08\uC785\uB2C8\uB2E4.\n *\n * \uAC31\uC2E0 \uC131\uACF5 \uC2DC `onTokenRefreshed`, \uC2E4\uD328 \uC2DC `onSessionExpired` \uCF5C\uBC31\uC774 \uD638\uCD9C\uB429\uB2C8\uB2E4.\n *\n * \uAE30\uBCF8\uAC12: `false`\n */\n keepSession?: boolean;\n /**\n * \uB9CC\uB8CC \uBA87 \uCD08 \uC804\uC5D0 \uC790\uB3D9 \uAC31\uC2E0\uC744 \uC2DC\uB3C4\uD560\uC9C0 \uC124\uC815\uD569\uB2C8\uB2E4.\n *\n * \uC608: `expires_in = 3600`, `refreshBuffer = 60` \u2192 3540\uCD08 \uD6C4 \uAC31\uC2E0\n *\n * \uAE30\uBCF8\uAC12: `60`\n */\n refreshBuffer?: number;\n /**\n * \uC790\uB3D9 \uAC31\uC2E0 \uC131\uACF5 \uC2DC \uD638\uCD9C\uB418\uB294 \uCF5C\uBC31\uC785\uB2C8\uB2E4.\n * \uC0C8 `access_token`\uACFC `expires_in`\uC774 \uC804\uB2EC\uB429\uB2C8\uB2E4.\n * \uC571\uC740 \uC774 \uCF5C\uBC31\uC5D0\uC11C localStorage \uB4F1\uC5D0 \uD1A0\uD070\uC744 \uC800\uC7A5\uD574\uC57C \uD569\uB2C8\uB2E4.\n */\n onTokenRefreshed?: (accessToken: string, expiresIn: number) => void;\n /**\n * \uC138\uC158 \uC720\uC9C0 \uAC31\uC2E0 \uC2E4\uD328 \uC2DC \uD638\uCD9C\uB418\uB294 \uCF5C\uBC31\uC785\uB2C8\uB2E4.\n * refresh_token \uB9CC\uB8CC \uB4F1\uC73C\uB85C \uC7AC\uBC1C\uAE09\uC774 \uBD88\uAC00\uB2A5\uD55C \uACBD\uC6B0\uC785\uB2C8\uB2E4.\n * \uC571\uC740 \uC774 \uCF5C\uBC31\uC5D0\uC11C \uB85C\uADF8\uC778 \uD398\uC774\uC9C0\uB85C \uC774\uB3D9\uD558\uB294 \uB4F1\uC758 \uCC98\uB9AC\uB97C \uD574\uC57C \uD569\uB2C8\uB2E4.\n */\n onSessionExpired?: (error: Error) => void;\n}\n\n/**\n * `list()`, `history()` \uC751\uB2F5\uC758 `data` \uD544\uB4DC \uAD6C\uC870\uC785\uB2C8\uB2E4.\n *\n * \uC11C\uBC84\uB294 \uD56D\uC0C1 \uC774 \uAD6C\uC870\uB85C \uBC18\uD658\uD569\uB2C8\uB2E4:\n * ```json\n * { \"ok\": true, \"data\": { \"items\": [...], \"total\": 100, \"page\": 1, \"limit\": 20 } }\n * ```\n */\nexport interface EntityListResult<T = unknown> {\n items: T[];\n /** \uC804\uCCB4 \uB808\uCF54\uB4DC \uC218 */\n total: number;\n /** \uD604\uC7AC \uD398\uC774\uC9C0 \uBC88\uD638 */\n page: number;\n /** \uD398\uC774\uC9C0\uB2F9 \uB808\uCF54\uB4DC \uC218 */\n limit: number;\n}\n\n/**\n * `history()` \uC751\uB2F5\uC758 \uAC1C\uBCC4 \uC774\uB825 \uB808\uCF54\uB4DC \uAD6C\uC870\uC785\uB2C8\uB2E4.\n *\n * - `action`: `\"INSERT\"` | `\"UPDATE\"` | `\"DELETE_SOFT\"` | `\"DELETE_HARD\"` | `\"ROLLBACK\"`\n * - `data_snapshot`: \uBCC0\uACBD \uB2F9\uC2DC \uC5D4\uD2F0\uD2F0 \uB370\uC774\uD130 \uC2A4\uB0C5\uC0F7\n */\nexport interface EntityHistoryRecord<T = unknown> {\n seq: number;\n action:\n | \"INSERT\"\n | \"UPDATE\"\n | \"DELETE_SOFT\"\n | \"DELETE_HARD\"\n | \"ROLLBACK\"\n | string;\n data_snapshot: T | null;\n changed_by: number | null;\n changed_time: string;\n}\n\n/** Vite \uD658\uACBD\uBCC0\uC218(`import.meta.env`)\uC5D0\uC11C \uAC12\uC744 \uC77D\uC2B5\uB2C8\uB2E4. */\nfunction readEnv(name: string): string | undefined {\n const meta = import.meta as unknown as {\n env?: Record<string, string | undefined>;\n };\n return meta?.env?.[name];\n}\n\nexport class EntityServerClient {\n private baseUrl: string;\n private token: string;\n private packetMagicLen: number;\n private encryptRequests: boolean;\n private activeTxId: string | null = null;\n\n // \uC138\uC158 \uC720\uC9C0 \uAD00\uB828\n private keepSession: boolean;\n private refreshBuffer: number;\n private onTokenRefreshed?: (accessToken: string, expiresIn: number) => void;\n private onSessionExpired?: (error: Error) => void;\n private _sessionRefreshToken: string | null = null;\n private _refreshTimer: ReturnType<typeof setTimeout> | null = null;\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 `http://localhost:47200`\n * - `packetMagicLen`: `VITE_ENTITY_SERVER_PACKET_MAGIC_LEN` \uB610\uB294 `4`\n */\n constructor(options: EntityServerClientOptions = {}) {\n const envBaseUrl = readEnv(\"VITE_ENTITY_SERVER_URL\");\n const envMagicLen = readEnv(\"VITE_ENTITY_SERVER_PACKET_MAGIC_LEN\");\n\n this.baseUrl = (\n options.baseUrl ??\n envBaseUrl ??\n \"http://localhost:47200\"\n ).replace(/\\/$/, \"\");\n\n this.token = options.token ?? \"\";\n this.packetMagicLen =\n options.packetMagicLen ?? (envMagicLen ? Number(envMagicLen) : 4);\n this.encryptRequests = options.encryptRequests ?? false;\n this.keepSession = options.keepSession ?? false;\n this.refreshBuffer = options.refreshBuffer ?? 60;\n this.onTokenRefreshed = options.onTokenRefreshed;\n this.onSessionExpired = options.onSessionExpired;\n }\n\n /** baseUrl, token, packetMagicLen, encryptRequests \uAC12\uC744 \uB7F0\uD0C0\uC784\uC5D0 \uAC31\uC2E0\uD569\uB2C8\uB2E4. */\n configure(options: Partial<EntityServerClientOptions>): void {\n if (options.baseUrl) {\n this.baseUrl = options.baseUrl.replace(/\\/$/, \"\");\n }\n if (typeof options.token === \"string\") {\n this.token = options.token;\n }\n if (typeof options.packetMagicLen === \"number\") {\n this.packetMagicLen = options.packetMagicLen;\n }\n if (typeof options.encryptRequests === \"boolean\") {\n this.encryptRequests = options.encryptRequests;\n }\n if (typeof options.keepSession === \"boolean\") {\n this.keepSession = options.keepSession;\n }\n if (typeof options.refreshBuffer === \"number\") {\n this.refreshBuffer = options.refreshBuffer;\n }\n if (options.onTokenRefreshed) {\n this.onTokenRefreshed = options.onTokenRefreshed;\n }\n if (options.onSessionExpired) {\n this.onSessionExpired = options.onSessionExpired;\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 }\n\n /** \uC554\uD638\uD654 \uD328\uD0B7 magic \uAE38\uC774(`packet_magic_len`)\uB97C \uC124\uC815\uD569\uB2C8\uB2E4. */\n setPacketMagicLen(length: number): void {\n this.packetMagicLen = length;\n }\n\n /** \uD604\uC7AC \uC554\uD638\uD654 \uD328\uD0B7 magic \uAE38\uC774\uB97C \uBC18\uD658\uD569\uB2C8\uB2E4. */\n getPacketMagicLen(): number {\n return this.packetMagicLen;\n }\n\n /**\n * \uC790\uB3D9 \uD1A0\uD070 \uAC31\uC2E0 \uD0C0\uC774\uBA38\uB97C \uC2DC\uC791\uD569\uB2C8\uB2E4.\n * @param refreshToken \uAC31\uC2E0\uC5D0 \uC0AC\uC6A9\uD560 Refresh Token\n * @param expiresIn Access Token\uC758 \uC720\uD6A8 \uAE30\uAC04 (\uCD08)\n */\n private _scheduleKeepSession(\n refreshToken: string,\n expiresIn: number,\n ): void {\n this._clearRefreshTimer();\n this._sessionRefreshToken = refreshToken;\n\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 this.refreshToken(\n this._sessionRefreshToken,\n );\n this.onTokenRefreshed?.(result.access_token, result.expires_in);\n // \uAC31\uC2E0 \uC131\uACF5 \uC2DC \uB2E4\uC74C \uB9CC\uB8CC \uC804 \uD0C0\uC774\uBA38 \uC7AC\uC608\uC57D\n this._scheduleKeepSession(\n this._sessionRefreshToken,\n result.expires_in,\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 /** \uC790\uB3D9 \uAC31\uC2E0 \uD0C0\uC774\uBA38\uB97C \uC815\uB9AC\uD569\uB2C8\uB2E4. */\n private _clearRefreshTimer(): void {\n if (this._refreshTimer !== null) {\n clearTimeout(this._refreshTimer);\n this._refreshTimer = null;\n }\n }\n\n /**\n * \uC138\uC158 \uC720\uC9C0 \uD0C0\uC774\uBA38\uB97C \uC911\uC9C0\uD569\uB2C8\uB2E4.\n * `logout()` \uD638\uCD9C \uC2DC \uC790\uB3D9\uC73C\uB85C \uC911\uC9C0\uB418\uBBC0\uB85C \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 /**\n * \uC11C\uBC84 \uD5EC\uC2A4 \uCCB4\uD06C\uB97C \uC218\uD589\uD558\uACE0 \uD328\uD0B7 \uC554\uD638\uD654 \uD65C\uC131 \uC5EC\uBD80\uB97C \uC790\uB3D9\uC73C\uB85C \uAC10\uC9C0\uD569\uB2C8\uB2E4.\n *\n * \uC11C\uBC84\uAC00 `packet_encryption: true`\uB97C \uC751\uB2F5\uD558\uBA74 \uC774\uD6C4 \uBAA8\uB4E0 \uC694\uCCAD\uC5D0 \uC554\uD638\uD654\uAC00 \uC790\uB3D9 \uC801\uC6A9\uB429\uB2C8\uB2E4.\n * \uCD08\uAE30\uD654 \uC9C1\uD6C4 \uB610\uB294 \uB85C\uADF8\uC778 \uC804\uC5D0 \uD638\uCD9C\uD558\uBA74 \uC554\uD638\uD654 \uC124\uC815\uC744 \uC790\uB3D9\uC73C\uB85C \uAD6C\uC131\uD560 \uC218 \uC788\uC2B5\uB2C8\uB2E4.\n *\n * ```ts\n * await client.checkHealth();\n * await client.login(email, password); // \uC774\uD6C4 \uC694\uCCAD\uC740 \uC554\uD638\uD654 \uC790\uB3D9 \uC801\uC6A9\n * ```\n *\n * @returns `{ ok: true }` \uB610\uB294 `{ ok: true, packet_encryption: true }`\n */\n async checkHealth(): Promise<{ ok: boolean; packet_encryption?: boolean }> {\n const res = await fetch(`${this.baseUrl}/v1/health`, {\n signal: AbortSignal.timeout(3000),\n });\n const data = (await res.json()) as {\n ok: boolean;\n packet_encryption?: boolean;\n };\n if (data.packet_encryption) {\n this.encryptRequests = true;\n }\n return data;\n }\n\n /** \uB85C\uADF8\uC778 \uD6C4 `access_token`\uC744 \uB0B4\uBD80 \uC0C1\uD0DC\uC5D0 \uC800\uC7A5\uD569\uB2C8\uB2E4. */\n async login(\n email: string,\n password: string,\n ): Promise<{\n access_token: string;\n refresh_token: string;\n expires_in: number;\n }> {\n const data = await this.request<{\n data: {\n access_token: string;\n refresh_token: string;\n expires_in: number;\n };\n }>(\"POST\", \"/v1/auth/login\", { email, passwd: password }, false);\n this.token = data.data.access_token;\n if (this.keepSession) {\n this._scheduleKeepSession(\n data.data.refresh_token,\n data.data.expires_in,\n );\n }\n return data.data;\n }\n\n /** Refresh Token\uC73C\uB85C Access Token\uC744 \uC7AC\uBC1C\uAE09\uBC1B\uC544 \uB0B4\uBD80 \uD1A0\uD070\uC744 \uAD50\uCCB4\uD569\uB2C8\uB2E4. */\n async refreshToken(\n refreshToken: string,\n ): Promise<{ access_token: string; expires_in: number }> {\n const data = await this.request<{\n data: { access_token: string; expires_in: number };\n }>(\"POST\", \"/v1/auth/refresh\", { refresh_token: refreshToken }, false);\n this.token = data.data.access_token;\n if (this.keepSession) {\n this._scheduleKeepSession(refreshToken, data.data.expires_in);\n }\n return data.data;\n }\n\n /**\n * \uC11C\uBC84\uC5D0 \uB85C\uADF8\uC544\uC6C3\uC744 \uC694\uCCAD\uD558\uACE0 \uB0B4\uBD80 \uD1A0\uD070\uC744 \uCD08\uAE30\uD654\uD569\uB2C8\uB2E4.\n * refresh_token\uC744 \uC11C\uBC84\uC5D0 \uC804\uB2EC\uD574 \uBB34\uD6A8\uD654\uD569\uB2C8\uB2E4.\n */\n async logout(refreshToken: string): Promise<{ ok: boolean }> {\n this.stopKeepSession();\n const data = await this.request<{ ok: boolean }>(\n \"POST\",\n \"/v1/auth/logout\",\n { refresh_token: refreshToken },\n false,\n );\n this.token = \"\";\n return data;\n }\n\n /** \uD2B8\uB79C\uC7AD\uC158\uC744 \uC2DC\uC791\uD558\uACE0 \uD65C\uC131 \uD2B8\uB79C\uC7AD\uC158 ID\uB97C \uC800\uC7A5\uD569\uB2C8\uB2E4. */\n async transStart(): Promise<string> {\n const res = await this.request<{ ok: boolean; transaction_id: string }>(\n \"POST\",\n \"/v1/transaction/start\",\n undefined,\n false,\n );\n this.activeTxId = res.transaction_id;\n return this.activeTxId;\n }\n\n /** \uD65C\uC131 \uD2B8\uB79C\uC7AD\uC158(\uB610\uB294 \uC804\uB2EC\uB41C transactionId)\uC744 \uB864\uBC31\uD569\uB2C8\uB2E4. */\n transRollback(transactionId?: string): Promise<{ ok: boolean }> {\n const txId = transactionId ?? this.activeTxId;\n if (!txId) {\n return Promise.reject(\n new Error(\"No active transaction. Call transStart() first.\"),\n );\n }\n this.activeTxId = null;\n return this.request(\"POST\", `/v1/transaction/rollback/${txId}`);\n }\n\n /** \uD65C\uC131 \uD2B8\uB79C\uC7AD\uC158(\uB610\uB294 \uC804\uB2EC\uB41C transactionId)\uC744 \uCEE4\uBC0B\uD569\uB2C8\uB2E4.\n *\n * @returns `results` \uBC30\uC5F4: commit\uB41C \uAC01 \uC791\uC5C5\uC758 `entity`, `action`, `seq`\n */\n transCommit(transactionId?: string): Promise<{\n ok: boolean;\n results: Array<{ entity: string; action: string; seq: number }>;\n }> {\n const txId = transactionId ?? this.activeTxId;\n if (!txId) {\n return Promise.reject(\n new Error(\"No active transaction. Call transStart() first.\"),\n );\n }\n this.activeTxId = null;\n return this.request(\"POST\", `/v1/transaction/commit/${txId}`);\n }\n\n /** \uC2DC\uD000\uC2A4 ID\uB85C \uC5D4\uD2F0\uD2F0 \uB2E8\uAC74\uC744 \uC870\uD68C\uD569\uB2C8\uB2E4. */\n get<T = unknown>(\n entity: string,\n seq: number,\n opts: { skipHooks?: boolean } = {},\n ): Promise<{ ok: boolean; data: T }> {\n const q = opts.skipHooks ? \"?skipHooks=true\" : \"\";\n return this.request(\"GET\", `/v1/entity/${entity}/${seq}${q}`);\n }\n\n /** \uC870\uAC74\uC73C\uB85C \uC5D4\uD2F0\uD2F0 \uB2E8\uAC74\uC744 \uC870\uD68C\uD569\uB2C8\uB2E4. data \uCEEC\uB7FC\uC744 \uC644\uC804\uD788 \uBCF5\uD638\uD654\uD558\uC5EC \uBC18\uD658\uD569\uB2C8\uB2E4. */\n find<T = unknown>(\n entity: string,\n conditions?: Record<string, unknown>,\n opts: { skipHooks?: boolean } = {},\n ): Promise<{ ok: boolean; data: T }> {\n const q = opts.skipHooks ? \"?skipHooks=true\" : \"\";\n return this.request(\n \"POST\",\n `/v1/entity/${entity}/find${q}`,\n conditions ?? {},\n );\n }\n\n /** \uD398\uC774\uC9C0\uB124\uC774\uC158/\uC815\uB82C/\uD544\uD130 \uC870\uAC74\uC73C\uB85C \uC5D4\uD2F0\uD2F0 \uBAA9\uB85D\uC744 \uC870\uD68C\uD569\uB2C8\uB2E4. */\n list<T = unknown>(\n entity: string,\n params: EntityListParams = {},\n ): Promise<{ ok: boolean; data: EntityListResult<T> }> {\n const { conditions, fields, orderDir, orderBy, ...rest } = params;\n\n const queryObj: Record<string, unknown> = {\n page: 1,\n limit: 20,\n ...rest,\n };\n if (orderBy) {\n queryObj.orderBy = orderDir === \"DESC\" ? `-${orderBy}` : orderBy;\n }\n if (fields?.length) {\n queryObj.fields = fields.join(\",\");\n }\n\n const q = buildQuery(queryObj);\n return this.request(\n \"POST\",\n `/v1/entity/${entity}/list?${q}`,\n conditions ?? {},\n );\n }\n\n /**\n * \uC5D4\uD2F0\uD2F0 \uCD1D \uAC74\uC218\uB97C \uC870\uD68C\uD569\uB2C8\uB2E4.\n *\n * @param conditions \uD544\uD130 \uC870\uAC74 (\uC608: `{ status: \"active\" }`)\n */\n count(\n entity: string,\n conditions?: Record<string, unknown>,\n ): Promise<{ ok: boolean; count: number }> {\n return this.request(\n \"POST\",\n `/v1/entity/${entity}/count`,\n conditions ?? {},\n );\n }\n\n /**\n * \uCEE4\uC2A4\uD140 SQL\uB85C \uC5D4\uD2F0\uD2F0\uB97C \uC870\uD68C\uD569\uB2C8\uB2E4.\n *\n * SELECT \uC804\uC6A9\uC774\uBA70 \uC778\uB371\uC2A4 \uD14C\uC774\uBE14\uB9CC \uC870\uD68C \uAC00\uB2A5\uD569\uB2C8\uB2E4.\n * JOIN\uC744 \uC0AC\uC6A9\uD574 \uC5EC\uB7EC \uC5D4\uD2F0\uD2F0\uB97C \uC870\uD569\uD560 \uC218 \uC788\uC2B5\uB2C8\uB2E4.\n * `entity`\uB294 SQL\uC5D0 \uD3EC\uD568\uB41C \uAE30\uBCF8 \uC5D4\uD2F0\uD2F0\uBA85(\uB77C\uC6B0\uD2B8 \uACBD\uB85C\uC6A9)\uC785\uB2C8\uB2E4.\n */\n query<T = unknown>(\n entity: string,\n req: EntityQueryRequest,\n ): Promise<{ ok: boolean; data: { items: T[]; count: number } }> {\n return this.request(\"POST\", `/v1/entity/${entity}/query`, req);\n }\n\n /** \uC5D4\uD2F0\uD2F0 \uB370\uC774\uD130\uB97C \uC0DD\uC131/\uC218\uC815(Submit)\uD569\uB2C8\uB2E4. `seq`\uAC00 \uC5C6\uC73C\uBA74 INSERT, \uC788\uC73C\uBA74 UPDATE\uC785\uB2C8\uB2E4. */\n submit(\n entity: string,\n data: Record<string, unknown>,\n opts: { transactionId?: string; skipHooks?: boolean } = {},\n ): Promise<{ ok: boolean; seq: number }> {\n const txId = opts.transactionId ?? this.activeTxId;\n const extraHeaders = txId ? { \"X-Transaction-ID\": txId } : undefined;\n const q = opts.skipHooks ? \"?skipHooks=true\" : \"\";\n\n return this.request(\n \"POST\",\n `/v1/entity/${entity}/submit${q}`,\n data,\n true,\n extraHeaders,\n );\n }\n\n /** \uC2DC\uD000\uC2A4 ID\uB85C \uC5D4\uD2F0\uD2F0\uB97C \uC0AD\uC81C\uD569\uB2C8\uB2E4(`hard=true`\uBA74 \uD558\uB4DC \uC0AD\uC81C, \uAE30\uBCF8\uC740 \uC18C\uD504\uD2B8 \uC0AD\uC81C). */\n delete(\n entity: string,\n seq: number,\n opts: {\n transactionId?: string;\n hard?: boolean;\n skipHooks?: boolean;\n } = {},\n ): Promise<{ ok: boolean; deleted: number }> {\n const params = new URLSearchParams();\n if (opts.hard) params.set(\"hard\", \"true\");\n if (opts.skipHooks) params.set(\"skipHooks\", \"true\");\n const q = params.size ? `?${params}` : \"\";\n const txId = opts.transactionId ?? this.activeTxId;\n const extraHeaders = txId ? { \"X-Transaction-ID\": txId } : undefined;\n\n return this.request(\n \"POST\",\n `/v1/entity/${entity}/delete/${seq}${q}`,\n undefined,\n true,\n extraHeaders,\n );\n }\n\n /** \uC5D4\uD2F0\uD2F0 \uB2E8\uAC74\uC758 \uBCC0\uACBD \uC774\uB825\uC744 \uC870\uD68C\uD569\uB2C8\uB2E4. \uC774\uB825 \uD56D\uBAA9\uB2F9 `action`, `data_snapshot`, `changed_by`, `changed_time`\uC744 \uD3EC\uD568\uD569\uB2C8\uB2E4. */\n history<T = unknown>(\n entity: string,\n seq: number,\n params: Pick<EntityListParams, \"page\" | \"limit\"> = {},\n ): Promise<{\n ok: boolean;\n data: EntityListResult<EntityHistoryRecord<T>>;\n }> {\n const q = buildQuery({ page: 1, limit: 50, ...params });\n return this.request(\"GET\", `/v1/entity/${entity}/history/${seq}?${q}`);\n }\n\n /** \uD2B9\uC815 \uC774\uB825 \uC2DC\uC810\uC73C\uB85C \uC5D4\uD2F0\uD2F0\uB97C \uB864\uBC31\uD569\uB2C8\uB2E4. */\n rollback(entity: string, historySeq: number): Promise<{ ok: boolean }> {\n return this.request(\n \"POST\",\n `/v1/entity/${entity}/rollback/${historySeq}`,\n );\n }\n\n /** \uD478\uC2DC \uAD00\uB828 \uC5D4\uD2F0\uD2F0\uB85C payload\uB97C \uC804\uC1A1(Submit)\uD569\uB2C8\uB2E4. */\n push(\n pushEntity: string,\n payload: Record<string, unknown>,\n opts: { transactionId?: string } = {},\n ): Promise<{ ok: boolean; seq: number }> {\n return this.submit(pushEntity, payload, opts);\n }\n\n /** \uD478\uC2DC \uB85C\uADF8 \uC5D4\uD2F0\uD2F0 \uBAA9\uB85D\uC744 \uC870\uD68C\uD569\uB2C8\uB2E4. */\n pushLogList<T = unknown>(\n params: EntityListParams = {},\n ): Promise<{ ok: boolean; data: EntityListResult<T> }> {\n return this.list<T>(\"push_log\", params);\n }\n\n /** \uACC4\uC815\uC758 \uD478\uC2DC \uB514\uBC14\uC774\uC2A4\uB97C \uB4F1\uB85D\uD569\uB2C8\uB2E4. */\n registerPushDevice(\n accountSeq: number,\n deviceId: string,\n pushToken: string,\n opts: RegisterPushDeviceOptions = {},\n ): Promise<{ ok: boolean; seq: number }> {\n const {\n platform,\n deviceType,\n browser,\n browserVersion,\n pushEnabled = true,\n transactionId,\n } = opts;\n\n return this.submit(\n \"account_device\",\n {\n id: deviceId,\n account_seq: accountSeq,\n push_token: pushToken,\n push_enabled: pushEnabled,\n ...(platform ? { platform } : {}),\n ...(deviceType ? { device_type: deviceType } : {}),\n ...(browser ? { browser } : {}),\n ...(browserVersion ? { browser_version: browserVersion } : {}),\n },\n { transactionId },\n );\n }\n\n /** \uB514\uBC14\uC774\uC2A4 \uB808\uCF54\uB4DC\uC758 \uD478\uC2DC \uD1A0\uD070\uC744 \uAC31\uC2E0\uD569\uB2C8\uB2E4. */\n updatePushDeviceToken(\n deviceSeq: number,\n pushToken: string,\n opts: { pushEnabled?: boolean; transactionId?: string } = {},\n ): Promise<{ ok: boolean; seq: number }> {\n const { pushEnabled = true, transactionId } = opts;\n return this.submit(\n \"account_device\",\n {\n seq: deviceSeq,\n push_token: pushToken,\n push_enabled: pushEnabled,\n },\n { transactionId },\n );\n }\n\n /** \uB514\uBC14\uC774\uC2A4\uC758 \uD478\uC2DC \uC218\uC2E0\uC744 \uBE44\uD65C\uC131\uD654\uD569\uB2C8\uB2E4. */\n disablePushDevice(\n deviceSeq: number,\n opts: { transactionId?: string } = {},\n ): Promise<{ ok: boolean; seq: number }> {\n return this.submit(\n \"account_device\",\n {\n seq: deviceSeq,\n push_enabled: false,\n },\n { transactionId: opts.transactionId },\n );\n }\n\n /**\n * \uC694\uCCAD \uBC14\uB514\uB97C \uD30C\uC2F1\uD558\uACE0 `application/octet-stream`\uC778 \uACBD\uC6B0 \uBCF5\uD638\uD654\uD569\uB2C8\uB2E4.\n *\n * \uC6D0\uC2DC \uC554\uD638\uD654 payload\uB97C \uC9C1\uC811 \uB2E4\uB8E8\uB294 \uD074\uB77C\uC774\uC5B8\uD2B8\uC5D0\uC11C \uC0AC\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 lowered = contentType.toLowerCase();\n const isEncrypted = lowered.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) {\n throw new Error(\"Encrypted request body is empty\");\n }\n if (body instanceof ArrayBuffer) {\n return this.decryptPacket<T>(body);\n }\n if (body instanceof Uint8Array) {\n const sliced = body.buffer.slice(\n body.byteOffset,\n body.byteOffset + body.byteLength,\n );\n return this.decryptPacket<T>(sliced as ArrayBuffer);\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\n /**\n * \uACF5\uD1B5 HTTP \uC694\uCCAD \uD568\uC218\uC785\uB2C8\uB2E4.\n *\n * - `encryptRequests`\uAC00 \uD65C\uC131\uD654\uB41C \uC778\uC99D \uC694\uCCAD\uC758 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 */\n private async request<T>(\n method: string,\n path: string,\n body?: unknown,\n withAuth = true,\n extraHeaders: Record<string, string> = {},\n ): Promise<T> {\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n ...extraHeaders,\n };\n if (withAuth && this.token) {\n headers.Authorization = `Bearer ${this.token}`;\n }\n\n // \uC694\uCCAD \uBC14\uB514 \uACB0\uC815: encryptRequests \uD65C\uC131\uD654 \uC2DC POST \uBC14\uB514\uB97C \uC554\uD638\uD654\uD569\uB2C8\uB2E4.\n // - \uB85C\uADF8\uC778/\uD1A0\uD070 \uAC31\uC2E0(withAuth=false)\uC740 \uC554\uD638\uD654\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.\n // - GET \uC740 \uBC14\uB514\uAC00 \uC5C6\uC73C\uBBC0\uB85C \uAC74\uB108\uB701\uB2C8\uB2E4.\n let fetchBody: string | Uint8Array | null = null;\n if (body != null) {\n const shouldEncrypt =\n this.encryptRequests &&\n withAuth &&\n this.token &&\n method !== \"GET\" &&\n method !== \"HEAD\";\n\n if (shouldEncrypt) {\n const plaintext = new TextEncoder().encode(\n JSON.stringify(body),\n );\n const encrypted = this.encryptPacket(plaintext);\n headers[\"Content-Type\"] = \"application/octet-stream\";\n fetchBody = encrypted;\n } else {\n fetchBody = JSON.stringify(body);\n }\n }\n\n const res = await fetch(this.baseUrl + path, {\n method,\n headers,\n ...(fetchBody != null ? { body: fetchBody as BodyInit } : {}),\n });\n\n const contentType = res.headers.get(\"Content-Type\") ?? \"\";\n\n if (contentType.includes(\"application/octet-stream\")) {\n const buffer = await res.arrayBuffer();\n return this.decryptPacket<T>(buffer);\n }\n\n const data = await res.json();\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 /**\n * \uD3C9\uBB38 \uBC14\uC774\uD2B8\uB97C XChaCha20-Poly1305\uB85C \uC554\uD638\uD654\uD569\uB2C8\uB2E4.\n * \uD3EC\uB9F7: [random_magic:packetMagicLen][random_nonce:24][ciphertext+tag]\n */\n private encryptPacket(plaintext: Uint8Array): Uint8Array {\n const key = sha256(new TextEncoder().encode(this.token));\n const magic = new Uint8Array(this.packetMagicLen);\n const nonce = new Uint8Array(24);\n crypto.getRandomValues(magic);\n crypto.getRandomValues(nonce);\n const cipher = xchacha20poly1305(key, nonce);\n const ciphertext = cipher.encrypt(plaintext);\n const result = new Uint8Array(\n this.packetMagicLen + 24 + ciphertext.length,\n );\n result.set(magic, 0);\n result.set(nonce, this.packetMagicLen);\n result.set(ciphertext, this.packetMagicLen + 24);\n return result;\n }\n\n /** \uC11C\uBC84\uC758 \uC554\uD638\uD654 \uD328\uD0B7\uC744 \uBCF5\uD638\uD654\uD574 JSON \uAC1D\uCCB4\uB85C \uBCC0\uD658\uD569\uB2C8\uB2E4. */\n private decryptPacket<T>(buffer: ArrayBuffer): T {\n const key = sha256(new TextEncoder().encode(this.token));\n const data = new Uint8Array(buffer);\n\n if (data.length < this.packetMagicLen + 24 + 16) {\n throw new Error(\"Encrypted packet too short\");\n }\n\n const nonce = data.slice(this.packetMagicLen, this.packetMagicLen + 24);\n const ciphertext = data.slice(this.packetMagicLen + 24);\n const cipher = xchacha20poly1305(key, nonce);\n const plaintext = cipher.decrypt(ciphertext);\n return JSON.parse(new TextDecoder().decode(plaintext)) as T;\n }\n}\n\n/** \uCFFC\uB9AC \uD30C\uB77C\uBBF8\uD130 \uAC1D\uCCB4\uB97C URL \uCFFC\uB9AC \uBB38\uC790\uC5F4\uB85C \uBCC0\uD658\uD569\uB2C8\uB2E4. */\nfunction 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\nexport const entityServer = new EntityServerClient();\n"],
|
|
5
|
-
"mappings": "
|
|
6
|
-
"names": ["xchacha20poly1305", "sha256", "
|
|
3
|
+
"sources": ["../src/client/utils.ts", "../src/client/packet.ts", "../src/client/hmac.ts", "../src/client/request.ts", "../src/EntityServerClient.ts", "../src/index.ts"],
|
|
4
|
+
"sourcesContent": ["/** Vite \uD658\uACBD\uBCC0\uC218(`import.meta.env`)\uC5D0\uC11C \uAC12\uC744 \uC77D\uC2B5\uB2C8\uB2E4. */\nexport function readEnv(name: string): string | undefined {\n const meta = import.meta as unknown as {\n env?: Record<string, string | undefined>;\n };\n return meta?.env?.[name];\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", "// @ts-ignore\nimport { xchacha20poly1305 } from \"@noble/ciphers/chacha\";\n// @ts-ignore\nimport { sha256 } from \"@noble/hashes/sha2\";\n// @ts-ignore\nimport { hkdf } from \"@noble/hashes/hkdf\";\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: SHA-256(jwt_token)\n */\nexport function derivePacketKey(hmacSecret: string, token: string): Uint8Array {\n if (hmacSecret) {\n const salt = new TextEncoder().encode(\"entity-server:hkdf:v1\");\n const info = new TextEncoder().encode(\n \"entity-server:packet-encryption\",\n );\n return hkdf(\n sha256,\n new TextEncoder().encode(hmacSecret),\n salt,\n info,\n 32,\n );\n }\n return sha256(new TextEncoder().encode(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:magicLen][random_nonce:24][ciphertext+tag]\n */\nexport function encryptPacket(\n plaintext: Uint8Array,\n key: Uint8Array,\n magicLen: number,\n): Uint8Array {\n const magic = new Uint8Array(magicLen);\n const nonce = new Uint8Array(24);\n crypto.getRandomValues(magic);\n crypto.getRandomValues(nonce);\n const cipher = xchacha20poly1305(key, nonce);\n const ciphertext = cipher.encrypt(plaintext);\n const result = new Uint8Array(magicLen + 24 + ciphertext.length);\n result.set(magic, 0);\n result.set(nonce, magicLen);\n result.set(ciphertext, magicLen + 24);\n return result;\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:magicLen][nonce:24][ciphertext+tag]\n */\nexport function decryptPacket<T>(\n buffer: ArrayBuffer,\n key: Uint8Array,\n magicLen: number,\n): T {\n const data = new Uint8Array(buffer);\n if (data.length < magicLen + 24 + 16) {\n throw new Error(\"Encrypted packet too short\");\n }\n const nonce = data.slice(magicLen, magicLen + 24);\n const ciphertext = data.slice(magicLen + 24);\n const cipher = xchacha20poly1305(key, nonce);\n const plaintext = cipher.decrypt(ciphertext);\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 magicLen: number,\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)\n return decryptPacket<T>(body, key, magicLen);\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, magicLen);\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", "// @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", "import { derivePacketKey, encryptPacket, decryptPacket } from \"./packet\";\nimport { buildHmacHeaders } from \"./hmac\";\n\nexport interface RequestOptions {\n baseUrl: string;\n token: string;\n apiKey: string;\n hmacSecret: string;\n packetMagicLen: number;\n encryptRequests: boolean;\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): Promise<T> {\n const {\n baseUrl,\n token,\n apiKey,\n hmacSecret,\n packetMagicLen,\n encryptRequests,\n } = opts;\n const isHmacMode = withAuth && !!(apiKey && hmacSecret);\n\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n ...extraHeaders,\n };\n if (!isHmacMode && withAuth && token) {\n headers.Authorization = `Bearer ${token}`;\n }\n\n let fetchBody: string | Uint8Array | null = null;\n if (body != null) {\n const shouldEncrypt =\n encryptRequests &&\n withAuth &&\n (token || isHmacMode) &&\n method !== \"GET\" &&\n method !== \"HEAD\";\n\n if (shouldEncrypt) {\n const key = derivePacketKey(hmacSecret, token);\n fetchBody = encryptPacket(\n new TextEncoder().encode(JSON.stringify(body)),\n key,\n packetMagicLen,\n );\n headers[\"Content-Type\"] = \"application/octet-stream\";\n } else {\n fetchBody = JSON.stringify(body);\n }\n }\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\n const res = await fetch(baseUrl + path, {\n method,\n headers,\n ...(fetchBody != null ? { body: fetchBody as BodyInit } : {}),\n });\n\n const contentType = res.headers.get(\"Content-Type\") ?? \"\";\n if (contentType.includes(\"application/octet-stream\")) {\n const key = derivePacketKey(hmacSecret, token);\n return decryptPacket<T>(await res.arrayBuffer(), key, packetMagicLen);\n }\n\n const data = await res.json();\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", "import type {\n EntityHistoryRecord,\n EntityListParams,\n EntityListResult,\n EntityQueryRequest,\n EntityServerClientOptions,\n RegisterPushDeviceOptions,\n} from \"./types\";\nimport { readEnv, buildQuery } from \"./client/utils\";\nimport { derivePacketKey, parseRequestBody } from \"./client/packet\";\nimport { entityRequest, type RequestOptions } from \"./client/request\";\n\nexport class EntityServerClient {\n private baseUrl: string;\n private token: string;\n private apiKey: string;\n private hmacSecret: string;\n private packetMagicLen: number;\n private encryptRequests: boolean;\n private activeTxId: string | null = null;\n\n // \uC138\uC158 \uC720\uC9C0 \uAD00\uB828\n private keepSession: boolean;\n private refreshBuffer: number;\n private onTokenRefreshed?: (accessToken: string, expiresIn: number) => void;\n private onSessionExpired?: (error: Error) => void;\n private _sessionRefreshToken: string | null = null;\n private _refreshTimer: ReturnType<typeof setTimeout> | null = null;\n\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 `http://localhost:47200`\n * - `packetMagicLen`: `VITE_ENTITY_SERVER_PACKET_MAGIC_LEN` \uB610\uB294 `4`\n */\n constructor(options: EntityServerClientOptions = {}) {\n const envBaseUrl = readEnv(\"VITE_ENTITY_SERVER_URL\");\n const envMagicLen = readEnv(\"VITE_ENTITY_SERVER_PACKET_MAGIC_LEN\");\n\n this.baseUrl = (\n options.baseUrl ??\n envBaseUrl ??\n \"http://localhost:47200\"\n ).replace(/\\/$/, \"\");\n this.token = options.token ?? \"\";\n this.apiKey = options.apiKey ?? \"\";\n this.hmacSecret = options.hmacSecret ?? \"\";\n this.packetMagicLen =\n options.packetMagicLen ?? (envMagicLen ? Number(envMagicLen) : 4);\n this.encryptRequests = options.encryptRequests ?? false;\n this.keepSession = options.keepSession ?? false;\n this.refreshBuffer = options.refreshBuffer ?? 60;\n this.onTokenRefreshed = options.onTokenRefreshed;\n this.onSessionExpired = options.onSessionExpired;\n }\n\n /** baseUrl, token, packetMagicLen, encryptRequests \uAC12\uC744 \uB7F0\uD0C0\uC784\uC5D0 \uAC31\uC2E0\uD569\uB2C8\uB2E4. */\n configure(options: Partial<EntityServerClientOptions>): void {\n if (options.baseUrl) this.baseUrl = options.baseUrl.replace(/\\/$/, \"\");\n if (typeof options.token === \"string\") this.token = options.token;\n if (typeof options.packetMagicLen === \"number\")\n this.packetMagicLen = options.packetMagicLen;\n if (typeof options.encryptRequests === \"boolean\")\n this.encryptRequests = options.encryptRequests;\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 }\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 }\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 \uD328\uD0B7 magic \uAE38\uC774(`packet_magic_len`)\uB97C \uC124\uC815\uD569\uB2C8\uB2E4. */\n setPacketMagicLen(length: number): void {\n this.packetMagicLen = length;\n }\n\n /** \uD604\uC7AC \uC554\uD638\uD654 \uD328\uD0B7 magic \uAE38\uC774\uB97C \uBC18\uD658\uD569\uB2C8\uB2E4. */\n getPacketMagicLen(): number {\n return this.packetMagicLen;\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 /** @internal \uC790\uB3D9 \uD1A0\uD070 \uAC31\uC2E0 \uD0C0\uC774\uBA38\uB97C \uC2DC\uC791\uD569\uB2C8\uB2E4. */\n private _scheduleKeepSession(\n refreshToken: string,\n expiresIn: 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 this.refreshToken(\n this._sessionRefreshToken,\n );\n this.onTokenRefreshed?.(result.access_token, result.expires_in);\n this._scheduleKeepSession(\n this._sessionRefreshToken,\n result.expires_in,\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 /** @internal \uC790\uB3D9 \uAC31\uC2E0 \uD0C0\uC774\uBA38\uB97C \uC815\uB9AC\uD569\uB2C8\uB2E4. */\n private _clearRefreshTimer(): void {\n if (this._refreshTimer !== null) {\n clearTimeout(this._refreshTimer);\n this._refreshTimer = null;\n }\n }\n\n /**\n * \uC138\uC158 \uC720\uC9C0 \uD0C0\uC774\uBA38\uB97C \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 // \u2500\u2500\u2500 \uC778\uC99D \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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 * \uC11C\uBC84 \uD5EC\uC2A4 \uCCB4\uD06C\uB97C \uC218\uD589\uD558\uACE0 \uD328\uD0B7 \uC554\uD638\uD654 \uD65C\uC131 \uC5EC\uBD80\uB97C \uC790\uB3D9\uC73C\uB85C \uAC10\uC9C0\uD569\uB2C8\uB2E4.\n *\n * \uC11C\uBC84\uAC00 `packet_encryption: true`\uB97C \uC751\uB2F5\uD558\uBA74 \uC774\uD6C4 \uBAA8\uB4E0 \uC694\uCCAD\uC5D0 \uC554\uD638\uD654\uAC00 \uC790\uB3D9 \uC801\uC6A9\uB429\uB2C8\uB2E4.\n *\n * ```ts\n * await client.checkHealth();\n * await client.login(email, password);\n * ```\n */\n async checkHealth(): Promise<{ ok: boolean; packet_encryption?: boolean }> {\n const res = await fetch(`${this.baseUrl}/v1/health`, {\n signal: AbortSignal.timeout(3000),\n });\n const data = (await res.json()) as {\n ok: boolean;\n packet_encryption?: boolean;\n };\n if (data.packet_encryption) this.encryptRequests = true;\n return data;\n }\n\n /** \uB85C\uADF8\uC778 \uD6C4 `access_token`\uC744 \uB0B4\uBD80 \uC0C1\uD0DC\uC5D0 \uC800\uC7A5\uD569\uB2C8\uB2E4. */\n async login(\n email: string,\n password: string,\n ): Promise<{\n access_token: string;\n refresh_token: string;\n expires_in: number;\n }> {\n const data = await this.request<{\n data: {\n access_token: string;\n refresh_token: string;\n expires_in: number;\n };\n }>(\"POST\", \"/v1/auth/login\", { email, passwd: password }, false);\n this.token = data.data.access_token;\n if (this.keepSession)\n this._scheduleKeepSession(\n data.data.refresh_token,\n data.data.expires_in,\n );\n return data.data;\n }\n\n /** Refresh Token\uC73C\uB85C Access Token\uC744 \uC7AC\uBC1C\uAE09\uBC1B\uC544 \uB0B4\uBD80 \uD1A0\uD070\uC744 \uAD50\uCCB4\uD569\uB2C8\uB2E4. */\n async refreshToken(\n refreshToken: string,\n ): Promise<{ access_token: string; expires_in: number }> {\n const data = await this.request<{\n data: { access_token: string; expires_in: number };\n }>(\"POST\", \"/v1/auth/refresh\", { refresh_token: refreshToken }, false);\n this.token = data.data.access_token;\n if (this.keepSession)\n this._scheduleKeepSession(refreshToken, data.data.expires_in);\n return data.data;\n }\n\n /**\n * \uC11C\uBC84\uC5D0 \uB85C\uADF8\uC544\uC6C3\uC744 \uC694\uCCAD\uD558\uACE0 \uB0B4\uBD80 \uD1A0\uD070\uC744 \uCD08\uAE30\uD654\uD569\uB2C8\uB2E4.\n * refresh_token\uC744 \uC11C\uBC84\uC5D0 \uC804\uB2EC\uD574 \uBB34\uD6A8\uD654\uD569\uB2C8\uB2E4.\n */\n async logout(refreshToken: string): Promise<{ ok: boolean }> {\n this.stopKeepSession();\n const data = await this.request<{ ok: boolean }>(\n \"POST\",\n \"/v1/auth/logout\",\n { refresh_token: refreshToken },\n false,\n );\n this.token = \"\";\n return data;\n }\n\n // \u2500\u2500\u2500 \uD2B8\uB79C\uC7AD\uC158 \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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 /** \uD2B8\uB79C\uC7AD\uC158\uC744 \uC2DC\uC791\uD558\uACE0 \uD65C\uC131 \uD2B8\uB79C\uC7AD\uC158 ID\uB97C \uC800\uC7A5\uD569\uB2C8\uB2E4. */\n async transStart(): Promise<string> {\n const res = await this.request<{ ok: boolean; transaction_id: string }>(\n \"POST\",\n \"/v1/transaction/start\",\n undefined,\n false,\n );\n this.activeTxId = res.transaction_id;\n return this.activeTxId;\n }\n\n /** \uD65C\uC131 \uD2B8\uB79C\uC7AD\uC158(\uB610\uB294 \uC804\uB2EC\uB41C transactionId)\uC744 \uB864\uBC31\uD569\uB2C8\uB2E4. */\n transRollback(transactionId?: string): Promise<{ ok: boolean }> {\n const txId = transactionId ?? this.activeTxId;\n if (!txId)\n return Promise.reject(\n new Error(\"No active transaction. Call transStart() first.\"),\n );\n this.activeTxId = null;\n return this.request(\"POST\", `/v1/transaction/rollback/${txId}`);\n }\n\n /**\n * \uD65C\uC131 \uD2B8\uB79C\uC7AD\uC158(\uB610\uB294 \uC804\uB2EC\uB41C transactionId)\uC744 \uCEE4\uBC0B\uD569\uB2C8\uB2E4.\n *\n * @returns `results` \uBC30\uC5F4: commit\uB41C \uAC01 \uC791\uC5C5\uC758 `entity`, `action`, `seq`\n */\n transCommit(transactionId?: string): Promise<{\n ok: boolean;\n results: Array<{ entity: string; action: string; seq: number }>;\n }> {\n const txId = transactionId ?? this.activeTxId;\n if (!txId)\n return Promise.reject(\n new Error(\"No active transaction. Call transStart() first.\"),\n );\n this.activeTxId = null;\n return this.request(\"POST\", `/v1/transaction/commit/${txId}`);\n }\n\n // \u2500\u2500\u2500 \uC5D4\uD2F0\uD2F0 CRUD \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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 /** \uC2DC\uD000\uC2A4 ID\uB85C \uC5D4\uD2F0\uD2F0 \uB2E8\uAC74\uC744 \uC870\uD68C\uD569\uB2C8\uB2E4. */\n get<T = unknown>(\n entity: string,\n seq: number,\n opts: { skipHooks?: boolean } = {},\n ): Promise<{ ok: boolean; data: T }> {\n const q = opts.skipHooks ? \"?skipHooks=true\" : \"\";\n return this.request(\"GET\", `/v1/entity/${entity}/${seq}${q}`);\n }\n\n /** \uC870\uAC74\uC73C\uB85C \uC5D4\uD2F0\uD2F0 \uB2E8\uAC74\uC744 \uC870\uD68C\uD569\uB2C8\uB2E4. data \uCEEC\uB7FC\uC744 \uC644\uC804\uD788 \uBCF5\uD638\uD654\uD558\uC5EC \uBC18\uD658\uD569\uB2C8\uB2E4. */\n find<T = unknown>(\n entity: string,\n conditions?: Record<string, unknown>,\n opts: { skipHooks?: boolean } = {},\n ): Promise<{ ok: boolean; data: T }> {\n const q = opts.skipHooks ? \"?skipHooks=true\" : \"\";\n return this.request(\n \"POST\",\n `/v1/entity/${entity}/find${q}`,\n conditions ?? {},\n );\n }\n\n /** \uD398\uC774\uC9C0\uB124\uC774\uC158/\uC815\uB82C/\uD544\uD130 \uC870\uAC74\uC73C\uB85C \uC5D4\uD2F0\uD2F0 \uBAA9\uB85D\uC744 \uC870\uD68C\uD569\uB2C8\uB2E4. */\n list<T = unknown>(\n entity: string,\n params: EntityListParams = {},\n ): Promise<{ ok: boolean; data: EntityListResult<T> }> {\n const { conditions, fields, orderDir, orderBy, ...rest } = params;\n const queryObj: Record<string, unknown> = {\n page: 1,\n limit: 20,\n ...rest,\n };\n if (orderBy)\n queryObj.orderBy = orderDir === \"DESC\" ? `-${orderBy}` : orderBy;\n if (fields?.length) queryObj.fields = fields.join(\",\");\n return this.request(\n \"POST\",\n `/v1/entity/${entity}/list?${buildQuery(queryObj)}`,\n conditions ?? {},\n );\n }\n\n /**\n * \uC5D4\uD2F0\uD2F0 \uCD1D \uAC74\uC218\uB97C \uC870\uD68C\uD569\uB2C8\uB2E4.\n *\n * @param conditions \uD544\uD130 \uC870\uAC74 (\uC608: `{ status: \"active\" }`)\n */\n count(\n entity: string,\n conditions?: Record<string, unknown>,\n ): Promise<{ ok: boolean; count: number }> {\n return this.request(\n \"POST\",\n `/v1/entity/${entity}/count`,\n conditions ?? {},\n );\n }\n\n /**\n * \uCEE4\uC2A4\uD140 SQL\uB85C \uC5D4\uD2F0\uD2F0\uB97C \uC870\uD68C\uD569\uB2C8\uB2E4.\n *\n * SELECT \uC804\uC6A9\uC774\uBA70 \uC778\uB371\uC2A4 \uD14C\uC774\uBE14\uB9CC \uC870\uD68C \uAC00\uB2A5\uD569\uB2C8\uB2E4. JOIN \uC9C0\uC6D0.\n */\n query<T = unknown>(\n entity: string,\n req: EntityQueryRequest,\n ): Promise<{ ok: boolean; data: { items: T[]; count: number } }> {\n return this.request(\"POST\", `/v1/entity/${entity}/query`, req);\n }\n\n /** \uC5D4\uD2F0\uD2F0 \uB370\uC774\uD130\uB97C \uC0DD\uC131/\uC218\uC815(Submit)\uD569\uB2C8\uB2E4. `seq`\uAC00 \uC5C6\uC73C\uBA74 INSERT, \uC788\uC73C\uBA74 UPDATE\uC785\uB2C8\uB2E4. */\n submit(\n entity: string,\n data: Record<string, unknown>,\n opts: { transactionId?: string; skipHooks?: boolean } = {},\n ): Promise<{ ok: boolean; seq: number }> {\n const txId = opts.transactionId ?? this.activeTxId;\n const extraHeaders = txId ? { \"X-Transaction-ID\": txId } : undefined;\n const q = opts.skipHooks ? \"?skipHooks=true\" : \"\";\n return this.request(\n \"POST\",\n `/v1/entity/${entity}/submit${q}`,\n data,\n true,\n extraHeaders,\n );\n }\n\n /** \uC2DC\uD000\uC2A4 ID\uB85C \uC5D4\uD2F0\uD2F0\uB97C \uC0AD\uC81C\uD569\uB2C8\uB2E4(`hard=true`\uBA74 \uD558\uB4DC \uC0AD\uC81C, \uAE30\uBCF8\uC740 \uC18C\uD504\uD2B8 \uC0AD\uC81C). */\n delete(\n entity: string,\n seq: number,\n opts: {\n transactionId?: string;\n hard?: boolean;\n skipHooks?: boolean;\n } = {},\n ): Promise<{ ok: boolean; deleted: number }> {\n const params = new URLSearchParams();\n if (opts.hard) params.set(\"hard\", \"true\");\n if (opts.skipHooks) params.set(\"skipHooks\", \"true\");\n const q = params.size ? `?${params}` : \"\";\n const txId = opts.transactionId ?? this.activeTxId;\n const extraHeaders = txId ? { \"X-Transaction-ID\": txId } : undefined;\n return this.request(\n \"POST\",\n `/v1/entity/${entity}/delete/${seq}${q}`,\n undefined,\n true,\n extraHeaders,\n );\n }\n\n /** \uC5D4\uD2F0\uD2F0 \uB2E8\uAC74\uC758 \uBCC0\uACBD \uC774\uB825\uC744 \uC870\uD68C\uD569\uB2C8\uB2E4. */\n history<T = unknown>(\n entity: string,\n seq: number,\n params: Pick<EntityListParams, \"page\" | \"limit\"> = {},\n ): Promise<{\n ok: boolean;\n data: EntityListResult<EntityHistoryRecord<T>>;\n }> {\n return this.request(\n \"GET\",\n `/v1/entity/${entity}/history/${seq}?${buildQuery({ page: 1, limit: 50, ...params })}`,\n );\n }\n\n /** \uD2B9\uC815 \uC774\uB825 \uC2DC\uC810\uC73C\uB85C \uC5D4\uD2F0\uD2F0\uB97C \uB864\uBC31\uD569\uB2C8\uB2E4. */\n rollback(entity: string, historySeq: number): Promise<{ ok: boolean }> {\n return this.request(\n \"POST\",\n `/v1/entity/${entity}/rollback/${historySeq}`,\n );\n }\n\n // \u2500\u2500\u2500 \uD478\uC2DC \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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 /** \uD478\uC2DC \uAD00\uB828 \uC5D4\uD2F0\uD2F0\uB85C payload\uB97C \uC804\uC1A1(Submit)\uD569\uB2C8\uB2E4. */\n push(\n pushEntity: string,\n payload: Record<string, unknown>,\n opts: { transactionId?: string } = {},\n ): Promise<{ ok: boolean; seq: number }> {\n return this.submit(pushEntity, payload, opts);\n }\n\n /** \uD478\uC2DC \uB85C\uADF8 \uC5D4\uD2F0\uD2F0 \uBAA9\uB85D\uC744 \uC870\uD68C\uD569\uB2C8\uB2E4. */\n pushLogList<T = unknown>(\n params: EntityListParams = {},\n ): Promise<{ ok: boolean; data: EntityListResult<T> }> {\n return this.list<T>(\"push_log\", params);\n }\n\n /** \uACC4\uC815\uC758 \uD478\uC2DC \uB514\uBC14\uC774\uC2A4\uB97C \uB4F1\uB85D\uD569\uB2C8\uB2E4. */\n registerPushDevice(\n accountSeq: number,\n deviceId: string,\n pushToken: string,\n opts: RegisterPushDeviceOptions = {},\n ): Promise<{ ok: boolean; seq: number }> {\n const {\n platform,\n deviceType,\n browser,\n browserVersion,\n pushEnabled = true,\n transactionId,\n } = opts;\n return this.submit(\n \"account_device\",\n {\n id: deviceId,\n account_seq: accountSeq,\n push_token: pushToken,\n push_enabled: pushEnabled,\n ...(platform ? { platform } : {}),\n ...(deviceType ? { device_type: deviceType } : {}),\n ...(browser ? { browser } : {}),\n ...(browserVersion ? { browser_version: browserVersion } : {}),\n },\n { transactionId },\n );\n }\n\n /** \uB514\uBC14\uC774\uC2A4 \uB808\uCF54\uB4DC\uC758 \uD478\uC2DC \uD1A0\uD070\uC744 \uAC31\uC2E0\uD569\uB2C8\uB2E4. */\n updatePushDeviceToken(\n deviceSeq: number,\n pushToken: string,\n opts: { pushEnabled?: boolean; transactionId?: string } = {},\n ): Promise<{ ok: boolean; seq: number }> {\n const { pushEnabled = true, transactionId } = opts;\n return this.submit(\n \"account_device\",\n {\n seq: deviceSeq,\n push_token: pushToken,\n push_enabled: pushEnabled,\n },\n { transactionId },\n );\n }\n\n /** \uB514\uBC14\uC774\uC2A4\uC758 \uD478\uC2DC \uC218\uC2E0\uC744 \uBE44\uD65C\uC131\uD654\uD569\uB2C8\uB2E4. */\n disablePushDevice(\n deviceSeq: number,\n opts: { transactionId?: string } = {},\n ): Promise<{ ok: boolean; seq: number }> {\n return this.submit(\n \"account_device\",\n { seq: deviceSeq, push_enabled: false },\n { transactionId: opts.transactionId },\n );\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(this.hmacSecret, this.token);\n return parseRequestBody<T>(\n body,\n contentType,\n requireEncrypted,\n key,\n this.packetMagicLen,\n );\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 private get _reqOpts(): RequestOptions {\n return {\n baseUrl: this.baseUrl,\n token: this.token,\n apiKey: this.apiKey,\n hmacSecret: this.hmacSecret,\n packetMagicLen: this.packetMagicLen,\n encryptRequests: this.encryptRequests,\n };\n }\n\n private request<T>(\n method: string,\n path: string,\n body?: unknown,\n withAuth = true,\n extraHeaders?: Record<string, string>,\n ): Promise<T> {\n return entityRequest<T>(\n this._reqOpts,\n method,\n path,\n body,\n withAuth,\n extraHeaders,\n );\n }\n}\n", "export * from \"./types\";\nexport * from \"./EntityServerClient\";\n\nimport { EntityServerClient } from \"./EntityServerClient\";\n\nexport const entityServer = new EntityServerClient();\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["readEnv", "name", "buildQuery", "params", "value", "key", "xchacha20poly1305", "sha256", "hkdf", "derivePacketKey", "hmacSecret", "token", "salt", "info", "encryptPacket", "plaintext", "key", "magicLen", "magic", "nonce", "ciphertext", "result", "decryptPacket", "buffer", "data", "parseRequestBody", "body", "contentType", "requireEncrypted", "isEncrypted", "sliced", "sha256", "hmac", "buildHmacHeaders", "method", "path", "bodyBytes", "apiKey", "hmacSecret", "timestamp", "nonce", "prefix", "payload", "signature", "b", "entityRequest", "opts", "method", "path", "body", "withAuth", "extraHeaders", "baseUrl", "token", "apiKey", "hmacSecret", "packetMagicLen", "encryptRequests", "isHmacMode", "headers", "fetchBody", "key", "derivePacketKey", "encryptPacket", "bodyBytes", "buildHmacHeaders", "res", "decryptPacket", "data", "err", "EntityServerClient", "options", "envBaseUrl", "readEnv", "envMagicLen", "token", "apiKey", "secret", "length", "refreshToken", "expiresIn", "delayMs", "result", "err", "data", "email", "password", "res", "transactionId", "txId", "entity", "seq", "opts", "q", "conditions", "params", "fields", "orderDir", "orderBy", "rest", "queryObj", "buildQuery", "req", "extraHeaders", "historySeq", "pushEntity", "payload", "accountSeq", "deviceId", "pushToken", "platform", "deviceType", "browser", "browserVersion", "pushEnabled", "deviceSeq", "body", "contentType", "requireEncrypted", "key", "derivePacketKey", "parseRequestBody", "method", "path", "withAuth", "entityRequest", "entityServer", "EntityServerClient"]
|
|
7
7
|
}
|
package/dist/react.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{useCallback as
|
|
1
|
+
import{useCallback as S,useEffect as H,useMemo as D,useRef as L,useState as B}from"react";function P(s){return import.meta?.env?.[s]}function q(s){return Object.entries(s).filter(([,e])=>e!=null).map(([e,t])=>`${encodeURIComponent(e==="orderBy"?"order_by":e)}=${encodeURIComponent(String(t))}`).join("&")}import{xchacha20poly1305 as x}from"@noble/ciphers/chacha";import{sha256 as w}from"@noble/hashes/sha2";import{hkdf as K}from"@noble/hashes/hkdf";function E(s,e){if(s){let t=new TextEncoder().encode("entity-server:hkdf:v1"),r=new TextEncoder().encode("entity-server:packet-encryption");return K(w,new TextEncoder().encode(s),t,r,32)}return w(new TextEncoder().encode(e))}function U(s,e,t){let r=new Uint8Array(t),n=new Uint8Array(24);crypto.getRandomValues(r),crypto.getRandomValues(n);let a=x(e,n).encrypt(s),o=new Uint8Array(t+24+a.length);return o.set(r,0),o.set(n,t),o.set(a,t+24),o}function R(s,e,t){let r=new Uint8Array(s);if(r.length<t+24+16)throw new Error("Encrypted packet too short");let n=r.slice(t,t+24),i=r.slice(t+24),o=x(e,n).decrypt(i);return JSON.parse(new TextDecoder().decode(o))}function I(s,e,t,r,n){let i=e.toLowerCase().includes("application/octet-stream");if(t&&!i)throw new Error("Encrypted request required: Content-Type must be application/octet-stream");if(i){if(s==null)throw new Error("Encrypted request body is empty");if(s instanceof ArrayBuffer)return R(s,r,n);if(s instanceof Uint8Array){let a=s.buffer.slice(s.byteOffset,s.byteOffset+s.byteLength);return R(a,r,n)}throw new Error("Encrypted request body must be ArrayBuffer or Uint8Array")}return s==null||s===""?{}:typeof s=="string"?JSON.parse(s):s}import{sha256 as M}from"@noble/hashes/sha2";import{hmac as C}from"@noble/hashes/hmac";function O(s,e,t,r,n){let i=String(Math.floor(Date.now()/1e3)),a=crypto.randomUUID(),o=new TextEncoder().encode(`${s}|${e}|${i}|${a}|`),c=new Uint8Array(o.length+t.length);c.set(o,0),c.set(t,o.length);let h=[...C(M,new TextEncoder().encode(n),c)].map(y=>y.toString(16).padStart(2,"0")).join("");return{"X-API-Key":r,"X-Timestamp":i,"X-Nonce":a,"X-Signature":h}}async function $(s,e,t,r,n=!0,i={}){let{baseUrl:a,token:o,apiKey:c,hmacSecret:f,packetMagicLen:h,encryptRequests:y}=s,b=n&&!!(c&&f),p={"Content-Type":"application/json",...i};!b&&n&&o&&(p.Authorization=`Bearer ${o}`);let l=null;if(r!=null)if(y&&n&&(o||b)&&e!=="GET"&&e!=="HEAD"){let u=E(f,o);l=U(new TextEncoder().encode(JSON.stringify(r)),u,h),p["Content-Type"]="application/octet-stream"}else l=JSON.stringify(r);if(b){let m=l instanceof Uint8Array?l:typeof l=="string"?new TextEncoder().encode(l):new Uint8Array(0);Object.assign(p,O(e,t,m,c,f))}let k=await fetch(a+t,{method:e,headers:p,...l!=null?{body:l}:{}});if((k.headers.get("Content-Type")??"").includes("application/octet-stream")){let m=E(f,o);return R(await k.arrayBuffer(),m,h)}let v=await k.json();if(!v.ok){let m=new Error(v.message??`EntityServer error (HTTP ${k.status})`);throw m.status=k.status,m}return v}var T=class{baseUrl;token;apiKey;hmacSecret;packetMagicLen;encryptRequests;activeTxId=null;keepSession;refreshBuffer;onTokenRefreshed;onSessionExpired;_sessionRefreshToken=null;_refreshTimer=null;constructor(e={}){let t=P("VITE_ENTITY_SERVER_URL"),r=P("VITE_ENTITY_SERVER_PACKET_MAGIC_LEN");this.baseUrl=(e.baseUrl??t??"http://localhost:47200").replace(/\/$/,""),this.token=e.token??"",this.apiKey=e.apiKey??"",this.hmacSecret=e.hmacSecret??"",this.packetMagicLen=e.packetMagicLen??(r?Number(r):4),this.encryptRequests=e.encryptRequests??!1,this.keepSession=e.keepSession??!1,this.refreshBuffer=e.refreshBuffer??60,this.onTokenRefreshed=e.onTokenRefreshed,this.onSessionExpired=e.onSessionExpired}configure(e){e.baseUrl&&(this.baseUrl=e.baseUrl.replace(/\/$/,"")),typeof e.token=="string"&&(this.token=e.token),typeof e.packetMagicLen=="number"&&(this.packetMagicLen=e.packetMagicLen),typeof e.encryptRequests=="boolean"&&(this.encryptRequests=e.encryptRequests),typeof e.apiKey=="string"&&(this.apiKey=e.apiKey),typeof e.hmacSecret=="string"&&(this.hmacSecret=e.hmacSecret),typeof e.keepSession=="boolean"&&(this.keepSession=e.keepSession),typeof e.refreshBuffer=="number"&&(this.refreshBuffer=e.refreshBuffer),e.onTokenRefreshed&&(this.onTokenRefreshed=e.onTokenRefreshed),e.onSessionExpired&&(this.onSessionExpired=e.onSessionExpired)}setToken(e){this.token=e}setApiKey(e){this.apiKey=e}setHmacSecret(e){this.hmacSecret=e}setPacketMagicLen(e){this.packetMagicLen=e}getPacketMagicLen(){return this.packetMagicLen}_scheduleKeepSession(e,t){this._clearRefreshTimer(),this._sessionRefreshToken=e;let r=Math.max((t-this.refreshBuffer)*1e3,0);this._refreshTimer=setTimeout(async()=>{if(this._sessionRefreshToken)try{let n=await this.refreshToken(this._sessionRefreshToken);this.onTokenRefreshed?.(n.access_token,n.expires_in),this._scheduleKeepSession(this._sessionRefreshToken,n.expires_in)}catch(n){this._clearRefreshTimer(),this.onSessionExpired?.(n instanceof Error?n:new Error(String(n)))}},r)}_clearRefreshTimer(){this._refreshTimer!==null&&(clearTimeout(this._refreshTimer),this._refreshTimer=null)}stopKeepSession(){this._clearRefreshTimer(),this._sessionRefreshToken=null}async checkHealth(){let t=await(await fetch(`${this.baseUrl}/v1/health`,{signal:AbortSignal.timeout(3e3)})).json();return t.packet_encryption&&(this.encryptRequests=!0),t}async login(e,t){let r=await this.request("POST","/v1/auth/login",{email:e,passwd:t},!1);return this.token=r.data.access_token,this.keepSession&&this._scheduleKeepSession(r.data.refresh_token,r.data.expires_in),r.data}async refreshToken(e){let t=await this.request("POST","/v1/auth/refresh",{refresh_token:e},!1);return this.token=t.data.access_token,this.keepSession&&this._scheduleKeepSession(e,t.data.expires_in),t.data}async logout(e){this.stopKeepSession();let t=await this.request("POST","/v1/auth/logout",{refresh_token:e},!1);return this.token="",t}async transStart(){let e=await this.request("POST","/v1/transaction/start",void 0,!1);return this.activeTxId=e.transaction_id,this.activeTxId}transRollback(e){let t=e??this.activeTxId;return t?(this.activeTxId=null,this.request("POST",`/v1/transaction/rollback/${t}`)):Promise.reject(new Error("No active transaction. Call transStart() first."))}transCommit(e){let t=e??this.activeTxId;return t?(this.activeTxId=null,this.request("POST",`/v1/transaction/commit/${t}`)):Promise.reject(new Error("No active transaction. Call transStart() first."))}get(e,t,r={}){let n=r.skipHooks?"?skipHooks=true":"";return this.request("GET",`/v1/entity/${e}/${t}${n}`)}find(e,t,r={}){let n=r.skipHooks?"?skipHooks=true":"";return this.request("POST",`/v1/entity/${e}/find${n}`,t??{})}list(e,t={}){let{conditions:r,fields:n,orderDir:i,orderBy:a,...o}=t,c={page:1,limit:20,...o};return a&&(c.orderBy=i==="DESC"?`-${a}`:a),n?.length&&(c.fields=n.join(",")),this.request("POST",`/v1/entity/${e}/list?${q(c)}`,r??{})}count(e,t){return this.request("POST",`/v1/entity/${e}/count`,t??{})}query(e,t){return this.request("POST",`/v1/entity/${e}/query`,t)}submit(e,t,r={}){let n=r.transactionId??this.activeTxId,i=n?{"X-Transaction-ID":n}:void 0,a=r.skipHooks?"?skipHooks=true":"";return this.request("POST",`/v1/entity/${e}/submit${a}`,t,!0,i)}delete(e,t,r={}){let n=new URLSearchParams;r.hard&&n.set("hard","true"),r.skipHooks&&n.set("skipHooks","true");let i=n.size?`?${n}`:"",a=r.transactionId??this.activeTxId,o=a?{"X-Transaction-ID":a}:void 0;return this.request("POST",`/v1/entity/${e}/delete/${t}${i}`,void 0,!0,o)}history(e,t,r={}){return this.request("GET",`/v1/entity/${e}/history/${t}?${q({page:1,limit:50,...r})}`)}rollback(e,t){return this.request("POST",`/v1/entity/${e}/rollback/${t}`)}push(e,t,r={}){return this.submit(e,t,r)}pushLogList(e={}){return this.list("push_log",e)}registerPushDevice(e,t,r,n={}){let{platform:i,deviceType:a,browser:o,browserVersion:c,pushEnabled:f=!0,transactionId:h}=n;return this.submit("account_device",{id:t,account_seq:e,push_token:r,push_enabled:f,...i?{platform:i}:{},...a?{device_type:a}:{},...o?{browser:o}:{},...c?{browser_version:c}:{}},{transactionId:h})}updatePushDeviceToken(e,t,r={}){let{pushEnabled:n=!0,transactionId:i}=r;return this.submit("account_device",{seq:e,push_token:t,push_enabled:n},{transactionId:i})}disablePushDevice(e,t={}){return this.submit("account_device",{seq:e,push_enabled:!1},{transactionId:t.transactionId})}readRequestBody(e,t="application/json",r=!1){let n=E(this.hmacSecret,this.token);return I(e,t,r,n,this.packetMagicLen)}get _reqOpts(){return{baseUrl:this.baseUrl,token:this.token,apiKey:this.apiKey,hmacSecret:this.hmacSecret,packetMagicLen:this.packetMagicLen,encryptRequests:this.encryptRequests}}request(e,t,r,n=!0,i){return $(this._reqOpts,e,t,r,n,i)}};var A=new T;function ue(s={}){let{singleton:e=!0,tokenResolver:t,baseUrl:r,packetMagicLen:n,token:i,resumeSession:a}=s,[o,c]=B(!1),[f,h]=B(null),y=L(!0);H(()=>(y.current=!0,()=>{y.current=!1}),[]);let b=L(a);H(()=>{let u=b.current;u&&p.refreshToken(u).catch(()=>{})},[]);let p=D(()=>{let u=e?A:new T({baseUrl:r,packetMagicLen:n,token:i});e&&u.configure({baseUrl:r,packetMagicLen:n,token:i});let d=t?.();return typeof d=="string"&&u.setToken(d),u},[e,t,r,n,i]),l=S(async u=>{y.current&&(c(!0),h(null));try{return await u()}catch(d){let g=d instanceof Error?d:new Error(String(d));throw y.current&&h(g),g}finally{y.current&&c(!1)}},[]),k=S((u,d,g)=>l(()=>p.submit(u,d,g)),[p,l]),_=S((u,d,g)=>l(()=>p.delete(u,d,g)),[p,l]),v=S((u,d)=>l(()=>p.query(u,d)),[p,l]),m=S(()=>{c(!1),h(null)},[]);return{client:p,isPending:o,error:f,reset:m,submit:k,del:_,query:v}}export{ue as useEntityServer};
|
|
2
2
|
//# sourceMappingURL=react.js.map
|
package/dist/react.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
|
-
"sources": ["../src/hooks/useEntityServer.ts", "../src/index.ts"],
|
|
4
|
-
"sourcesContent": ["import { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport {\n EntityServerClient,\n entityServer,\n type EntityListParams,\n type EntityQueryRequest,\n type EntityServerClientOptions,\n} from \"../index\";\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 * \uC774 \uAC12\uC774 \uC788\uC73C\uBA74 \uB9C8\uC6B4\uD2B8 \uC2DC `client.refreshToken()`\uC744 \uD638\uCD9C\uD574 \uC0C8 access_token\uC744 \uBC1C\uAE09\uBC1B\uC2B5\uB2C8\uB2E4.\n * `keepSession: true`\uC640 \uD568\uAED8 \uC0AC\uC6A9\uD558\uBA74 \uC138\uC158 \uC720\uC9C0 \uD0C0\uC774\uBA38\uB3C4 \uC7AC\uC2DC\uC791\uB429\uB2C8\uB2E4.\n * \uAC31\uC2E0 \uC131\uACF5 \uC2DC `onTokenRefreshed` \uCF5C\uBC31\uC774 \uD638\uCD9C\uB429\uB2C8\uB2E4.\n */\n resumeSession?: string;\n}\n\nexport interface UseEntityServerResult {\n /** EntityServerClient \uC778\uC2A4\uD134\uC2A4 (read \uC804\uC6A9 \uBA54\uC11C\uB4DC \uC9C1\uC811 \uD638\uCD9C \uC2DC \uC0AC\uC6A9) */\n client: EntityServerClient;\n /** submit \uB610\uB294 delete \uC9C4\uD589 \uC911 \uC5EC\uBD80 */\n isPending: boolean;\n /** \uB9C8\uC9C0\uB9C9 mutation \uC5D0\uB7EC (\uC5C6\uC73C\uBA74 null) */\n error: Error | null;\n /** \uC5D0\uB7EC\u00B7\uACB0\uACFC \uC0C1\uD0DC \uCD08\uAE30\uD654 */\n reset: () => void;\n /** entity \uB370\uC774\uD130 \uC0DD\uC131/\uC218\uC815 (seq \uC5C6\uC73C\uBA74 INSERT, \uC788\uC73C\uBA74 UPDATE) */\n submit: (\n entity: string,\n data: Record<string, unknown>,\n opts?: { transactionId?: string; skipHooks?: boolean },\n ) => Promise<{ ok: boolean; seq: number }>;\n /** entity \uB370\uC774\uD130 \uC0AD\uC81C */\n del: (\n entity: string,\n seq: number,\n opts?: { transactionId?: string; hard?: boolean; skipHooks?: boolean },\n ) => Promise<{ ok: boolean; deleted: number }>;\n /** \uCEE4\uC2A4\uD140 SQL \uC870\uD68C */\n query: <T = unknown>(\n entity: string,\n req: EntityQueryRequest,\n ) => Promise<{ ok: boolean; data: { items: T[]; count: number } }>;\n}\n\n/**\n * React \uD658\uACBD\uC5D0\uC11C EntityServerClient \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 const {\n singleton = true,\n tokenResolver,\n baseUrl,\n packetMagicLen,\n token,\n resumeSession,\n } = options;\n\n const [isPending, setIsPending] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n\n // \uC5B8\uB9C8\uC6B4\uD2B8 \uD6C4 setState \uBC29\uC9C0\n const mountedRef = useRef(true);\n useEffect(() => {\n mountedRef.current = true;\n return () => {\n mountedRef.current = false;\n };\n }, []);\n\n // \uC0C8\uB85C\uACE0\uCE68 \uD6C4 \uB85C\uADF8\uC778 \uC0C1\uD0DC \uBCF5\uC6D0: resumeSession\uC774 \uC788\uC73C\uBA74 \uB9C8\uC6B4\uD2B8 \uC2DC refreshToken() \uD638\uCD9C\n const resumeTokenRef = useRef(resumeSession);\n useEffect(() => {\n const storedRefreshToken = resumeTokenRef.current;\n if (!storedRefreshToken) return;\n client.refreshToken(storedRefreshToken).catch(() => {\n // refresh_token \uB9CC\uB8CC \uB4F1 \u2014 onSessionExpired \uCF5C\uBC31\uC774 \uC774\uBBF8 \uCC98\uB9AC\n });\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n const client = useMemo(() => {\n const c = singleton\n ? entityServer\n : new EntityServerClient({ baseUrl, packetMagicLen, token });\n\n if (singleton) {\n c.configure({ baseUrl, packetMagicLen, token });\n }\n\n const resolvedToken = tokenResolver?.();\n if (typeof resolvedToken === \"string\") {\n c.setToken(resolvedToken);\n }\n\n return c;\n }, [singleton, tokenResolver, baseUrl, packetMagicLen, token]);\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 e = err instanceof Error ? err : new Error(String(err));\n if (mountedRef.current) setError(e);\n throw e;\n } finally {\n if (mountedRef.current) setIsPending(false);\n }\n }, []);\n\n const submit = useCallback<UseEntityServerResult[\"submit\"]>(\n (entity, data, opts) => run(() => client.submit(entity, data, opts)),\n [client, run],\n );\n\n const del = useCallback<UseEntityServerResult[\"del\"]>(\n (entity, seq, opts) => run(() => client.delete(entity, seq, opts)),\n [client, run],\n );\n\n const query = useCallback<UseEntityServerResult[\"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", "// @ts-ignore\nimport { xchacha20poly1305 } from \"@noble/ciphers/chacha\";\n// @ts-ignore\nimport { sha256 } from \"@noble/hashes/sha2\";\n\n/**\n * \uC5D4\uD2F0\uD2F0 \uBAA9\uB85D \uC870\uD68C \uD30C\uB77C\uBBF8\uD130\uC785\uB2C8\uB2E4.\n *\n * ```ts\n * client.list(\"post\", {\n * page: 1, limit: 10,\n * orderBy: \"created_time\", orderDir: \"DESC\",\n * fields: [\"seq\", \"title\", \"created_time\"],\n * conditions: { status: \"active\" },\n * });\n * ```\n */\nexport interface EntityListParams {\n /** \uC870\uD68C \uD398\uC774\uC9C0 \uBC88\uD638. \uAE30\uBCF8\uAC12: `1` */\n page?: number;\n /** \uD398\uC774\uC9C0\uB2F9 \uB808\uCF54\uB4DC \uC218. \uAE30\uBCF8\uAC12: `20` */\n limit?: number;\n /** \uC815\uB82C \uAE30\uC900 \uD544\uB4DC\uBA85 */\n orderBy?: string;\n /** \uC815\uB82C \uBC29\uD5A5. \uAE30\uBCF8\uAC12: `\"ASC\"` */\n orderDir?: \"ASC\" | \"DESC\";\n /**\n * \uBC18\uD658\uD560 \uD544\uB4DC \uBAA9\uB85D.\n *\n * - **\uBBF8\uC9C0\uC815 (\uAE30\uBCF8\uAC12)**: \uC5D4\uD2F0\uD2F0\uC758 \uC778\uB371\uC2A4 \uD544\uB4DC\uB9CC \uBC18\uD658\uD569\uB2C8\uB2E4.\n * \uBCF5\uD638\uD654\uB97C \uAC74\uB108\uB6F0\uAE30 \uB54C\uBB38\uC5D0 **\uAC00\uC7A5 \uBE60\uB985\uB2C8\uB2E4**.\n * - `[\"*\"]`: \uC804\uCCB4 \uD544\uB4DC \uBC18\uD658 (\uBCF5\uD638\uD654 \uC218\uD589).\n * - \uD544\uB4DC\uBA85 \uBAA9\uB85D: \uD574\uB2F9 \uD544\uB4DC\uB9CC \uBC18\uD658\uD569\uB2C8\uB2E4.\n * \uC5D4\uD2F0\uD2F0 \uC124\uC815\uC5D0 `index`\uB85C \uC120\uC5B8\uB41C \uD544\uB4DC\uB9CC \uC9C0\uC815 \uAC00\uB2A5\uD569\uB2C8\uB2E4.\n * \uC874\uC7AC\uD558\uC9C0 \uC54A\uB294 \uD544\uB4DC\uBA85\uC744 \uC9C0\uC815\uD558\uBA74 \uC11C\uBC84 \uC5D0\uB7EC\uAC00 \uBC1C\uC0DD\uD569\uB2C8\uB2E4.\n * - `seq`, `created_time`, `updated_time`, `license_seq`\uB294 \uD544\uB4DC\uC5D0 \uAD00\uACC4\uC5C6\uC774 \uD56D\uC0C1 \uD3EC\uD568\uB429\uB2C8\uB2E4.\n *\n * ```ts\n * // \uAE30\uBCF8\uAC12 (\uC778\uB371\uC2A4 \uD544\uB4DC\uB9CC, \uAC00\uC7A5 \uBE60\uB984)\n * client.list(\"account\")\n * // \uC804\uCCB4 \uD544\uB4DC\n * client.list(\"account\", { fields: [\"*\"] })\n * // seq, name, email\uB9CC\n * client.list(\"account\", { fields: [\"seq\", \"name\", \"email\"] })\n * ```\n */\n fields?: string[];\n /** \uD544\uD130 \uC870\uAC74. POST body\uB85C \uC804\uB2EC\uB429\uB2C8\uB2E4. (\uC608: `{ status: \"active\" }`) */\n conditions?: Record<string, unknown>;\n}\n\n/**\n * `query()` \uBA54\uC11C\uB4DC\uC5D0 \uC804\uB2EC\uD558\uB294 SQL \uCFFC\uB9AC \uC694\uCCAD\uC785\uB2C8\uB2E4.\n *\n * - `sql`: SELECT \uC804\uC6A9 SQL. \uC778\uB371\uC2A4 \uD14C\uC774\uBE14\uB9CC \uC870\uD68C \uAC00\uB2A5\uD558\uBA70 JOIN \uC9C0\uC6D0.\n * - `params`: SQL \uBC14\uC778\uB529 \uD30C\uB77C\uBBF8\uD130 (`?` \uD50C\uB808\uC774\uC2A4\uD640\uB354 \uB300\uC751).\n * - `limit`: \uCD5C\uB300 \uBC18\uD658 \uAC74\uC218 (\uCD5C\uB300 1000. \uBBF8\uC9C0\uC815 \uC2DC \uC11C\uBC84 \uAE30\uBCF8\uAC12 \uC801\uC6A9).\n *\n * ```ts\n * client.query(\"order\", {\n * sql: `SELECT o.seq, o.status, u.name\n * FROM order o\n * JOIN account u ON u.data_seq = o.account_seq\n * WHERE o.status = ?`,\n * params: [\"pending\"],\n * limit: 100,\n * });\n * ```\n */\nexport interface EntityQueryRequest {\n sql: string;\n params?: unknown[];\n limit?: number;\n}\n\nexport interface RegisterPushDeviceOptions {\n platform?: string;\n deviceType?: string;\n browser?: string;\n browserVersion?: string;\n pushEnabled?: boolean;\n transactionId?: string;\n}\n\n/** EntityServerClient \uC0DD\uC131/\uC124\uC815 \uC635\uC158\uC785\uB2C8\uB2E4. */\nexport interface EntityServerClientOptions {\n baseUrl?: string;\n token?: string;\n packetMagicLen?: number;\n /**\n * `true`\uC774\uBA74 \uC778\uC99D\uB41C POST/PUT \uC694\uCCAD \uBC14\uB514\uB97C XChaCha20-Poly1305\uB85C \uC554\uD638\uD654\uD569\uB2C8\uB2E4.\n *\n * \uC11C\uBC84\uC758 `EnablePacketEncryption`\uC774 \uD65C\uC131\uD654\uB41C \uACBD\uC6B0 \uD544\uC218\uB85C \uC124\uC815\uD574\uC57C \uD569\uB2C8\uB2E4.\n * \uB85C\uADF8\uC778(`login()`)\u00B7\uD1A0\uD070 \uAC31\uC2E0(`refreshToken()`)\uC740 \uC778\uC99D \uC804 \uC694\uCCAD\uC774\uBBC0\uB85C \uC790\uB3D9\uC73C\uB85C \uAC74\uB108\uB701\uB2C8\uB2E4.\n *\n * \uAE30\uBCF8\uAC12: `false`\n */\n encryptRequests?: boolean;\n /**\n * `true`\uC774\uBA74 `login()` \uC131\uACF5 \uD6C4 Access Token \uB9CC\uB8CC \uC804\uC5D0 \uC790\uB3D9\uC73C\uB85C \uAC31\uC2E0(silent refresh)\uD569\uB2C8\uB2E4.\n * \uAC31\uC2E0 \uC2DC\uC810\uC740 `expires_in - refreshBuffer` \uCD08\uC785\uB2C8\uB2E4.\n *\n * \uAC31\uC2E0 \uC131\uACF5 \uC2DC `onTokenRefreshed`, \uC2E4\uD328 \uC2DC `onSessionExpired` \uCF5C\uBC31\uC774 \uD638\uCD9C\uB429\uB2C8\uB2E4.\n *\n * \uAE30\uBCF8\uAC12: `false`\n */\n keepSession?: boolean;\n /**\n * \uB9CC\uB8CC \uBA87 \uCD08 \uC804\uC5D0 \uC790\uB3D9 \uAC31\uC2E0\uC744 \uC2DC\uB3C4\uD560\uC9C0 \uC124\uC815\uD569\uB2C8\uB2E4.\n *\n * \uC608: `expires_in = 3600`, `refreshBuffer = 60` \u2192 3540\uCD08 \uD6C4 \uAC31\uC2E0\n *\n * \uAE30\uBCF8\uAC12: `60`\n */\n refreshBuffer?: number;\n /**\n * \uC790\uB3D9 \uAC31\uC2E0 \uC131\uACF5 \uC2DC \uD638\uCD9C\uB418\uB294 \uCF5C\uBC31\uC785\uB2C8\uB2E4.\n * \uC0C8 `access_token`\uACFC `expires_in`\uC774 \uC804\uB2EC\uB429\uB2C8\uB2E4.\n * \uC571\uC740 \uC774 \uCF5C\uBC31\uC5D0\uC11C localStorage \uB4F1\uC5D0 \uD1A0\uD070\uC744 \uC800\uC7A5\uD574\uC57C \uD569\uB2C8\uB2E4.\n */\n onTokenRefreshed?: (accessToken: string, expiresIn: number) => void;\n /**\n * \uC138\uC158 \uC720\uC9C0 \uAC31\uC2E0 \uC2E4\uD328 \uC2DC \uD638\uCD9C\uB418\uB294 \uCF5C\uBC31\uC785\uB2C8\uB2E4.\n * refresh_token \uB9CC\uB8CC \uB4F1\uC73C\uB85C \uC7AC\uBC1C\uAE09\uC774 \uBD88\uAC00\uB2A5\uD55C \uACBD\uC6B0\uC785\uB2C8\uB2E4.\n * \uC571\uC740 \uC774 \uCF5C\uBC31\uC5D0\uC11C \uB85C\uADF8\uC778 \uD398\uC774\uC9C0\uB85C \uC774\uB3D9\uD558\uB294 \uB4F1\uC758 \uCC98\uB9AC\uB97C \uD574\uC57C \uD569\uB2C8\uB2E4.\n */\n onSessionExpired?: (error: Error) => void;\n}\n\n/**\n * `list()`, `history()` \uC751\uB2F5\uC758 `data` \uD544\uB4DC \uAD6C\uC870\uC785\uB2C8\uB2E4.\n *\n * \uC11C\uBC84\uB294 \uD56D\uC0C1 \uC774 \uAD6C\uC870\uB85C \uBC18\uD658\uD569\uB2C8\uB2E4:\n * ```json\n * { \"ok\": true, \"data\": { \"items\": [...], \"total\": 100, \"page\": 1, \"limit\": 20 } }\n * ```\n */\nexport interface EntityListResult<T = unknown> {\n items: T[];\n /** \uC804\uCCB4 \uB808\uCF54\uB4DC \uC218 */\n total: number;\n /** \uD604\uC7AC \uD398\uC774\uC9C0 \uBC88\uD638 */\n page: number;\n /** \uD398\uC774\uC9C0\uB2F9 \uB808\uCF54\uB4DC \uC218 */\n limit: number;\n}\n\n/**\n * `history()` \uC751\uB2F5\uC758 \uAC1C\uBCC4 \uC774\uB825 \uB808\uCF54\uB4DC \uAD6C\uC870\uC785\uB2C8\uB2E4.\n *\n * - `action`: `\"INSERT\"` | `\"UPDATE\"` | `\"DELETE_SOFT\"` | `\"DELETE_HARD\"` | `\"ROLLBACK\"`\n * - `data_snapshot`: \uBCC0\uACBD \uB2F9\uC2DC \uC5D4\uD2F0\uD2F0 \uB370\uC774\uD130 \uC2A4\uB0C5\uC0F7\n */\nexport interface EntityHistoryRecord<T = unknown> {\n seq: number;\n action:\n | \"INSERT\"\n | \"UPDATE\"\n | \"DELETE_SOFT\"\n | \"DELETE_HARD\"\n | \"ROLLBACK\"\n | string;\n data_snapshot: T | null;\n changed_by: number | null;\n changed_time: string;\n}\n\n/** Vite \uD658\uACBD\uBCC0\uC218(`import.meta.env`)\uC5D0\uC11C \uAC12\uC744 \uC77D\uC2B5\uB2C8\uB2E4. */\nfunction readEnv(name: string): string | undefined {\n const meta = import.meta as unknown as {\n env?: Record<string, string | undefined>;\n };\n return meta?.env?.[name];\n}\n\nexport class EntityServerClient {\n private baseUrl: string;\n private token: string;\n private packetMagicLen: number;\n private encryptRequests: boolean;\n private activeTxId: string | null = null;\n\n // \uC138\uC158 \uC720\uC9C0 \uAD00\uB828\n private keepSession: boolean;\n private refreshBuffer: number;\n private onTokenRefreshed?: (accessToken: string, expiresIn: number) => void;\n private onSessionExpired?: (error: Error) => void;\n private _sessionRefreshToken: string | null = null;\n private _refreshTimer: ReturnType<typeof setTimeout> | null = null;\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 `http://localhost:47200`\n * - `packetMagicLen`: `VITE_ENTITY_SERVER_PACKET_MAGIC_LEN` \uB610\uB294 `4`\n */\n constructor(options: EntityServerClientOptions = {}) {\n const envBaseUrl = readEnv(\"VITE_ENTITY_SERVER_URL\");\n const envMagicLen = readEnv(\"VITE_ENTITY_SERVER_PACKET_MAGIC_LEN\");\n\n this.baseUrl = (\n options.baseUrl ??\n envBaseUrl ??\n \"http://localhost:47200\"\n ).replace(/\\/$/, \"\");\n\n this.token = options.token ?? \"\";\n this.packetMagicLen =\n options.packetMagicLen ?? (envMagicLen ? Number(envMagicLen) : 4);\n this.encryptRequests = options.encryptRequests ?? false;\n this.keepSession = options.keepSession ?? false;\n this.refreshBuffer = options.refreshBuffer ?? 60;\n this.onTokenRefreshed = options.onTokenRefreshed;\n this.onSessionExpired = options.onSessionExpired;\n }\n\n /** baseUrl, token, packetMagicLen, encryptRequests \uAC12\uC744 \uB7F0\uD0C0\uC784\uC5D0 \uAC31\uC2E0\uD569\uB2C8\uB2E4. */\n configure(options: Partial<EntityServerClientOptions>): void {\n if (options.baseUrl) {\n this.baseUrl = options.baseUrl.replace(/\\/$/, \"\");\n }\n if (typeof options.token === \"string\") {\n this.token = options.token;\n }\n if (typeof options.packetMagicLen === \"number\") {\n this.packetMagicLen = options.packetMagicLen;\n }\n if (typeof options.encryptRequests === \"boolean\") {\n this.encryptRequests = options.encryptRequests;\n }\n if (typeof options.keepSession === \"boolean\") {\n this.keepSession = options.keepSession;\n }\n if (typeof options.refreshBuffer === \"number\") {\n this.refreshBuffer = options.refreshBuffer;\n }\n if (options.onTokenRefreshed) {\n this.onTokenRefreshed = options.onTokenRefreshed;\n }\n if (options.onSessionExpired) {\n this.onSessionExpired = options.onSessionExpired;\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 }\n\n /** \uC554\uD638\uD654 \uD328\uD0B7 magic \uAE38\uC774(`packet_magic_len`)\uB97C \uC124\uC815\uD569\uB2C8\uB2E4. */\n setPacketMagicLen(length: number): void {\n this.packetMagicLen = length;\n }\n\n /** \uD604\uC7AC \uC554\uD638\uD654 \uD328\uD0B7 magic \uAE38\uC774\uB97C \uBC18\uD658\uD569\uB2C8\uB2E4. */\n getPacketMagicLen(): number {\n return this.packetMagicLen;\n }\n\n /**\n * \uC790\uB3D9 \uD1A0\uD070 \uAC31\uC2E0 \uD0C0\uC774\uBA38\uB97C \uC2DC\uC791\uD569\uB2C8\uB2E4.\n * @param refreshToken \uAC31\uC2E0\uC5D0 \uC0AC\uC6A9\uD560 Refresh Token\n * @param expiresIn Access Token\uC758 \uC720\uD6A8 \uAE30\uAC04 (\uCD08)\n */\n private _scheduleKeepSession(\n refreshToken: string,\n expiresIn: number,\n ): void {\n this._clearRefreshTimer();\n this._sessionRefreshToken = refreshToken;\n\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 this.refreshToken(\n this._sessionRefreshToken,\n );\n this.onTokenRefreshed?.(result.access_token, result.expires_in);\n // \uAC31\uC2E0 \uC131\uACF5 \uC2DC \uB2E4\uC74C \uB9CC\uB8CC \uC804 \uD0C0\uC774\uBA38 \uC7AC\uC608\uC57D\n this._scheduleKeepSession(\n this._sessionRefreshToken,\n result.expires_in,\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 /** \uC790\uB3D9 \uAC31\uC2E0 \uD0C0\uC774\uBA38\uB97C \uC815\uB9AC\uD569\uB2C8\uB2E4. */\n private _clearRefreshTimer(): void {\n if (this._refreshTimer !== null) {\n clearTimeout(this._refreshTimer);\n this._refreshTimer = null;\n }\n }\n\n /**\n * \uC138\uC158 \uC720\uC9C0 \uD0C0\uC774\uBA38\uB97C \uC911\uC9C0\uD569\uB2C8\uB2E4.\n * `logout()` \uD638\uCD9C \uC2DC \uC790\uB3D9\uC73C\uB85C \uC911\uC9C0\uB418\uBBC0\uB85C \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 /**\n * \uC11C\uBC84 \uD5EC\uC2A4 \uCCB4\uD06C\uB97C \uC218\uD589\uD558\uACE0 \uD328\uD0B7 \uC554\uD638\uD654 \uD65C\uC131 \uC5EC\uBD80\uB97C \uC790\uB3D9\uC73C\uB85C \uAC10\uC9C0\uD569\uB2C8\uB2E4.\n *\n * \uC11C\uBC84\uAC00 `packet_encryption: true`\uB97C \uC751\uB2F5\uD558\uBA74 \uC774\uD6C4 \uBAA8\uB4E0 \uC694\uCCAD\uC5D0 \uC554\uD638\uD654\uAC00 \uC790\uB3D9 \uC801\uC6A9\uB429\uB2C8\uB2E4.\n * \uCD08\uAE30\uD654 \uC9C1\uD6C4 \uB610\uB294 \uB85C\uADF8\uC778 \uC804\uC5D0 \uD638\uCD9C\uD558\uBA74 \uC554\uD638\uD654 \uC124\uC815\uC744 \uC790\uB3D9\uC73C\uB85C \uAD6C\uC131\uD560 \uC218 \uC788\uC2B5\uB2C8\uB2E4.\n *\n * ```ts\n * await client.checkHealth();\n * await client.login(email, password); // \uC774\uD6C4 \uC694\uCCAD\uC740 \uC554\uD638\uD654 \uC790\uB3D9 \uC801\uC6A9\n * ```\n *\n * @returns `{ ok: true }` \uB610\uB294 `{ ok: true, packet_encryption: true }`\n */\n async checkHealth(): Promise<{ ok: boolean; packet_encryption?: boolean }> {\n const res = await fetch(`${this.baseUrl}/v1/health`, {\n signal: AbortSignal.timeout(3000),\n });\n const data = (await res.json()) as {\n ok: boolean;\n packet_encryption?: boolean;\n };\n if (data.packet_encryption) {\n this.encryptRequests = true;\n }\n return data;\n }\n\n /** \uB85C\uADF8\uC778 \uD6C4 `access_token`\uC744 \uB0B4\uBD80 \uC0C1\uD0DC\uC5D0 \uC800\uC7A5\uD569\uB2C8\uB2E4. */\n async login(\n email: string,\n password: string,\n ): Promise<{\n access_token: string;\n refresh_token: string;\n expires_in: number;\n }> {\n const data = await this.request<{\n data: {\n access_token: string;\n refresh_token: string;\n expires_in: number;\n };\n }>(\"POST\", \"/v1/auth/login\", { email, passwd: password }, false);\n this.token = data.data.access_token;\n if (this.keepSession) {\n this._scheduleKeepSession(\n data.data.refresh_token,\n data.data.expires_in,\n );\n }\n return data.data;\n }\n\n /** Refresh Token\uC73C\uB85C Access Token\uC744 \uC7AC\uBC1C\uAE09\uBC1B\uC544 \uB0B4\uBD80 \uD1A0\uD070\uC744 \uAD50\uCCB4\uD569\uB2C8\uB2E4. */\n async refreshToken(\n refreshToken: string,\n ): Promise<{ access_token: string; expires_in: number }> {\n const data = await this.request<{\n data: { access_token: string; expires_in: number };\n }>(\"POST\", \"/v1/auth/refresh\", { refresh_token: refreshToken }, false);\n this.token = data.data.access_token;\n if (this.keepSession) {\n this._scheduleKeepSession(refreshToken, data.data.expires_in);\n }\n return data.data;\n }\n\n /**\n * \uC11C\uBC84\uC5D0 \uB85C\uADF8\uC544\uC6C3\uC744 \uC694\uCCAD\uD558\uACE0 \uB0B4\uBD80 \uD1A0\uD070\uC744 \uCD08\uAE30\uD654\uD569\uB2C8\uB2E4.\n * refresh_token\uC744 \uC11C\uBC84\uC5D0 \uC804\uB2EC\uD574 \uBB34\uD6A8\uD654\uD569\uB2C8\uB2E4.\n */\n async logout(refreshToken: string): Promise<{ ok: boolean }> {\n this.stopKeepSession();\n const data = await this.request<{ ok: boolean }>(\n \"POST\",\n \"/v1/auth/logout\",\n { refresh_token: refreshToken },\n false,\n );\n this.token = \"\";\n return data;\n }\n\n /** \uD2B8\uB79C\uC7AD\uC158\uC744 \uC2DC\uC791\uD558\uACE0 \uD65C\uC131 \uD2B8\uB79C\uC7AD\uC158 ID\uB97C \uC800\uC7A5\uD569\uB2C8\uB2E4. */\n async transStart(): Promise<string> {\n const res = await this.request<{ ok: boolean; transaction_id: string }>(\n \"POST\",\n \"/v1/transaction/start\",\n undefined,\n false,\n );\n this.activeTxId = res.transaction_id;\n return this.activeTxId;\n }\n\n /** \uD65C\uC131 \uD2B8\uB79C\uC7AD\uC158(\uB610\uB294 \uC804\uB2EC\uB41C transactionId)\uC744 \uB864\uBC31\uD569\uB2C8\uB2E4. */\n transRollback(transactionId?: string): Promise<{ ok: boolean }> {\n const txId = transactionId ?? this.activeTxId;\n if (!txId) {\n return Promise.reject(\n new Error(\"No active transaction. Call transStart() first.\"),\n );\n }\n this.activeTxId = null;\n return this.request(\"POST\", `/v1/transaction/rollback/${txId}`);\n }\n\n /** \uD65C\uC131 \uD2B8\uB79C\uC7AD\uC158(\uB610\uB294 \uC804\uB2EC\uB41C transactionId)\uC744 \uCEE4\uBC0B\uD569\uB2C8\uB2E4.\n *\n * @returns `results` \uBC30\uC5F4: commit\uB41C \uAC01 \uC791\uC5C5\uC758 `entity`, `action`, `seq`\n */\n transCommit(transactionId?: string): Promise<{\n ok: boolean;\n results: Array<{ entity: string; action: string; seq: number }>;\n }> {\n const txId = transactionId ?? this.activeTxId;\n if (!txId) {\n return Promise.reject(\n new Error(\"No active transaction. Call transStart() first.\"),\n );\n }\n this.activeTxId = null;\n return this.request(\"POST\", `/v1/transaction/commit/${txId}`);\n }\n\n /** \uC2DC\uD000\uC2A4 ID\uB85C \uC5D4\uD2F0\uD2F0 \uB2E8\uAC74\uC744 \uC870\uD68C\uD569\uB2C8\uB2E4. */\n get<T = unknown>(\n entity: string,\n seq: number,\n opts: { skipHooks?: boolean } = {},\n ): Promise<{ ok: boolean; data: T }> {\n const q = opts.skipHooks ? \"?skipHooks=true\" : \"\";\n return this.request(\"GET\", `/v1/entity/${entity}/${seq}${q}`);\n }\n\n /** \uC870\uAC74\uC73C\uB85C \uC5D4\uD2F0\uD2F0 \uB2E8\uAC74\uC744 \uC870\uD68C\uD569\uB2C8\uB2E4. data \uCEEC\uB7FC\uC744 \uC644\uC804\uD788 \uBCF5\uD638\uD654\uD558\uC5EC \uBC18\uD658\uD569\uB2C8\uB2E4. */\n find<T = unknown>(\n entity: string,\n conditions?: Record<string, unknown>,\n opts: { skipHooks?: boolean } = {},\n ): Promise<{ ok: boolean; data: T }> {\n const q = opts.skipHooks ? \"?skipHooks=true\" : \"\";\n return this.request(\n \"POST\",\n `/v1/entity/${entity}/find${q}`,\n conditions ?? {},\n );\n }\n\n /** \uD398\uC774\uC9C0\uB124\uC774\uC158/\uC815\uB82C/\uD544\uD130 \uC870\uAC74\uC73C\uB85C \uC5D4\uD2F0\uD2F0 \uBAA9\uB85D\uC744 \uC870\uD68C\uD569\uB2C8\uB2E4. */\n list<T = unknown>(\n entity: string,\n params: EntityListParams = {},\n ): Promise<{ ok: boolean; data: EntityListResult<T> }> {\n const { conditions, fields, orderDir, orderBy, ...rest } = params;\n\n const queryObj: Record<string, unknown> = {\n page: 1,\n limit: 20,\n ...rest,\n };\n if (orderBy) {\n queryObj.orderBy = orderDir === \"DESC\" ? `-${orderBy}` : orderBy;\n }\n if (fields?.length) {\n queryObj.fields = fields.join(\",\");\n }\n\n const q = buildQuery(queryObj);\n return this.request(\n \"POST\",\n `/v1/entity/${entity}/list?${q}`,\n conditions ?? {},\n );\n }\n\n /**\n * \uC5D4\uD2F0\uD2F0 \uCD1D \uAC74\uC218\uB97C \uC870\uD68C\uD569\uB2C8\uB2E4.\n *\n * @param conditions \uD544\uD130 \uC870\uAC74 (\uC608: `{ status: \"active\" }`)\n */\n count(\n entity: string,\n conditions?: Record<string, unknown>,\n ): Promise<{ ok: boolean; count: number }> {\n return this.request(\n \"POST\",\n `/v1/entity/${entity}/count`,\n conditions ?? {},\n );\n }\n\n /**\n * \uCEE4\uC2A4\uD140 SQL\uB85C \uC5D4\uD2F0\uD2F0\uB97C \uC870\uD68C\uD569\uB2C8\uB2E4.\n *\n * SELECT \uC804\uC6A9\uC774\uBA70 \uC778\uB371\uC2A4 \uD14C\uC774\uBE14\uB9CC \uC870\uD68C \uAC00\uB2A5\uD569\uB2C8\uB2E4.\n * JOIN\uC744 \uC0AC\uC6A9\uD574 \uC5EC\uB7EC \uC5D4\uD2F0\uD2F0\uB97C \uC870\uD569\uD560 \uC218 \uC788\uC2B5\uB2C8\uB2E4.\n * `entity`\uB294 SQL\uC5D0 \uD3EC\uD568\uB41C \uAE30\uBCF8 \uC5D4\uD2F0\uD2F0\uBA85(\uB77C\uC6B0\uD2B8 \uACBD\uB85C\uC6A9)\uC785\uB2C8\uB2E4.\n */\n query<T = unknown>(\n entity: string,\n req: EntityQueryRequest,\n ): Promise<{ ok: boolean; data: { items: T[]; count: number } }> {\n return this.request(\"POST\", `/v1/entity/${entity}/query`, req);\n }\n\n /** \uC5D4\uD2F0\uD2F0 \uB370\uC774\uD130\uB97C \uC0DD\uC131/\uC218\uC815(Submit)\uD569\uB2C8\uB2E4. `seq`\uAC00 \uC5C6\uC73C\uBA74 INSERT, \uC788\uC73C\uBA74 UPDATE\uC785\uB2C8\uB2E4. */\n submit(\n entity: string,\n data: Record<string, unknown>,\n opts: { transactionId?: string; skipHooks?: boolean } = {},\n ): Promise<{ ok: boolean; seq: number }> {\n const txId = opts.transactionId ?? this.activeTxId;\n const extraHeaders = txId ? { \"X-Transaction-ID\": txId } : undefined;\n const q = opts.skipHooks ? \"?skipHooks=true\" : \"\";\n\n return this.request(\n \"POST\",\n `/v1/entity/${entity}/submit${q}`,\n data,\n true,\n extraHeaders,\n );\n }\n\n /** \uC2DC\uD000\uC2A4 ID\uB85C \uC5D4\uD2F0\uD2F0\uB97C \uC0AD\uC81C\uD569\uB2C8\uB2E4(`hard=true`\uBA74 \uD558\uB4DC \uC0AD\uC81C, \uAE30\uBCF8\uC740 \uC18C\uD504\uD2B8 \uC0AD\uC81C). */\n delete(\n entity: string,\n seq: number,\n opts: {\n transactionId?: string;\n hard?: boolean;\n skipHooks?: boolean;\n } = {},\n ): Promise<{ ok: boolean; deleted: number }> {\n const params = new URLSearchParams();\n if (opts.hard) params.set(\"hard\", \"true\");\n if (opts.skipHooks) params.set(\"skipHooks\", \"true\");\n const q = params.size ? `?${params}` : \"\";\n const txId = opts.transactionId ?? this.activeTxId;\n const extraHeaders = txId ? { \"X-Transaction-ID\": txId } : undefined;\n\n return this.request(\n \"POST\",\n `/v1/entity/${entity}/delete/${seq}${q}`,\n undefined,\n true,\n extraHeaders,\n );\n }\n\n /** \uC5D4\uD2F0\uD2F0 \uB2E8\uAC74\uC758 \uBCC0\uACBD \uC774\uB825\uC744 \uC870\uD68C\uD569\uB2C8\uB2E4. \uC774\uB825 \uD56D\uBAA9\uB2F9 `action`, `data_snapshot`, `changed_by`, `changed_time`\uC744 \uD3EC\uD568\uD569\uB2C8\uB2E4. */\n history<T = unknown>(\n entity: string,\n seq: number,\n params: Pick<EntityListParams, \"page\" | \"limit\"> = {},\n ): Promise<{\n ok: boolean;\n data: EntityListResult<EntityHistoryRecord<T>>;\n }> {\n const q = buildQuery({ page: 1, limit: 50, ...params });\n return this.request(\"GET\", `/v1/entity/${entity}/history/${seq}?${q}`);\n }\n\n /** \uD2B9\uC815 \uC774\uB825 \uC2DC\uC810\uC73C\uB85C \uC5D4\uD2F0\uD2F0\uB97C \uB864\uBC31\uD569\uB2C8\uB2E4. */\n rollback(entity: string, historySeq: number): Promise<{ ok: boolean }> {\n return this.request(\n \"POST\",\n `/v1/entity/${entity}/rollback/${historySeq}`,\n );\n }\n\n /** \uD478\uC2DC \uAD00\uB828 \uC5D4\uD2F0\uD2F0\uB85C payload\uB97C \uC804\uC1A1(Submit)\uD569\uB2C8\uB2E4. */\n push(\n pushEntity: string,\n payload: Record<string, unknown>,\n opts: { transactionId?: string } = {},\n ): Promise<{ ok: boolean; seq: number }> {\n return this.submit(pushEntity, payload, opts);\n }\n\n /** \uD478\uC2DC \uB85C\uADF8 \uC5D4\uD2F0\uD2F0 \uBAA9\uB85D\uC744 \uC870\uD68C\uD569\uB2C8\uB2E4. */\n pushLogList<T = unknown>(\n params: EntityListParams = {},\n ): Promise<{ ok: boolean; data: EntityListResult<T> }> {\n return this.list<T>(\"push_log\", params);\n }\n\n /** \uACC4\uC815\uC758 \uD478\uC2DC \uB514\uBC14\uC774\uC2A4\uB97C \uB4F1\uB85D\uD569\uB2C8\uB2E4. */\n registerPushDevice(\n accountSeq: number,\n deviceId: string,\n pushToken: string,\n opts: RegisterPushDeviceOptions = {},\n ): Promise<{ ok: boolean; seq: number }> {\n const {\n platform,\n deviceType,\n browser,\n browserVersion,\n pushEnabled = true,\n transactionId,\n } = opts;\n\n return this.submit(\n \"account_device\",\n {\n id: deviceId,\n account_seq: accountSeq,\n push_token: pushToken,\n push_enabled: pushEnabled,\n ...(platform ? { platform } : {}),\n ...(deviceType ? { device_type: deviceType } : {}),\n ...(browser ? { browser } : {}),\n ...(browserVersion ? { browser_version: browserVersion } : {}),\n },\n { transactionId },\n );\n }\n\n /** \uB514\uBC14\uC774\uC2A4 \uB808\uCF54\uB4DC\uC758 \uD478\uC2DC \uD1A0\uD070\uC744 \uAC31\uC2E0\uD569\uB2C8\uB2E4. */\n updatePushDeviceToken(\n deviceSeq: number,\n pushToken: string,\n opts: { pushEnabled?: boolean; transactionId?: string } = {},\n ): Promise<{ ok: boolean; seq: number }> {\n const { pushEnabled = true, transactionId } = opts;\n return this.submit(\n \"account_device\",\n {\n seq: deviceSeq,\n push_token: pushToken,\n push_enabled: pushEnabled,\n },\n { transactionId },\n );\n }\n\n /** \uB514\uBC14\uC774\uC2A4\uC758 \uD478\uC2DC \uC218\uC2E0\uC744 \uBE44\uD65C\uC131\uD654\uD569\uB2C8\uB2E4. */\n disablePushDevice(\n deviceSeq: number,\n opts: { transactionId?: string } = {},\n ): Promise<{ ok: boolean; seq: number }> {\n return this.submit(\n \"account_device\",\n {\n seq: deviceSeq,\n push_enabled: false,\n },\n { transactionId: opts.transactionId },\n );\n }\n\n /**\n * \uC694\uCCAD \uBC14\uB514\uB97C \uD30C\uC2F1\uD558\uACE0 `application/octet-stream`\uC778 \uACBD\uC6B0 \uBCF5\uD638\uD654\uD569\uB2C8\uB2E4.\n *\n * \uC6D0\uC2DC \uC554\uD638\uD654 payload\uB97C \uC9C1\uC811 \uB2E4\uB8E8\uB294 \uD074\uB77C\uC774\uC5B8\uD2B8\uC5D0\uC11C \uC0AC\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 lowered = contentType.toLowerCase();\n const isEncrypted = lowered.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) {\n throw new Error(\"Encrypted request body is empty\");\n }\n if (body instanceof ArrayBuffer) {\n return this.decryptPacket<T>(body);\n }\n if (body instanceof Uint8Array) {\n const sliced = body.buffer.slice(\n body.byteOffset,\n body.byteOffset + body.byteLength,\n );\n return this.decryptPacket<T>(sliced as ArrayBuffer);\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\n /**\n * \uACF5\uD1B5 HTTP \uC694\uCCAD \uD568\uC218\uC785\uB2C8\uB2E4.\n *\n * - `encryptRequests`\uAC00 \uD65C\uC131\uD654\uB41C \uC778\uC99D \uC694\uCCAD\uC758 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 */\n private async request<T>(\n method: string,\n path: string,\n body?: unknown,\n withAuth = true,\n extraHeaders: Record<string, string> = {},\n ): Promise<T> {\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n ...extraHeaders,\n };\n if (withAuth && this.token) {\n headers.Authorization = `Bearer ${this.token}`;\n }\n\n // \uC694\uCCAD \uBC14\uB514 \uACB0\uC815: encryptRequests \uD65C\uC131\uD654 \uC2DC POST \uBC14\uB514\uB97C \uC554\uD638\uD654\uD569\uB2C8\uB2E4.\n // - \uB85C\uADF8\uC778/\uD1A0\uD070 \uAC31\uC2E0(withAuth=false)\uC740 \uC554\uD638\uD654\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.\n // - GET \uC740 \uBC14\uB514\uAC00 \uC5C6\uC73C\uBBC0\uB85C \uAC74\uB108\uB701\uB2C8\uB2E4.\n let fetchBody: string | Uint8Array | null = null;\n if (body != null) {\n const shouldEncrypt =\n this.encryptRequests &&\n withAuth &&\n this.token &&\n method !== \"GET\" &&\n method !== \"HEAD\";\n\n if (shouldEncrypt) {\n const plaintext = new TextEncoder().encode(\n JSON.stringify(body),\n );\n const encrypted = this.encryptPacket(plaintext);\n headers[\"Content-Type\"] = \"application/octet-stream\";\n fetchBody = encrypted;\n } else {\n fetchBody = JSON.stringify(body);\n }\n }\n\n const res = await fetch(this.baseUrl + path, {\n method,\n headers,\n ...(fetchBody != null ? { body: fetchBody as BodyInit } : {}),\n });\n\n const contentType = res.headers.get(\"Content-Type\") ?? \"\";\n\n if (contentType.includes(\"application/octet-stream\")) {\n const buffer = await res.arrayBuffer();\n return this.decryptPacket<T>(buffer);\n }\n\n const data = await res.json();\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 /**\n * \uD3C9\uBB38 \uBC14\uC774\uD2B8\uB97C XChaCha20-Poly1305\uB85C \uC554\uD638\uD654\uD569\uB2C8\uB2E4.\n * \uD3EC\uB9F7: [random_magic:packetMagicLen][random_nonce:24][ciphertext+tag]\n */\n private encryptPacket(plaintext: Uint8Array): Uint8Array {\n const key = sha256(new TextEncoder().encode(this.token));\n const magic = new Uint8Array(this.packetMagicLen);\n const nonce = new Uint8Array(24);\n crypto.getRandomValues(magic);\n crypto.getRandomValues(nonce);\n const cipher = xchacha20poly1305(key, nonce);\n const ciphertext = cipher.encrypt(plaintext);\n const result = new Uint8Array(\n this.packetMagicLen + 24 + ciphertext.length,\n );\n result.set(magic, 0);\n result.set(nonce, this.packetMagicLen);\n result.set(ciphertext, this.packetMagicLen + 24);\n return result;\n }\n\n /** \uC11C\uBC84\uC758 \uC554\uD638\uD654 \uD328\uD0B7\uC744 \uBCF5\uD638\uD654\uD574 JSON \uAC1D\uCCB4\uB85C \uBCC0\uD658\uD569\uB2C8\uB2E4. */\n private decryptPacket<T>(buffer: ArrayBuffer): T {\n const key = sha256(new TextEncoder().encode(this.token));\n const data = new Uint8Array(buffer);\n\n if (data.length < this.packetMagicLen + 24 + 16) {\n throw new Error(\"Encrypted packet too short\");\n }\n\n const nonce = data.slice(this.packetMagicLen, this.packetMagicLen + 24);\n const ciphertext = data.slice(this.packetMagicLen + 24);\n const cipher = xchacha20poly1305(key, nonce);\n const plaintext = cipher.decrypt(ciphertext);\n return JSON.parse(new TextDecoder().decode(plaintext)) as T;\n }\n}\n\n/** \uCFFC\uB9AC \uD30C\uB77C\uBBF8\uD130 \uAC1D\uCCB4\uB97C URL \uCFFC\uB9AC \uBB38\uC790\uC5F4\uB85C \uBCC0\uD658\uD569\uB2C8\uB2E4. */\nfunction 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\nexport const entityServer = new EntityServerClient();\n"],
|
|
5
|
-
"mappings": "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",
|
|
6
|
-
"names": ["useCallback", "useEffect", "useMemo", "useRef", "useState", "xchacha20poly1305", "sha256", "
|
|
3
|
+
"sources": ["../src/hooks/useEntityServer.ts", "../src/client/utils.ts", "../src/client/packet.ts", "../src/client/hmac.ts", "../src/client/request.ts", "../src/EntityServerClient.ts", "../src/index.ts"],
|
|
4
|
+
"sourcesContent": ["import { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport {\n EntityServerClient,\n entityServer,\n type EntityListParams,\n type EntityQueryRequest,\n type EntityServerClientOptions,\n} from \"../index\";\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 * \uC774 \uAC12\uC774 \uC788\uC73C\uBA74 \uB9C8\uC6B4\uD2B8 \uC2DC `client.refreshToken()`\uC744 \uD638\uCD9C\uD574 \uC0C8 access_token\uC744 \uBC1C\uAE09\uBC1B\uC2B5\uB2C8\uB2E4.\n * `keepSession: true`\uC640 \uD568\uAED8 \uC0AC\uC6A9\uD558\uBA74 \uC138\uC158 \uC720\uC9C0 \uD0C0\uC774\uBA38\uB3C4 \uC7AC\uC2DC\uC791\uB429\uB2C8\uB2E4.\n * \uAC31\uC2E0 \uC131\uACF5 \uC2DC `onTokenRefreshed` \uCF5C\uBC31\uC774 \uD638\uCD9C\uB429\uB2C8\uB2E4.\n */\n resumeSession?: string;\n}\n\nexport interface UseEntityServerResult {\n /** EntityServerClient \uC778\uC2A4\uD134\uC2A4 (read \uC804\uC6A9 \uBA54\uC11C\uB4DC \uC9C1\uC811 \uD638\uCD9C \uC2DC \uC0AC\uC6A9) */\n client: EntityServerClient;\n /** submit \uB610\uB294 delete \uC9C4\uD589 \uC911 \uC5EC\uBD80 */\n isPending: boolean;\n /** \uB9C8\uC9C0\uB9C9 mutation \uC5D0\uB7EC (\uC5C6\uC73C\uBA74 null) */\n error: Error | null;\n /** \uC5D0\uB7EC\u00B7\uACB0\uACFC \uC0C1\uD0DC \uCD08\uAE30\uD654 */\n reset: () => void;\n /** entity \uB370\uC774\uD130 \uC0DD\uC131/\uC218\uC815 (seq \uC5C6\uC73C\uBA74 INSERT, \uC788\uC73C\uBA74 UPDATE) */\n submit: (\n entity: string,\n data: Record<string, unknown>,\n opts?: { transactionId?: string; skipHooks?: boolean },\n ) => Promise<{ ok: boolean; seq: number }>;\n /** entity \uB370\uC774\uD130 \uC0AD\uC81C */\n del: (\n entity: string,\n seq: number,\n opts?: { transactionId?: string; hard?: boolean; skipHooks?: boolean },\n ) => Promise<{ ok: boolean; deleted: number }>;\n /** \uCEE4\uC2A4\uD140 SQL \uC870\uD68C */\n query: <T = unknown>(\n entity: string,\n req: EntityQueryRequest,\n ) => Promise<{ ok: boolean; data: { items: T[]; count: number } }>;\n}\n\n/**\n * React \uD658\uACBD\uC5D0\uC11C EntityServerClient \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 const {\n singleton = true,\n tokenResolver,\n baseUrl,\n packetMagicLen,\n token,\n resumeSession,\n } = options;\n\n const [isPending, setIsPending] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n\n // \uC5B8\uB9C8\uC6B4\uD2B8 \uD6C4 setState \uBC29\uC9C0\n const mountedRef = useRef(true);\n useEffect(() => {\n mountedRef.current = true;\n return () => {\n mountedRef.current = false;\n };\n }, []);\n\n // \uC0C8\uB85C\uACE0\uCE68 \uD6C4 \uB85C\uADF8\uC778 \uC0C1\uD0DC \uBCF5\uC6D0: resumeSession\uC774 \uC788\uC73C\uBA74 \uB9C8\uC6B4\uD2B8 \uC2DC refreshToken() \uD638\uCD9C\n const resumeTokenRef = useRef(resumeSession);\n useEffect(() => {\n const storedRefreshToken = resumeTokenRef.current;\n if (!storedRefreshToken) return;\n client.refreshToken(storedRefreshToken).catch(() => {\n // refresh_token \uB9CC\uB8CC \uB4F1 \u2014 onSessionExpired \uCF5C\uBC31\uC774 \uC774\uBBF8 \uCC98\uB9AC\n });\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n const client = useMemo(() => {\n const c = singleton\n ? entityServer\n : new EntityServerClient({ baseUrl, packetMagicLen, token });\n\n if (singleton) {\n c.configure({ baseUrl, packetMagicLen, token });\n }\n\n const resolvedToken = tokenResolver?.();\n if (typeof resolvedToken === \"string\") {\n c.setToken(resolvedToken);\n }\n\n return c;\n }, [singleton, tokenResolver, baseUrl, packetMagicLen, token]);\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 e = err instanceof Error ? err : new Error(String(err));\n if (mountedRef.current) setError(e);\n throw e;\n } finally {\n if (mountedRef.current) setIsPending(false);\n }\n }, []);\n\n const submit = useCallback<UseEntityServerResult[\"submit\"]>(\n (entity, data, opts) => run(() => client.submit(entity, data, opts)),\n [client, run],\n );\n\n const del = useCallback<UseEntityServerResult[\"del\"]>(\n (entity, seq, opts) => run(() => client.delete(entity, seq, opts)),\n [client, run],\n );\n\n const query = useCallback<UseEntityServerResult[\"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", "/** Vite \uD658\uACBD\uBCC0\uC218(`import.meta.env`)\uC5D0\uC11C \uAC12\uC744 \uC77D\uC2B5\uB2C8\uB2E4. */\nexport function readEnv(name: string): string | undefined {\n const meta = import.meta as unknown as {\n env?: Record<string, string | undefined>;\n };\n return meta?.env?.[name];\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", "// @ts-ignore\nimport { xchacha20poly1305 } from \"@noble/ciphers/chacha\";\n// @ts-ignore\nimport { sha256 } from \"@noble/hashes/sha2\";\n// @ts-ignore\nimport { hkdf } from \"@noble/hashes/hkdf\";\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: SHA-256(jwt_token)\n */\nexport function derivePacketKey(hmacSecret: string, token: string): Uint8Array {\n if (hmacSecret) {\n const salt = new TextEncoder().encode(\"entity-server:hkdf:v1\");\n const info = new TextEncoder().encode(\n \"entity-server:packet-encryption\",\n );\n return hkdf(\n sha256,\n new TextEncoder().encode(hmacSecret),\n salt,\n info,\n 32,\n );\n }\n return sha256(new TextEncoder().encode(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:magicLen][random_nonce:24][ciphertext+tag]\n */\nexport function encryptPacket(\n plaintext: Uint8Array,\n key: Uint8Array,\n magicLen: number,\n): Uint8Array {\n const magic = new Uint8Array(magicLen);\n const nonce = new Uint8Array(24);\n crypto.getRandomValues(magic);\n crypto.getRandomValues(nonce);\n const cipher = xchacha20poly1305(key, nonce);\n const ciphertext = cipher.encrypt(plaintext);\n const result = new Uint8Array(magicLen + 24 + ciphertext.length);\n result.set(magic, 0);\n result.set(nonce, magicLen);\n result.set(ciphertext, magicLen + 24);\n return result;\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:magicLen][nonce:24][ciphertext+tag]\n */\nexport function decryptPacket<T>(\n buffer: ArrayBuffer,\n key: Uint8Array,\n magicLen: number,\n): T {\n const data = new Uint8Array(buffer);\n if (data.length < magicLen + 24 + 16) {\n throw new Error(\"Encrypted packet too short\");\n }\n const nonce = data.slice(magicLen, magicLen + 24);\n const ciphertext = data.slice(magicLen + 24);\n const cipher = xchacha20poly1305(key, nonce);\n const plaintext = cipher.decrypt(ciphertext);\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 magicLen: number,\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)\n return decryptPacket<T>(body, key, magicLen);\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, magicLen);\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", "// @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", "import { derivePacketKey, encryptPacket, decryptPacket } from \"./packet\";\nimport { buildHmacHeaders } from \"./hmac\";\n\nexport interface RequestOptions {\n baseUrl: string;\n token: string;\n apiKey: string;\n hmacSecret: string;\n packetMagicLen: number;\n encryptRequests: boolean;\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): Promise<T> {\n const {\n baseUrl,\n token,\n apiKey,\n hmacSecret,\n packetMagicLen,\n encryptRequests,\n } = opts;\n const isHmacMode = withAuth && !!(apiKey && hmacSecret);\n\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n ...extraHeaders,\n };\n if (!isHmacMode && withAuth && token) {\n headers.Authorization = `Bearer ${token}`;\n }\n\n let fetchBody: string | Uint8Array | null = null;\n if (body != null) {\n const shouldEncrypt =\n encryptRequests &&\n withAuth &&\n (token || isHmacMode) &&\n method !== \"GET\" &&\n method !== \"HEAD\";\n\n if (shouldEncrypt) {\n const key = derivePacketKey(hmacSecret, token);\n fetchBody = encryptPacket(\n new TextEncoder().encode(JSON.stringify(body)),\n key,\n packetMagicLen,\n );\n headers[\"Content-Type\"] = \"application/octet-stream\";\n } else {\n fetchBody = JSON.stringify(body);\n }\n }\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\n const res = await fetch(baseUrl + path, {\n method,\n headers,\n ...(fetchBody != null ? { body: fetchBody as BodyInit } : {}),\n });\n\n const contentType = res.headers.get(\"Content-Type\") ?? \"\";\n if (contentType.includes(\"application/octet-stream\")) {\n const key = derivePacketKey(hmacSecret, token);\n return decryptPacket<T>(await res.arrayBuffer(), key, packetMagicLen);\n }\n\n const data = await res.json();\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", "import type {\n EntityHistoryRecord,\n EntityListParams,\n EntityListResult,\n EntityQueryRequest,\n EntityServerClientOptions,\n RegisterPushDeviceOptions,\n} from \"./types\";\nimport { readEnv, buildQuery } from \"./client/utils\";\nimport { derivePacketKey, parseRequestBody } from \"./client/packet\";\nimport { entityRequest, type RequestOptions } from \"./client/request\";\n\nexport class EntityServerClient {\n private baseUrl: string;\n private token: string;\n private apiKey: string;\n private hmacSecret: string;\n private packetMagicLen: number;\n private encryptRequests: boolean;\n private activeTxId: string | null = null;\n\n // \uC138\uC158 \uC720\uC9C0 \uAD00\uB828\n private keepSession: boolean;\n private refreshBuffer: number;\n private onTokenRefreshed?: (accessToken: string, expiresIn: number) => void;\n private onSessionExpired?: (error: Error) => void;\n private _sessionRefreshToken: string | null = null;\n private _refreshTimer: ReturnType<typeof setTimeout> | null = null;\n\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 `http://localhost:47200`\n * - `packetMagicLen`: `VITE_ENTITY_SERVER_PACKET_MAGIC_LEN` \uB610\uB294 `4`\n */\n constructor(options: EntityServerClientOptions = {}) {\n const envBaseUrl = readEnv(\"VITE_ENTITY_SERVER_URL\");\n const envMagicLen = readEnv(\"VITE_ENTITY_SERVER_PACKET_MAGIC_LEN\");\n\n this.baseUrl = (\n options.baseUrl ??\n envBaseUrl ??\n \"http://localhost:47200\"\n ).replace(/\\/$/, \"\");\n this.token = options.token ?? \"\";\n this.apiKey = options.apiKey ?? \"\";\n this.hmacSecret = options.hmacSecret ?? \"\";\n this.packetMagicLen =\n options.packetMagicLen ?? (envMagicLen ? Number(envMagicLen) : 4);\n this.encryptRequests = options.encryptRequests ?? false;\n this.keepSession = options.keepSession ?? false;\n this.refreshBuffer = options.refreshBuffer ?? 60;\n this.onTokenRefreshed = options.onTokenRefreshed;\n this.onSessionExpired = options.onSessionExpired;\n }\n\n /** baseUrl, token, packetMagicLen, encryptRequests \uAC12\uC744 \uB7F0\uD0C0\uC784\uC5D0 \uAC31\uC2E0\uD569\uB2C8\uB2E4. */\n configure(options: Partial<EntityServerClientOptions>): void {\n if (options.baseUrl) this.baseUrl = options.baseUrl.replace(/\\/$/, \"\");\n if (typeof options.token === \"string\") this.token = options.token;\n if (typeof options.packetMagicLen === \"number\")\n this.packetMagicLen = options.packetMagicLen;\n if (typeof options.encryptRequests === \"boolean\")\n this.encryptRequests = options.encryptRequests;\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 }\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 }\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 \uD328\uD0B7 magic \uAE38\uC774(`packet_magic_len`)\uB97C \uC124\uC815\uD569\uB2C8\uB2E4. */\n setPacketMagicLen(length: number): void {\n this.packetMagicLen = length;\n }\n\n /** \uD604\uC7AC \uC554\uD638\uD654 \uD328\uD0B7 magic \uAE38\uC774\uB97C \uBC18\uD658\uD569\uB2C8\uB2E4. */\n getPacketMagicLen(): number {\n return this.packetMagicLen;\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 /** @internal \uC790\uB3D9 \uD1A0\uD070 \uAC31\uC2E0 \uD0C0\uC774\uBA38\uB97C \uC2DC\uC791\uD569\uB2C8\uB2E4. */\n private _scheduleKeepSession(\n refreshToken: string,\n expiresIn: 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 this.refreshToken(\n this._sessionRefreshToken,\n );\n this.onTokenRefreshed?.(result.access_token, result.expires_in);\n this._scheduleKeepSession(\n this._sessionRefreshToken,\n result.expires_in,\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 /** @internal \uC790\uB3D9 \uAC31\uC2E0 \uD0C0\uC774\uBA38\uB97C \uC815\uB9AC\uD569\uB2C8\uB2E4. */\n private _clearRefreshTimer(): void {\n if (this._refreshTimer !== null) {\n clearTimeout(this._refreshTimer);\n this._refreshTimer = null;\n }\n }\n\n /**\n * \uC138\uC158 \uC720\uC9C0 \uD0C0\uC774\uBA38\uB97C \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 // \u2500\u2500\u2500 \uC778\uC99D \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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 * \uC11C\uBC84 \uD5EC\uC2A4 \uCCB4\uD06C\uB97C \uC218\uD589\uD558\uACE0 \uD328\uD0B7 \uC554\uD638\uD654 \uD65C\uC131 \uC5EC\uBD80\uB97C \uC790\uB3D9\uC73C\uB85C \uAC10\uC9C0\uD569\uB2C8\uB2E4.\n *\n * \uC11C\uBC84\uAC00 `packet_encryption: true`\uB97C \uC751\uB2F5\uD558\uBA74 \uC774\uD6C4 \uBAA8\uB4E0 \uC694\uCCAD\uC5D0 \uC554\uD638\uD654\uAC00 \uC790\uB3D9 \uC801\uC6A9\uB429\uB2C8\uB2E4.\n *\n * ```ts\n * await client.checkHealth();\n * await client.login(email, password);\n * ```\n */\n async checkHealth(): Promise<{ ok: boolean; packet_encryption?: boolean }> {\n const res = await fetch(`${this.baseUrl}/v1/health`, {\n signal: AbortSignal.timeout(3000),\n });\n const data = (await res.json()) as {\n ok: boolean;\n packet_encryption?: boolean;\n };\n if (data.packet_encryption) this.encryptRequests = true;\n return data;\n }\n\n /** \uB85C\uADF8\uC778 \uD6C4 `access_token`\uC744 \uB0B4\uBD80 \uC0C1\uD0DC\uC5D0 \uC800\uC7A5\uD569\uB2C8\uB2E4. */\n async login(\n email: string,\n password: string,\n ): Promise<{\n access_token: string;\n refresh_token: string;\n expires_in: number;\n }> {\n const data = await this.request<{\n data: {\n access_token: string;\n refresh_token: string;\n expires_in: number;\n };\n }>(\"POST\", \"/v1/auth/login\", { email, passwd: password }, false);\n this.token = data.data.access_token;\n if (this.keepSession)\n this._scheduleKeepSession(\n data.data.refresh_token,\n data.data.expires_in,\n );\n return data.data;\n }\n\n /** Refresh Token\uC73C\uB85C Access Token\uC744 \uC7AC\uBC1C\uAE09\uBC1B\uC544 \uB0B4\uBD80 \uD1A0\uD070\uC744 \uAD50\uCCB4\uD569\uB2C8\uB2E4. */\n async refreshToken(\n refreshToken: string,\n ): Promise<{ access_token: string; expires_in: number }> {\n const data = await this.request<{\n data: { access_token: string; expires_in: number };\n }>(\"POST\", \"/v1/auth/refresh\", { refresh_token: refreshToken }, false);\n this.token = data.data.access_token;\n if (this.keepSession)\n this._scheduleKeepSession(refreshToken, data.data.expires_in);\n return data.data;\n }\n\n /**\n * \uC11C\uBC84\uC5D0 \uB85C\uADF8\uC544\uC6C3\uC744 \uC694\uCCAD\uD558\uACE0 \uB0B4\uBD80 \uD1A0\uD070\uC744 \uCD08\uAE30\uD654\uD569\uB2C8\uB2E4.\n * refresh_token\uC744 \uC11C\uBC84\uC5D0 \uC804\uB2EC\uD574 \uBB34\uD6A8\uD654\uD569\uB2C8\uB2E4.\n */\n async logout(refreshToken: string): Promise<{ ok: boolean }> {\n this.stopKeepSession();\n const data = await this.request<{ ok: boolean }>(\n \"POST\",\n \"/v1/auth/logout\",\n { refresh_token: refreshToken },\n false,\n );\n this.token = \"\";\n return data;\n }\n\n // \u2500\u2500\u2500 \uD2B8\uB79C\uC7AD\uC158 \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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 /** \uD2B8\uB79C\uC7AD\uC158\uC744 \uC2DC\uC791\uD558\uACE0 \uD65C\uC131 \uD2B8\uB79C\uC7AD\uC158 ID\uB97C \uC800\uC7A5\uD569\uB2C8\uB2E4. */\n async transStart(): Promise<string> {\n const res = await this.request<{ ok: boolean; transaction_id: string }>(\n \"POST\",\n \"/v1/transaction/start\",\n undefined,\n false,\n );\n this.activeTxId = res.transaction_id;\n return this.activeTxId;\n }\n\n /** \uD65C\uC131 \uD2B8\uB79C\uC7AD\uC158(\uB610\uB294 \uC804\uB2EC\uB41C transactionId)\uC744 \uB864\uBC31\uD569\uB2C8\uB2E4. */\n transRollback(transactionId?: string): Promise<{ ok: boolean }> {\n const txId = transactionId ?? this.activeTxId;\n if (!txId)\n return Promise.reject(\n new Error(\"No active transaction. Call transStart() first.\"),\n );\n this.activeTxId = null;\n return this.request(\"POST\", `/v1/transaction/rollback/${txId}`);\n }\n\n /**\n * \uD65C\uC131 \uD2B8\uB79C\uC7AD\uC158(\uB610\uB294 \uC804\uB2EC\uB41C transactionId)\uC744 \uCEE4\uBC0B\uD569\uB2C8\uB2E4.\n *\n * @returns `results` \uBC30\uC5F4: commit\uB41C \uAC01 \uC791\uC5C5\uC758 `entity`, `action`, `seq`\n */\n transCommit(transactionId?: string): Promise<{\n ok: boolean;\n results: Array<{ entity: string; action: string; seq: number }>;\n }> {\n const txId = transactionId ?? this.activeTxId;\n if (!txId)\n return Promise.reject(\n new Error(\"No active transaction. Call transStart() first.\"),\n );\n this.activeTxId = null;\n return this.request(\"POST\", `/v1/transaction/commit/${txId}`);\n }\n\n // \u2500\u2500\u2500 \uC5D4\uD2F0\uD2F0 CRUD \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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 /** \uC2DC\uD000\uC2A4 ID\uB85C \uC5D4\uD2F0\uD2F0 \uB2E8\uAC74\uC744 \uC870\uD68C\uD569\uB2C8\uB2E4. */\n get<T = unknown>(\n entity: string,\n seq: number,\n opts: { skipHooks?: boolean } = {},\n ): Promise<{ ok: boolean; data: T }> {\n const q = opts.skipHooks ? \"?skipHooks=true\" : \"\";\n return this.request(\"GET\", `/v1/entity/${entity}/${seq}${q}`);\n }\n\n /** \uC870\uAC74\uC73C\uB85C \uC5D4\uD2F0\uD2F0 \uB2E8\uAC74\uC744 \uC870\uD68C\uD569\uB2C8\uB2E4. data \uCEEC\uB7FC\uC744 \uC644\uC804\uD788 \uBCF5\uD638\uD654\uD558\uC5EC \uBC18\uD658\uD569\uB2C8\uB2E4. */\n find<T = unknown>(\n entity: string,\n conditions?: Record<string, unknown>,\n opts: { skipHooks?: boolean } = {},\n ): Promise<{ ok: boolean; data: T }> {\n const q = opts.skipHooks ? \"?skipHooks=true\" : \"\";\n return this.request(\n \"POST\",\n `/v1/entity/${entity}/find${q}`,\n conditions ?? {},\n );\n }\n\n /** \uD398\uC774\uC9C0\uB124\uC774\uC158/\uC815\uB82C/\uD544\uD130 \uC870\uAC74\uC73C\uB85C \uC5D4\uD2F0\uD2F0 \uBAA9\uB85D\uC744 \uC870\uD68C\uD569\uB2C8\uB2E4. */\n list<T = unknown>(\n entity: string,\n params: EntityListParams = {},\n ): Promise<{ ok: boolean; data: EntityListResult<T> }> {\n const { conditions, fields, orderDir, orderBy, ...rest } = params;\n const queryObj: Record<string, unknown> = {\n page: 1,\n limit: 20,\n ...rest,\n };\n if (orderBy)\n queryObj.orderBy = orderDir === \"DESC\" ? `-${orderBy}` : orderBy;\n if (fields?.length) queryObj.fields = fields.join(\",\");\n return this.request(\n \"POST\",\n `/v1/entity/${entity}/list?${buildQuery(queryObj)}`,\n conditions ?? {},\n );\n }\n\n /**\n * \uC5D4\uD2F0\uD2F0 \uCD1D \uAC74\uC218\uB97C \uC870\uD68C\uD569\uB2C8\uB2E4.\n *\n * @param conditions \uD544\uD130 \uC870\uAC74 (\uC608: `{ status: \"active\" }`)\n */\n count(\n entity: string,\n conditions?: Record<string, unknown>,\n ): Promise<{ ok: boolean; count: number }> {\n return this.request(\n \"POST\",\n `/v1/entity/${entity}/count`,\n conditions ?? {},\n );\n }\n\n /**\n * \uCEE4\uC2A4\uD140 SQL\uB85C \uC5D4\uD2F0\uD2F0\uB97C \uC870\uD68C\uD569\uB2C8\uB2E4.\n *\n * SELECT \uC804\uC6A9\uC774\uBA70 \uC778\uB371\uC2A4 \uD14C\uC774\uBE14\uB9CC \uC870\uD68C \uAC00\uB2A5\uD569\uB2C8\uB2E4. JOIN \uC9C0\uC6D0.\n */\n query<T = unknown>(\n entity: string,\n req: EntityQueryRequest,\n ): Promise<{ ok: boolean; data: { items: T[]; count: number } }> {\n return this.request(\"POST\", `/v1/entity/${entity}/query`, req);\n }\n\n /** \uC5D4\uD2F0\uD2F0 \uB370\uC774\uD130\uB97C \uC0DD\uC131/\uC218\uC815(Submit)\uD569\uB2C8\uB2E4. `seq`\uAC00 \uC5C6\uC73C\uBA74 INSERT, \uC788\uC73C\uBA74 UPDATE\uC785\uB2C8\uB2E4. */\n submit(\n entity: string,\n data: Record<string, unknown>,\n opts: { transactionId?: string; skipHooks?: boolean } = {},\n ): Promise<{ ok: boolean; seq: number }> {\n const txId = opts.transactionId ?? this.activeTxId;\n const extraHeaders = txId ? { \"X-Transaction-ID\": txId } : undefined;\n const q = opts.skipHooks ? \"?skipHooks=true\" : \"\";\n return this.request(\n \"POST\",\n `/v1/entity/${entity}/submit${q}`,\n data,\n true,\n extraHeaders,\n );\n }\n\n /** \uC2DC\uD000\uC2A4 ID\uB85C \uC5D4\uD2F0\uD2F0\uB97C \uC0AD\uC81C\uD569\uB2C8\uB2E4(`hard=true`\uBA74 \uD558\uB4DC \uC0AD\uC81C, \uAE30\uBCF8\uC740 \uC18C\uD504\uD2B8 \uC0AD\uC81C). */\n delete(\n entity: string,\n seq: number,\n opts: {\n transactionId?: string;\n hard?: boolean;\n skipHooks?: boolean;\n } = {},\n ): Promise<{ ok: boolean; deleted: number }> {\n const params = new URLSearchParams();\n if (opts.hard) params.set(\"hard\", \"true\");\n if (opts.skipHooks) params.set(\"skipHooks\", \"true\");\n const q = params.size ? `?${params}` : \"\";\n const txId = opts.transactionId ?? this.activeTxId;\n const extraHeaders = txId ? { \"X-Transaction-ID\": txId } : undefined;\n return this.request(\n \"POST\",\n `/v1/entity/${entity}/delete/${seq}${q}`,\n undefined,\n true,\n extraHeaders,\n );\n }\n\n /** \uC5D4\uD2F0\uD2F0 \uB2E8\uAC74\uC758 \uBCC0\uACBD \uC774\uB825\uC744 \uC870\uD68C\uD569\uB2C8\uB2E4. */\n history<T = unknown>(\n entity: string,\n seq: number,\n params: Pick<EntityListParams, \"page\" | \"limit\"> = {},\n ): Promise<{\n ok: boolean;\n data: EntityListResult<EntityHistoryRecord<T>>;\n }> {\n return this.request(\n \"GET\",\n `/v1/entity/${entity}/history/${seq}?${buildQuery({ page: 1, limit: 50, ...params })}`,\n );\n }\n\n /** \uD2B9\uC815 \uC774\uB825 \uC2DC\uC810\uC73C\uB85C \uC5D4\uD2F0\uD2F0\uB97C \uB864\uBC31\uD569\uB2C8\uB2E4. */\n rollback(entity: string, historySeq: number): Promise<{ ok: boolean }> {\n return this.request(\n \"POST\",\n `/v1/entity/${entity}/rollback/${historySeq}`,\n );\n }\n\n // \u2500\u2500\u2500 \uD478\uC2DC \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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 /** \uD478\uC2DC \uAD00\uB828 \uC5D4\uD2F0\uD2F0\uB85C payload\uB97C \uC804\uC1A1(Submit)\uD569\uB2C8\uB2E4. */\n push(\n pushEntity: string,\n payload: Record<string, unknown>,\n opts: { transactionId?: string } = {},\n ): Promise<{ ok: boolean; seq: number }> {\n return this.submit(pushEntity, payload, opts);\n }\n\n /** \uD478\uC2DC \uB85C\uADF8 \uC5D4\uD2F0\uD2F0 \uBAA9\uB85D\uC744 \uC870\uD68C\uD569\uB2C8\uB2E4. */\n pushLogList<T = unknown>(\n params: EntityListParams = {},\n ): Promise<{ ok: boolean; data: EntityListResult<T> }> {\n return this.list<T>(\"push_log\", params);\n }\n\n /** \uACC4\uC815\uC758 \uD478\uC2DC \uB514\uBC14\uC774\uC2A4\uB97C \uB4F1\uB85D\uD569\uB2C8\uB2E4. */\n registerPushDevice(\n accountSeq: number,\n deviceId: string,\n pushToken: string,\n opts: RegisterPushDeviceOptions = {},\n ): Promise<{ ok: boolean; seq: number }> {\n const {\n platform,\n deviceType,\n browser,\n browserVersion,\n pushEnabled = true,\n transactionId,\n } = opts;\n return this.submit(\n \"account_device\",\n {\n id: deviceId,\n account_seq: accountSeq,\n push_token: pushToken,\n push_enabled: pushEnabled,\n ...(platform ? { platform } : {}),\n ...(deviceType ? { device_type: deviceType } : {}),\n ...(browser ? { browser } : {}),\n ...(browserVersion ? { browser_version: browserVersion } : {}),\n },\n { transactionId },\n );\n }\n\n /** \uB514\uBC14\uC774\uC2A4 \uB808\uCF54\uB4DC\uC758 \uD478\uC2DC \uD1A0\uD070\uC744 \uAC31\uC2E0\uD569\uB2C8\uB2E4. */\n updatePushDeviceToken(\n deviceSeq: number,\n pushToken: string,\n opts: { pushEnabled?: boolean; transactionId?: string } = {},\n ): Promise<{ ok: boolean; seq: number }> {\n const { pushEnabled = true, transactionId } = opts;\n return this.submit(\n \"account_device\",\n {\n seq: deviceSeq,\n push_token: pushToken,\n push_enabled: pushEnabled,\n },\n { transactionId },\n );\n }\n\n /** \uB514\uBC14\uC774\uC2A4\uC758 \uD478\uC2DC \uC218\uC2E0\uC744 \uBE44\uD65C\uC131\uD654\uD569\uB2C8\uB2E4. */\n disablePushDevice(\n deviceSeq: number,\n opts: { transactionId?: string } = {},\n ): Promise<{ ok: boolean; seq: number }> {\n return this.submit(\n \"account_device\",\n { seq: deviceSeq, push_enabled: false },\n { transactionId: opts.transactionId },\n );\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(this.hmacSecret, this.token);\n return parseRequestBody<T>(\n body,\n contentType,\n requireEncrypted,\n key,\n this.packetMagicLen,\n );\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 private get _reqOpts(): RequestOptions {\n return {\n baseUrl: this.baseUrl,\n token: this.token,\n apiKey: this.apiKey,\n hmacSecret: this.hmacSecret,\n packetMagicLen: this.packetMagicLen,\n encryptRequests: this.encryptRequests,\n };\n }\n\n private request<T>(\n method: string,\n path: string,\n body?: unknown,\n withAuth = true,\n extraHeaders?: Record<string, string>,\n ): Promise<T> {\n return entityRequest<T>(\n this._reqOpts,\n method,\n path,\n body,\n withAuth,\n extraHeaders,\n );\n }\n}\n", "export * from \"./types\";\nexport * from \"./EntityServerClient\";\n\nimport { EntityServerClient } from \"./EntityServerClient\";\n\nexport const entityServer = new EntityServerClient();\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["useCallback", "useEffect", "useMemo", "useRef", "useState", "readEnv", "name", "buildQuery", "params", "value", "key", "xchacha20poly1305", "sha256", "hkdf", "derivePacketKey", "hmacSecret", "token", "salt", "info", "encryptPacket", "plaintext", "key", "magicLen", "magic", "nonce", "ciphertext", "result", "decryptPacket", "buffer", "data", "parseRequestBody", "body", "contentType", "requireEncrypted", "isEncrypted", "sliced", "sha256", "hmac", "buildHmacHeaders", "method", "path", "bodyBytes", "apiKey", "hmacSecret", "timestamp", "nonce", "prefix", "payload", "signature", "b", "entityRequest", "opts", "method", "path", "body", "withAuth", "extraHeaders", "baseUrl", "token", "apiKey", "hmacSecret", "packetMagicLen", "encryptRequests", "isHmacMode", "headers", "fetchBody", "key", "derivePacketKey", "encryptPacket", "bodyBytes", "buildHmacHeaders", "res", "decryptPacket", "data", "err", "EntityServerClient", "options", "envBaseUrl", "readEnv", "envMagicLen", "token", "apiKey", "secret", "length", "refreshToken", "expiresIn", "delayMs", "result", "err", "data", "email", "password", "res", "transactionId", "txId", "entity", "seq", "opts", "q", "conditions", "params", "fields", "orderDir", "orderBy", "rest", "queryObj", "buildQuery", "req", "extraHeaders", "historySeq", "pushEntity", "payload", "accountSeq", "deviceId", "pushToken", "platform", "deviceType", "browser", "browserVersion", "pushEnabled", "deviceSeq", "body", "contentType", "requireEncrypted", "key", "derivePacketKey", "parseRequestBody", "method", "path", "withAuth", "entityRequest", "entityServer", "EntityServerClient", "useEntityServer", "options", "singleton", "tokenResolver", "baseUrl", "packetMagicLen", "token", "resumeSession", "isPending", "setIsPending", "useState", "error", "setError", "mountedRef", "useRef", "useEffect", "resumeTokenRef", "storedRefreshToken", "client", "useMemo", "c", "entityServer", "EntityServerClient", "resolvedToken", "run", "useCallback", "fn", "err", "e", "submit", "entity", "data", "opts", "del", "seq", "query", "req", "reset"]
|
|
7
7
|
}
|