@simplysm/service-common 13.0.84 → 13.0.86

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/README.md +229 -174
  2. package/package.json +3 -3
package/README.md CHANGED
@@ -1,237 +1,292 @@
1
1
  # @simplysm/service-common
2
2
 
3
- > Simplysm package - Service module (common)
3
+ 클라이언트-서버 통신을 위한 공유 프로토콜, 타입, 이벤트 정의.
4
4
 
5
- Shared types and utilities for the simplysm service layer. Provides the binary protocol for client-server communication, type-safe event definitions, and interface contracts for built-in services (ORM, auto-update, SMTP).
6
-
7
- ## Installation
5
+ ## 설치
8
6
 
9
7
  ```bash
10
8
  npm install @simplysm/service-common
11
9
  ```
12
10
 
13
- ## Protocol
11
+ **의존성:** `@simplysm/core-common`, `@simplysm/orm-common`
12
+
13
+ ## 주요 기능
14
+
15
+ ### 바이너리 프로토콜
16
+
17
+ 28바이트 헤더 + JSON 바디 구조. 3MB 초과 시 300KB 청크로 자동 분할. 최대 메시지 크기 100MB.
14
18
 
15
- The service protocol handles binary encoding/decoding of messages between client and server over WebSocket. Large messages are automatically chunked and reassembled.
19
+ #### 프로토콜 설정값 (`PROTOCOL_CONFIG`)
16
20
 
17
- ### `createServiceProtocol()`
21
+ ```typescript
22
+ import { PROTOCOL_CONFIG } from "@simplysm/service-common";
23
+
24
+ PROTOCOL_CONFIG.MAX_TOTAL_SIZE; // 100MB - 최대 메시지 크기
25
+ PROTOCOL_CONFIG.SPLIT_MESSAGE_SIZE; // 3MB - 청크 분할 기준
26
+ PROTOCOL_CONFIG.CHUNK_SIZE; // 300KB - 청크 크기
27
+ PROTOCOL_CONFIG.GC_INTERVAL; // 10초 - 미완성 청크 GC 주기
28
+ PROTOCOL_CONFIG.EXPIRE_TIME; // 60초 - 미완성 메시지 만료 시간
29
+ ```
18
30
 
19
- Creates a `ServiceProtocol` encoder/decoder instance.
31
+ #### 프로토콜 생성 사용
20
32
 
21
33
  ```typescript
22
34
  import { createServiceProtocol } from "@simplysm/service-common";
35
+ import type { ServiceProtocol, ServiceMessageDecodeResult } from "@simplysm/service-common";
23
36
 
24
- const protocol = createServiceProtocol();
37
+ const protocol: ServiceProtocol = createServiceProtocol();
25
38
 
26
- // Encode a request message
27
- const { chunks, totalSize } = protocol.encode(uuid, {
28
- name: "MyService.getData",
29
- body: [arg1, arg2],
30
- });
39
+ // 인코딩: 메시지를 바이너리 청크 배열로 변환
40
+ const { chunks, totalSize } = protocol.encode(uuid, message);
41
+ // chunks: Bytes[] - 전송할 바이너리 청크 배열
42
+ // totalSize: number - 전체 메시지 크기
43
+
44
+ // 디코딩: 수신된 바이너리를 메시지로 복원 (청크 자동 재조립)
45
+ const result: ServiceMessageDecodeResult<ServiceMessage> = protocol.decode(bytes);
31
46
 
32
- // Decode incoming bytes
33
- const result = protocol.decode(bytes);
34
47
  if (result.type === "complete") {
35
- console.log(result.message); // fully reassembled message
48
+ // 모든 청크 수신 완료
49
+ result.uuid; // string - 메시지 UUID
50
+ result.message; // ServiceMessage - 복원된 메시지
36
51
  } else {
37
- console.log(`${result.completedSize}/${result.totalSize} bytes received`);
52
+ // result.type === "progress" - 청크 수신 중
53
+ result.uuid; // string
54
+ result.totalSize; // number - 전체 크기
55
+ result.completedSize; // number - 수신 완료된 크기
38
56
  }
39
57
 
40
- // Cleanup when done
58
+ // 사용 완료 후 반드시 dispose 호출 (내부 GC 타이머 해제)
41
59
  protocol.dispose();
42
60
  ```
