@simplysm/service-client 13.0.100 → 14.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +403 -89
- package/dist/features/event-client.d.ts.map +1 -1
- package/dist/features/event-client.js +75 -67
- package/dist/features/event-client.js.map +1 -6
- package/dist/features/file-client.d.ts +3 -2
- package/dist/features/file-client.d.ts.map +1 -1
- package/dist/features/file-client.js +41 -39
- package/dist/features/file-client.js.map +1 -6
- package/dist/features/orm/orm-client-connector.js +37 -38
- package/dist/features/orm/orm-client-connector.js.map +1 -6
- package/dist/features/orm/orm-client-db-context-executor.d.ts.map +1 -1
- package/dist/features/orm/orm-client-db-context-executor.js +60 -60
- package/dist/features/orm/orm-client-db-context-executor.js.map +1 -6
- package/dist/features/orm/orm-connect-options.js +2 -1
- package/dist/features/orm/orm-connect-options.js.map +1 -6
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -1
- package/dist/index.js.map +1 -6
- package/dist/protocol/client-protocol-wrapper.d.ts +1 -0
- package/dist/protocol/client-protocol-wrapper.d.ts.map +1 -1
- package/dist/protocol/client-protocol-wrapper.js +93 -70
- package/dist/protocol/client-protocol-wrapper.js.map +1 -6
- package/dist/service-client.d.ts +5 -3
- package/dist/service-client.d.ts.map +1 -1
- package/dist/service-client.js +110 -111
- package/dist/service-client.js.map +1 -6
- package/dist/transport/service-transport.d.ts +0 -1
- package/dist/transport/service-transport.d.ts.map +1 -1
- package/dist/transport/service-transport.js +115 -104
- package/dist/transport/service-transport.js.map +1 -6
- package/dist/transport/socket-provider.d.ts.map +1 -1
- package/dist/transport/socket-provider.js +185 -155
- package/dist/transport/socket-provider.js.map +1 -6
- package/dist/types/browser-compat.d.ts +33 -0
- package/dist/types/browser-compat.d.ts.map +1 -0
- package/dist/types/browser-compat.js +17 -0
- package/dist/types/browser-compat.js.map +1 -0
- package/dist/types/connection-options.d.ts +1 -1
- package/dist/types/connection-options.d.ts.map +1 -1
- package/dist/types/connection-options.js +2 -1
- package/dist/types/connection-options.js.map +1 -6
- package/dist/types/progress.types.d.ts +1 -0
- package/dist/types/progress.types.d.ts.map +1 -1
- package/dist/types/progress.types.js +2 -1
- package/dist/types/progress.types.js.map +1 -6
- package/dist/workers/client-protocol.worker.js +38 -24
- package/dist/workers/client-protocol.worker.js.map +1 -6
- package/package.json +16 -9
- package/src/features/event-client.ts +19 -17
- package/src/features/file-client.ts +11 -10
- package/src/features/orm/orm-client-connector.ts +2 -2
- package/src/features/orm/orm-client-db-context-executor.ts +8 -7
- package/src/index.ts +6 -5
- package/src/protocol/client-protocol-wrapper.ts +37 -28
- package/src/service-client.ts +24 -20
- package/src/transport/service-transport.ts +19 -25
- package/src/transport/socket-provider.ts +44 -38
- package/src/types/browser-compat.ts +47 -0
- package/src/types/connection-options.ts +1 -1
- package/src/types/progress.types.ts +1 -0
- package/src/workers/client-protocol.worker.ts +10 -10
- package/docs/features.md +0 -143
- package/docs/protocol.md +0 -29
- package/docs/service-client.md +0 -93
- package/docs/transport.md +0 -96
- package/docs/types.md +0 -55
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cross-environment compatible types for browser globals.
|
|
3
|
+
* DOM-only 타입(FileList, BlobPart, Worker, Transferable)을 대체하여
|
|
4
|
+
* Node.js / browser 양쪽 환경에서 typecheck가 통과하도록 한다.
|
|
5
|
+
*/
|
|
6
|
+
/** Blob constructor가 허용하는 데이터 타입 (DOM BlobPart 대체) */
|
|
7
|
+
export type BlobInput = Blob | Uint8Array<ArrayBuffer> | ArrayBuffer | string;
|
|
8
|
+
/**
|
|
9
|
+
* File 컬렉션 인터페이스 (DOM FileList 대체).
|
|
10
|
+
* 브라우저 FileList와 구조적으로 호환됨.
|
|
11
|
+
*/
|
|
12
|
+
export interface FileCollection {
|
|
13
|
+
readonly length: number;
|
|
14
|
+
item(index: number): File | null;
|
|
15
|
+
[index: number]: File;
|
|
16
|
+
[Symbol.iterator](): IterableIterator<File>;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Web Worker 인터페이스 (DOM Worker 대체).
|
|
20
|
+
* 브라우저 Worker와 구조적으로 호환됨.
|
|
21
|
+
*/
|
|
22
|
+
export interface WorkerLike {
|
|
23
|
+
onmessage: ((ev: MessageEvent) => void) | null;
|
|
24
|
+
postMessage(message: unknown, transfer?: unknown[]): void;
|
|
25
|
+
terminate(): void;
|
|
26
|
+
}
|
|
27
|
+
/** Web Worker API 지원 여부 확인 */
|
|
28
|
+
export declare function isWorkerSupported(): boolean;
|
|
29
|
+
/** Web Worker 생성 (미지원 환경이면 undefined) */
|
|
30
|
+
export declare function createBrowserWorker(url: URL, options: {
|
|
31
|
+
type: string;
|
|
32
|
+
}): WorkerLike | undefined;
|
|
33
|
+
//# sourceMappingURL=browser-compat.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"browser-compat.d.ts","sourceRoot":"","sources":["..\\..\\src\\types\\browser-compat.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,sDAAsD;AACtD,MAAM,MAAM,SAAS,GAAG,IAAI,GAAG,UAAU,CAAC,WAAW,CAAC,GAAG,WAAW,GAAG,MAAM,CAAC;AAE9E;;;GAGG;AACH,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,IAAI,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAAC;IACjC,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,gBAAgB,CAAC,IAAI,CAAC,CAAC;CAC7C;AAED;;;GAGG;AACH,MAAM,WAAW,UAAU;IACzB,SAAS,EAAE,CAAC,CAAC,EAAE,EAAE,YAAY,KAAK,IAAI,CAAC,GAAG,IAAI,CAAC;IAC/C,WAAW,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,CAAC,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;IAC1D,SAAS,IAAI,IAAI,CAAC;CACnB;AAED,8BAA8B;AAC9B,wBAAgB,iBAAiB,IAAI,OAAO,CAE3C;AAED,yCAAyC;AACzC,wBAAgB,mBAAmB,CACjC,GAAG,EAAE,GAAG,EACR,OAAO,EAAE;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GACxB,UAAU,GAAG,SAAS,CAOxB"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cross-environment compatible types for browser globals.
|
|
3
|
+
* DOM-only 타입(FileList, BlobPart, Worker, Transferable)을 대체하여
|
|
4
|
+
* Node.js / browser 양쪽 환경에서 typecheck가 통과하도록 한다.
|
|
5
|
+
*/
|
|
6
|
+
/** Web Worker API 지원 여부 확인 */
|
|
7
|
+
export function isWorkerSupported() {
|
|
8
|
+
return "Worker" in globalThis;
|
|
9
|
+
}
|
|
10
|
+
/** Web Worker 생성 (미지원 환경이면 undefined) */
|
|
11
|
+
export function createBrowserWorker(url, options) {
|
|
12
|
+
if (!isWorkerSupported())
|
|
13
|
+
return undefined;
|
|
14
|
+
const ctor = globalThis["Worker"];
|
|
15
|
+
return new ctor(url, options);
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=browser-compat.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"browser-compat.js","sourceRoot":"","sources":["..\\..\\src\\types\\browser-compat.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AA0BH,8BAA8B;AAC9B,MAAM,UAAU,iBAAiB;IAC/B,OAAO,QAAQ,IAAI,UAAU,CAAC;AAChC,CAAC;AAED,yCAAyC;AACzC,MAAM,UAAU,mBAAmB,CACjC,GAAQ,EACR,OAAyB;IAEzB,IAAI,CAAC,iBAAiB,EAAE;QAAE,OAAO,SAAS,CAAC;IAC3C,MAAM,IAAI,GAAI,UAAsC,CAAC,QAAQ,CAG9C,CAAC;IAChB,OAAO,IAAI,IAAI,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;AAChC,CAAC"}
|
|
@@ -2,7 +2,7 @@ export interface ServiceConnectionOptions {
|
|
|
2
2
|
port: number;
|
|
3
3
|
host: string;
|
|
4
4
|
ssl?: boolean;
|
|
5
|
-
/**
|
|
5
|
+
/** 0으로 설정하면 재연결을 비활성화하고 즉시 연결을 끊음 */
|
|
6
6
|
maxReconnectCount?: number;
|
|
7
7
|
}
|
|
8
8
|
//# sourceMappingURL=connection-options.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"connection-options.d.ts","sourceRoot":"","sources":["..\\..\\src\\types\\connection-options.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,wBAAwB;IACvC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,
|
|
1
|
+
{"version":3,"file":"connection-options.d.ts","sourceRoot":"","sources":["..\\..\\src\\types\\connection-options.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,wBAAwB;IACvC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,qCAAqC;IACrC,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B"}
|
|
@@ -1 +1,2 @@
|
|
|
1
|
-
|
|
1
|
+
export {};
|
|
2
|
+
//# sourceMappingURL=connection-options.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"progress.types.d.ts","sourceRoot":"","sources":["..\\..\\src\\types\\progress.types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,eAAe;IAC9B,OAAO,CAAC,EAAE,CAAC,CAAC,EAAE,oBAAoB,KAAK,IAAI,CAAC;IAC5C,QAAQ,CAAC,EAAE,CAAC,CAAC,EAAE,oBAAoB,KAAK,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"progress.types.d.ts","sourceRoot":"","sources":["..\\..\\src\\types\\progress.types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,eAAe;IAC9B,OAAO,CAAC,EAAE,CAAC,CAAC,EAAE,oBAAoB,KAAK,IAAI,CAAC;IAC5C,QAAQ,CAAC,EAAE,CAAC,CAAC,EAAE,oBAAoB,KAAK,IAAI,CAAC;IAC7C,MAAM,CAAC,EAAE,CAAC,CAAC,EAAE,oBAAoB,KAAK,IAAI,CAAC;CAC5C;AAED,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;CACvB"}
|
|
@@ -1 +1,2 @@
|
|
|
1
|
-
|
|
1
|
+
export {};
|
|
2
|
+
//# sourceMappingURL=progress.types.js.map
|
|
@@ -1,30 +1,44 @@
|
|
|
1
|
+
/// <reference lib="webworker" />
|
|
1
2
|
import { createServiceProtocol } from "@simplysm/service-common";
|
|
2
3
|
import { transfer } from "@simplysm/core-common";
|
|
3
4
|
const protocol = createServiceProtocol();
|
|
4
5
|
self.onmessage = (event) => {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
6
|
+
const { id, type, data } = event.data;
|
|
7
|
+
try {
|
|
8
|
+
let result;
|
|
9
|
+
let transferList = [];
|
|
10
|
+
if (type === "encode") {
|
|
11
|
+
// [Main -> Worker] 인코딩 요청 (data: { uuid, message })
|
|
12
|
+
// message는 이미 Plain Object임 (Structured Clone을 통해 전달)
|
|
13
|
+
const { uuid, message } = data;
|
|
14
|
+
const { chunks } = protocol.encode(uuid, message);
|
|
15
|
+
// Buffer[]는 전송 가능하므로 결과로 반환
|
|
16
|
+
result = chunks;
|
|
17
|
+
// 결과 chunk의 내부 ArrayBuffer를 전송 목록에 추가
|
|
18
|
+
transferList = chunks.map((chunk) => chunk.buffer);
|
|
19
|
+
}
|
|
20
|
+
else {
|
|
21
|
+
// [Main -> Worker] 디코딩 요청 (data: Uint8Array)
|
|
22
|
+
// data는 Uint8Array로 전달됨
|
|
23
|
+
const bytes = new Uint8Array(data);
|
|
24
|
+
const decodeResult = protocol.decode(bytes);
|
|
25
|
+
// 결과 객체를 전송 가능한 형태로 변환 (zero-copy 준비)
|
|
26
|
+
const encoded = transfer.encode(decodeResult);
|
|
27
|
+
result = encoded.result;
|
|
28
|
+
transferList = encoded.transferList;
|
|
29
|
+
}
|
|
30
|
+
// [Worker -> Main] 성공 응답
|
|
31
|
+
self.postMessage({ id, type: "success", result }, transferList);
|
|
32
|
+
}
|
|
33
|
+
catch (err) {
|
|
34
|
+
// [Worker -> Main] 에러 응답
|
|
35
|
+
self.postMessage({
|
|
36
|
+
id,
|
|
37
|
+
type: "error",
|
|
38
|
+
error: err instanceof Error
|
|
39
|
+
? { message: err.message, stack: err.stack }
|
|
40
|
+
: { message: String(err) },
|
|
41
|
+
});
|
|
20
42
|
}
|
|
21
|
-
self.postMessage({ id, type: "success", result }, { transfer: transferList });
|
|
22
|
-
} catch (err) {
|
|
23
|
-
self.postMessage({
|
|
24
|
-
id,
|
|
25
|
-
type: "error",
|
|
26
|
-
error: err instanceof Error ? { message: err.message, stack: err.stack } : { message: String(err) }
|
|
27
|
-
});
|
|
28
|
-
}
|
|
29
43
|
};
|
|
30
|
-
//# sourceMappingURL=client-protocol.worker.js.map
|
|
44
|
+
//# sourceMappingURL=client-protocol.worker.js.map
|
|
@@ -1,6 +1 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../../src/workers/client-protocol.worker.ts"],
|
|
4
|
-
"mappings": "AAEA,SAAS,6BAA6B;AACtC,SAAS,gBAAgB;AAEzB,MAAM,WAAW,sBAAsB;AAEvC,KAAK,YAAY,CAAC,UAAwB;AACxC,QAAM,EAAE,IAAI,MAAM,KAAK,IAAI,MAAM;AAMjC,MAAI;AACF,QAAI;AACJ,QAAI,eAA+B,CAAC;AAEpC,QAAI,SAAS,UAAU;AAGrB,YAAM,EAAE,MAAM,QAAQ,IAAI;AAI1B,YAAM,EAAE,OAAO,IAAI,SAAS,OAAO,MAAM,OAAO;AAGhD,eAAS;AAET,qBAAe,OAAO,IAAI,CAAC,UAAU,MAAM,MAAqB;AAAA,IAClE,OAAO;AAGL,YAAM,QAAQ,IAAI,WAAW,IAAmB;AAChD,YAAM,eAAe,SAAS,OAAO,KAAK;AAG1C,YAAM,UAAU,SAAS,OAAO,YAAY;AAC5C,eAAS,QAAQ;AACjB,qBAAe,QAAQ;AAAA,IACzB;AAGA,SAAK,YAAY,EAAE,IAAI,MAAM,WAAW,OAAO,GAAG,EAAE,UAAU,aAAa,CAAC;AAAA,EAC9E,SAAS,KAAK;AAEZ,SAAK,YAAY;AAAA,MACf;AAAA,MACA,MAAM;AAAA,MACN,OACE,eAAe,QACX,EAAE,SAAS,IAAI,SAAS,OAAO,IAAI,MAAM,IACzC,EAAE,SAAS,OAAO,GAAG,EAAE;AAAA,IAC/B,CAAC;AAAA,EACH;AACF;",
|
|
5
|
-
"names": []
|
|
6
|
-
}
|
|
1
|
+
{"version":3,"file":"client-protocol.worker.js","sourceRoot":"","sources":["..\\..\\src\\workers\\client-protocol.worker.ts"],"names":[],"mappings":"AAAA,iCAAiC;AAEjC,OAAO,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AACjE,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAEjD,MAAM,QAAQ,GAAG,qBAAqB,EAAE,CAAC;AAEzC,IAAI,CAAC,SAAS,GAAG,CAAC,KAAmB,EAAE,EAAE;IACvC,MAAM,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,KAAK,CAAC,IAIhC,CAAC;IAEF,IAAI,CAAC;QACH,IAAI,MAAe,CAAC;QACpB,IAAI,YAAY,GAAmB,EAAE,CAAC;QAEtC,IAAI,IAAI,KAAK,QAAQ,EAAE,CAAC;YACtB,oDAAoD;YACpD,sDAAsD;YACtD,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,IAGzB,CAAC;YACF,MAAM,EAAE,MAAM,EAAE,GAAG,QAAQ,CAAC,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;YAElD,4BAA4B;YAC5B,MAAM,GAAG,MAAM,CAAC;YAChB,sCAAsC;YACtC,YAAY,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,MAAqB,CAAC,CAAC;QACpE,CAAC;aAAM,CAAC;YACN,6CAA6C;YAC7C,wBAAwB;YACxB,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,IAAmB,CAAC,CAAC;YAClD,MAAM,YAAY,GAAG,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YAE5C,sCAAsC;YACtC,MAAM,OAAO,GAAG,QAAQ,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC;YAC9C,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;YACxB,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC;QACtC,CAAC;QAED,yBAAyB;QACzB,IAAI,CAAC,WAAW,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,EAAE,YAAY,CAAC,CAAC;IAClE,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,yBAAyB;QACzB,IAAI,CAAC,WAAW,CAAC;YACf,EAAE;YACF,IAAI,EAAE,OAAO;YACb,KAAK,EACH,GAAG,YAAY,KAAK;gBAClB,CAAC,CAAC,EAAE,OAAO,EAAE,GAAG,CAAC,OAAO,EAAE,KAAK,EAAE,GAAG,CAAC,KAAK,EAAE;gBAC5C,CAAC,CAAC,EAAE,OAAO,EAAE,MAAM,CAAC,GAAG,CAAC,EAAE;SAC/B,CAAC,CAAC;IACL,CAAC;AACH,CAAC,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@simplysm/service-client",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "
|
|
5
|
-
"author": "
|
|
3
|
+
"version": "14.0.4",
|
|
4
|
+
"description": "심플리즘 패키지 - 서비스 (client)",
|
|
5
|
+
"author": "심플리즘",
|
|
6
6
|
"license": "Apache-2.0",
|
|
7
7
|
"repository": {
|
|
8
8
|
"type": "git",
|
|
@@ -14,18 +14,25 @@
|
|
|
14
14
|
"types": "./dist/index.d.ts",
|
|
15
15
|
"files": [
|
|
16
16
|
"dist",
|
|
17
|
-
"src"
|
|
18
|
-
"docs"
|
|
17
|
+
"src"
|
|
19
18
|
],
|
|
20
19
|
"sideEffects": false,
|
|
21
20
|
"dependencies": {
|
|
22
21
|
"consola": "^3.4.2",
|
|
23
|
-
"@simplysm/core-common": "
|
|
24
|
-
"@simplysm/orm-common": "
|
|
25
|
-
"@simplysm/service-common": "
|
|
22
|
+
"@simplysm/core-common": "14.0.4",
|
|
23
|
+
"@simplysm/orm-common": "14.0.4",
|
|
24
|
+
"@simplysm/service-common": "14.0.4"
|
|
26
25
|
},
|
|
27
26
|
"devDependencies": {
|
|
28
27
|
"@types/ws": "^8.18.1",
|
|
29
|
-
"ws": "^8.
|
|
28
|
+
"ws": "^8.20.0"
|
|
29
|
+
},
|
|
30
|
+
"peerDependencies": {
|
|
31
|
+
"ws": "^8"
|
|
32
|
+
},
|
|
33
|
+
"peerDependenciesMeta": {
|
|
34
|
+
"ws": {
|
|
35
|
+
"optional": true
|
|
36
|
+
}
|
|
30
37
|
}
|
|
31
38
|
}
|
|
@@ -38,13 +38,13 @@ export function createEventClient(transport: ServiceTransport): EventClient {
|
|
|
38
38
|
const key = Uuid.generate().toString();
|
|
39
39
|
const eventName = eventDef.eventName;
|
|
40
40
|
|
|
41
|
-
//
|
|
41
|
+
// 서버에 등록 요청 전송
|
|
42
42
|
await transport.send({
|
|
43
43
|
name: "evt:add",
|
|
44
44
|
body: { key, name: eventName, info },
|
|
45
45
|
});
|
|
46
46
|
|
|
47
|
-
//
|
|
47
|
+
// 로컬 맵에 저장 (재연결 시 복구용)
|
|
48
48
|
listenerMap.set(key, {
|
|
49
49
|
eventName,
|
|
50
50
|
info,
|
|
@@ -59,7 +59,7 @@ export function createEventClient(transport: ServiceTransport): EventClient {
|
|
|
59
59
|
try {
|
|
60
60
|
await transport.send({ name: "evt:remove", body: { key } });
|
|
61
61
|
} catch {
|
|
62
|
-
//
|
|
62
|
+
// 서버가 연결 끊김 시 이벤트 리스너를 자동 정리하므로 무시해도 안전함
|
|
63
63
|
}
|
|
64
64
|
}
|
|
65
65
|
|
|
@@ -70,7 +70,7 @@ export function createEventClient(transport: ServiceTransport): EventClient {
|
|
|
70
70
|
): Promise<void> {
|
|
71
71
|
const eventName = eventDef.eventName;
|
|
72
72
|
|
|
73
|
-
//
|
|
73
|
+
// 서버에 'gets' 요청을 보내 대상 목록 조회
|
|
74
74
|
const listenerInfos = (await transport.send({
|
|
75
75
|
name: "evt:gets",
|
|
76
76
|
body: { name: eventName },
|
|
@@ -88,21 +88,23 @@ export function createEventClient(transport: ServiceTransport): EventClient {
|
|
|
88
88
|
}
|
|
89
89
|
}
|
|
90
90
|
|
|
91
|
-
//
|
|
91
|
+
// 재연결 시 호출
|
|
92
92
|
async function resubscribeAll(): Promise<void> {
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
93
|
+
await Promise.allSettled(
|
|
94
|
+
Array.from(listenerMap.entries()).map(async ([key, value]) => {
|
|
95
|
+
try {
|
|
96
|
+
await transport.send({
|
|
97
|
+
name: "evt:add",
|
|
98
|
+
body: { key, name: value.eventName, info: value.info },
|
|
99
|
+
});
|
|
100
|
+
} catch (err) {
|
|
101
|
+
logger.error("이벤트 리스너 복구 실패", { err, eventName: value.eventName });
|
|
102
|
+
}
|
|
103
|
+
}),
|
|
104
|
+
);
|
|
103
105
|
}
|
|
104
106
|
|
|
105
|
-
//
|
|
107
|
+
// 서버 이벤트를 로컬 리스너에 디스패치
|
|
106
108
|
async function executeByKey(keys: string[], data: unknown): Promise<void> {
|
|
107
109
|
for (const key of keys) {
|
|
108
110
|
const entry = listenerMap.get(key);
|
|
@@ -110,7 +112,7 @@ export function createEventClient(transport: ServiceTransport): EventClient {
|
|
|
110
112
|
try {
|
|
111
113
|
await entry.cb(data);
|
|
112
114
|
} catch (err) {
|
|
113
|
-
logger.error("
|
|
115
|
+
logger.error("이벤트 핸들러 에러", { err, eventName: entry.eventName });
|
|
114
116
|
}
|
|
115
117
|
}
|
|
116
118
|
}
|
|
@@ -1,22 +1,23 @@
|
|
|
1
1
|
import type { Bytes } from "@simplysm/core-common";
|
|
2
2
|
import type { ServiceUploadResult } from "@simplysm/service-common";
|
|
3
|
+
import type { BlobInput, FileCollection } from "../types/browser-compat";
|
|
3
4
|
|
|
4
5
|
export interface FileClient {
|
|
5
6
|
download(relPath: string): Promise<Bytes>;
|
|
6
7
|
upload(
|
|
7
|
-
files: File[] |
|
|
8
|
+
files: File[] | FileCollection | { name: string; data: BlobInput }[],
|
|
8
9
|
authToken: string,
|
|
9
10
|
): Promise<ServiceUploadResult[]>;
|
|
10
11
|
}
|
|
11
12
|
|
|
12
13
|
export function createFileClient(hostUrl: string, clientName: string): FileClient {
|
|
13
14
|
async function download(relPath: string): Promise<Bytes> {
|
|
14
|
-
//
|
|
15
|
+
// URL 생성
|
|
15
16
|
const url = `${hostUrl}${relPath.startsWith("/") ? "" : "/"}${relPath}`;
|
|
16
17
|
|
|
17
18
|
const res = await fetch(url);
|
|
18
19
|
if (!res.ok) {
|
|
19
|
-
throw new Error(
|
|
20
|
+
throw new Error(`다운로드 실패: ${res.status} ${res.statusText}`);
|
|
20
21
|
}
|
|
21
22
|
|
|
22
23
|
// ArrayBuffer -> Uint8Array
|
|
@@ -24,19 +25,19 @@ export function createFileClient(hostUrl: string, clientName: string): FileClien
|
|
|
24
25
|
}
|
|
25
26
|
|
|
26
27
|
async function upload(
|
|
27
|
-
files: File[] |
|
|
28
|
+
files: File[] | FileCollection | { name: string; data: BlobInput }[],
|
|
28
29
|
authToken: string,
|
|
29
30
|
): Promise<ServiceUploadResult[]> {
|
|
30
31
|
const formData = new FormData();
|
|
31
|
-
const
|
|
32
|
+
const fileArr = Array.isArray(files) ? files : Array.from(files);
|
|
32
33
|
|
|
33
|
-
for (const file of
|
|
34
|
+
for (const file of fileArr) {
|
|
34
35
|
if ("data" in file) {
|
|
35
|
-
//
|
|
36
|
+
// 커스텀 객체 ({ name, data })
|
|
36
37
|
const blob = file.data instanceof Blob ? file.data : new Blob([file.data]);
|
|
37
38
|
formData.append("files", blob, file.name);
|
|
38
39
|
} else {
|
|
39
|
-
//
|
|
40
|
+
// 브라우저 File 객체
|
|
40
41
|
formData.append("files", file, file.name);
|
|
41
42
|
}
|
|
42
43
|
}
|
|
@@ -51,10 +52,10 @@ export function createFileClient(hostUrl: string, clientName: string): FileClien
|
|
|
51
52
|
});
|
|
52
53
|
|
|
53
54
|
if (!res.ok) {
|
|
54
|
-
throw new Error(
|
|
55
|
+
throw new Error(`업로드 실패: ${res.statusText}`);
|
|
55
56
|
}
|
|
56
57
|
|
|
57
|
-
return res.json();
|
|
58
|
+
return (await res.json()) as ServiceUploadResult[];
|
|
58
59
|
}
|
|
59
60
|
|
|
60
61
|
return {
|
|
@@ -22,7 +22,7 @@ export function createOrmClientConnector(serviceClient: ServiceClient): OrmClien
|
|
|
22
22
|
const info = await executor.getInfo();
|
|
23
23
|
const database = config.dbContextOpt?.database ?? info.database;
|
|
24
24
|
if (database == null || database === "") {
|
|
25
|
-
throw new Error("database
|
|
25
|
+
throw new Error("database는 필수입니다.");
|
|
26
26
|
}
|
|
27
27
|
return createDbContext(config.dbContextDef, executor, {
|
|
28
28
|
database,
|
|
@@ -44,7 +44,7 @@ export function createOrmClientConnector(serviceClient: ServiceClient): OrmClien
|
|
|
44
44
|
(err.message.includes("a parent row: a foreign key constraint") ||
|
|
45
45
|
err.message.includes("conflicted with the REFERENCE"))
|
|
46
46
|
) {
|
|
47
|
-
throw new Error("
|
|
47
|
+
throw new Error("경고! 연관된 작업으로 인해 작업이 거부되었습니다. 후속 작업을 확인해 주세요.", { cause: err });
|
|
48
48
|
}
|
|
49
49
|
|
|
50
50
|
throw err;
|
|
@@ -34,7 +34,7 @@ export class OrmClientDbContextExecutor implements DbContextExecutor {
|
|
|
34
34
|
|
|
35
35
|
async beginTransaction(isolationLevel?: IsolationLevel): Promise<void> {
|
|
36
36
|
if (this._connId === undefined) {
|
|
37
|
-
throw new Error("
|
|
37
|
+
throw new Error("데이터베이스에 연결되지 않았습니다.");
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
await this._ormService.beginTransaction(this._connId, isolationLevel);
|
|
@@ -42,7 +42,7 @@ export class OrmClientDbContextExecutor implements DbContextExecutor {
|
|
|
42
42
|
|
|
43
43
|
async commitTransaction(): Promise<void> {
|
|
44
44
|
if (this._connId === undefined) {
|
|
45
|
-
throw new Error("
|
|
45
|
+
throw new Error("데이터베이스에 연결되지 않았습니다.");
|
|
46
46
|
}
|
|
47
47
|
|
|
48
48
|
await this._ormService.commitTransaction(this._connId);
|
|
@@ -50,7 +50,7 @@ export class OrmClientDbContextExecutor implements DbContextExecutor {
|
|
|
50
50
|
|
|
51
51
|
async rollbackTransaction(): Promise<void> {
|
|
52
52
|
if (this._connId === undefined) {
|
|
53
|
-
throw new Error("
|
|
53
|
+
throw new Error("데이터베이스에 연결되지 않았습니다.");
|
|
54
54
|
}
|
|
55
55
|
|
|
56
56
|
await this._ormService.rollbackTransaction(this._connId);
|
|
@@ -58,10 +58,11 @@ export class OrmClientDbContextExecutor implements DbContextExecutor {
|
|
|
58
58
|
|
|
59
59
|
async close(): Promise<void> {
|
|
60
60
|
if (this._connId === undefined) {
|
|
61
|
-
throw new Error("
|
|
61
|
+
throw new Error("데이터베이스에 연결되지 않았습니다.");
|
|
62
62
|
}
|
|
63
63
|
|
|
64
64
|
await this._ormService.close(this._connId);
|
|
65
|
+
this._connId = undefined;
|
|
65
66
|
}
|
|
66
67
|
|
|
67
68
|
async executeDefs<T = Record<string, unknown>>(
|
|
@@ -69,7 +70,7 @@ export class OrmClientDbContextExecutor implements DbContextExecutor {
|
|
|
69
70
|
options?: (ResultMeta | undefined)[],
|
|
70
71
|
): Promise<T[][]> {
|
|
71
72
|
if (this._connId === undefined) {
|
|
72
|
-
throw new Error("
|
|
73
|
+
throw new Error("데이터베이스에 연결되지 않았습니다.");
|
|
73
74
|
}
|
|
74
75
|
|
|
75
76
|
return (await this._ormService.executeDefs(this._connId, defs, options)) as T[][];
|
|
@@ -77,7 +78,7 @@ export class OrmClientDbContextExecutor implements DbContextExecutor {
|
|
|
77
78
|
|
|
78
79
|
async executeParametrized(query: string, params?: unknown[]): Promise<unknown[][]> {
|
|
79
80
|
if (this._connId === undefined) {
|
|
80
|
-
throw new Error("
|
|
81
|
+
throw new Error("데이터베이스에 연결되지 않았습니다.");
|
|
81
82
|
}
|
|
82
83
|
|
|
83
84
|
return this._ormService.executeParametrized(this._connId, query, params);
|
|
@@ -89,7 +90,7 @@ export class OrmClientDbContextExecutor implements DbContextExecutor {
|
|
|
89
90
|
records: Record<string, unknown>[],
|
|
90
91
|
): Promise<void> {
|
|
91
92
|
if (this._connId === undefined) {
|
|
92
|
-
throw new Error("
|
|
93
|
+
throw new Error("데이터베이스에 연결되지 않았습니다.");
|
|
93
94
|
}
|
|
94
95
|
|
|
95
96
|
return this._ormService.bulkInsert(this._connId, tableName, columnDefs, records);
|
package/src/index.ts
CHANGED
|
@@ -1,20 +1,21 @@
|
|
|
1
|
-
//
|
|
1
|
+
// 타입
|
|
2
|
+
export * from "./types/browser-compat";
|
|
2
3
|
export * from "./types/connection-options";
|
|
3
4
|
export * from "./types/progress.types";
|
|
4
5
|
|
|
5
|
-
//
|
|
6
|
+
// 전송 계층
|
|
6
7
|
export * from "./transport/socket-provider";
|
|
7
8
|
export * from "./transport/service-transport";
|
|
8
9
|
|
|
9
|
-
//
|
|
10
|
+
// 프로토콜
|
|
10
11
|
export * from "./protocol/client-protocol-wrapper";
|
|
11
12
|
|
|
12
|
-
//
|
|
13
|
+
// 기능
|
|
13
14
|
export * from "./features/event-client";
|
|
14
15
|
export * from "./features/file-client";
|
|
15
16
|
export * from "./features/orm/orm-connect-options";
|
|
16
17
|
export * from "./features/orm/orm-client-connector";
|
|
17
18
|
export * from "./features/orm/orm-client-db-context-executor";
|
|
18
19
|
|
|
19
|
-
//
|
|
20
|
+
// 메인
|
|
20
21
|
export * from "./service-client";
|