@simplysm/service-common 13.0.69 → 13.0.70

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/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "@simplysm/service-common",
3
- "version": "13.0.69",
4
- "description": "심플리즘 패키지 - 서비스 모듈 (common)",
5
- "author": "김석래",
3
+ "version": "13.0.70",
4
+ "description": "Simplysm package - Service module (common)",
5
+ "author": "simplysm",
6
6
  "license": "Apache-2.0",
7
7
  "repository": {
8
8
  "type": "git",
@@ -14,11 +14,12 @@
14
14
  "types": "./dist/index.d.ts",
15
15
  "files": [
16
16
  "dist",
17
- "src"
17
+ "src",
18
+ "tests"
18
19
  ],
19
20
  "sideEffects": false,
20
21
  "dependencies": {
21
- "@simplysm/core-common": "13.0.69",
22
- "@simplysm/orm-common": "13.0.69"
22
+ "@simplysm/core-common": "13.0.70",
23
+ "@simplysm/orm-common": "13.0.70"
23
24
  }
24
25
  }
@@ -11,52 +11,52 @@ import {
11
11
  import { PROTOCOL_CONFIG, type ServiceMessage } from "./protocol.types";
12
12
 
13
13
  /**
14
- * 서비스 프로토콜 인터페이스
14
+ * Service protocol interface
15
15
  *
16
16
  * Binary Protocol V2:
17
17
  * - Header: 28 bytes (UUID 16 + TotalSize 8 + Index 4)
18
18
  * - Body: JSON
19
- * - 자동 청킹: 3MB 초과 300KB 단위 분할
20
- * - 최대 메시지: 100MB
19
+ * - Auto chunking: splits into 300KB chunks when exceeding 3MB
20
+ * - Max message size: 100MB
21
21
  */
22
22
  export interface ServiceProtocol {
23
23
  /**
24
- * 메시지 인코딩 (필요 자동 분할)
24
+ * Encode a message (auto-split if needed)
25
25
  */
26
26
  encode(uuid: string, message: ServiceMessage): { chunks: Bytes[]; totalSize: number };
27
27
 
28
28
  /**
29
- * 메시지 디코딩 (분할 패킷 자동 조립)
29
+ * Decode a message (auto-reassemble chunked packets)
30
30
  */
31
31
  decode<T extends ServiceMessage>(bytes: Bytes): ServiceMessageDecodeResult<T>;
32
32
 
33
33
  /**
34
- * 프로토콜 인스턴스를 정리한다.
34
+ * Dispose the protocol instance.
35
35
  *
36
- * 내부 청크 누적기의 GC 타이머를 해제하고 메모리를 정리한다.
37
- * 프로토콜 인스턴스 사용이 끝나면 반드시 호출해야 한다.
36
+ * Releases the internal chunk accumulator's GC timer and frees memory.
37
+ * Must be called when the protocol instance is no longer needed.
38
38
  */
39
39
  dispose(): void;
40
40
  }
41
41
 
42
42
  /**
43
- * 메시지 디코딩 결과 타입 (유니온)
43
+ * Message decode result type (union)
44
44
  *
45
- * - `type: "complete"`: 모든 청크가 수신되어 메시지 조립이 완료됨
46
- * - `type: "progress"`: 분할 메시지 수신 (일부 청크만 도착)
45
+ * - `type: "complete"`: all chunks received and message reassembly is complete
46
+ * - `type: "progress"`: chunked message in progress (only some chunks arrived)
47
47
  */
48
48
  export type ServiceMessageDecodeResult<TMessage extends ServiceMessage> =
49
49
  | { type: "complete"; uuid: string; message: TMessage }
50
50
  | { type: "progress"; uuid: string; totalSize: number; completedSize: number };
51
51
 
52
52
  /**
53
- * 서비스 프로토콜 인코더/디코더 생성
53
+ * Create a service protocol encoder/decoder
54
54
  *
55
55
  * Binary Protocol V2:
56
56
  * - Header: 28 bytes (UUID 16 + TotalSize 8 + Index 4)
57
57
  * - Body: JSON
58
- * - 자동 청킹: 3MB 초과 300KB 단위 분할
59
- * - 최대 메시지: 100MB
58
+ * - Auto chunking: splits into 300KB chunks when exceeding 3MB
59
+ * - Max message size: 100MB
60
60
  */
61
61
  export function createServiceProtocol(): ServiceProtocol {
62
62
  // -------------------------------------------------------------------
@@ -80,9 +80,9 @@ export function createServiceProtocol(): ServiceProtocol {
80
80
  // -------------------------------------------------------------------
81
81
 
82
82
  /**
83
- * 메시지 청크 인코딩 (헤더 + 바디)
83
+ * Encode a message chunk (header + body)
84
84
  *
85
- * 헤더 구조 (28 bytes, Big Endian):
85
+ * Header structure (28 bytes, Big Endian):
86
86
  * ```
87
87
  * Offset Size Field
88
88
  * ------ ---- -----
@@ -128,20 +128,20 @@ export function createServiceProtocol(): ServiceProtocol {
128
128
 
129
129
  const totalSize = msgBytes.length;
130
130
 
131
- // 전체 사이즈 제한 체크 (가장 먼저 수행)
131
+ // Total size limit check (performed first)
132
132
  if (totalSize > PROTOCOL_CONFIG.MAX_TOTAL_SIZE) {
133
- throw new ArgumentError("메시지 크기가 제한을 초과했습니다.", {
133
+ throw new ArgumentError("Message size exceeds the limit.", {
134
134
  totalSize,
135
135
  maxSize: PROTOCOL_CONFIG.MAX_TOTAL_SIZE,
136
136
  });
137
137
  }
138
138
 
139
- // 사이즈가 작으면 그대로 반환
139
+ // Return as-is if small enough
140
140
  if (totalSize <= PROTOCOL_CONFIG.SPLIT_MESSAGE_SIZE) {
141
141
  return { chunks: [encodeChunk({ uuid, totalSize, index: 0 }, msgBytes)], totalSize };
142
142
  }
143
143
 
144
- // 분할 처리
144
+ // Split into chunks
145
145
  const chunks: Bytes[] = [];
146
146
  let offset = 0;
147
147
  let index = 0;
@@ -161,13 +161,13 @@ export function createServiceProtocol(): ServiceProtocol {
161
161
 
162
162
  decode<T extends ServiceMessage>(bytes: Bytes): ServiceMessageDecodeResult<T> {
163
163
  if (bytes.length < 28) {
164
- throw new ArgumentError("버퍼 크기가 헤더 크기보다 작습니다.", {
164
+ throw new ArgumentError("Buffer size is smaller than header size.", {
165
165
  bufferSize: bytes.length,
166
166
  minimumSize: 28,
167
167
  });
168
168
  }
169
169
 
170
- // 1. 헤더 읽기
170
+ // 1. Read header
171
171
 
172
172
  // UUID
173
173
  const uuidBytes = bytes.subarray(0, 16);
@@ -178,9 +178,9 @@ export function createServiceProtocol(): ServiceProtocol {
178
178
  const totalSize = Number(headerView.getBigUint64(16, false));
179
179
  const index = headerView.getUint32(24, false);
180
180
 
181
- // 전체 사이즈 제한 체크 (가장 먼저 수행)
181
+ // Total size limit check (performed first)
182
182
  if (totalSize > PROTOCOL_CONFIG.MAX_TOTAL_SIZE) {
183
- throw new ArgumentError("메시지 크기가 제한을 초과했습니다.", {
183
+ throw new ArgumentError("Message size exceeds the limit.", {
184
184
  totalSize,
185
185
  maxSize: PROTOCOL_CONFIG.MAX_TOTAL_SIZE,
186
186
  });
@@ -194,7 +194,7 @@ export function createServiceProtocol(): ServiceProtocol {
194
194
  chunks: [],
195
195
  }));
196
196
  if (accItem.chunks[index] == null) {
197
- // 패킷중복 방어
197
+ // Duplicate packet guard
198
198
  accItem.chunks[index] = bodyBytes;
199
199
  accItem.completedSize += bodyBytes.length;
200
200
  }
@@ -207,14 +207,14 @@ export function createServiceProtocol(): ServiceProtocol {
207
207
  completedSize: accItem.completedSize,
208
208
  };
209
209
  } else {
210
- accumulator.delete(uuid); // 메모리 해제
210
+ accumulator.delete(uuid); // Free memory
211
211
 
212
212
  const resultBytes = bytesConcat(accItem.chunks.filterExists());
213
213
  let messageArr: [string, unknown];
214
214
  try {
215
215
  messageArr = jsonParse<[string, unknown]>(new TextDecoder().decode(resultBytes));
216
216
  } catch (err) {
217
- throw new ArgumentError("메시지 디코딩에 실패했습니다.", { uuid, cause: err });
217
+ throw new ArgumentError("Failed to decode message.", { uuid, cause: err });
218
218
  }
219
219
  return {
220
220
  type: "complete",
@@ -2,17 +2,17 @@
2
2
  // Protocol Constants
3
3
  // ----------------------------------------------------------------------
4
4
 
5
- /** 서비스 프로토콜 설정 */
5
+ /** Service protocol configuration */
6
6
  export const PROTOCOL_CONFIG = {
7
- /** 최대 메시지 크기 (100MB) */
7
+ /** Max message size (100MB) */
8
8
  MAX_TOTAL_SIZE: 100 * 1024 * 1024,
9
- /** 청킹 임계값 (3MB) */
9
+ /** Chunking threshold (3MB) */
10
10
  SPLIT_MESSAGE_SIZE: 3 * 1024 * 1024,
11
- /** 청크 크기 (300KB) */
11
+ /** Chunk size (300KB) */
12
12
  CHUNK_SIZE: 300 * 1024,
13
- /** GC 주기 (10초) */
13
+ /** GC interval (10s) */
14
14
  GC_INTERVAL: 10 * 1000,
15
- /** 미완성 메시지 만료 시간 (60초) */
15
+ /** Incomplete message expiry time (60s) */
16
16
  EXPIRE_TIME: 60 * 1000,
17
17
  } as const;
18
18
 
@@ -34,10 +34,10 @@ export type ServiceMessage =
34
34
  | ServiceEventMessage;
35
35
 
36
36
  export type ServiceServerMessage =
37
- | ServiceReloadMessage // 알림
37
+ | ServiceReloadMessage // Notification
38
38
  | ServiceResponseMessage
39
39
  | ServiceErrorMessage
40
- | ServiceEventMessage; // 알림
40
+ | ServiceEventMessage; // Notification
41
41
 
42
42
  export type ServiceServerRawMessage = ServiceProgressMessage | ServiceServerMessage;
43
43
 
@@ -50,28 +50,28 @@ export type ServiceClientMessage =
50
50
  | ServiceEmitEventMessage;
51
51
 
52
52
  // ----------------------------------------------------------------------
53
- // System 공통
53
+ // System (common)
54
54
  // ----------------------------------------------------------------------
55
55
 
56
- /** 서버: 클라이언트에게 reload 명령 */
56
+ /** Server: reload command to client */
57
57
  export interface ServiceReloadMessage {
58
58
  name: "reload";
59
59
  body: {
60
- clientName: string | undefined; // 클라이언트명
61
- changedFileSet: Set<string>; // 변경파일목록
60
+ clientName: string | undefined; // Client name
61
+ changedFileSet: Set<string>; // Changed file list
62
62
  };
63
63
  }
64
64
 
65
- /** 서버: 받은 분할메시지에 대한 progress 알림 */
65
+ /** Server: progress notification for received chunked message */
66
66
  export interface ServiceProgressMessage {
67
67
  name: "progress";
68
68
  body: {
69
- totalSize: number; // 크기 (Bytes)
70
- completedSize: number; // 완료된 크기 (Bytes)
69
+ totalSize: number; // Total size (bytes)
70
+ completedSize: number; // Completed size (bytes)
71
71
  };
72
72
  }
73
73
 
74
- /** 서버: 에러 발생 알림 */
74
+ /** Server: error notification */
75
75
  export interface ServiceErrorMessage {
76
76
  name: "error";
77
77
  body: {
@@ -84,72 +84,72 @@ export interface ServiceErrorMessage {
84
84
  };
85
85
  }
86
86
 
87
- /** 클라: 인증 메시지 */
87
+ /** Client: authentication message */
88
88
  export interface ServiceAuthMessage {
89
89
  name: "auth";
90
- body: string; // 토큰
90
+ body: string; // Token
91
91
  }
92
92
 
93
93
  // ----------------------------------------------------------------------
94
94
  // Service.Method
95
95
  // ----------------------------------------------------------------------
96
96
 
97
- /** 클라: ServiceMethod 요청 */
97
+ /** Client: service method request */
98
98
  export interface ServiceRequestMessage {
99
99
  name: `${string}.${string}`; // ${service}.${method}
100
100
  body: unknown[]; // params
101
101
  }
102
102
 
103
- /** 서버: ServiceMethod 응답 */
103
+ /** Server: service method response */
104
104
  export interface ServiceResponseMessage {
105
105
  name: "response";
106
106
  body?: unknown; // result
107
107
  }
108
108
 
109
109
  // ----------------------------------------------------------------------
110
- // 이벤트
110
+ // Events
111
111
  // ----------------------------------------------------------------------
112
112
 
113
- /** 클라: 이벤트 리스너 등록 */
113
+ /** Client: add event listener */
114
114
  export interface ServiceAddEventListenerMessage {
115
115
  name: "evt:add";
116
116
  body: {
117
- key: string; // 리스너키 (uuid) - 차후 removeEventListener를 위해서라도 필요함
118
- name: string; // 이벤트명 (Type.name)
119
- info: unknown; // 이벤트 발생시, 리스너 필터링이 가능하도록 하기 위한 "추가 리스너 정보"
117
+ key: string; // Listener key (uuid) - needed for removeEventListener
118
+ name: string; // Event name (Type.name)
119
+ info: unknown; // Additional listener info for filtering when events fire
120
120
  };
121
121
  }
122
122
 
123
- /** 클라: 이벤트 리스너 제거 */
123
+ /** Client: remove event listener */
124
124
  export interface ServiceRemoveEventListenerMessage {
125
125
  name: "evt:remove";
126
126
  body: {
127
- key: string; // 리스너키 (uuid)
127
+ key: string; // Listener key (uuid)
128
128
  };
129
129
  }
130
130
 
131
- /** 클라: 이벤트 리스너 정보 목록 요청 */
131
+ /** Client: request event listener info list */
132
132
  export interface ServiceGetEventListenerInfosMessage {
133
133
  name: "evt:gets";
134
134
  body: {
135
- name: string; // 이벤트명
135
+ name: string; // Event name
136
136
  };
137
137
  }
138
138
 
139
- /** 클라: 이벤트 발생 */
139
+ /** Client: emit event */
140
140
  export interface ServiceEmitEventMessage {
141
141
  name: "evt:emit";
142
142
  body: {
143
- keys: string[]; // 리스너키 목록
144
- data: unknown; // 데이터
143
+ keys: string[]; // Listener key list
144
+ data: unknown; // Data
145
145
  };
146
146
  }
147
147
 
148
- /** 서버: 이벤트 발생 알림 */
148
+ /** Server: event notification */
149
149
  export interface ServiceEventMessage {
150
150
  name: "evt:on";
151
151
  body: {
152
- keys: string[]; // 리스너키 목록
153
- data: unknown; // 데이터
152
+ keys: string[]; // Listener key list
153
+ data: unknown; // Data
154
154
  };
155
155
  }
@@ -1,13 +1,13 @@
1
1
  /**
2
- * 자동 업데이트 서비스 인터페이스
2
+ * Auto-update service interface
3
3
  *
4
- * 클라이언트 애플리케이션의 최신 버전 정보를 조회한다.
4
+ * Retrieves the latest version info for client applications.
5
5
  */
6
6
  export interface AutoUpdateService {
7
7
  /**
8
- * 지정된 플랫폼의 최신 버전 정보를 조회한다.
9
- * @param platform 대상 플랫폼 (예: "win32", "darwin", "linux")
10
- * @returns 최신 버전 정보. 버전이 없으면 undefined
8
+ * Retrieve the latest version info for the specified platform.
9
+ * @param platform Target platform (e.g., "win32", "darwin", "linux")
10
+ * @returns Latest version info, or undefined if no version exists
11
11
  */
12
12
  getLastVersion(platform: string): Promise<
13
13
  | {
@@ -7,10 +7,10 @@ import type {
7
7
  } from "@simplysm/orm-common";
8
8
 
9
9
  /**
10
- * ORM 서비스 인터페이스
10
+ * ORM service interface
11
11
  *
12
- * 데이터베이스 연결, 트랜잭션 관리, 쿼리 실행 기능을 제공한다.
13
- * MySQL, MSSQL, PostgreSQL을 지원한다.
12
+ * Provides database connection, transaction management, and query execution.
13
+ * Supports MySQL, MSSQL, and PostgreSQL.
14
14
  */
15
15
  export interface OrmService {
16
16
  getInfo(opt: DbConnOptions & { configName: string }): Promise<{
@@ -45,5 +45,5 @@ export interface OrmService {
45
45
  ): Promise<void>;
46
46
  }
47
47
 
48
- /** 데이터베이스 연결 옵션 */
48
+ /** Database connection options */
49
49
  export type DbConnOptions = { configName?: string; config?: Record<string, unknown> };
package/src/types.ts CHANGED
@@ -1,13 +1,13 @@
1
1
  /**
2
- * 파일 업로드 결과
2
+ * File upload result
3
3
  *
4
- * 서버에 업로드된 파일의 정보를 담는다.
4
+ * Contains information about a file uploaded to the server.
5
5
  */
6
6
  export interface ServiceUploadResult {
7
- /** 서버 저장 경로 */
7
+ /** Storage path on the server */
8
8
  path: string;
9
- /** 원본 파일명 */
9
+ /** Original filename */
10
10
  filename: string;
11
- /** 파일 크기 (bytes) */
11
+ /** File size (bytes) */
12
12
  size: number;
13
13
  }
@@ -0,0 +1,21 @@
1
+ // packages/service-common/tests/define-event.spec.ts
2
+ import { describe, it, expect } from "vitest";
3
+ import { defineEvent } from "@simplysm/service-common";
4
+
5
+ describe("defineEvent", () => {
6
+ it("create event definition with given name", () => {
7
+ const evt = defineEvent<{ channel: string }, string>("OrderUpdated");
8
+ expect(evt.eventName).toBe("OrderUpdated");
9
+ });
10
+
11
+ it("can be used for type inference (checked at compile time)", () => {
12
+ const _evt = defineEvent<{ orderId: number }, { status: string }>("OrderUpdated");
13
+
14
+ // Type level verification — fails at compile time if incorrect
15
+ const info: typeof _evt.$info = { orderId: 123 };
16
+ const data: typeof _evt.$data = { status: "shipped" };
17
+
18
+ expect(info.orderId).toBe(123);
19
+ expect(data.status).toBe("shipped");
20
+ });
21
+ });