43
61
 
44
- **`ServiceProtocol` methods:**
45
-
46
- | Method | Signature | Description |
47
- |---|---|---|
48
- | `encode` | `(uuid: string, message: ServiceMessage) => { chunks: Bytes[]; totalSize: number }` | Encode a message, auto-splitting into chunks if needed |
49
- | `decode` | `(bytes: Bytes) => ServiceMessageDecodeResult<T>` | Decode bytes, auto-reassembling chunked packets |
50
- | `dispose` | `() => void` | Release the internal chunk accumulator GC timer |
62
+ #### 헤더 구조 (28바이트, Big Endian)
51
63
 
52
- **Binary Protocol V2 header (28 bytes, Big Endian):**
53
-
54
- | Offset | Size | Field |
55
- |---|---|---|
64
+ | 오프셋 | 크기 | 필드 |
65
+ |--------|------|------|
56
66
  | 0 | 16 | UUID (binary) |
57
67
  | 16 | 8 | TotalSize (uint64) |
58
68
  | 24 | 4 | Index (uint32) |
59
69
 
60
- ### `PROTOCOL_CONFIG`
70
+ ### 이벤트 정의
61
71
 
62
- Protocol configuration constants.
72
+ 타입 안전한 클라이언트-서버 이벤트 시스템.
63
73
 
64
- | Constant | Value | Description |
65
- |---|---|---|
66
- | `MAX_TOTAL_SIZE` | 100 MB | Maximum message size |
67
- | `SPLIT_MESSAGE_SIZE` | 3 MB | Chunking threshold |
68
- | `CHUNK_SIZE` | 300 KB | Individual chunk size |
69
- | `GC_INTERVAL` | 10 s | Garbage collection interval for incomplete messages |
70
- | `EXPIRE_TIME` | 60 s | Expiry time for incomplete messages |
74
+ ```typescript
75
+ import { defineEvent } from "@simplysm/service-common";
76
+ import type { ServiceEventDef } from "@simplysm/service-common";
71
77
 
72
- ### `ServiceMessageDecodeResult<T>`
78
+ // 이벤트 정의 (TInfo: 구독 조건 타입, TData: 이벤트 데이터 타입)
79
+ const OrderUpdated = defineEvent<{ orderId: number }, { status: string }>("OrderUpdated");
73
80
 
74
- Union type returned by `decode()`:
81
+ // 서버에서 이벤트 발행
82
+ ctx.socket?.emitEvent(OrderUpdated, { orderId: 123 }, { status: "shipped" });
75
83
 
76
- - `{ type: "complete"; uuid: string; message: T }` -- all chunks received, message fully reassembled
77
- - `{ type: "progress"; uuid: string; totalSize: number; completedSize: number }` -- chunked message still in progress
84
+ // 클라이언트에서 이벤트 구독
85
+ await client.addEventListener(OrderUpdated, { orderId: 123 }, (data) => {
86
+ // data.status는 string으로 타입 추론됨
87
+ });
88
+ ```
78
89
 
79
- ### Message Types
90
+ #### `ServiceEventDef<TInfo, TData>`
80
91
 
81
- All messages exchanged between client and server are typed as `ServiceMessage`, which is a union of the following:
92
+ ```typescript
93
+ interface ServiceEventDef<TInfo = unknown, TData = unknown> {
94
+ eventName: string;
95
+ readonly $info: TInfo; // 타입 추출 전용 (런타임 미사용)
96
+ readonly $data: TData; // 타입 추출 전용 (런타임 미사용)
97
+ }
98
+ ```
82
99
 
83
- **Client messages (`ServiceClientMessage`):**
100
+ #### `defineEvent<TInfo, TData>(eventName: string): ServiceEventDef<TInfo, TData>`
84
101
 
