@simplysm/service-common 14.0.51 → 14.0.53

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,6 +1,6 @@
1
1
  {
2
2
  "name": "@simplysm/service-common",
3
- "version": "14.0.51",
3
+ "version": "14.0.53",
4
4
  "description": "심플리즘 패키지 - 서비스 (common)",
5
5
  "author": "심플리즘",
6
6
  "license": "Apache-2.0",
@@ -14,15 +14,14 @@
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
  "devDependencies": {
22
21
  "@types/node": "^20.19.39"
23
22
  },
24
23
  "dependencies": {
25
- "@simplysm/core-common": "14.0.51",
26
- "@simplysm/orm-common": "14.0.51"
24
+ "@simplysm/core-common": "14.0.53",
25
+ "@simplysm/orm-common": "14.0.53"
27
26
  }
28
27
  }
package/README.md DELETED
@@ -1,142 +0,0 @@
1
- # @simplysm/service-common
2
-
3
- 서비스 클라이언트와 서버가 공유하는 바이너리 프로토콜, 메시지 타입, 서비스 인터페이스, 앱 구조 정의 패키지.
4
-
5
- ## 소비앱 설치 안내 (v14)
6
-
7
- v14에서는 `import type`으로 타입을 직접 가져올 수 있으므로, 이전 버전에서 클라이언트-서버 간 타입 공유를 위해 필요하던 중간 패키지(`@simplysm/service-common`, `@simplysm/orm-common`)는 **소비앱의 의존성으로 불필요**하다. 서버 패키지(`@simplysm/service-server`, `@simplysm/orm-node`)의 타입을 직접 import하여 사용한다.
8
-
9
- ```typescript
10
- // v14: 서버 패키지에서 타입을 직접 import — common 패키지 의존성 불필요
11
- import type { ServiceMethods } from "@simplysm/service-server";
12
- ```
13
-
14
- ## Installation
15
-
16
- ```bash
17
- npm install @simplysm/service-common
18
- ```
19
-
20
- ## API Overview
21
-
22
- ### Protocol
23
-
24
- | Entry | Kind | Description |
25
- |-------|------|-------------|
26
- | [`PROTOCOL_CONFIG`](./docs/protocol/protocol-config.md) | const | 프로토콜 설정 상수 (최대 크기, 청킹 임계값, 청크 크기, GC 주기, 만료 시간) |
27
- | [`ServiceMessage`](./docs/protocol/service-message.md) | type | 양방향 메시지 유니언 (`ServiceClientMessage`, `ServiceServerMessage`, `ServiceServerRawMessage` 포함) |
28
- | [`ServiceProgressMessage`](./docs/protocol/service-progress-message.md) | interface | 청크 수신 진행 상태 알림 |
29
- | [`ServiceErrorMessage`](./docs/protocol/service-error-message.md) | interface | 서버 에러 알림 |
30
- | [`ServiceAuthMessage`](./docs/protocol/service-auth-message.md) | interface | 클라이언트 인증 메시지 (토큰) |
31
- | [`ServiceRequestMessage`](./docs/protocol/service-request-message.md) | interface | 서비스 메서드 요청 |
32
- | [`ServiceResponseMessage`](./docs/protocol/service-response-message.md) | interface | 서비스 메서드 응답 |
33
- | [`ServiceAddEventListenerMessage`](./docs/protocol/service-add-event-listener-message.md) | interface | 이벤트 리스너 추가 요청 |
34
- | [`ServiceRemoveEventListenerMessage`](./docs/protocol/service-remove-event-listener-message.md) | interface | 이벤트 리스너 제거 요청 |
35
- | [`ServiceGetEventListenerInfosMessage`](./docs/protocol/service-get-event-listener-infos-message.md) | interface | 이벤트 리스너 정보 목록 요청 |
36
- | [`ServiceEmitEventMessage`](./docs/protocol/service-emit-event-message.md) | interface | 이벤트 발생 요청 |
37
- | [`ServiceEventMessage`](./docs/protocol/service-event-message.md) | interface | 서버 이벤트 알림 |
38
- | [`createServiceProtocol`](./docs/protocol/create-service-protocol.md) | function | ServiceProtocol 인스턴스 생성 팩토리 (`ServiceProtocol`, `ServiceMessageDecodeResult` 포함) |
39
-
40
- ### Service Types
41
-
42
- | Entry | Kind | Description |
43
- |-------|------|-------------|
44
- | [`OrmService`](./docs/service-types/orm-service.md) | interface | DB 연결, 트랜잭션, 쿼리 실행 서비스 인터페이스 (`DbConnOptions` 포함) |
45
- | [`AutoUpdateService`](./docs/service-types/auto-update-service.md) | interface | 클라이언트 최신 버전 조회 서비스 인터페이스 |
46
- | [`AppStructureService`](./docs/service-types/app-structure-service.md) | interface | 앱 구조 항목 조회 서비스 인터페이스 |
47
-
48
- ### Types
49
-
50
- | Entry | Kind | Description |
51
- |-------|------|-------------|
52
- | [`ServiceUploadResult`](./docs/types/service-upload-result.md) | interface | 파일 업로드 결과 |
53
-
54
- ### App Structure
55
-
56
- | Entry | Kind | Description |
57
- |-------|------|-------------|
58
- | [`AppStructureItem`](./docs/app-structure/app-structure-item.md) | type | 앱 구조 항목 유니언 (`AppStructureGroupItem`, `AppStructureLeafItem`, `AppStructureSubPermission`, `FlatPermission` 포함) |
59
- | [`isUsableModules`](./docs/app-structure/is-usable-modules.md) | function | 단일 항목의 모듈 접근 가능 여부 판단 |
60
- | [`isUsableModulesChain`](./docs/app-structure/is-usable-modules-chain.md) | function | 모듈 체인 전체의 접근 가능 여부 판단 |
61
- | [`getFlatPermissions`](./docs/app-structure/get-flat-permissions.md) | function | 앱 구조 트리를 플래트닝하여 권한 배열 반환 |
62
-
63
- ### Events
64
-
65
- | Entry | Kind | Description |
66
- |-------|------|-------------|
67
- | [`defineEvent`](./docs/events/define-event.md) | function | 타입 안전 이벤트를 정의하는 팩토리 함수 (`ServiceEventDef` 포함) |
68
-
69
- ## Usage Examples
70
-
71
- ### 프로토콜 인코딩/디코딩
72
-
73
- ```typescript
74
- import { createServiceProtocol } from "@simplysm/service-common";
75
-
76
- const protocol = createServiceProtocol();
77
-
78
- // 메시지 인코딩 (3MB 초과 시 자동 청킹)
79
- const { chunks, totalSize } = protocol.encode(uuid, {
80
- name: "OrmService.connect",
81
- body: [{ configName: "default" }],
82
- });
83
-
84
- // 메시지 디코딩 (청크 자동 재조립)
85
- for (const chunk of chunks) {
86
- const result = protocol.decode(chunk);
87
- if (result.type === "complete") {
88
- // result.message: 재조립된 메시지
89
- }
90
- }
91
-
92
- // 사용 후 반드시 해제
93
- protocol.dispose();
94
- ```
95
-
96
- ### 타입 안전 이벤트 정의
97
-
98
- ```typescript
99
- import { defineEvent } from "@simplysm/service-common";
100
-
101
- // 서버에서 이벤트 정의 + 타입 export
102
- export const OrderUpdated = defineEvent<{ orderId: number }, { status: string }>("OrderUpdated");
103
-
104
- // 서버에서 이벤트 발생 (제네릭 타입 파라미터 + 문자열 이름 패턴)
105
- await server.emitEvent<typeof OrderUpdated>("OrderUpdated", (info) => info.orderId === 123, { status: "shipped" });
106
-
107
- // 클라이언트에서 구독 (import type으로 타입만 가져옴)
108
- import type { OrderUpdated } from "@server-package";
109
- await client.addListener<typeof OrderUpdated>("OrderUpdated", { orderId: 123 }, async (data) => {
110
- // data.status는 string으로 타입 추론됨
111
- });
112
- ```
113
-
114
- ### 앱 구조 권한 플래트닝
115
-
116
- ```typescript
117
- import { getFlatPermissions, isUsableModules } from "@simplysm/service-common";
118
- import type { AppStructureItem } from "@simplysm/service-common";
119
-
120
- const items: AppStructureItem<string>[] = [
121
- {
122
- code: "admin",
123
- title: "관리",
124
- children: [
125
- { code: "user", title: "사용자", perms: ["use", "edit"] },
126
- ],
127
- },
128
- {
129
- code: "report",
130
- title: "리포트",
131
- modules: ["moduleA"],
132
- perms: ["use"],
133
- },
134
- ];
135
-
136
- // 활성 모듈 기준으로 권한 플래트닝
137
- const perms = getFlatPermissions(items, ["moduleA"]);
138
- // [{ codeChain: ["admin", "user", "use"], ... }, { codeChain: ["admin", "user", "edit"], ... }, ...]
139
-
140
- // 개별 모듈 접근 가능 여부 확인
141
- const canAccess = isUsableModules(["moduleA", "moduleB"], undefined, ["moduleA"]); // true (OR 조건)
142
- ```
@@ -1,107 +0,0 @@
1
- # AppStructureItem
2
-
3
- 앱 구조 항목 유니언 타입. `children` 필드 유무로 그룹(`AppStructureGroupItem`)과 리프(`AppStructureLeafItem`)를 구분한다.
4
-
5
- ```typescript
6
- export type AppStructureItem<TModule = unknown> =
7
- | AppStructureGroupItem<TModule>
8
- | AppStructureLeafItem<TModule>;
9
- ```
10
-
11
- `TModule` 제네릭은 모듈 식별자 타입이다 (일반적으로 `string`).
12
-
13
- ## Related Types
14
-
15
- ### `AppStructureGroupItem`
16
-
17
- 자식을 가진 그룹 메뉴 항목. `children` 필드로 하위 항목을 재귀적으로 포함한다.
18
-
19
- ```typescript
20
- export interface AppStructureGroupItem<TModule> {
21
- code: string;
22
- title: string;
23
- modules?: TModule[];
24
- requiredModules?: TModule[];
25
- icon?: string;
26
- children: AppStructureItem<TModule>[];
27
- }
28
- ```
29
-
30
- | Field | Type | Description |
31
- |-------|------|-------------|
32
- | `code` | `string` | 항목 코드 (권한 코드 체인에 사용) |
33
- | `title` | `string` | 표시 이름 |
34
- | `modules` | `TModule[]?` | 접근에 필요한 모듈 목록 (OR 조건: 하나라도 있으면 접근 가능) |
35
- | `requiredModules` | `TModule[]?` | 접근에 필수인 모듈 목록 (AND 조건: 모두 있어야 접근 가능) |
36
- | `icon` | `string?` | 아이콘 식별자 |
37
- | `children` | `AppStructureItem<TModule>[]` | 하위 메뉴 항목 배열 |
38
-
39
- ### `AppStructureLeafItem`
40
-
41
- 말단 메뉴 항목. 실제 페이지 URL과 권한(`perms`)을 가진다.
42
-
43
- ```typescript
44
- export interface AppStructureLeafItem<TModule> {
45
- code: string;
46
- title: string;
47
- modules?: TModule[];
48
- requiredModules?: TModule[];
49
- perms?: ("use" | "edit")[];
50
- subPerms?: AppStructureSubPermission<TModule>[];
51
- icon?: string;
52
- url?: string;
53
- isNotMenu?: boolean;
54
- }
55
- ```
56
-
57
- | Field | Type | Description |
58
- |-------|------|-------------|
59
- | `code` | `string` | 항목 코드 |
60
- | `title` | `string` | 표시 이름 |
61
- | `modules` | `TModule[]?` | 접근에 필요한 모듈 목록 (OR 조건) |
62
- | `requiredModules` | `TModule[]?` | 접근에 필수인 모듈 목록 (AND 조건) |
63
- | `perms` | `("use" \| "edit")[]?` | 이 항목에 부여 가능한 권한 종류 |
64
- | `subPerms` | `AppStructureSubPermission<TModule>[]?` | 하위 권한 정의 배열 |
65
- | `icon` | `string?` | 아이콘 식별자 |
66
- | `url` | `string?` | 페이지 URL |
67
- | `isNotMenu` | `boolean?` | `true`이면 메뉴에 표시하지 않음 |
68
-
69
- ### `AppStructureSubPermission`
70
-
71
- 리프 항목의 하위 권한 정의. 각 하위 권한도 모듈 접근 제어를 가진다.
72
-
73
- ```typescript
74
- export interface AppStructureSubPermission<TModule> {
75
- code: string;
76
- title: string;
77
- modules?: TModule[];
78
- requiredModules?: TModule[];
79
- perms: ("use" | "edit")[];
80
- }
81
- ```
82
-
83
- | Field | Type | Description |
84
- |-------|------|-------------|
85
- | `code` | `string` | 하위 권한 코드 |
86
- | `title` | `string` | 하위 권한 표시 이름 |
87
- | `modules` | `TModule[]?` | 접근에 필요한 모듈 목록 (OR 조건) |
88
- | `requiredModules` | `TModule[]?` | 접근에 필수인 모듈 목록 (AND 조건) |
89
- | `perms` | `("use" \| "edit")[]` | 부여 가능한 권한 종류 |
90
-
91
- ### `FlatPermission`
92
-
93
- 트리를 플래트닝한 권한 결과. [`getFlatPermissions`](./get-flat-permissions.md)의 반환 타입이다.
94
-
95
- ```typescript
96
- export interface FlatPermission<TModule = unknown> {
97
- titleChain: string[];
98
- codeChain: string[];
99
- modulesChain: TModule[][];
100
- }
101
- ```
102
-
103
- | Field | Type | Description |
104
- |-------|------|-------------|
105
- | `titleChain` | `string[]` | 루트부터 현재 권한까지의 표시 이름 체인 (예: `["관리", "사용자"]`) |
106
- | `codeChain` | `string[]` | 루트부터 현재 권한까지의 코드 체인 (예: `["admin", "user", "use"]`) |
107
- | `modulesChain` | `TModule[][]` | 각 레벨에서 필요한 모듈 목록의 체인 |
@@ -1,57 +0,0 @@
1
- # getFlatPermissions
2
-
3
- 앱 구조 트리를 BFS로 순회하며 모듈 조건을 필터링하여 [`FlatPermission`](./app-structure-item.md)`[]`으로 플래트닝한다.
4
-
5
- ```typescript
6
- export function getFlatPermissions<TModule>(
7
- items: AppStructureItem<TModule>[],
8
- usableModules: TModule[] | undefined,
9
- ): FlatPermission<TModule>[];
10
- ```
11
-
12
- ## Parameters
13
-
14
- | Param | Type | Description |
15
- |-------|------|-------------|
16
- | `items` | `AppStructureItem<TModule>[]` | 앱 구조 트리의 최상위 항목 배열 |
17
- | `usableModules` | `TModule[] \| undefined` | 사용자가 보유한 활성 모듈 목록. `undefined`이면 모듈 조건이 없는 항목만 포함 |
18
-
19
- ## Returns
20
-
21
- `FlatPermission<TModule>[]` — 모듈 조건을 만족하는 모든 권한의 플랫 목록.
22
-
23
- 처리 로직:
24
- 1. BFS로 트리를 순회하며 각 레벨의 `modules`(OR)와 `requiredModules`(AND) 조건을 체크
25
- 2. 조건 미충족 항목은 하위 트리 전체를 건너뜀
26
- 3. `AppStructureLeafItem`의 `perms`를 `codeChain`에 추가하여 `FlatPermission` 생성
27
- 4. `subPerms`도 개별 모듈 조건을 체크하여 `FlatPermission`으로 변환
28
-
29
- ## Usage
30
-
31
- ```typescript
32
- import { getFlatPermissions } from "@simplysm/service-common";
33
- import type { AppStructureItem } from "@simplysm/service-common";
34
-
35
- const items: AppStructureItem<string>[] = [
36
- {
37
- code: "admin",
38
- title: "관리",
39
- children: [
40
- { code: "user", title: "사용자", perms: ["use", "edit"] },
41
- ],
42
- },
43
- {
44
- code: "report",
45
- title: "리포트",
46
- modules: ["moduleA"],
47
- perms: ["use"],
48
- },
49
- ];
50
-
51
- const perms = getFlatPermissions(items, ["moduleA"]);
52
- // [
53
- // { titleChain: ["관리", "사용자"], codeChain: ["admin", "user", "use"], modulesChain: [] },
54
- // { titleChain: ["관리", "사용자"], codeChain: ["admin", "user", "edit"], modulesChain: [] },
55
- // { titleChain: ["리포트"], codeChain: ["report", "use"], modulesChain: [["moduleA"]] },
56
- // ]
57
- ```
@@ -1,23 +0,0 @@
1
- # isUsableModulesChain
2
-
3
- 모듈 체인 전체의 접근 가능 여부를 판단한다. 트리의 각 레벨에서 모듈 조건을 모두 만족해야 한다.
4
-
5
- ```typescript
6
- export function isUsableModulesChain<TModule>(
7
- modulesChain: TModule[][],
8
- requiredModulesChain: TModule[][],
9
- usableModules: TModule[] | undefined,
10
- ): boolean;
11
- ```
12
-
13
- ## Parameters
14
-
15
- | Param | Type | Description |
16
- |-------|------|-------------|
17
- | `modulesChain` | `TModule[][]` | 각 레벨의 OR 조건 모듈 배열 |
18
- | `requiredModulesChain` | `TModule[][]` | 각 레벨의 AND 조건 모듈 배열 |
19
- | `usableModules` | `TModule[] \| undefined` | 사용자가 보유한 활성 모듈 목록 |
20
-
21
- ## Returns
22
-
23
- `boolean` — 모든 레벨의 조건을 만족하면 `true`. 하나라도 실패하면 `false`.
@@ -1,42 +0,0 @@
1
- # isUsableModules
2
-
3
- 단일 항목의 모듈 접근 가능 여부를 판단한다.
4
-
5
- ```typescript
6
- export function isUsableModules<TModule>(
7
- modules: TModule[] | undefined,
8
- requiredModules: TModule[] | undefined,
9
- usableModules: TModule[] | undefined,
10
- ): boolean;
11
- ```
12
-
13
- ## Parameters
14
-
15
- | Param | Type | Description |
16
- |-------|------|-------------|
17
- | `modules` | `TModule[] \| undefined` | OR 조건 모듈 목록. 하나라도 `usableModules`에 포함되면 통과 |
18
- | `requiredModules` | `TModule[] \| undefined` | AND 조건 모듈 목록. 모두 `usableModules`에 포함되어야 통과 |
19
- | `usableModules` | `TModule[] \| undefined` | 사용자가 보유한 활성 모듈 목록 |
20
-
21
- ## Returns
22
-
23
- `boolean` — `modules`와 `requiredModules` 조건을 모두 만족하면 `true`.
24
-
25
- - `modules`가 `undefined`이거나 빈 배열이면 OR 조건은 자동 통과
26
- - `requiredModules`가 `undefined`이거나 빈 배열이면 AND 조건은 자동 통과
27
- - `usableModules`가 `undefined`이면 `modules`가 있을 때 `false`
28
-
29
- ## Usage
30
-
31
- ```typescript
32
- import { isUsableModules } from "@simplysm/service-common";
33
-
34
- // OR 조건: moduleA 또는 moduleB 중 하나라도 있으면 true
35
- isUsableModules(["moduleA", "moduleB"], undefined, ["moduleA"]); // true
36
-
37
- // AND 조건: 모두 있어야 true
38
- isUsableModules(undefined, ["moduleA", "moduleB"], ["moduleA"]); // false
39
-
40
- // 모듈 없음: 자동 통과
41
- isUsableModules(undefined, undefined, undefined); // true
42
- ```
@@ -1,68 +0,0 @@
1
- # defineEvent
2
-
3
- 타입 안전한 서비스 이벤트를 정의하는 팩토리 함수.
4
-
5
- ```typescript
6
- export function defineEvent<TInfo = unknown, TData = unknown>(
7
- eventName: string,
8
- ): ServiceEventDef<TInfo, TData>;
9
- ```
10
-
11
- ## Parameters
12
-
13
- | Param | Type | Description |
14
- |-------|------|-------------|
15
- | `eventName` | `string` | 이벤트 이름 (고유해야 함) |
16
-
17
- | Type Parameter | Default | Description |
18
- |---------------|---------|-------------|
19
- | `TInfo` | `unknown` | 이벤트 필터링 조건의 타입. 구독 시 필터로 사용 |
20
- | `TData` | `unknown` | 이벤트 페이로드의 타입. 이벤트 발생/수신 시 데이터 타입 |
21
-
22
- ## Returns
23
-
24
- `ServiceEventDef<TInfo, TData>` — 이벤트 정의 인스턴스.
25
-
26
- ## Related Types
27
-
28
- ### `ServiceEventDef`
29
-
30
- `defineEvent()`로 생성된 이벤트 정의. `$info`와 `$data`는 런타임에서 사용되지 않는 타입 전용 마커다.
31
-
32
- ```typescript
33
- export interface ServiceEventDef<TInfo = unknown, TData = unknown> {
34
- eventName: string;
35
- readonly $info: TInfo;
36
- readonly $data: TData;
37
- }
38
- ```
39
-
40
- | Field | Type | Description |
41
- |-------|------|-------------|
42
- | `eventName` | `string` | 이벤트 이름 |
43
- | `$info` | `TInfo` | 타입 추출 전용 마커 (런타임에서 사용하지 않음). 이벤트 필터링 조건 타입 |
44
- | `$data` | `TData` | 타입 추출 전용 마커 (런타임에서 사용하지 않음). 이벤트 페이로드 타입 |
45
-
46
- ## Usage
47
-
48
- ```typescript
49
- import { defineEvent } from "@simplysm/service-common";
50
-
51
- // 서버에서 이벤트 정의 + 타입 export
52
- export const OrderUpdated = defineEvent<{ orderId: number }, { status: string }>("OrderUpdated");
53
-
54
- // 서버에서 이벤트 발생 — getEvent() 프록시 방식 (권장)
55
- const orderEvt = server.getEvent<typeof OrderUpdated>("OrderUpdated");
56
- await orderEvt.emit((info) => info.orderId === 123, { status: "shipped" });
57
-
58
- // 클라이언트에서 구독 (import type으로 타입만 가져옴)
59
- import type { OrderUpdated } from "@server-package";
60
- const orderEvt = client.getEvent<typeof OrderUpdated>("OrderUpdated");
61
- const key = await orderEvt.addListener({ orderId: 123 }, async (data) => {
62
- // data.status는 string으로 타입 추론됨
63
- });
64
-
65
- // 직접 호출 방식 (하위 호환)
66
- await server.emitEvent<typeof OrderUpdated>("OrderUpdated", (info) => info.orderId === 123, { status: "shipped" });
67
- await client.addListener<typeof OrderUpdated>("OrderUpdated", { orderId: 123 }, async (data) => { /* ... */ });
68
- ```
@@ -1,93 +0,0 @@
1
- # createServiceProtocol
2
-
3
- ServiceProtocol 인스턴스를 생성하는 팩토리 함수.
4
-
5
- ```typescript
6
- export function createServiceProtocol(): ServiceProtocol;
7
- ```
8
-
9
- 내부에 `LazyGcMap` 기반 청크 누적기를 캡슐화한다. 미완성 메시지는 60초 후 GC로 자동 정리된다. 사용 후 반드시 `dispose()`를 호출하여 GC 타이머를 해제해야 한다.
10
-
11
- ## Returns
12
-
13
- `ServiceProtocol` — 인코딩/디코딩/해제 메서드를 포함한 프로토콜 인스턴스.
14
-
15
- ## Related Types
16
-
17
- ### `ServiceProtocol`
18
-
19
- 바이너리 프로토콜 V2 인코더/디코더 인터페이스.
20
-
21
- ```typescript
22
- export interface ServiceProtocol {
23
- encode(uuid: string, message: ServiceMessage): { chunks: Bytes[]; totalSize: number };
24
- decode<T extends ServiceMessage>(bytes: Bytes): ServiceMessageDecodeResult<T>;
25
- dispose(): void;
26
- }
27
- ```
28
-
29
- | Method | Parameters | Return | Description |
30
- |--------|-----------|--------|-------------|
31
- | `encode` | `uuid: string, message: ServiceMessage` | `{ chunks: Bytes[]; totalSize: number }` | 메시지를 인코딩한다. 3MB 초과 시 300KB 청크로 자동 분할. `totalSize` > 100MB이면 `ArgumentError` 발생 |
32
- | `decode` | `bytes: Bytes` | `ServiceMessageDecodeResult<T>` | 청크를 디코딩한다. 청크가 모두 도착하면 `complete`, 아니면 `progress` 반환 |
33
- | `dispose` | 없음 | `void` | 내부 GC 타이머와 청크 누적기를 해제한다. 사용 후 반드시 호출 |
34
-
35
- 헤더 구조 (28바이트, Big Endian):
36
-
37
- | Offset | Size | Field |
38
- |--------|------|-------|
39
- | 0 | 16 | UUID (바이너리) |
40
- | 16 | 8 | TotalSize (uint64, 상위 4바이트 = 0) |
41
- | 24 | 4 | Index (uint32) |
42
-
43
- ### `ServiceMessageDecodeResult`
44
-
45
- 메시지 디코딩 결과 유니언 타입. `type` 필드로 분기한다.
46
-
47
- ```typescript
48
- export type ServiceMessageDecodeResult<TMessage extends ServiceMessage> =
49
- | { type: "complete"; uuid: string; message: TMessage }
50
- | { type: "progress"; uuid: string; totalSize: number; completedSize: number };
51
- ```
52
-
53
- **Variant: `complete`** — 모든 청크가 도착하여 메시지 재조립이 완료된 상태.
54
-
55
- | Field | Type | Description |
56
- |-------|------|-------------|
57
- | `type` | `"complete"` | discriminant |
58
- | `uuid` | `string` | 메시지 UUID |
59
- | `message` | `TMessage` | 재조립된 메시지 |
60
-
61
- **Variant: `progress`** — 청크 메시지 수신 진행 중.
62
-
63
- | Field | Type | Description |
64
- |-------|------|-------------|
65
- | `type` | `"progress"` | discriminant |
66
- | `uuid` | `string` | 메시지 UUID |
67
- | `totalSize` | `number` | 전체 크기 (바이트) |
68
- | `completedSize` | `number` | 수신 완료된 크기 (바이트) |
69
-
70
- ## Usage
71
-
72
- ```typescript
73
- import { createServiceProtocol } from "@simplysm/service-common";
74
-
75
- const protocol = createServiceProtocol();
76
-
77
- // 메시지 인코딩 (3MB 초과 시 자동 청킹)
78
- const { chunks, totalSize } = protocol.encode(uuid, {
79
- name: "OrmService.connect",
80
- body: [{ configName: "default" }],
81
- });
82
-
83
- // 메시지 디코딩 (청크 자동 재조립)
84
- for (const chunk of chunks) {
85
- const result = protocol.decode(chunk);
86
- if (result.type === "complete") {
87
- // result.message: 재조립된 메시지
88
- }
89
- }
90
-
91
- // 사용 후 반드시 해제
92
- protocol.dispose();
93
- ```
@@ -1,21 +0,0 @@
1
- # PROTOCOL_CONFIG
2
-
3
- 서비스 프로토콜 설정 상수.
4
-
5
- ```typescript
6
- export const PROTOCOL_CONFIG = {
7
- MAX_TOTAL_SIZE: 100 * 1024 * 1024,
8
- SPLIT_MESSAGE_SIZE: 3 * 1024 * 1024,
9
- CHUNK_SIZE: 300 * 1024,
10
- GC_INTERVAL: 10 * 1000,
11
- EXPIRE_TIME: 60 * 1000,
12
- } as const;
13
- ```
14
-
15
- | Field | Type | Description |
16
- |-------|------|-------------|
17
- | `MAX_TOTAL_SIZE` | `number` | 단일 메시지의 최대 허용 크기 (100MB). 초과 시 `ArgumentError` 발생 |
18
- | `SPLIT_MESSAGE_SIZE` | `number` | 이 크기를 초과하면 자동으로 청크 분할 (3MB) |
19
- | `CHUNK_SIZE` | `number` | 분할된 각 청크의 크기 (300KB) |
20
- | `GC_INTERVAL` | `number` | 내부 청크 누적기의 가비지 컬렉션 주기 (10초, 밀리초 단위) |
21
- | `EXPIRE_TIME` | `number` | 미완성 청크 메시지의 만료 시간 (60초). 이 시간 내에 모든 청크가 도착하지 않으면 제거 |
@@ -1,23 +0,0 @@
1
- # ServiceAddEventListenerMessage
2
-
3
- 클라이언트가 보내는 이벤트 리스너 추가 메시지.
4
-
5
- ```typescript
6
- export interface ServiceAddEventListenerMessage {
7
- name: "evt:add";
8
- body: {
9
- key: string;
10
- name: string;
11
- info: unknown;
12
- };
13
- }
14
- ```
15
-
16
- ## Members
17
-
18
- | Field | Type | Description |
19
- |-------|------|-------------|
20
- | `name` | `"evt:add"` | 고정 문자열 discriminant |
21
- | `body.key` | `string` | 리스너 키 (UUID). `ServiceRemoveEventListenerMessage`에서 사용 |
22
- | `body.name` | `string` | 이벤트 이름 (`ServiceEventDef.eventName`) |
23
- | `body.info` | `unknown` | 이벤트 발생 시 필터링을 위한 추가 리스너 정보 |
@@ -1,17 +0,0 @@
1
- # ServiceAuthMessage
2
-
3
- 클라이언트가 보내는 인증 메시지.
4
-
5
- ```typescript
6
- export interface ServiceAuthMessage {
7
- name: "auth";
8
- body: string;
9
- }
10
- ```
11
-
12
- ## Members
13
-
14
- | Field | Type | Description |
15
- |-------|------|-------------|
16
- | `name` | `"auth"` | 고정 문자열 discriminant |
17
- | `body` | `string` | 인증 토큰 |
@@ -1,21 +0,0 @@
1
- # ServiceEmitEventMessage
2
-
3
- 클라이언트가 보내는 이벤트 발생 메시지.
4
-
5
- ```typescript
6
- export interface ServiceEmitEventMessage {
7
- name: "evt:emit";
8
- body: {
9
- keys: string[];
10
- data: unknown;
11
- };
12
- }
13
- ```
14
-
15
- ## Members
16
-
17
- | Field | Type | Description |
18
- |-------|------|-------------|
19
- | `name` | `"evt:emit"` | 고정 문자열 discriminant |
20
- | `body.keys` | `string[]` | 대상 리스너 키 목록 |
21
- | `body.data` | `unknown` | 이벤트 데이터 |
@@ -1,29 +0,0 @@
1
- # ServiceErrorMessage
2
-
3
- 서버가 보내는 에러 알림 메시지.
4
-
5
- ```typescript
6
- export interface ServiceErrorMessage {
7
- name: "error";
8
- body: {
9
- name: string;
10
- message: string;
11
- code: string;
12
- stack?: string;
13
- detail?: unknown;
14
- cause?: unknown;
15
- };
16
- }
17
- ```
18
-
19
- ## Members
20
-
21
- | Field | Type | Description |
22
- |-------|------|-------------|
23
- | `name` | `"error"` | 고정 문자열 discriminant |
24
- | `body.name` | `string` | 에러 이름 (클래스명) |
25
- | `body.message` | `string` | 에러 메시지 |
26
- | `body.code` | `string` | 에러 코드 |
27
- | `body.stack` | `string?` | 스택 트레이스 (선택) |
28
- | `body.detail` | `unknown?` | 추가 상세 정보 (선택) |
29
- | `body.cause` | `unknown?` | 원인 에러 (선택) |
@@ -1,21 +0,0 @@
1
- # ServiceEventMessage
2
-
3
- 서버가 보내는 이벤트 알림 메시지.
4
-
5
- ```typescript
6
- export interface ServiceEventMessage {
7
- name: "evt:on";
8
- body: {
9
- keys: string[];
10
- data: unknown;
11
- };
12
- }
13
- ```
14
-
15
- ## Members
16
-
17
- | Field | Type | Description |
18
- |-------|------|-------------|
19
- | `name` | `"evt:on"` | 고정 문자열 discriminant |
20
- | `body.keys` | `string[]` | 대상 리스너 키 목록 |
21
- | `body.data` | `unknown` | 이벤트 데이터 |
@@ -1,19 +0,0 @@
1
- # ServiceGetEventListenerInfosMessage
2
-
3
- 클라이언트가 보내는 이벤트 리스너 정보 목록 요청 메시지.
4
-
5
- ```typescript
6
- export interface ServiceGetEventListenerInfosMessage {
7
- name: "evt:gets";
8
- body: {
9
- name: string;
10
- };
11
- }
12
- ```
13
-
14
- ## Members
15
-
16
- | Field | Type | Description |
17
- |-------|------|-------------|
18
- | `name` | `"evt:gets"` | 고정 문자열 discriminant |
19
- | `body.name` | `string` | 조회할 이벤트 이름 |
@@ -1,52 +0,0 @@
1
- # ServiceMessage
2
-
3
- 모든 서비스 메시지의 유니언 타입. 클라이언트·서버 양방향 메시지를 모두 포함한다.
4
-
5
- ```typescript
6
- export type ServiceMessage =
7
- | ServiceRequestMessage
8
- | ServiceAuthMessage
9
- | ServiceProgressMessage
10
- | ServiceResponseMessage
11
- | ServiceErrorMessage
12
- | ServiceAddEventListenerMessage
13
- | ServiceRemoveEventListenerMessage
14
- | ServiceGetEventListenerInfosMessage
15
- | ServiceEmitEventMessage
16
- | ServiceEventMessage;
17
- ```
18
-
19
- ## Related Types
20
-
21
- ### `ServiceClientMessage`
22
-
23
- 클라이언트 → 서버 메시지 유니언.
24
-
25
- ```typescript
26
- export type ServiceClientMessage =
27
- | ServiceRequestMessage
28
- | ServiceAuthMessage
29
- | ServiceAddEventListenerMessage
30
- | ServiceRemoveEventListenerMessage
31
- | ServiceGetEventListenerInfosMessage
32
- | ServiceEmitEventMessage;
33
- ```
34
-
35
- ### `ServiceServerMessage`
36
-
37
- 서버 → 클라이언트 메시지 유니언.
38
-
39
- ```typescript
40
- export type ServiceServerMessage =
41
- | ServiceResponseMessage
42
- | ServiceErrorMessage
43
- | ServiceEventMessage;
44
- ```
45
-
46
- ### `ServiceServerRawMessage`
47
-
48
- 서버가 보내는 모든 메시지 (진행 상태 포함).
49
-
50
- ```typescript
51
- export type ServiceServerRawMessage = ServiceProgressMessage | ServiceServerMessage;
52
- ```
@@ -1,21 +0,0 @@
1
- # ServiceProgressMessage
2
-
3
- 서버가 보내는 청크 수신 진행 상태 알림 메시지.
4
-
5
- ```typescript
6
- export interface ServiceProgressMessage {
7
- name: "progress";
8
- body: {
9
- totalSize: number;
10
- completedSize: number;
11
- };
12
- }
13
- ```
14
-
15
- ## Members
16
-
17
- | Field | Type | Description |
18
- |-------|------|-------------|
19
- | `name` | `"progress"` | 고정 문자열 discriminant |
20
- | `body.totalSize` | `number` | 전체 메시지 크기 (바이트) |
21
- | `body.completedSize` | `number` | 현재까지 수신 완료된 크기 (바이트) |
@@ -1,19 +0,0 @@
1
- # ServiceRemoveEventListenerMessage
2
-
3
- 클라이언트가 보내는 이벤트 리스너 제거 메시지.
4
-
5
- ```typescript
6
- export interface ServiceRemoveEventListenerMessage {
7
- name: "evt:remove";
8
- body: {
9
- key: string;
10
- };
11
- }
12
- ```
13
-
14
- ## Members
15
-
16
- | Field | Type | Description |
17
- |-------|------|-------------|
18
- | `name` | `"evt:remove"` | 고정 문자열 discriminant |
19
- | `body.key` | `string` | 제거할 리스너 키 (UUID) |
@@ -1,17 +0,0 @@
1
- # ServiceRequestMessage
2
-
3
- 클라이언트가 보내는 서비스 메서드 요청 메시지.
4
-
5
- ```typescript
6
- export interface ServiceRequestMessage {
7
- name: `${string}.${string}`;
8
- body: unknown[];
9
- }
10
- ```
11
-
12
- ## Members
13
-
14
- | Field | Type | Description |
15
- |-------|------|-------------|
16
- | `name` | `` `${string}.${string}` `` | 서비스명.메서드명 형식 (예: `"OrmService.connect"`) |
17
- | `body` | `unknown[]` | 메서드 매개변수 배열 |
@@ -1,17 +0,0 @@
1
- # ServiceResponseMessage
2
-
3
- 서버가 보내는 서비스 메서드 응답 메시지.
4
-
5
- ```typescript
6
- export interface ServiceResponseMessage {
7
- name: "response";
8
- body?: unknown;
9
- }
10
- ```
11
-
12
- ## Members
13
-
14
- | Field | Type | Description |
15
- |-------|------|-------------|
16
- | `name` | `"response"` | 고정 문자열 discriminant |
17
- | `body` | `unknown?` | 메서드 실행 결과 (없으면 void) |
@@ -1,15 +0,0 @@
1
- # AppStructureService
2
-
3
- 서버에 등록된 앱 구조 항목을 클라이언트명 기준 맵으로 조회하는 서비스 인터페이스.
4
-
5
- ```typescript
6
- export interface AppStructureService {
7
- getItems(): Record<string, AppStructureItem[]>;
8
- }
9
- ```
10
-
11
- ## Members
12
-
13
- | Method | Parameters | Return | Description |
14
- |--------|-----------|--------|-------------|
15
- | `getItems` | 없음 | `Record<string, AppStructureItem[]>` | 클라이언트명을 키로, 해당 클라이언트의 앱 구조 항목 배열을 값으로 하는 맵 반환 |
@@ -1,20 +0,0 @@
1
- # AutoUpdateService
2
-
3
- 클라이언트 애플리케이션의 최신 버전 정보를 조회하는 서비스 인터페이스.
4
-
5
- ```typescript
6
- export interface AutoUpdateService {
7
- getLastVersion(platform: string): Promise<
8
- | { version: string; downloadPath: string }
9
- | undefined
10
- >;
11
- }
12
- ```
13
-
14
- ## Members
15
-
16
- | Method | Parameters | Return | Description |
17
- |--------|-----------|--------|-------------|
18
- | `getLastVersion` | `platform: string` | `Promise<{ version: string; downloadPath: string } \| undefined>` | 지정된 플랫폼의 최신 버전 정보 조회. 버전이 없으면 `undefined` |
19
-
20
- `platform` 예시: `"win32"`, `"darwin"`, `"linux"`
@@ -1,61 +0,0 @@
1
- # OrmService
2
-
3
- 데이터베이스 연결, 트랜잭션 관리, 쿼리 실행을 제공하는 서비스 인터페이스. MySQL, MSSQL, PostgreSQL을 지원한다. 이 패키지에는 구현체가 없으며, 서버(`service-server`)와 클라이언트(`service-client`)가 공유하는 타입 계약이다.
4
-
5
- ```typescript
6
- export interface OrmService {
7
- getInfo(opt: DbConnOptions & { configName: string }): Promise<{
8
- dialect: Dialect;
9
- database?: string;
10
- schema?: string;
11
- }>;
12
- connect(opt: DbConnOptions & { configName: string }): Promise<number>;
13
- close(connId: number): Promise<void>;
14
- beginTransaction(connId: number, isolationLevel?: IsolationLevel): Promise<void>;
15
- commitTransaction(connId: number): Promise<void>;
16
- rollbackTransaction(connId: number): Promise<void>;
17
- executeParametrized(connId: number, query: string, params?: unknown[]): Promise<unknown[][]>;
18
- executeDefs(
19
- connId: number,
20
- defs: QueryDef[],
21
- options?: (ResultMeta | undefined)[],
22
- ): Promise<unknown[][]>;
23
- bulkInsert(
24
- connId: number,
25
- tableName: string,
26
- columnDefs: Record<string, ColumnMeta>,
27
- records: Record<string, unknown>[],
28
- ): Promise<void>;
29
- }
30
- ```
31
-
32
- ## Members
33
-
34
- | Method | Parameters | Return | Description |
35
- |--------|-----------|--------|-------------|
36
- | `getInfo` | `opt: DbConnOptions & { configName: string }` | `Promise<{ dialect: Dialect; database?: string; schema?: string }>` | DB 연결 정보 조회 |
37
- | `connect` | `opt: DbConnOptions & { configName: string }` | `Promise<number>` | DB 연결을 생성하고 연결 ID 반환 |
38
- | `close` | `connId: number` | `Promise<void>` | 연결 종료 |
39
- | `beginTransaction` | `connId: number, isolationLevel?: IsolationLevel` | `Promise<void>` | 트랜잭션 시작 |
40
- | `commitTransaction` | `connId: number` | `Promise<void>` | 트랜잭션 커밋 |
41
- | `rollbackTransaction` | `connId: number` | `Promise<void>` | 트랜잭션 롤백 |
42
- | `executeParametrized` | `connId: number, query: string, params?: unknown[]` | `Promise<unknown[][]>` | 파라미터 바인딩 쿼리 실행 |
43
- | `executeDefs` | `connId: number, defs: QueryDef[], options?: (ResultMeta \| undefined)[]` | `Promise<unknown[][]>` | QueryDef 배열로 쿼리 실행 |
44
- | `bulkInsert` | `connId: number, tableName: string, columnDefs: Record<string, ColumnMeta>, records: Record<string, unknown>[]` | `Promise<void>` | 대량 삽입 |
45
-
46
- 사용 순서: `connect()` → `beginTransaction()` → `executeDefs()`/`executeParametrized()` → `commitTransaction()`/`rollbackTransaction()` → `close()`
47
-
48
- ## Related Types
49
-
50
- ### `DbConnOptions`
51
-
52
- 데이터베이스 연결 옵션.
53
-
54
- ```typescript
55
- export type DbConnOptions = { configName?: string; config?: Record<string, unknown> };
56
- ```
57
-
58
- | Field | Type | Description |
59
- |-------|------|-------------|
60
- | `configName` | `string?` | 서버에 등록된 DB 설정 이름 |
61
- | `config` | `Record<string, unknown>?` | 직접 지정하는 DB 연결 설정 |
@@ -1,19 +0,0 @@
1
- # ServiceUploadResult
2
-
3
- 파일 업로드 결과. 서버에 업로드된 파일의 정보를 포함한다.
4
-
5
- ```typescript
6
- export interface ServiceUploadResult {
7
- path: string;
8
- filename: string;
9
- size: number;
10
- }
11
- ```
12
-
13
- ## Members
14
-
15
- | Field | Type | Description |
16
- |-------|------|-------------|
17
- | `path` | `string` | 서버 내 저장 경로 |
18
- | `filename` | `string` | 원본 파일명 |
19
- | `size` | `number` | 파일 크기 (바이트) |