@simplysm/service-client 13.0.95 → 13.0.97

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.
Files changed (2) hide show
  1. package/package.json +4 -4
  2. package/README.md +0 -308
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@simplysm/service-client",
3
- "version": "13.0.95",
3
+ "version": "13.0.97",
4
4
  "description": "Simplysm package - Service module (client)",
5
5
  "author": "simplysm",
6
6
  "license": "Apache-2.0",
@@ -20,9 +20,9 @@
20
20
  "sideEffects": false,
21
21
  "dependencies": {
22
22
  "consola": "^3.4.2",
23
- "@simplysm/core-common": "13.0.95",
24
- "@simplysm/service-common": "13.0.95",
25
- "@simplysm/orm-common": "13.0.95"
23
+ "@simplysm/core-common": "13.0.97",
24
+ "@simplysm/orm-common": "13.0.97",
25
+ "@simplysm/service-common": "13.0.97"
26
26
  },
27
27
  "devDependencies": {
28
28
  "@types/ws": "^8.18.1",
package/README.md DELETED
@@ -1,308 +0,0 @@
1
- # @simplysm/service-client
2
-
3
- WebSocket 기반 RPC 서비스 클라이언트. 자동 재연결, 이벤트 구독, 파일 업로드/다운로드, ORM 연동을 지원한다.
4
-
5
- ## 설치
6
-
7
- ```bash
8
- npm install @simplysm/service-client
9
- ```
10
-
11
- **의존성:** `@simplysm/core-common`, `@simplysm/orm-common`, `@simplysm/service-common`
12
-
13
- ## 주요 사용법
14
-
15
- ### 클라이언트 생성 및 연결
16
-
17
- ```typescript
18
- import { createServiceClient } from "@simplysm/service-client";
19
-
20
- const client = createServiceClient("my-app", {
21
- host: "localhost",
22
- port: 3000,
23
- ssl: false,
24
- maxReconnectCount: 10, // 0이면 재연결 비활성화
25
- });
26
-
27
- await client.connect();
28
- // ... 사용 ...
29
- await client.close();
30
- ```
31
-
32
- `ServiceClient` 클래스를 직접 사용할 수도 있다.
33
-
34
- ```typescript
35
- import { ServiceClient } from "@simplysm/service-client";
36
-
37
- const client = new ServiceClient("my-app", {
38
- host: "localhost",
39
- port: 3000,
40
- });
41
- ```
42
-
43
- ### 서비스 호출 (RPC)
44
-
45
- ```typescript
46
- // 타입 안전한 서비스 프록시
47
- const userService = client.getService<UserService>("User");
48
- const users = await userService.findAll();
49
- const user = await userService.findById(1);
50
-
51
- // 직접 호출
52
- const result = await client.send("User", "findById", [1]);
53
-
54
- // 진행률 콜백과 함께 호출
55
- const result = await client.send("User", "exportData", [], {
56
- request: (state) => console.log(`요청 전송: ${state.completedSize}/${state.totalSize}`),
57
- response: (state) => console.log(`응답 수신: ${state.completedSize}/${state.totalSize}`),
58
- });
59
- ```
60
-
61
- ### 인증
62
-
63
- ```typescript
64
- await client.auth(jwtToken);
65
- ```
66
-
67
- 재연결 시 인증 토큰이 자동으로 재전송된다.
68
-
69
- ### 이벤트 구독
70
-
71
- ```typescript
72
- import { defineEvent } from "@simplysm/service-common";
73
-
74
- const OrderCreated = defineEvent<{ shopId: string }, { orderId: string; amount: number }>(
75
- "order-created"
76
- );
77
-
78
- // 이벤트 구독 (info로 필터 조건 전달)
79
- const key = await client.addListener(
80
- OrderCreated,
81
- { shopId: "shop-1" },
82
- async (data) => {
83
- // data: { orderId: string; amount: number }
84
- }
85
- );
86
-
87
- // 이벤트 구독 해제
88
- await client.removeListener(key);
89
-
90
- // 이벤트 발행 (서버를 통해 다른 클라이언트에 전달)
91
- await client.emitEvent(
92
- OrderCreated,
93
- (info) => info.shopId === "shop-1",
94
- { orderId: "order-123", amount: 50000 }
95
- );
96
- ```
97
-
98
- 재연결 시 이벤트 리스너가 서버에 자동으로 재등록된다.
99
-
100
- ### 파일 업로드/다운로드
101
-
102
- 파일 업로드는 `auth()`로 인증한 후에만 사용할 수 있다.
103
-
104
- ```typescript
105
- // 업로드 (인증 필수)
106
- await client.auth(jwtToken);
107
- const results = await client.uploadFile(fileInput.files);
108
- // results: ServiceUploadResult[] (path, filename, size)
109
-
110
- // { name, data } 객체 배열도 지원
111
- await client.uploadFile([
112
- { name: "report.xlsx", data: uint8ArrayData },
113
- ]);
114
-
115
- // 다운로드 (Uint8Array 반환)
116
- const buffer = await client.downloadFileBuffer("uploads/report.xlsx");
117
- ```
118
-
119
- ### 진행률 추적
120
-
121
- ```typescript
122
- // 이벤트 기반 (모든 요청/응답에 대해)
123
- client.on("request-progress", ({ uuid, totalSize, completedSize }) => {
124
- // 요청 전송 진행률
125
- });
126
-
127
- client.on("response-progress", ({ uuid, totalSize, completedSize }) => {
128
- // 응답 수신 진행률
129
- });
130
-
131
- // 연결 상태 변경
132
- client.on("state", (state) => {
133
- // "connected" | "closed" | "reconnecting"
134
- });
135
-
136
- // 서버 HMR 리로드 알림
137
- client.on("reload", (changedFiles) => {
138
- // changedFiles: Set<string>
139
- location.reload();
140
- });
141
- ```
142
-
143
- ### ORM 클라이언트 연동
144
-
145
- 서버의 ORM 서비스를 통해 클라이언트에서 DbContext를 사용한다.
146
-
147
- ```typescript
148
- import { createOrmClientConnector } from "@simplysm/service-client";
149
-
150
- const ormConnector = createOrmClientConnector(client);
151
-
152
- // 트랜잭션 포함 연결
153
- const result = await ormConnector.connect(
154
- {
155
- dbContextDef: MyDb,
156
- connOpt: { configName: "main" },
157
- // 선택적: DB/스키마 오버라이드
158
- // dbContextOpt: { database: "mydb", schema: "dbo" },
159
- },
160
- async (db) => {
161
- return await db.user().execute();
162
- }
163
- );
164
-
165
- // 트랜잭션 없이 연결
166
- const result = await ormConnector.connectWithoutTransaction(
167
- { dbContextDef: MyDb, connOpt: { configName: "main" } },
168
- async (db) => {
169
- return await db.user().execute();
170
- }
171
- );
172
- ```
173
-
174
- ## API 레퍼런스
175
-
176
- ### `createServiceClient(name, options)`
177
-
178
- `ServiceClient` 인스턴스를 생성하는 팩토리 함수.
179
-
180
- | 파라미터 | 타입 | 설명 |
181
- |---------|------|------|
182
- | `name` | `string` | 클라이언트 식별 이름 |
183
- | `options` | `ServiceConnectionOptions` | 연결 설정 |
184
-
185
- ### `ServiceClient`
186
-
187
- `EventEmitter<ServiceClientEvents>`를 확장한 메인 클라이언트 클래스.
188
-
189
- **속성:**
190
-
191
- | 이름 | 타입 | 설명 |
192
- |------|------|------|
193
- | `name` | `string` | 클라이언트 이름 (읽기 전용) |
194
- | `options` | `ServiceConnectionOptions` | 연결 설정 (읽기 전용) |
195
- | `connected` | `boolean` | 현재 연결 상태 |
196
- | `hostUrl` | `string` | `http(s)://host:port` 형식 URL |
197
-
198
- **메서드:**
199
-
200
- | 메서드 | 반환 | 설명 |
201
- |--------|------|------|
202
- | `connect()` | `Promise<void>` | 서버에 연결 |
203
- | `close()` | `Promise<void>` | 연결 종료 |
204
- | `auth(token)` | `Promise<void>` | JWT 토큰으로 인증 |
205
- | `send(serviceName, methodName, params, progress?)` | `Promise<unknown>` | RPC 호출 |
206
- | `getService<T>(serviceName)` | `ServiceProxy<T>` | 타입 안전 서비스 프록시 생성 |
207
- | `addListener(eventDef, info, cb)` | `Promise<string>` | 이벤트 구독 (키 반환) |
208
- | `removeListener(key)` | `Promise<void>` | 이벤트 구독 해제 |
209
- | `emitEvent(eventDef, infoSelector, data)` | `Promise<void>` | 이벤트 발행 |
210
- | `uploadFile(files)` | `Promise<ServiceUploadResult[]>` | 파일 업로드 (인증 필수) |
211
- | `downloadFileBuffer(relPath)` | `Promise<Bytes>` | 파일 다운로드 |
212
-
213
- **이벤트:**
214
-
215
- | 이벤트 | 데이터 타입 | 설명 |
216
- |--------|-----------|------|
217
- | `request-progress` | `ServiceProgressState` | 요청 전송 진행률 |
218
- | `response-progress` | `ServiceProgressState` | 응답 수신 진행률 |
219
- | `state` | `"connected" \| "closed" \| "reconnecting"` | 연결 상태 변경 |
220
- | `reload` | `Set<string>` | 서버 HMR 리로드 알림 |
221
-
222
- ### `ServiceProxy<TService>`
223
-
224
- 서비스의 모든 메서드 반환 타입을 `Promise`로 감싸는 유틸리티 타입.
225
-
226
- ```typescript
227
- type ServiceProxy<TService> = {
228
- [K in keyof TService]: TService[K] extends (...args: infer P) => infer R
229
- ? (...args: P) => Promise<Awaited<R>>
230
- : never;
231
- };
232
- ```
233
-
234
- ### `ServiceConnectionOptions`
235
-
236
- ```typescript
237
- interface ServiceConnectionOptions {
238
- port: number;
239
- host: string;
240
- ssl?: boolean; // HTTPS/WSS 사용 (기본: false)
241
- maxReconnectCount?: number; // 최대 재연결 시도 (기본: 10, 0=비활성화)
242
- }
243
- ```
244
-
245
- ### `ServiceProgress` / `ServiceProgressState`
246
-
247
- ```typescript
248
- interface ServiceProgress {
249
- request?: (s: ServiceProgressState) => void;
250
- response?: (s: ServiceProgressState) => void;
251
- }
252
-
253
- interface ServiceProgressState {
254
- uuid: string;
255
- totalSize: number;
256
- completedSize: number;
257
- }
258
- ```
259
-
260
- ### `createOrmClientConnector(serviceClient)`
261
-
262
- `OrmClientConnector` 인스턴스를 생성한다.
263
-
264
- **`OrmClientConnector` 메서드:**
265
-
266
- | 메서드 | 설명 |
267
- |--------|------|
268
- | `connect(config, callback)` | 트랜잭션 포함 DB 연결. 외래 키 제약 위반 시 친화적 에러 메시지 제공 |
269
- | `connectWithoutTransaction(config, callback)` | 트랜잭션 없이 DB 연결 |
270
-
271
- ### `OrmConnectOptions<TDef>`
272
-
273
- ```typescript
274
- interface OrmConnectOptions<TDef extends DbContextDef<any, any, any>> {
275
- dbContextDef: TDef;
276
- connOpt: DbConnOptions & { configName: string };
277
- dbContextOpt?: {
278
- database: string;
279
- schema: string;
280
- };
281
- }
282
- ```
283
-
284
- ### 하위 모듈
285
-
286
- 다음 인터페이스와 팩토리 함수도 export되며, 커스텀 구성이 필요할 때 사용한다.
287
-
288
- | Export | 설명 |
289
- |--------|------|
290
- | `createSocketProvider(url, clientName, maxReconnectCount)` | WebSocket 연결 관리 (하트비트, 재연결) |
291
- | `SocketProvider` | 소켓 프로바이더 인터페이스 |
292
- | `createServiceTransport(socket, protocol)` | 요청/응답 매칭 및 메시지 라우팅 |
293
- | `ServiceTransport` | 트랜스포트 인터페이스 |
294
- | `createClientProtocolWrapper(protocol)` | Worker 기반 인코딩/디코딩 래퍼 |
295
- | `ClientProtocolWrapper` | 프로토콜 래퍼 인터페이스 |
296
- | `createEventClient(transport)` | 이벤트 구독/발행 관리 |
297
- | `EventClient` | 이벤트 클라이언트 인터페이스 |
298
- | `createFileClient(hostUrl, clientName)` | HTTP 기반 파일 업로드/다운로드 |
299
- | `FileClient` | 파일 클라이언트 인터페이스 |
300
- | `OrmClientDbContextExecutor` | `DbContextExecutor` 구현체 (RPC 경유) |
301
-
302
- ## 내부 동작
303
-
304
- - **하트비트:** 5초 간격 ping 전송, 30초 타임아웃 시 연결 끊김 감지 후 자동 재연결
305
- - **재연결:** 3초 간격 재시도, 재연결 성공 시 인증 토큰 재전송 및 이벤트 자동 재구독
306
- - **대용량 메시지:** Web Worker에서 인코딩/디코딩 (30KB 이상 또는 Uint8Array 포함 시)
307
- - **프로토콜:** 3MB 초과 시 300KB 청크 자동 분할, 진행률 이벤트 발생
308
- - **소켓 종료 시:** 모든 대기 중인 요청이 자동으로 reject되어 메모리 누수 방지