85
- | Interface | `name` | Description |
86
- |---|---|---|
87
- | `ServiceAuthMessage` | `"auth"` | Authentication with token |
88
- | `ServiceRequestMessage` | `` `${service}.${method}` `` | Service method invocation |
89
- | `ServiceAddEventListenerMessage` | `"evt:add"` | Subscribe to an event |
90
- | `ServiceRemoveEventListenerMessage` | `"evt:remove"` | Unsubscribe from an event |
91
- | `ServiceGetEventListenerInfosMessage` | `"evt:gets"` | Query event listener info |
92
- | `ServiceEmitEventMessage` | `"evt:emit"` | Emit an event to listeners |
102
+ 이벤트 이름과 타입 파라미터로 타입 안전한 이벤트 정의 객체를 생성한다.
93
103
 
94
- **Server messages (`ServiceServerMessage`):**
104
+ ### 메시지 타입
95
105
 
96
- | Interface | `name` | Description |
97
- |---|---|---|
98
- | `ServiceReloadMessage` | `"reload"` | Hot-reload command to client |
99
- | `ServiceResponseMessage` | `"response"` | Response to a service method request |
100
- | `ServiceErrorMessage` | `"error"` | Error notification |
101
- | `ServiceEventMessage` | `"evt:on"` | Event notification to subscribers |
106
+ 모든 메시지는 `ServiceMessage` 유니온 타입에 포함된다.
102
107
 
103
- **Internal server messages (`ServiceServerRawMessage`):**
108
+ #### 방향별 메시지 그룹
104
109
 
105
- | Interface | `name` | Description |
106
- |---|---|---|
107
- | `ServiceProgressMessage` | `"progress"` | Chunk upload progress notification |
110
+ ```typescript
111
+ // 서버 → 클라이언트 메시지
112
+ type ServiceServerMessage =
113
+ | ServiceReloadMessage
114
+ | ServiceResponseMessage
115
+ | ServiceErrorMessage
116
+ | ServiceEventMessage;
117
+
118
+ // 서버 → 클라이언트 (progress 포함)
119
+ type ServiceServerRawMessage = ServiceProgressMessage | ServiceServerMessage;
120
+
121
+ // 클라이언트 → 서버 메시지
122
+ type ServiceClientMessage =
123
+ | ServiceRequestMessage
124
+ | ServiceAuthMessage
125
+ | ServiceAddEventListenerMessage
126
+ | ServiceRemoveEventListenerMessage
127
+ | ServiceGetEventListenerInfosMessage
128
+ | ServiceEmitEventMessage;
129
+ ```
108
130
 
109
- ## Events
131
+ #### 전체 메시지 타입 목록
110
132
 
111
- ### `defineEvent<TInfo, TData>(eventName)`
133
+ | 타입 | name 필드 | 방향 | 설명 |
134
+ |------|-----------|------|------|
135
+ | `ServiceRequestMessage` | `` `${service}.${method}` `` | C->S | RPC 호출. body: `unknown[]` (파라미터 배열) |
136
+ | `ServiceResponseMessage` | `"response"` | S->C | RPC 응답. body: `unknown` (결과값) |
137
+ | `ServiceErrorMessage` | `"error"` | S->C | 에러. body: `{ name, message, code, stack?, detail?, cause? }` |
138
+ | `ServiceAuthMessage` | `"auth"` | C->S | 인증. body: `string` (Bearer 토큰) |
139
+ | `ServiceProgressMessage` | `"progress"` | 양방향 | 청크 진행률. body: `{ totalSize, completedSize }` |
140
+ | `ServiceReloadMessage` | `"reload"` | S->C | 리로드 알림. body: `{ clientName, changedFileSet }` |
141
+ | `ServiceAddEventListenerMessage` | `"evt:add"` | C->S | 이벤트 리스너 등록. body: `{ key, name, info }` |
142
+ | `ServiceRemoveEventListenerMessage` | `"evt:remove"` | C->S | 이벤트 리스너 해제. body: `{ key }` |
143
+ | `ServiceGetEventListenerInfosMessage` | `"evt:gets"` | C->S | 이벤트 리스너 목록 조회. body: `{ name }` |
144
+ | `ServiceEmitEventMessage` | `"evt:emit"` | C->S | 이벤트 발행. body: `{ keys, data }` |
145
+ | `ServiceEventMessage` | `"evt:on"` | S->C | 이벤트 브로드캐스트. body: `{ keys, data }` |
112
146
 
