@simplysm/sd-claude 14.0.88 → 14.0.90
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/claude/references/sd-simplysm14/README.md +16 -17
- package/claude/references/sd-simplysm14/apis/angular/README.md +39 -43
- package/claude/references/sd-simplysm14/apis/angular/controls.md +174 -80
- package/claude/references/sd-simplysm14/apis/angular/crud.md +41 -50
- package/claude/references/sd-simplysm14/apis/angular/directives.md +60 -26
- package/claude/references/sd-simplysm14/apis/angular/features.md +109 -37
- package/claude/references/sd-simplysm14/apis/angular/infra.md +61 -44
- package/claude/references/sd-simplysm14/apis/angular/layout.md +39 -31
- package/claude/references/sd-simplysm14/apis/angular/overlay.md +73 -85
- package/claude/references/sd-simplysm14/apis/angular/routing-appstructure.md +54 -39
- package/claude/references/sd-simplysm14/apis/angular/selection-managers.md +55 -30
- package/claude/references/sd-simplysm14/apis/angular/shared-data.md +71 -67
- package/claude/references/sd-simplysm14/apis/angular/sheet.md +82 -72
- package/claude/references/sd-simplysm14/apis/capacitor-plugin-auto-update/README.md +35 -36
- package/claude/references/sd-simplysm14/apis/capacitor-plugin-file-system/README.md +71 -43
- package/claude/references/sd-simplysm14/apis/capacitor-plugin-intent/README.md +38 -30
- package/claude/references/sd-simplysm14/apis/capacitor-plugin-usb-storage/README.md +45 -50
- package/claude/references/sd-simplysm14/apis/core-browser/README.md +42 -55
- package/claude/references/sd-simplysm14/apis/core-browser/dom-element.md +62 -0
- package/claude/references/sd-simplysm14/apis/core-browser/indexed-db.md +39 -38
- package/claude/references/sd-simplysm14/apis/core-common/README.md +95 -103
- package/claude/references/sd-simplysm14/apis/core-common/array-ext.md +59 -54
- package/claude/references/sd-simplysm14/apis/core-common/async-runtime.md +86 -0
- package/claude/references/sd-simplysm14/apis/core-common/datetime.md +57 -66
- package/claude/references/sd-simplysm14/apis/core-common/errors.md +86 -0
- package/claude/references/sd-simplysm14/apis/core-common/obj.md +60 -42
- package/claude/references/sd-simplysm14/apis/core-common/serialization.md +55 -0
- package/claude/references/sd-simplysm14/apis/core-node/README.md +10 -8
- package/claude/references/sd-simplysm14/apis/core-node/consola.md +29 -32
- package/claude/references/sd-simplysm14/apis/core-node/cpx.md +34 -22
- package/claude/references/sd-simplysm14/apis/core-node/fs-watcher.md +29 -25
- package/claude/references/sd-simplysm14/apis/core-node/fsx.md +40 -53
- package/claude/references/sd-simplysm14/apis/core-node/pathx.md +22 -29
- package/claude/references/sd-simplysm14/apis/core-node/worker.md +31 -31
- package/claude/references/sd-simplysm14/apis/excel/README.md +26 -26
- package/claude/references/sd-simplysm14/apis/excel/cell.md +37 -29
- package/claude/references/sd-simplysm14/apis/excel/conditional-format.md +29 -15
- package/claude/references/sd-simplysm14/apis/excel/style.md +33 -27
- package/claude/references/sd-simplysm14/apis/excel/utils.md +29 -19
- package/claude/references/sd-simplysm14/apis/excel/workbook-worksheet.md +78 -55
- package/claude/references/sd-simplysm14/apis/excel/wrapper.md +42 -45
- package/claude/references/sd-simplysm14/apis/lint/README.md +27 -21
- package/claude/references/sd-simplysm14/apis/lint/rules.md +89 -49
- package/claude/references/sd-simplysm14/apis/orm-common/README.md +6 -62
- package/claude/references/sd-simplysm14/apis/orm-common/db-context.md +149 -67
- package/claude/references/sd-simplysm14/apis/orm-common/expr.md +111 -99
- package/claude/references/sd-simplysm14/apis/orm-common/queryable.md +115 -72
- package/claude/references/sd-simplysm14/apis/orm-common/schema.md +134 -92
- package/claude/references/sd-simplysm14/apis/orm-common/types.md +67 -52
- package/claude/references/sd-simplysm14/apis/orm-node/README.md +63 -26
- package/claude/references/sd-simplysm14/apis/orm-node/db-conn.md +51 -40
- package/claude/references/sd-simplysm14/apis/sd-cli/README.md +10 -12
- package/claude/references/sd-simplysm14/apis/sd-cli/SdTsCompiler.md +92 -45
- package/claude/references/sd-simplysm14/apis/sd-cli/sd-config-types.md +226 -108
- package/claude/references/sd-simplysm14/apis/service-client/README.md +90 -88
- package/claude/references/sd-simplysm14/apis/service-client/orm.md +37 -29
- package/claude/references/sd-simplysm14/apis/service-client/transport.md +45 -20
- package/claude/references/sd-simplysm14/apis/service-common/README.md +89 -40
- package/claude/references/sd-simplysm14/apis/service-common/app-structure.md +126 -34
- package/claude/references/sd-simplysm14/apis/service-common/protocol.md +109 -54
- package/claude/references/sd-simplysm14/apis/service-server/README.md +70 -66
- package/claude/references/sd-simplysm14/apis/service-server/service-authoring.md +47 -47
- package/claude/references/sd-simplysm14/apis/service-server/transport-internals.md +71 -34
- package/claude/references/sd-simplysm14/apis/service-server/v1-legacy.md +31 -32
- package/claude/references/sd-simplysm14/apis/storage/README.md +34 -28
- package/claude/references/sd-simplysm14/manuals/client-app-structure.md +142 -140
- package/claude/references/sd-simplysm14/manuals/client-orm.md +1 -1
- package/claude/references/sd-simplysm14/manuals/client-service.md +19 -7
- package/claude/references/sd-simplysm14/manuals/client-shared-data.md +2 -2
- package/claude/references/sd-simplysm14/manuals/client-system-log.md +11 -3
- package/claude/references/sd-simplysm14/manuals/data-log.md +0 -1
- package/claude/references/sd-simplysm14/manuals/orm.md +16 -0
- package/claude/rules/sd-design-rules.md +10 -0
- package/claude/skills/sd-docs/SKILL.md +58 -46
- package/claude/skills/sd-docs/references/{doc-rules.md → subagent-prompt.md} +103 -103
- package/claude/skills/sd-impl/SKILL.md +1 -1
- package/claude/skills/sd-spec/SKILL.md +858 -858
- package/claude/skills/sd-spec/references/example-spec.md +26 -36
- package/package.json +1 -1
- package/claude/references/sd-simplysm14/apis/core-common/json-transfer.md +0 -47
- package/claude/references/sd-simplysm14/apis/orm-common/query-builder.md +0 -29
- package/claude/skills/sd-demo/evals/fixtures/inventory-list/.specs/inventory/spec.md +0 -99
- package/claude/skills/sd-demo/evals/fixtures/inventory-list/packages/demo-client/package.json +0 -12
- package/claude/skills/sd-demo/evals/fixtures/inventory-list/packages/demo-client/src/index.ts +0 -3
- package/claude/skills/sd-demo/evals/fixtures/inventory-list/packages/demo-client/src/screens/inbound/inbound.list.ts +0 -150
- package/claude/skills/sd-demo/evals/fixtures/inventory-list/packages/demo-client/src/screens/inventory/inventory-master.list.ts +0 -143
- package/claude/skills/sd-demo/evals/fixtures/inventory-list/packages/demo-client/src/screens/outbound/outbound.list.ts +0 -150
- package/claude/skills/sd-demo/evals/fixtures/inventory-list/pnpm-workspace.yaml +0 -2
- package/claude/skills/sd-demo/evals/fixtures/inventory-list/sd.config.ts +0 -12
- package/claude/skills/sd-demo/evals/golden.jsonl +0 -1
- package/claude/skills/sd-dev/evals/fixtures/minimal-ts-pkg/package.json +0 -8
- package/claude/skills/sd-dev/evals/fixtures/minimal-ts-pkg/src/.gitkeep +0 -0
- package/claude/skills/sd-dev/evals/fixtures/minimal-ts-pkg/tests/.gitkeep +0 -0
- package/claude/skills/sd-dev/evals/fixtures/minimal-ts-pkg/tsconfig.json +0 -10
- package/claude/skills/sd-dev/evals/golden.jsonl +0 -1
- package/claude/skills/sd-docs/evals/fixtures/new-write/.claude/references/sd-simplysm14/README.md +0 -7
- package/claude/skills/sd-docs/evals/fixtures/new-write/packages/bar/package.json +0 -5
- package/claude/skills/sd-docs/evals/fixtures/new-write/packages/bar/src/index.ts +0 -3
- package/claude/skills/sd-docs/evals/fixtures/new-write/packages/baz/package.json +0 -6
- package/claude/skills/sd-docs/evals/fixtures/new-write/packages/baz/src/index.ts +0 -1
- package/claude/skills/sd-docs/evals/fixtures/new-write/packages/foo/package.json +0 -5
- package/claude/skills/sd-docs/evals/fixtures/new-write/packages/foo/src/index.ts +0 -8
- package/claude/skills/sd-docs/evals/fixtures/update-mixed/.claude/references/sd-simplysm14/README.md +0 -7
- package/claude/skills/sd-docs/evals/fixtures/update-mixed/.claude/references/sd-simplysm14/apis/foo/README.md +0 -3
- package/claude/skills/sd-docs/evals/fixtures/update-mixed/packages/bar/package.json +0 -5
- package/claude/skills/sd-docs/evals/fixtures/update-mixed/packages/bar/src/index.ts +0 -3
- package/claude/skills/sd-docs/evals/fixtures/update-mixed/packages/baz/package.json +0 -6
- package/claude/skills/sd-docs/evals/fixtures/update-mixed/packages/baz/src/index.ts +0 -1
- package/claude/skills/sd-docs/evals/fixtures/update-mixed/packages/foo/package.json +0 -5
- package/claude/skills/sd-docs/evals/fixtures/update-mixed/packages/foo/src/index.ts +0 -8
- package/claude/skills/sd-docs/evals/golden.jsonl +0 -2
- package/claude/skills/sd-impl/evals/fixtures/case-a-new-screen/.specs/260513120000_warehouse/spec.md +0 -101
- package/claude/skills/sd-impl/evals/fixtures/case-b-update-with-demo/.specs/260513120000_warehouse/spec.md +0 -101
- package/claude/skills/sd-impl/evals/fixtures/case-b-update-with-demo/packages/app/src/screens/box-register/box-register.view.ts +0 -46
- package/claude/skills/sd-impl/evals/fixtures/case-c-new-cross/.specs/260513120000_warehouse/spec.md +0 -89
- package/claude/skills/sd-impl/evals/fixtures/case-d-spec-modify/.specs/260513120000_warehouse/spec.md +0 -101
- package/claude/skills/sd-impl/evals/golden.jsonl +0 -4
- package/claude/skills/sd-manual/evals/fixtures/new-manual/src/notification.ts +0 -25
- package/claude/skills/sd-manual/evals/fixtures/update-manual/.claude/references/sd-simplysm14/manuals/notification.md +0 -14
- package/claude/skills/sd-manual/evals/fixtures/update-manual/src/notification.ts +0 -37
- package/claude/skills/sd-manual/evals/golden.jsonl +0 -2
- package/claude/skills/sd-review/evals/fixtures/code-review/src/foo.ts +0 -7
- package/claude/skills/sd-review/evals/fixtures/doc-review/docs/foo.md +0 -4
- package/claude/skills/sd-review/evals/golden.jsonl +0 -2
- package/claude/skills/sd-skill/evals/fixtures/existing-skill/.claude/skills/todo-format/SKILL.md +0 -14
- package/claude/skills/sd-skill/evals/fixtures/new-skill/.gitkeep +0 -0
- package/claude/skills/sd-skill/evals/golden.jsonl +0 -2
- package/claude/skills/sd-spec/evals/fixtures/case-a-split//355/232/214/354/235/230/353/241/235.md +0 -20
- package/claude/skills/sd-spec/evals/fixtures/case-b-detail/.specs/260513120000_warehouse/spec.md +0 -95
- package/claude/skills/sd-spec/evals/golden.jsonl +0 -2
- package/claude/skills/sd-unpack/evals/fixtures/eml-with-text-attachment/meeting.eml +0 -21
- package/claude/skills/sd-unpack/evals/fixtures/simple-eml/meeting.eml +0 -10
- package/claude/skills/sd-unpack/evals/golden.jsonl +0 -2
- package/claude/skills/sd-use/evals/fixtures/empty/.gitkeep +0 -0
- package/claude/skills/sd-use/evals/golden.jsonl +0 -6
|
@@ -1,122 +1,120 @@
|
|
|
1
1
|
# @simplysm/service-client
|
|
2
2
|
|
|
3
|
-
WebSocket
|
|
3
|
+
WebSocket 으로 서비스 서버(`@simplysm/service-server`)에 접속해 서비스 메서드 RPC 호출·서버 푸시 이벤트 구독/발행·파일 업/다운로드·서버측 ORM 원격 실행을 수행하는 클라이언트. 브라우저(DOM Worker)와 Node.js(글로벌 `WebSocket` 없으면 `ws` 로 polyfill, `worker_threads`) 양쪽에서 동작.
|
|
4
4
|
|
|
5
5
|
## 사용 트리거 인덱스
|
|
6
6
|
|
|
7
|
-
- **createServiceClient / ServiceClient** — 서버
|
|
8
|
-
- **ServiceConnectionOptions** — 클라이언트 생성 시
|
|
9
|
-
- **getService / ServiceProxy** — 서버 서비스 인터페이스를 타입 안전 프록시로 호출할 때.
|
|
10
|
-
- **이벤트
|
|
11
|
-
- **파일
|
|
12
|
-
- **진행률
|
|
13
|
-
- **환경 호환
|
|
14
|
-
- **ORM 원격
|
|
15
|
-
- **저수준 전송
|
|
7
|
+
- **createServiceClient / ServiceClient** — 서버 접속, 서비스 호출, 인증, 연결 상태 추적이 필요할 때. 이 패키지의 주 진입점. (아래 인라인 섹션)
|
|
8
|
+
- **ServiceConnectionOptions** — 클라이언트 생성 시 접속 대상(host/port/ssl)·재연결 정책을 정할 때. (아래 인라인 섹션)
|
|
9
|
+
- **getService / ServiceProxy** — 서버 서비스 인터페이스를 타입 안전 프록시로 호출할 때. (아래 인라인 섹션)
|
|
10
|
+
- **이벤트 구독·발행 (addListener / removeListener / emitEvent / getEvent / ClientEventProxy / EventClient)** — 서버 푸시 이벤트를 구독·발행할 때. (아래 인라인 섹션)
|
|
11
|
+
- **파일 업/다운로드 (uploadFile / downloadFileBuffer / FileClient)** — 인증된 파일 업로드, 서버 상대경로 파일 다운로드 시. (아래 인라인 섹션)
|
|
12
|
+
- **진행률 (ServiceProgress / ServiceProgressState)** — 대용량 요청·응답의 청크 전송 진행률을 추적할 때. (아래 인라인 섹션)
|
|
13
|
+
- **환경 호환 타입·헬퍼 (BlobInput / FileCollection / BrowserWorker / isWorkerSupported 등)** — Node/browser 공용 코드에서 DOM 전용 타입 회피, Worker 지원 분기 시. (아래 인라인 섹션)
|
|
14
|
+
- **ORM 원격 실행 (createOrmClientConnector / OrmClientConnector / OrmConnectOptions / OrmClientDbContextExecutor)** — 서버측 ORM DbContext 를 클라이언트에서 트랜잭션 단위로 실행할 때. 자세히: [orm.md](./orm.md)
|
|
15
|
+
- **저수준 전송 계층 (SocketProvider / ServiceTransport / ClientProtocolWrapper 및 create\*)** — 일반적으로 직접 쓰지 않음. `ServiceClient` 가 내부에서 조립. 소켓·하트비트·프로토콜·청크 동작을 이해해야 할 때. 자세히: [transport.md](./transport.md)
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
> 앱(Angular) 레이어에서는 `ServiceClient` 를 화면에서 직접 만들지 않고 `AppServiceProvider`(root provider) 의 `client` getter 를 경유해 서비스·이벤트·ORM 진입점을 모은다. 아래 예시는 client 직접 호출 형태로 보여주지만, 실제 앱 코드는 manuals/client-service.md·client-orm.md 의 provider 패턴을 따른다.
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
## 메인 클라이언트 (createServiceClient / ServiceClient)
|
|
20
20
|
|
|
21
|
-
|
|
22
|
-
const client: ServiceClient = createServiceClient(name, options);
|
|
23
|
-
```
|
|
24
|
-
|
|
25
|
-
- `createServiceClient(name: string, options: ServiceConnectionOptions): ServiceClient` — 클라이언트 인스턴스 생성. `new ServiceClient(...)` 와 동일.
|
|
26
|
-
- `name: string` (생성자, readonly) — 클라이언트 식별 이름. WebSocket 접속 쿼리의 `clientName`, 파일 업로드 헤더 `x-sd-client-name` 으로 전송.
|
|
27
|
-
- `options: ServiceConnectionOptions` (생성자, readonly) — 접속 옵션. 아래 ServiceConnectionOptions 참조.
|
|
28
|
-
|
|
29
|
-
상태 접근자:
|
|
21
|
+
`createServiceClient(name, options): ServiceClient` — 클라이언트 인스턴스 생성. `new ServiceClient(name, options)` 와 동일.
|
|
30
22
|
|
|
31
|
-
-
|
|
32
|
-
-
|
|
23
|
+
- name: string — 클라이언트 식별 이름. WebSocket 접속 쿼리의 `clientName`·파일 업로드 헤더 `x-sd-client-name` 으로 서버에 전달. 서버 로그·연결 구분에 사용.
|
|
24
|
+
- options: ServiceConnectionOptions — 접속 대상·재연결 정책 (아래 섹션).
|
|
33
25
|
|
|
34
|
-
|
|
26
|
+
`ServiceClient` 는 `EventEmitter<ServiceClientEvents>` 를 상속하며 다음을 노출:
|
|
35
27
|
|
|
36
|
-
-
|
|
37
|
-
-
|
|
38
|
-
-
|
|
39
|
-
-
|
|
40
|
-
-
|
|
41
|
-
-
|
|
42
|
-
-
|
|
28
|
+
- name: string (readonly) — 생성 시 받은 클라이언트 이름.
|
|
29
|
+
- options: ServiceConnectionOptions (readonly) — 생성 시 받은 접속 옵션.
|
|
30
|
+
- connected: boolean (getter) — 현재 WebSocket 이 OPEN 상태인지. 재연결 중·종료 시 false. 이벤트 등록 가능 여부 판단에 사용 (`addListener` 는 false 면 throw).
|
|
31
|
+
- hostUrl: string (getter) — `http(s)://host:port` 형태의 HTTP 베이스 URL. `ssl` 이 true 면 https. 파일 업/다운로드가 이 URL 을 베이스로 사용.
|
|
32
|
+
- connect(): Promise\<void\> — 서버에 WebSocket 연결. 초기 연결 실패 시 throw. 통신(서비스 호출·이벤트 등록) 전에 반드시 1회 호출.
|
|
33
|
+
- close(): Promise\<void\> — 연결 수동 종료(이후 자동 재연결 안 함) 및 프로토콜 워커 자원 해제. 종료한 인스턴스는 재사용하지 말 것.
|
|
34
|
+
- send(serviceName, methodName, params, progress?): Promise\<unknown\> — 저수준 서비스 호출. `serviceName.methodName` 메시지를 보내고 응답 반환. 보통 `getService` 프록시로 간접 호출. progress 인자를 주지 않아도 client 의 `request/response/server-progress` 이벤트는 항상 발생.
|
|
35
|
+
- auth(token): Promise\<void\> — 인증 토큰 전송 후 내부 보관. 보관 토큰은 재연결 시 자동 재인증·파일 업로드 Bearer 인증에 재사용.
|
|
36
|
+
- getService / getEvent / addListener / removeListener / emitEvent / uploadFile / downloadFileBuffer — 아래 각 섹션 참조.
|
|
43
37
|
|
|
44
38
|
```ts
|
|
45
39
|
const client = createServiceClient("my-app", { host: "localhost", port: 50080, ssl: false });
|
|
46
40
|
await client.connect();
|
|
47
41
|
await client.auth(jwtToken);
|
|
48
|
-
client.on("state", (state) => console.log(state)); // "connected" | "closed" | "reconnecting"
|
|
49
42
|
```
|
|
50
43
|
|
|
51
|
-
ServiceClientEvents (EventEmitter 이벤트):
|
|
44
|
+
**ServiceClientEvents** (EventEmitter 이벤트):
|
|
52
45
|
|
|
53
|
-
-
|
|
54
|
-
-
|
|
55
|
-
-
|
|
56
|
-
-
|
|
46
|
+
- "request-progress": ServiceProgressState — 요청(업로드) 청크 진행률. 요청 본문이 청크 2개 이상으로 분할될 때만 발생.
|
|
47
|
+
- "response-progress": ServiceProgressState — 응답(다운로드) 청크 수신 진행률. 분할 응답 완료 시 100% 한 번 더 보고.
|
|
48
|
+
- "server-progress": ServiceProgressState — 서버가 처리 중 직접 보고하는 진행률(서버측 `progress` 메시지 수신 시).
|
|
49
|
+
- "state": "connected" | "closed" | "reconnecting" — 연결 상태 변화. "connected" = 연결/재연결 성공(이 전이 시 보관 토큰으로 자동 재인증 + 이벤트 리스너 자동 복구), "closed" = 정상 종료 또는 재연결 한도 초과, "reconnecting" = 재연결 시도 중. 오프라인 배너 토글 등에 사용.
|
|
50
|
+
|
|
51
|
+
```ts
|
|
52
|
+
client.on("state", (s) => { if (s === "reconnecting") showOfflineBanner(); });
|
|
53
|
+
```
|
|
57
54
|
|
|
58
55
|
## ServiceConnectionOptions
|
|
59
56
|
|
|
60
57
|
`createServiceClient` 의 두 번째 인자.
|
|
61
58
|
|
|
62
|
-
-
|
|
63
|
-
-
|
|
64
|
-
-
|
|
65
|
-
-
|
|
59
|
+
- port: number — 서버 포트. 필수.
|
|
60
|
+
- host: string — 서버 호스트. 필수.
|
|
61
|
+
- ssl?: boolean — TLS 사용 여부. true 면 `wss`/`https`, false·미지정이면 `ws`/`http`. TLS 서버에 붙을 때만 true.
|
|
62
|
+
- maxReconnectCount?: number — 연결 끊김 시 최대 재연결 시도 횟수. 미지정 시 10. 0 이면 재연결 비활성화(끊기면 즉시 포기). 테스트·단발성 연결이면 0.
|
|
66
63
|
|
|
67
64
|
## getService / ServiceProxy
|
|
68
65
|
|
|
69
|
-
서버 서비스 인터페이스의 각 메서드를 `Promise` 반환 함수로 노출하는 프록시.
|
|
66
|
+
서버 서비스 인터페이스의 각 메서드를 `Promise` 반환 함수로 노출하는 타입 안전 프록시.
|
|
70
67
|
|
|
71
|
-
|
|
72
|
-
|
|
68
|
+
`getService<TService>(serviceName): ServiceProxy<TService>` — `serviceName` 으로 등록된 서버 서비스의 프록시 반환. 프록시 메서드 호출은 내부적으로 `client.send(serviceName, 메서드명, 인자배열)` 로 위임.
|
|
69
|
+
|
|
70
|
+
- TService — 서버 서비스 메서드 인터페이스 타입. 컴파일 타임 시그니처 검증용(런타임 검증 아님). 앱에선 server 패키지가 export 한 `ServiceMethods<typeof XxxService>` 사용.
|
|
71
|
+
- serviceName: string — 서버의 `defineService("XxxName", ...)` 이름과 일치해야 함.
|
|
72
|
+
- ServiceProxy\<TService\> — TService 의 각 함수 멤버를 `(...args) => Promise<Awaited<R>>` 로 매핑. 함수 아닌 속성은 `never` 로 제외.
|
|
73
73
|
|
|
74
74
|
```ts
|
|
75
|
-
const svc = client.getService<
|
|
76
|
-
const result = await svc.echo("hi"); //
|
|
75
|
+
const svc = client.getService<TestServiceMethods>("TestService");
|
|
76
|
+
const result = await svc.echo("hi"); // 서버 TestService.echo("hi") 호출, Promise<string>
|
|
77
77
|
```
|
|
78
78
|
|
|
79
|
-
## 이벤트
|
|
79
|
+
## 이벤트 구독·발행 (addListener / removeListener / emitEvent / getEvent)
|
|
80
|
+
|
|
81
|
+
서버 푸시 이벤트는 `@simplysm/service-common` 의 `defineEvent` 산출물(`ServiceEventDef`. `$info` = 구독 필터 정보 타입, `$data` = 페이로드 타입) 단위로 다룬다. 등록한 리스너는 재연결 시 자동 복구됨.
|
|
82
|
+
|
|
83
|
+
`addListener<TEventDef>(eventDef, info, cb): Promise<string>` — 리스너 등록. 미연결(`connected === false`)이면 throw. 반환 key 로 나중에 제거.
|
|
84
|
+
|
|
85
|
+
- eventDef: TEventDef — 이벤트 정의(`defineEvent` 결과). `$info`/`$data` 타입의 출처.
|
|
86
|
+
- info: TEventDef["$info"] — 이 구독을 식별·필터링할 정보. 서버가 emit 대상 선별에 사용.
|
|
87
|
+
- cb: (data: $data) => PromiseLike\<void\> — 이벤트 수신 콜백. 콜백 내 예외는 로깅만 되고 호출부로 전파되지 않음.
|
|
80
88
|
|
|
81
|
-
|
|
89
|
+
`removeListener(key): Promise<void>` — 등록 key 로 리스너 제거. 서버 전송 실패(연결 끊김 등)는 무시(서버가 끊김 시 리스너를 자동 정리하므로 안전).
|
|
82
90
|
|
|
83
|
-
|
|
91
|
+
`emitEvent<TEventDef>(eventDef, infoSelector, data): Promise<void>` — 이벤트 발행. 서버에서 동일 이벤트 구독자 목록을 조회한 뒤 `infoSelector(info)` 가 true 인 대상에게만 data 전송.
|
|
84
92
|
|
|
85
|
-
-
|
|
86
|
-
-
|
|
87
|
-
- `emitEvent<TEventDef>(eventDef, infoSelector, data): Promise<void>` — 이벤트 발행. `infoSelector: (info) => boolean` 로 서버에 등록된 리스너 중 대상을 골라 `data: TEventDef["$data"]` 전달.
|
|
88
|
-
- `getEvent<TEventDef>(eventDef): ClientEventProxy<TEventDef>` — 특정 이벤트 정의에 바인딩된 프록시 반환(eventDef 반복 전달 생략용).
|
|
93
|
+
- infoSelector: (item: $info) => boolean — 발행 대상 구독자를 info 기준으로 필터. true 반환 구독자에게만 전달.
|
|
94
|
+
- data: TEventDef["$data"] — 전송 페이로드.
|
|
89
95
|
|
|
90
|
-
ClientEventProxy<TEventDef
|
|
96
|
+
`getEvent<TEventDef>(eventDef): ClientEventProxy<TEventDef>` — 특정 eventDef 에 바인딩된 프록시 반환. eventDef 를 매번 넘기지 않고 짧게 쓰려 할 때(앱의 `AppServiceProvider.xxxEvent` getter 패턴).
|
|
91
97
|
|
|
92
|
-
|
|
93
|
-
- `removeListener(key): Promise<void>` — 리스너 해제.
|
|
94
|
-
- `emit(infoSelector, data): Promise<void>` — 위 `emitEvent` 의 eventDef 고정판.
|
|
98
|
+
`ClientEventProxy<TEventDef>` 멤버: `addListener(info, cb)`, `removeListener(key)`, `emit(infoSelector, data)` — 위 client 메서드의 eventDef 고정판.
|
|
95
99
|
|
|
96
100
|
```ts
|
|
97
|
-
const
|
|
98
|
-
const key = await client.addListener(
|
|
101
|
+
const chatEvent = defineEvent<{ channel: string }, string>("Chat");
|
|
102
|
+
const key = await client.addListener(chatEvent, { channel: "room1" }, async (msg) => render(msg));
|
|
103
|
+
await client.emitEvent(chatEvent, (info) => info.channel === "room1", "hello");
|
|
99
104
|
await client.removeListener(key);
|
|
100
105
|
```
|
|
101
106
|
|
|
102
|
-
`EventClient` / `createEventClient(transport)` 는 `ServiceClient` 가 내부 조립에 쓰는 저수준 구현. 위
|
|
107
|
+
`EventClient` / `createEventClient(transport)` 는 `ServiceClient` 가 내부 조립에 쓰는 저수준 구현. 위 메서드에 더해 `resubscribeAll(): Promise<void>`(보관된 모든 리스너를 서버에 재등록, 재연결 복구용)를 가짐. 일반 사용에선 직접 만들지 않음.
|
|
103
108
|
|
|
104
|
-
## 파일
|
|
109
|
+
## 파일 업/다운로드 (uploadFile / downloadFileBuffer)
|
|
105
110
|
|
|
106
|
-
|
|
111
|
+
`uploadFile(files): Promise<ServiceUploadResult[]>` — `POST <hostUrl>/upload` (multipart/form-data) 로 파일 업로드. 보관 토큰을 `Authorization: Bearer` 헤더로 전송하므로 사전 `auth()` 필수(미인증 시 throw). 응답 비정상 시 throw.
|
|
107
112
|
|
|
108
|
-
-
|
|
109
|
-
- `downloadFileBuffer(relPath: string): Promise<Bytes>` — `<hostUrl>/<relPath>` 를 GET 해 바이트(`Uint8Array`)로 반환. 응답 비정상(`!res.ok`) 시 throw.
|
|
113
|
+
- files: `File[] | FileCollection | { name: string; data: BlobInput }[]` — 업로드 대상. 브라우저 `File` 배열, `FileCollection`(FileList 호환), 또는 `{ name, data }` 커스텀 객체 배열. 커스텀 객체의 data 가 `Blob` 이 아니면 `new Blob([data])` 로 감싸 전송.
|
|
110
114
|
|
|
111
|
-
`
|
|
115
|
+
`downloadFileBuffer(relPath): Promise<Bytes>` — `<hostUrl>/<relPath>` 를 GET 해 `Uint8Array` 반환. 응답 비정상(`!res.ok`) 시 throw.
|
|
112
116
|
|
|
113
|
-
-
|
|
114
|
-
- `FileCollection` — DOM `FileList` 와 구조 호환 인터페이스(`length`, `item(i)`, 인덱스 접근, iterable). DOM lib 없이도 타입체크 통과용 대체 타입.
|
|
115
|
-
- `{ name: string; data: BlobInput }[]` — 커스텀 객체. `name` = 파일명, `data` = 본문. `data` 가 `Blob` 이 아니면 `new Blob([data])` 로 감쌈.
|
|
116
|
-
|
|
117
|
-
`BlobInput` — Blob 생성 입력 타입(DOM `BlobPart` 대체): `Blob | Uint8Array<ArrayBuffer> | ArrayBuffer | string` 중 하나.
|
|
118
|
-
|
|
119
|
-
`FileClient` / `createFileClient(hostUrl, clientName)` 는 `ServiceClient` 내부 구현. `download(relPath)`/`upload(files, authToken)` 두 메서드를 가지며 직접 생성은 보통 불필요.
|
|
117
|
+
- relPath: string — 서버 기준 상대경로. 선행 `/` 유무 모두 허용(없으면 자동으로 `/` 추가).
|
|
120
118
|
|
|
121
119
|
```ts
|
|
122
120
|
await client.auth(token);
|
|
@@ -124,29 +122,33 @@ const results = await client.uploadFile([{ name: "a.txt", data: "hello" }]);
|
|
|
124
122
|
const bytes = await client.downloadFileBuffer("/files/a.txt");
|
|
125
123
|
```
|
|
126
124
|
|
|
127
|
-
|
|
125
|
+
`FileClient` / `createFileClient(hostUrl, clientName)` 는 `ServiceClient` 내부 구현. `download(relPath)` / `upload(files, authToken)` 두 메서드를 가지며 직접 생성은 보통 불필요.
|
|
126
|
+
|
|
127
|
+
## 진행률 (ServiceProgress / ServiceProgressState)
|
|
128
128
|
|
|
129
129
|
대용량 요청/응답이 청크로 분할될 때 진행 상황을 보고하는 콜백·상태 타입.
|
|
130
130
|
|
|
131
|
-
ServiceProgress — `send`
|
|
131
|
+
`ServiceProgress` — `send(..., progress)` 에 넘기는 콜백 집합(해당 호출 단건 추적용, 전역 이벤트와 별개). 각 콜백은 `(s: ServiceProgressState) => void`:
|
|
132
132
|
|
|
133
|
-
-
|
|
134
|
-
-
|
|
135
|
-
-
|
|
133
|
+
- request? — 요청 청크 업로드 진행 시 호출. 요청 청크가 2개 이상일 때만 발생.
|
|
134
|
+
- response? — 응답 청크 수신 진행 시 호출. 분할 응답이었으면 완료 시 100%(`completedSize === totalSize`)를 한 번 더 보고.
|
|
135
|
+
- server? — 서버가 처리 중 보고한 진행률 수신 시 호출(`name: "progress"` 메시지).
|
|
136
136
|
|
|
137
|
-
ServiceProgressState
|
|
137
|
+
`ServiceProgressState` — 진행률 스냅샷.
|
|
138
138
|
|
|
139
|
-
-
|
|
140
|
-
-
|
|
141
|
-
-
|
|
139
|
+
- uuid: string — 해당 요청/응답 식별자. 동시 요청 구분용.
|
|
140
|
+
- totalSize: number — 전체 바이트 수.
|
|
141
|
+
- completedSize: number — 완료 바이트 수. `completedSize === totalSize` 면 완료.
|
|
142
142
|
|
|
143
|
-
|
|
143
|
+
전역 추적이면 콜백 대신 ServiceClient 의 `request/response/server-progress` 이벤트(`client.on("response-progress", ...)`)를 써도 됨 — `send` 는 progress 인자 유무와 무관하게 이 이벤트들을 항상 발생시킴.
|
|
144
144
|
|
|
145
|
-
## 환경 호환
|
|
145
|
+
## 환경 호환 타입·헬퍼 (browser-compat)
|
|
146
146
|
|
|
147
|
-
Node
|
|
147
|
+
Node/browser 공용 코드에서 DOM 전용 타입을 피하고 Worker 지원 여부를 분기하기 위한 타입·함수. 프로토콜 인코딩/파싱 Worker 오프로딩 판단 시 내부에서 사용.
|
|
148
148
|
|
|
149
|
-
- `
|
|
150
|
-
- `
|
|
151
|
-
-
|
|
152
|
-
-
|
|
149
|
+
- BlobInput = `Blob | Uint8Array<ArrayBuffer> | ArrayBuffer | string` — `Blob` 생성자가 받는 데이터 타입(DOM `BlobPart` 대체). `uploadFile` 의 커스텀 객체 data 타입.
|
|
150
|
+
- FileCollection (interface) — DOM `FileList` 대체. `length`, `item(index): File | null`, 인덱스 접근, `[Symbol.iterator]` 보유. 브라우저 `FileList` 와 구조적 호환.
|
|
151
|
+
- BrowserWorker (interface) — DOM `Worker` 최소 인터페이스(`onmessage`/`onerror` 핸들러, `postMessage(message, transfer?)`, `terminate()`). DOM lib 없이 타입체크 통과용.
|
|
152
|
+
- isBrowserWorkerSupported(): boolean — `globalThis` 에 `Worker` 존재 여부. 브라우저 DOM Worker 가용 판단.
|
|
153
|
+
- isNodeWorkerSupported(): boolean — `process.versions.node` 존재 여부. Node `worker_threads` 가용 판단.
|
|
154
|
+
- isWorkerSupported(): boolean — 위 둘 중 하나라도 true. 프로토콜 인코딩/파싱 오프로딩 가능 여부 판단(미지원 시 메인 스레드 폴백).
|
|
@@ -1,45 +1,53 @@
|
|
|
1
1
|
# @simplysm/service-client — ORM 원격 실행
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
서버측 ORM DbContext 를 클라이언트에서 원격으로 실행하는 묶음. 쿼리 자체는 서버 `Orm` 서비스가 DB 에 대해 수행하고, 클라이언트는 커넥션·트랜잭션·쿼리 정의(`QueryDef`)만 RPC 로 전송한다. 쿼리는 `connect`/`connectWithoutTransaction` 콜백 내부에서만 가능. ORM 작업을 트랜잭션 경계로 묶어 실행할 때 함께 읽힌다.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
> 앱(Angular)에서는 `OrmConnectOptions`(DbClass·connOpt·dbContextOpt)를 화면에 흩뿌리지 않고 `AppOrmProvider`(root provider) 한 곳에 고정한 뒤 `connectAsync`/`connectWithoutTransAsync` 만 호출한다. 쿼리 작성법은 apis/orm-common 참조. 아래 예시는 connector 직접 호출 형태지만 실제 앱은 manuals/client-orm.md 의 provider 패턴을 따른다.
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
## createOrmClientConnector / OrmClientConnector
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
- `connOpt: DbConnOptions & { configName: string }` — 서버 측 DB 접속 설정. `configName` = 서버에 등록된 DB 설정 이름(서버가 이 이름으로 실제 접속 정보를 찾음).
|
|
11
|
-
- `dbContextOpt?: { database: string; schema: string }` — DbContext 가 사용할 데이터베이스/스키마를 명시. 미지정 시 서버 `getInfo()` 가 돌려주는 기본 database/schema 를 사용. `database` 가 config·서버 양쪽에서 모두 비면 `"database는 필수입니다."` throw(결측을 임의 보정하지 않음).
|
|
9
|
+
`createOrmClientConnector(serviceClient): OrmClientConnector` — 주어진 `ServiceClient` 위에 ORM 커넥터를 만든다. 내부에서 `serviceClient.getService<OrmService>("Orm")` 프록시로 서버 ORM 서비스를 호출하므로, 사용 전 `ServiceClient.connect()` 로 소켓이 연결돼 있어야 함.
|
|
12
10
|
|
|
13
|
-
|
|
11
|
+
`OrmClientConnector` 메서드:
|
|
14
12
|
|
|
15
|
-
|
|
13
|
+
- connect<T, R>(config, callback): Promise\<R\> — 트랜잭션 안에서 callback 실행. DbContext 생성 → `db.connect(...)`(connect + beginTransaction + callback + commit/rollback) 수행. callback 정상 반환 시 커밋(반환값이 그대로 반환됨), throw 시 롤백되어 콜백 내 다건 작업이 원자 처리됨. callback 에서 발생한 에러 중 외래키 제약 위반 메시지(`a parent row: a foreign key constraint` / `conflicted with the REFERENCE`)는 "경고! 연관된 작업으로 인해 작업이 거부되었습니다. 후속 작업을 확인해 주세요." 로 감싸 throw(원본은 `cause` 에 보존), 그 외 에러는 그대로 throw.
|
|
14
|
+
- connectWithoutTransaction<T, R>(config, callback): Promise\<R\> — 트랜잭션 없이 callback 실행(`db.connectWithoutTransaction`). 트랜잭션 안에서 동작하지 않는 작업(예: DB initialize)·조회 전용 작업에 사용. callback 반환값이 그대로 반환됨.
|
|
16
15
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
-
|
|
16
|
+
공통 인자:
|
|
17
|
+
|
|
18
|
+
- config: OrmConnectOptions\<T\> — 아래 섹션. DbContext 클래스·서버 ORM 설정·DB명/스키마.
|
|
19
|
+
- callback: (db: T) => Promise\<R\> | R — 생성·연결된 DbContext 를 받아 쿼리하는 콜백. 동기/비동기 반환 모두 허용.
|
|
20
20
|
|
|
21
21
|
```ts
|
|
22
22
|
const connector = createOrmClientConnector(client);
|
|
23
|
-
await connector.connect(
|
|
24
|
-
{ DbClass:
|
|
25
|
-
async (db) => {
|
|
26
|
-
await db.foo.insertAsync({ /* ... */ });
|
|
27
|
-
return db.foo.where(/* ... */).resultAsync();
|
|
28
|
-
},
|
|
23
|
+
const rows = await connector.connect(
|
|
24
|
+
{ DbClass: MainDbContext, connOpt: { configName: "MAIN" }, dbContextOpt: { database: "mydb" } },
|
|
25
|
+
async (db) => db.order().select((item) => ({ id: item.id })).execute(),
|
|
29
26
|
); // 콜백 throw 시 자동 롤백
|
|
30
27
|
```
|
|
31
28
|
|
|
29
|
+
## OrmConnectOptions
|
|
30
|
+
|
|
31
|
+
`connect`/`connectWithoutTransaction` 의 첫 인자. DbContext 1회 실행에 필요한 설정.
|
|
32
|
+
|
|
33
|
+
- DbClass: `new (executor, opt) => T` — 실행할 DbContext 클래스 생성자. `executor`(아래 `OrmClientDbContextExecutor`)와 `{ database, schema? }` 를 받아 인스턴스화됨. 앱별 DbContext(예: `MainDbContext`)를 그대로 전달.
|
|
34
|
+
- connOpt: `DbConnOptions & { configName: string }` — 서버측 ORM 연결 설정. `configName` 은 서버에 등록된 ORM 설정 이름(서버가 이 이름으로 실제 DB 접속 정보를 찾음). 나머지 필드는 `@simplysm/service-common` 의 `DbConnOptions`.
|
|
35
|
+
- dbContextOpt?: `{ database: string; schema?: string }` — DbContext 에 적용할 DB명·스키마. 생략 시 서버 `getInfo()` 가 돌려준 `database`/`schema` 를 사용. database 가 옵션·서버 양쪽 모두 비어 있으면 throw("database는 필수입니다." — 결측을 임의 보정하지 않음).
|
|
36
|
+
- database: string — 대상 데이터베이스명.
|
|
37
|
+
- schema?: string — 대상 스키마명(미지정 시 서버 기본값).
|
|
38
|
+
|
|
32
39
|
## OrmClientDbContextExecutor
|
|
33
40
|
|
|
34
|
-
`DbContextExecutor`(`@simplysm/orm-common`) 구현체. 모든 메서드를 `
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
-
|
|
39
|
-
-
|
|
40
|
-
-
|
|
41
|
-
-
|
|
42
|
-
-
|
|
43
|
-
-
|
|
44
|
-
-
|
|
45
|
-
-
|
|
41
|
+
`DbContextExecutor`(`@simplysm/orm-common`) 구현체. 모든 메서드를 `client.getService<OrmService>("Orm")` RPC 로 위임. 커넥터가 내부에서 DbContext 에 주입하므로 직접 생성·호출은 보통 불필요.
|
|
42
|
+
|
|
43
|
+
`new OrmClientDbContextExecutor(client, opt)` — 생성. opt = `DbConnOptions & { configName: string }`. 생성 시 `Orm` 서비스 프록시 확보.
|
|
44
|
+
|
|
45
|
+
- getInfo(): `Promise<{ dialect; database?; schema? }>` — 서버 ORM 설정 정보(방언·기본 DB명·스키마) 조회. 커넥터가 dbContextOpt 미지정 시 fallback 으로 사용.
|
|
46
|
+
- connect(): Promise\<void\> — 서버에 커넥션 생성, 반환된 connId 를 내부 보관. 이후 트랜잭션·쿼리 호출의 핸들. 이후 모든 실행 메서드는 connId 없으면(미연결) throw.
|
|
47
|
+
- beginTransaction(isolationLevel?): Promise\<void\> — 트랜잭션 시작. isolationLevel(orm-common `IsolationLevel`) 미지정 시 서버 기본값.
|
|
48
|
+
- commitTransaction(): Promise\<void\> — 트랜잭션 커밋.
|
|
49
|
+
- rollbackTransaction(): Promise\<void\> — 트랜잭션 롤백.
|
|
50
|
+
- close(): Promise\<void\> — 커넥션 종료 후 보관 connId 해제.
|
|
51
|
+
- executeDefs\<T\>(defs, options?): Promise\<T[][]\> — 쿼리 정의 배열(`QueryDef[]`)을 서버에서 실행. options 는 정의별 결과 매핑 메타(`(ResultMeta | undefined)[]`, 항목별 nullable)로 행 역직렬화 방식 지정. 정의 1개당 결과 배열 1개를 가진 2차원 배열 반환.
|
|
52
|
+
- executeParametrized(query, params?): Promise\<unknown[][]\> — 파라미터 바인딩 raw SQL 실행. query = SQL 문자열, params = 바인딩 값 배열.
|
|
53
|
+
- bulkInsert(tableName, columnDefs, records): Promise\<void\> — 대량 삽입. columnDefs(`Record<string, ColumnMeta>`)로 컬럼별 메타를, records 로 삽입할 행 객체 배열을 전달.
|
|
@@ -1,36 +1,61 @@
|
|
|
1
1
|
# @simplysm/service-client — 저수준 전송 계층
|
|
2
2
|
|
|
3
|
-
`ServiceClient` 가 생성자에서 내부적으로 조립하는 저수준 모듈들. WebSocket 연결·하트비트·재연결(SocketProvider), 요청/응답 매칭과 메시지 디스패치(ServiceTransport), 인코딩/디코딩의 Worker 오프로딩(ClientProtocolWrapper). 일반 사용에서는 `ServiceClient` 만 쓰면
|
|
3
|
+
`ServiceClient` 가 생성자에서 내부적으로 조립하는 저수준 모듈들. WebSocket 연결·하트비트·재연결(SocketProvider), 요청/응답 매칭과 메시지 디스패치(ServiceTransport), 인코딩/디코딩의 Worker 오프로딩(ClientProtocolWrapper). 일반 사용에서는 `ServiceClient` 만 쓰면 되며, 이 계층은 소켓·청크·하트비트 동작을 이해해야 할 때만 읽는다.
|
|
4
4
|
|
|
5
5
|
## SocketProvider / createSocketProvider
|
|
6
6
|
|
|
7
|
-
WebSocket 1개의 연결·하트비트·자동
|
|
7
|
+
WebSocket 1개의 연결·하트비트·자동 재연결 담당.
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
- `clientName: string` (readonly) — 생성 시 받은 식별명.
|
|
11
|
-
- `connected: boolean` (getter) — 소켓이 OPEN 인지.
|
|
12
|
-
- `connect(): Promise<void>` — 접속 시작. 실패 시 throw, 성공 시 재연결 카운트 리셋하고 `state: "connected"` emit.
|
|
13
|
-
- `close(): Promise<void>` — 수동 종료. 이후 자동 재연결 안 함. `state: "closed"` emit.
|
|
14
|
-
- `send(data: Bytes): Promise<void>` — 바이트 전송. 일정 시간 내 미연결이면 throw.
|
|
15
|
-
- `on/off(type, listener)` — 이벤트 구독/해제. 이벤트(`SocketProviderEvents`): `message: Bytes`(수신 바이트), `state: "connected"|"closed"|"reconnecting"`(연결 상태 변화).
|
|
9
|
+
`createSocketProvider(url, clientName, maxReconnectCount): SocketProvider` — 프로바이더 생성. Node 환경에서 글로벌 `WebSocket` 이 없으면 모듈 로드 시 `ws` 패키지로 polyfill.
|
|
16
10
|
|
|
17
|
-
|
|
11
|
+
- url: string — `ws(s)://host:port/ws`. 접속 시 `ver=2`, 생성된 `clientId`(UUID), `clientName` 쿼리를 붙임.
|
|
12
|
+
- clientName: string — 접속 쿼리에 실리는 식별명.
|
|
13
|
+
- maxReconnectCount: number — 최대 재연결 시도 횟수. 0 이면 재연결 안 함.
|
|
14
|
+
|
|
15
|
+
내부 상수: 하트비트 ping 5초 간격, 30초 무수신 시 타임아웃, 재연결 3초 간격. 1바이트 `0x01` ping 전송, `0x02` pong 수신은 무시(타임스탬프만 갱신).
|
|
16
|
+
|
|
17
|
+
멤버:
|
|
18
|
+
|
|
19
|
+
- clientName: string (readonly) — 생성 시 받은 식별명.
|
|
20
|
+
- connected: boolean (getter) — 소켓이 OPEN 상태인지.
|
|
21
|
+
- connect(): Promise\<void\> — 접속 시작. 실패 시 throw, 성공 시 재연결 카운트 리셋하고 `state: "connected"` emit.
|
|
22
|
+
- close(): Promise\<void\> — 수동 종료. 이후 자동 재연결 안 함. 소켓 CLOSED 까지 대기 후 `state: "closed"` emit.
|
|
23
|
+
- send(data: Bytes): Promise\<void\> — 바이트 전송. 일정 시간 내 미연결이면 throw("서버에 연결되지 않았습니다...").
|
|
24
|
+
- on(type, listener) / off(type, listener) — 이벤트 구독/해제.
|
|
25
|
+
|
|
26
|
+
`SocketProviderEvents`:
|
|
27
|
+
|
|
28
|
+
- message: Bytes — 수신 바이트(ping/pong 1바이트 제어 프레임 제외).
|
|
29
|
+
- state: "connected" | "closed" | "reconnecting" — 연결 상태 변화. "connected" = 연결/재연결 성공, "closed" = 수동 종료 또는 재연결 한도 초과, "reconnecting" = 재연결 시도 중.
|
|
30
|
+
|
|
31
|
+
하트비트 타임아웃 감지 시 소켓을 강제 정리하고(늦은 onclose 로 인한 중복 재연결 방지를 위해 핸들러 해제) 수동 종료가 아니면 재연결을 시도. 최대 시도 초과 시 `state: "closed"` emit.
|
|
18
32
|
|
|
19
33
|
## ServiceTransport / createServiceTransport
|
|
20
34
|
|
|
21
|
-
요청별 uuid 매칭, 응답/에러/진행률/서버이벤트
|
|
35
|
+
요청별 uuid 매칭, 응답/에러/진행률/서버이벤트 디스패치 담당.
|
|
22
36
|
|
|
23
|
-
|
|
24
|
-
- `send(message: ServiceClientMessage, progress?: ServiceProgress): Promise<unknown>` — 요청 1건 전송 후 응답 Promise 반환. uuid 생성→리스너 등록→encode→청크 순차 전송. 응답 수신(`response`) 시 resolve, 에러(`error`) 시 서버 에러 필드를 머지한 `Error` 로 reject.
|
|
25
|
-
- `on/off(type, listener)` — 이벤트 구독/해제. 이벤트(`ServiceTransportEvents`): `event: { keys: string[]; data: unknown }`(서버가 푸시한 `evt:on` 메시지. `EventClient` 가 이걸 구독해 로컬 리스너로 디스패치).
|
|
37
|
+
`createServiceTransport(socket, protocol): ServiceTransport` — 트랜스포트 생성. 소켓 `message` 를 받아 decode 후 종류별 분기. 소켓이 `closed`/`reconnecting` 되면 대기 중인 모든 요청을 reject(메모리 해제).
|
|
26
38
|
|
|
27
|
-
|
|
39
|
+
- socket: SocketProvider — 하위 소켓.
|
|
40
|
+
- protocol: ClientProtocolWrapper — 인코드/디코드 래퍼.
|
|
41
|
+
|
|
42
|
+
멤버:
|
|
43
|
+
|
|
44
|
+
- send(message, progress?): Promise\<unknown\> — 요청 1건 전송 후 응답 Promise 반환. uuid 생성 → 리스너 등록 → encode → 청크 순차 전송. 응답(`response`) 수신 시 resolve, 에러(`error`) 수신 시 서버 에러 필드를 머지한 `Error` 로 reject. message = `ServiceClientMessage`, progress = `ServiceProgress`(선택).
|
|
45
|
+
- on(type, listener) / off(type, listener) — 이벤트 구독/해제.
|
|
46
|
+
|
|
47
|
+
`ServiceTransportEvents`:
|
|
48
|
+
|
|
49
|
+
- event: `{ keys: string[]; data: unknown }` — 서버가 푸시한 `evt:on` 메시지. `EventClient` 가 이걸 구독해 keys 에 매칭되는 로컬 리스너로 디스패치.
|
|
50
|
+
|
|
51
|
+
decode 실패 시에도 헤더 16바이트에서 uuid 를 선추출해 해당 요청만 reject. 분할 응답이면 완료 시 `progress.response` 로 100% 를 한 번 더 보고. 서버측 진행 메시지(`name: "progress"`)는 `progress.server` 로 전달.
|
|
28
52
|
|
|
29
53
|
## ClientProtocolWrapper / createClientProtocolWrapper
|
|
30
54
|
|
|
31
|
-
인코드/디코드를 크기 기준으로 Worker 에 오프로딩하는 래퍼. `@simplysm/service-common` 의 `ServiceProtocol` 을 감쌈.
|
|
55
|
+
인코드/디코드를 크기 기준으로 Worker 에 오프로딩하는 래퍼. `@simplysm/service-common` 의 `ServiceProtocol` 을 감쌈. Worker 미가용·임계값(30KB) 이하면 메인 스레드 처리로 폴백.
|
|
56
|
+
|
|
57
|
+
`createClientProtocolWrapper(protocol): ClientProtocolWrapper` — 래퍼 생성.
|
|
32
58
|
|
|
33
|
-
-
|
|
34
|
-
-
|
|
35
|
-
-
|
|
36
|
-
- `dispose(): void` — 프로토콜과 Worker 리졸버 정리. `ServiceClient.close()` 에서 호출.
|
|
59
|
+
- encode(uuid, message): Promise\<{ chunks: Bytes[]; totalSize: number }\> — 메시지를 청크 배열로 인코드. body 가 Uint8Array, 30KB 초과 문자열, 길이 100 초과 배열, 또는 첫 항목이 Uint8Array 인 배열이면 Worker 사용. message = `ServiceMessage`.
|
|
60
|
+
- decode(bytes): Promise\<ServiceMessageDecodeResult\<ServiceMessage\>\> — 수신 바이트 디코드. 청크 재조립(stateful)은 한 메시지의 청크가 흩어지지 않도록 항상 메인 스레드 단일 누적기에서 수행하고(#35), 재조립 완료 후 30KB 초과 JSON 파싱(stateless)만 Worker 에 위임. 미완료(progress) 상태면 그대로 반환.
|
|
61
|
+
- dispose(): void — 프로토콜과 Worker 리졸버 정리. `ServiceClient.close()` 에서 호출.
|