113
- Define a type-safe service event. Returns a `ServiceEventDef` descriptor used by the client and server to subscribe, emit, and handle events with full type inference.
147
+ ### 서비스 인터페이스
114
148
 
115
- ```typescript
116
- import { defineEvent } from "@simplysm/service-common";
149
+ #### ORM 서비스 (`OrmService`)
117
150
 
118
- // Define an event with typed info (filter) and data (payload)
119
- const OrderUpdated = defineEvent<{ orderId: number }, { status: string }>("OrderUpdated");
151
+ DB 연결, 트랜잭션, 쿼리 실행을 제공한다. MySQL, MSSQL, PostgreSQL 지원.
120
152
 
121
- // Server emit
122
- ctx.socket?.emitEvent(OrderUpdated, { orderId: 123 }, { status: "shipped" });
153
+ ```typescript
154
+ import type { OrmService, DbConnOptions } from "@simplysm/service-common";
155
+
156
+ interface OrmService {
157
+ getInfo(opt: DbConnOptions & { configName: string }): Promise<{
158
+ dialect: Dialect;
159
+ database?: string;
160
+ schema?: string;
161
+ }>;
162
+
163
+ connect(opt: Record<string, unknown>): Promise<number>;
164
+ close(connId: number): Promise<void>;
165
+
166
+ beginTransaction(connId: number, isolationLevel?: IsolationLevel): Promise<void>;
167
+ commitTransaction(connId: number): Promise<void>;
168
+ rollbackTransaction(connId: number): Promise<void>;
169
+
170
+ executeParametrized(connId: number, query: string, params?: unknown[]): Promise<unknown[][]>;
171
+ executeDefs(
172
+ connId: number,
173
+ defs: QueryDef[],
174
+ options?: (ResultMeta | undefined)[],
175
+ ): Promise<unknown[][]>;
176
+
177
+ bulkInsert(
178
+ connId: number,
179
+ tableName: string,
180
+ columnDefs: Record<string, ColumnMeta>,
181
+ records: Record<string, unknown>[],
182
+ ): Promise<void>;
183
+ }
184
+ ```
123
185
 
124
- // Client subscribe
125
- await client.addEventListener(OrderUpdated, { orderId: 123 }, (data) => {
126
- console.log(data.status); // typed as string
127
- });
186
+ ##### `DbConnOptions`
187
+
188
+ ```typescript
189
+ type DbConnOptions = {
190
+ configName?: string;
191
+ config?: Record<string, unknown>;
192
+ };
128
193
  ```
129
194
 
130
- ### `ServiceEventDef<TInfo, TData>`
195
+ #### 자동 업데이트 서비스 (`AutoUpdateService`)
131
196
 
132
- Event definition object returned by `defineEvent()`.
197
+ ```typescript
198
+ import type { AutoUpdateService } from "@simplysm/service-common";
199
+
200
+ interface AutoUpdateService {
201
+ getLastVersion(platform: string): Promise<
202
+ | { version: string; downloadPath: string }
203
+ | undefined
204
+ >;
205
+ }
206
+ ```
133
207
 
134
- | Property | Type | Description |
135
- |---|---|---|
136
- | `eventName` | `string` | Event name identifier |
137
- | `$info` | `TInfo` | Type-only marker for filter info (not used at runtime) |
138
- | `$data` | `TData` | Type-only marker for event data (not used at runtime) |
208
+ `platform`: `"win32"`, `"darwin"`, `"linux"` 등.
139
209
 
140
- ## Service Interfaces
210
+ #### SMTP 클라이언트 서비스 타입
141
211
 
142
- Contracts for built-in services. These interfaces are implemented on the server and consumed by the client.
212
+ ```typescript
213
+ import type {
214
+ SmtpClientSendOption,
215
+ SmtpClientSendByDefaultOption,
216
+ SmtpClientSendAttachment,
217
+ SmtpClientDefaultOptions,
218
+ } from "@simplysm/service-common";
219
+
220
+ // 직접 SMTP 설정 포함하여 메일 전송
221
+ interface SmtpClientSendOption {
222
+ host: string;
223
+ port?: number;
224
+ secure?: boolean;
225
+ user?: string;
226
+ pass?: string;
227
+ from: string;
228
+ to: string;
229
+ cc?: string;
230
+ bcc?: string;
231
+ subject: string;
232
+ html: string;
233
+ attachments?: SmtpClientSendAttachment[];
234
+ }
143
235
 
144
- ### `OrmService`
236
+ // 기본 SMTP 설정 사용 시 (from/host/user/pass 등 생략)
237
+ interface SmtpClientSendByDefaultOption {
238
+ to: string;
239
+ cc?: string;
240
+ bcc?: string;
241
+ subject: string;
242
+ html: string;
243
+ attachments?: SmtpClientSendAttachment[];
244
+ }
145
245
 
146
- Database connection, transaction management, and query execution. Supports MySQL, MSSQL, and PostgreSQL.
246
+ // 기본 SMTP 서버 설정
247
+ interface SmtpClientDefaultOptions {
248
+ senderName: string;
249
+ senderEmail?: string;
250
+ user?: string;
251
+ pass?: string;
252
+ host: string;
253
+ port?: number;
254
+ secure?: boolean;
255
+ }
147
256
 
148
- | Method | Signature | Description |
149
- |---|---|---|
150
- | `getInfo` | `(opt: DbConnOptions & { configName: string }) => Promise<{ dialect; database?; schema? }>` | Get database connection info |
151
- | `connect` | `(opt: Record<string, unknown>) => Promise<number>` | Open a connection, returns connection ID |
152
- | `close` | `(connId: number) => Promise<void>` | Close a connection |
153
- | `beginTransaction` | `(connId: number, isolationLevel?: IsolationLevel) => Promise<void>` | Begin a transaction |
154
- | `commitTransaction` | `(connId: number) => Promise<void>` | Commit a transaction |
155
- | `rollbackTransaction` | `(connId: number) => Promise<void>` | Rollback a transaction |
156
- | `executeParametrized` | `(connId: number, query: string, params?: unknown[]) => Promise<unknown[][]>` | Execute a parameterized query |
157
- | `executeDefs` | `(connId: number, defs: QueryDef[], options?: (ResultMeta \| undefined)[]) => Promise<unknown[][]>` | Execute query definitions |
158
- | `bulkInsert` | `(connId: number, tableName: string, columnDefs: Record<string, ColumnMeta>, records: Record<string, unknown>[]) => Promise<void>` | Bulk insert records |
257
+ // 첨부파일
258
+ interface SmtpClientSendAttachment {
259
+ filename: string;
260
+ content?: string | Uint8Array;
261
+ path?: any;
262
+ contentType?: string;
263
+ }
264
+ ```
159
265
 
160
- ### `DbConnOptions`
266
+ ### 파일 업로드 결과
161
267
 
162
268
  ```typescript
163
- type DbConnOptions = { configName?: string; config?: Record<string, unknown> };
269
+ import type { ServiceUploadResult } from "@simplysm/service-common";
270
+
271
+ interface ServiceUploadResult {
272
+ path: string; // 서버 저장 경로
273
+ filename: string; // 원본 파일명
274
+ size: number; // 파일 크기 (bytes)
275
+ }
164
276
  ```
165
277
 
166
- ### `AutoUpdateService`
167
-
168
- Retrieves the latest version info for client applications.
169
-
170
- | Method | Signature | Description |
171
- |---|---|---|
172
- | `getLastVersion` | `(platform: string) => Promise<{ version: string; downloadPath: string } \| undefined>` | Get latest version info for a platform (e.g., `"win32"`, `"darwin"`, `"linux"`) |
173
-
174
- ### SMTP Types
175
-
176
- Types for the SMTP email sending service.
177
-
178
- **`SmtpClientSendOption`** -- Full SMTP send configuration:
179
-
180
- | Property | Type | Required | Description |
181
- |---|---|---|---|
182
- | `host` | `string` | Yes | SMTP server host |
183
- | `port` | `number` | No | SMTP server port |
184
- | `secure` | `boolean` | No | Use TLS |
185
- | `user` | `string` | No | Authentication username |
186
- | `pass` | `string` | No | Authentication password |
187
- | `from` | `string` | Yes | Sender address |
188
- | `to` | `string` | Yes | Recipient address |
189
- | `cc` | `string` | No | CC address |
190
- | `bcc` | `string` | No | BCC address |
191
- | `subject` | `string` | Yes | Email subject |
192
- | `html` | `string` | Yes | Email body (HTML) |
193
- | `attachments` | `SmtpClientSendAttachment[]` | No | File attachments |
194
-
195
- **`SmtpClientSendByDefaultOption`** -- Send using pre-configured defaults (omits host/auth/from):
196
-
197
- | Property | Type | Required | Description |
198
- |---|---|---|---|
199
- | `to` | `string` | Yes | Recipient address |
200
- | `cc` | `string` | No | CC address |
201
- | `bcc` | `string` | No | BCC address |
202
- | `subject` | `string` | Yes | Email subject |
203
- | `html` | `string` | Yes | Email body (HTML) |
204
- | `attachments` | `SmtpClientSendAttachment[]` | No | File attachments |
205
-
206
- **`SmtpClientDefaultOptions`** -- Default SMTP configuration:
207
-
208
- | Property | Type | Required | Description |
209
- |---|---|---|---|
210
- | `senderName` | `string` | Yes | Display name for sender |
211
- | `senderEmail` | `string` | No | Sender email address |
212
- | `user` | `string` | No | Authentication username |
213
- | `pass` | `string` | No | Authentication password |
214
- | `host` | `string` | Yes | SMTP server host |
215
- | `port` | `number` | No | SMTP server port |
216
- | `secure` | `boolean` | No | Use TLS |
217
-
218
- **`SmtpClientSendAttachment`** -- Email attachment:
219
-
220
- | Property | Type | Required | Description |
221
- |---|---|---|---|
222
- | `filename` | `string` | Yes | Attachment filename |
223
- | `content` | `string \| Uint8Array` | No | Inline content |
224
- | `path` | `any` | No | File path |
225
- | `contentType` | `string` | No | MIME type |
226
-
227
- ## Common Types
228
-
229
- ### `ServiceUploadResult`
230
-
231
- File upload result returned by the server.
232
-
233
- | Property | Type | Description |
234
- |---|---|---|
235
- | `path` | `string` | Storage path on the server |
236
- | `filename` | `string` | Original filename |
237
- | `size` | `number` | File size in bytes |
278
+ ## 디렉토리 구조
279
+
280
+ ```
281
+ src/
282
+ index.ts # 엔트리포인트 (모든 export 재수출)
283
+ define-event.ts # defineEvent(), ServiceEventDef
284
+ types.ts # ServiceUploadResult
285
+ protocol/
286
+ protocol.types.ts # PROTOCOL_CONFIG, 메시지 타입 정의
287
+ create-service-protocol.ts # createServiceProtocol(), ServiceProtocol
288
+ service-types/
289
+ orm-service.types.ts # OrmService, DbConnOptions
290
+ auto-update-service.types.ts # AutoUpdateService
291
+ smtp-client-service.types.ts # SmtpClientSend*, SmtpClientDefault*
292
+ ```
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@simplysm/service-common",
3
- "version": "13.0.84",
3
+ "version": "13.0.86",
4
4
  "description": "Simplysm package - Service module (common)",
5
5
  "author": "simplysm",
6
6
  "license": "Apache-2.0",
@@ -19,7 +19,7 @@
19
19
  ],
20
20
  "sideEffects": false,
21
21
  "dependencies": {
22
- "@simplysm/core-common": "13.0.84",
23
- "@simplysm/orm-common": "13.0.84"
22
+ "@simplysm/orm-common": "13.0.86",
23
+ "@simplysm/core-common": "13.0.86"
24
24
  }
25
25
  }