@simplysm/sd-claude 14.0.71 → 14.0.73

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 (33) hide show
  1. package/claude/references/sd-simplysm14/README.md +3 -2
  2. package/claude/references/sd-simplysm14/apis/angular/README.md +50 -47
  3. package/claude/references/sd-simplysm14/apis/angular/buttons.md +13 -3
  4. package/claude/references/sd-simplysm14/apis/angular/forms.md +20 -9
  5. package/claude/references/sd-simplysm14/apis/angular/kanban.md +6 -3
  6. package/claude/references/sd-simplysm14/apis/angular/layout.md +18 -12
  7. package/claude/references/sd-simplysm14/apis/angular/modal.md +2 -2
  8. package/claude/references/sd-simplysm14/apis/angular/routing.md +3 -2
  9. package/claude/references/sd-simplysm14/apis/angular/selection-managers.md +2 -1
  10. package/claude/references/sd-simplysm14/apis/angular/sheet.md +1 -1
  11. package/claude/references/sd-simplysm14/apis/angular/visual.md +26 -8
  12. package/claude/references/sd-simplysm14/apis/capacitor-plugin-file-system/README.md +1 -1
  13. package/claude/references/sd-simplysm14/apis/core-browser/README.md +39 -8
  14. package/claude/references/sd-simplysm14/apis/core-common/README.md +87 -9
  15. package/claude/references/sd-simplysm14/apis/core-node/README.md +11 -2
  16. package/claude/references/sd-simplysm14/apis/excel/README.md +19 -5
  17. package/claude/references/sd-simplysm14/apis/lint/README.md +9 -0
  18. package/claude/references/sd-simplysm14/apis/orm-common/README.md +35 -10
  19. package/claude/references/sd-simplysm14/apis/orm-node/README.md +15 -5
  20. package/claude/references/sd-simplysm14/apis/sd-claude/README.md +3 -3
  21. package/claude/references/sd-simplysm14/apis/sd-cli/README.md +37 -7
  22. package/claude/references/sd-simplysm14/apis/service-client/README.md +56 -24
  23. package/claude/references/sd-simplysm14/apis/storage/README.md +3 -1
  24. package/claude/skills/sd-spec/SKILL.md +34 -14
  25. package/claude/skills/sd-spec/references/example-spec.md +6 -2
  26. package/claude/skills/sd-spec/references/spec-authoring.md +15 -4
  27. package/claude/skills/sd-unpack/scripts/handlers/__pycache__/__init__.cpython-314.pyc +0 -0
  28. package/claude/skills/sd-unpack/scripts/handlers/__pycache__/_common.cpython-314.pyc +0 -0
  29. package/claude/skills/sd-unpack/scripts/handlers/__pycache__/dispatch.cpython-314.pyc +0 -0
  30. package/claude/skills/sd-unpack/scripts/handlers/__pycache__/office_com.cpython-314.pyc +0 -0
  31. package/claude/skills/sd-unpack/scripts/handlers/office_com.py +4 -1
  32. package/claude/skills/sd-unpack/scripts/handlers/office_worker.py +5 -3
  33. package/package.json +1 -1
@@ -4,15 +4,52 @@
4
4
 
5
5
  ## 사용 트리거 인덱스
6
6
 
7
- - **에러 클래스** — throw 시 트리 메시지/원인 체인 필요할 때. `SdError`, `ArgumentError`, `NotImplementedError`, `TimeoutError`.
8
- - **날짜/시간/UUID/캐시 타입** `DateTime`, `DateOnly`, `Time`, `Uuid`, `LazyGcMap` 사용 시. (자세히: [types.md](./types.md))
9
- - **큐·이벤트 features** 디바운스·직렬 큐, 타입 안전 EventEmitter. (자세히: [features.md](./features.md))
10
- - **유틸리티 네임스페이스** — `obj`, `str`, `num`, `bytes`, `path`, `json`, `xml`, `wait`, `transfer`, `err`, `dt`, `primitive`. (자세히: [utils.md](./utils.md))
11
- - **Array/Set/Map 전역 확장 메서드** `.single()`, `.toMap()`, `.toTree()`, `.distinct()`, `Set.adds()`, `Map.getOrCreate()` 등. (자세히: [extensions.md](./extensions.md))
12
- - **환경변수** `env(key)`, `env(key, value)`, `parseBoolEnv(v)`. `process.env` 우선, fallback `import.meta.env`.
13
- - **템플릿 문자열 태그** — IDE 하이라이팅 + indent trim. `js`, `ts`, `html`, `tsql`, `mysql`, `pgsql`. 동작은 모두 동일(문자열 결합 + 들여쓰기 정규화).
14
- - **ZIP 처리** — `ZipArchive(data?)`: `get/exists/write/extractAll/compress/close`. 사용 후 반드시 `await archive.close()`.
15
- - **공통 타입** — `Bytes` (= `Uint8Array`), `PrimitiveTypeMap/Str/Type` (string/number/boolean/DateTime/DateOnly/Time/Uuid/Bytes), `DeepPartial<T>`, `Type<T>` (생성자 타입).
7
+ - **에러 클래스** — throw 시 트리 메시지/원인 체인 필요할 때. (자세히: 아래 [에러 클래스](#에러-클래스))
8
+ - `SdError`일반 에러 (cause 체인, "상위 => 하위" 메시지)
9
+ - `ArgumentError`인자 검증 실패 (인자 객체를 YAML 로 메시지에 첨부)
10
+ - `NotImplementedError` 미구현 분기/추상 메서드
11
+ - `TimeoutError`대기 시간 초과 (`wait.until` 에서 자동 throw)
12
+ - **날짜·시간·UUID·캐시 타입** (자세히: [types.md](./types.md))
13
+ - `DateTime` 불변 날짜+시간 (밀리초 정밀도, 로컬 타임존). 변환·산술·포맷.
14
+ - `DateOnly`불변 날짜만 (`yyyy-MM-dd`). ISO 8601 주차(`getWeekSeqOfYear`/`Month`).
15
+ - `Time` 불변 시간만 (`HH:mm:ss.fff`, 24h 순환).
16
+ - `Uuid` — UUID v4 (`Uuid.generate()`), bytes 변환.
17
+ - `LazyGcMap` — 마지막 접근 후 N ms 만료 LRU Map. **`dispose()` 필수**.
18
+ - **큐·이벤트 features** (자세히: [features.md](./features.md))
19
+ - `EventEmitter<TEvents>` — 타입 안전 이벤트 (브라우저·Node 공용).
20
+ - `DebounceQueue` — 연속 호출 중 마지막만 실행 (입력 자동완성·일괄 상태 변경).
21
+ - `SerialQueue` — 순차 실행 (작업 사이 gap 옵션, 에러 발생 후에도 계속 실행).
22
+ - **유틸리티 네임스페이스** (자세히: [utils.md](./utils.md))
23
+ - `obj` — 객체 깊은 복사/비교/병합(`clone`/`equal`/`merge`), 3-way merge, `omit`/`pick`/`map`, 체인 경로(`"a.b[0].c"`) get/set/delete, `unflatten`, `clearUndefined`.
24
+ - `str` — 한글 조사(`getKoreanSuffix`), 전각→반각(`replaceFullWidth`), case 변환(`toPascalCase`/`toCamelCase`/`toKebabCase`/`toSnakeCase`), `isNullOrEmpty`, `insert`.
25
+ - `num` — 비숫자 섞인 문자열 파싱(`parseInt`/`parseFloat`/`parseRoundedInt`), `isNullOrEmpty`(0 포함 타입 가드), 천 단위 + 소수점 포맷(`format`).
26
+ - `bytes` — `Uint8Array` 결합(`concat`), hex/base64 인코딩·디코딩.
27
+ - `path` — POSIX 경로 join/basename/extname (브라우저용, 슬래시 전용).
28
+ - `json` — 커스텀 타입(Date/DateTime/DateOnly/Time/Uuid/Set/Map/Error/Uint8Array) 마커 직렬화 `stringify`/`parse`, null→undefined 복원.
29
+ - `xml` — fast-xml-parser 래퍼 `parse`/`stringify`, `stripTagPrefix` 옵션.
30
+ - `wait` — `wait.time(ms)`, `wait.until(cond, interval, maxCount)` (초과 시 `TimeoutError`).
31
+ - `transfer` — Worker postMessage 용 `encode`/`decode`, `Uint8Array.buffer` zero-copy transferList.
32
+ - `err` — 미지의 에러를 메시지 문자열로(`err.message`).
33
+ - `dt` — date-format 저수준 `format`/`normalizeMonth`/`convert12To24` (`DateTime`/`DateOnly`/`Time` 내부용, 직접 사용 드묾).
34
+ - `primitive` — 런타임 값 타입 추론(`primitive.typeStr`) → `PrimitiveTypeStr`.
35
+ - **Array/Set/Map 전역 확장 메서드** — `index.ts` import 시 자동 적용. (자세히: [extensions.md](./extensions.md))
36
+ - Array 조회: `.single()` (0/1개 단언), `.first()`/`.last()` (조건부 find), `.filterExists()` (null 제거), `.ofType()`.
37
+ - Array 비동기: `.filterAsync()`/`.mapAsync()`/`.mapManyAsync()` (순차), `.parallelAsync()` (`Promise.all`).
38
+ - Array 변환: `.groupBy()`, `.toMap()`, `.toArrayMap()`, `.toSetMap()`, `.toObject()`, `.toTree("id", "parentId")`.
39
+ - Array 중복·정렬: `.distinct({ keyFn })`, `.orderBy()`/`.orderByDesc()`, `.shuffle()`.
40
+ - Array 비교·병합: `.diffs(target, { keys })` (INSERT/DELETE/UPDATE), `.oneWayDiffs()`, `.merge()`.
41
+ - Array 집계: `.sum()`, `.min()`, `.max()`.
42
+ - Array mutable: `.distinctThis()`, `.orderByThis()`, `.insert()`, `.remove()`, `.toggle()`, `.clear()`.
43
+ - Set: `.adds(...)`, `.toggle(value, "add"|"del"?)`.
44
+ - Map: `.getOrCreate(key, defaultOrFactory)`, `.update(key, (v) => newV)`.
45
+ - **환경변수** — `env(key)`/`env(key, value)`, `parseBoolEnv(v)`. `process.env` 우선, fallback `import.meta.env`. (자세히: 아래 [환경변수](#환경변수))
46
+ - **템플릿 문자열 태그** — IDE 코드 하이라이팅 + indent trim. `js`/`ts`/`html`/`tsql`/`mysql`/`pgsql` (모두 동일 동작, 하이라이팅 차별화 목적). (자세히: 아래 [템플릿 문자열 태그](#템플릿-문자열-태그))
47
+ - **ZIP 처리** — `ZipArchive(data?)`: 읽기·쓰기·압축·해제. `get/exists/write/extractAll/compress/close`. 사용 후 **`await archive.close()`** 필수. (자세히: 아래 [ZIP 처리](#zip-처리))
48
+ - **공통 타입** (자세히: 아래 [공통 타입](#공통-타입))
49
+ - `Bytes` — `Uint8Array` 별칭 (Node `Buffer` 대체).
50
+ - `PrimitiveTypeMap`/`PrimitiveTypeStr`/`PrimitiveType` — string/number/boolean/DateTime/DateOnly/Time/Uuid/Bytes 매핑 (orm-common 공유).
51
+ - `DeepPartial<T>` — 재귀 optional (원시 타입은 그대로).
52
+ - `Type<T>` — 클래스 생성자 타입 (DI·팩토리 패턴).
16
53
 
17
54
  ## 에러 클래스
18
55
 
@@ -51,3 +88,44 @@ const code = ts`
51
88
  ```
52
89
 
53
90
  모두 동일 함수, IDE 하이라이팅 차별화 목적.
91
+
92
+ ## ZIP 처리
93
+
94
+ ```typescript
95
+ import { ZipArchive } from "@simplysm/core-common";
96
+
97
+ // 읽기
98
+ const archive = new ZipArchive(zipBytes); // Blob 또는 Uint8Array
99
+ try {
100
+ const content = await archive.get("file.txt"); // Bytes | undefined
101
+ const exists = await archive.exists("file.txt"); // boolean
102
+ const all = await archive.extractAll(onProgress?); // Map<fileName, Bytes|undefined>
103
+ } finally {
104
+ await archive.close(); // 필수
105
+ }
106
+
107
+ // 쓰기
108
+ const archive = new ZipArchive();
109
+ archive.write("file.txt", bytes);
110
+ const zipBytes = await archive.compress(); // 내부적으로 extractAll → 전체 메모리 로드
111
+ await archive.close();
112
+ ```
113
+
114
+ `extractAll` 진행률 콜백: `{ fileName, totalSize, extractedSize }`. `compress()` 는 전체 파일을 메모리에 로드하므로 대용량 ZIP 주의.
115
+
116
+ ## 공통 타입
117
+
118
+ ```typescript
119
+ type Bytes = Uint8Array; // Buffer 대체
120
+
121
+ type PrimitiveTypeMap = { // orm-common 공유
122
+ string: string; number: number; boolean: boolean;
123
+ DateTime: DateTime; DateOnly: DateOnly; Time: Time;
124
+ Uuid: Uuid; Bytes: Bytes;
125
+ };
126
+ type PrimitiveTypeStr = keyof PrimitiveTypeMap;
127
+ type PrimitiveType = PrimitiveTypeMap[PrimitiveTypeStr] | undefined;
128
+
129
+ type DeepPartial<T>; // 재귀 optional, 원시 타입 유지
130
+ interface Type<T> extends Function { new (...args: unknown[]): T; }
131
+ ```
@@ -8,5 +8,14 @@ Node.js 전용 유틸·기능 묶음. 파일 IO/glob, 경로 변환, 자식 프
8
8
  - **`pathx` 네임스페이스** — POSIX 경로 변환, 하위 경로 판정, 디렉토리 치환, target 필터링. 자세히: [pathx.md](./pathx.md)
9
9
  - **`cpx` 네임스페이스** — 시스템 인코딩 감지 + 자식 프로세스 spawn/spawnSync (인코딩 자동 디코딩, exitCode 기반 reject). 자세히: [cpx.md](./cpx.md)
10
10
  - **`FsWatcher`** — chokidar 기반 디바운스/이벤트 병합 + Windows EPERM 자동 복구 파일 감시. 자세히: [fs-watcher.md](./fs-watcher.md)
11
- - **`setupConsola` / `PrettyReporter` / `createFileReporter` / `withMaxLevel`** — Node 앱 consola 셋업, 컬러 콘솔/JSON 파일 회전 리포터. 자세히: [consola.md](./consola.md)
12
- - **`Worker` / `createWorker` / `WorkerProxy` / `WorkerModule` / `PromisifyMethods`** worker_threads 위 타입 안전 RPC 래퍼 (메서드 호출 + 이벤트 send/on). 자세히: [worker.md](./worker.md)
11
+ - **consola 셋업** — Node 앱 진입점에서 로깅 환경(콘솔/파일) 구성. 자세히: [consola.md](./consola.md)
12
+ - **`setupConsola`** 진입점 1회 호출. dev/prod·`SD_DEBUG`·`cli` 조합으로 리포터 자동 구성.
13
+ - **`PrettyReporter`** — 색상·아이콘·tag·stack/cause 정리 포함 콘솔 출력 리포터.
14
+ - **`createFileReporter`** — `<cwd>/.logs/app.<날짜>.log` JSON 회전 + 보존 기간 정리.
15
+ - **`withMaxLevel`** — 기존 리포터에 level 상한 필터 씌우기 (dev 콘솔에서 debug 가리기 등).
16
+ - **Worker 래퍼** — worker_threads 위 타입 안전 RPC (메서드 호출 + 이벤트 + 워커 stdout 메인 전달). 자세히: [worker.md](./worker.md)
17
+ - **`Worker.create`** — 메인 측. 워커 파일을 띄우고 메서드 직접 호출 가능한 Proxy 반환.
18
+ - **`createWorker`** — 워커 측. `methods` 등록 + `send(event, data)` 로 이벤트 발행. `export default` 필수.
19
+ - **`WorkerProxy<TModule>`** — `Worker.create` 반환 타입. 워커 모듈 타입 추론에 사용.
20
+ - **`WorkerModule`** — 워커 default export 의 구조 인터페이스 (`__methods`/`__events`). 직접 구현 불필요.
21
+ - **`PromisifyMethods<T>`** — 메서드 반환을 `Promise<Awaited<R>>` 로 감싸는 매핑 타입. `WorkerProxy` 내부 사용.
@@ -4,11 +4,25 @@ OOXML(xlsx) 워크북을 lazy-load 로 읽고 쓰는 클래스 묶음. ZIP 내
4
4
 
5
5
  ## 사용 트리거 인덱스
6
6
  - **`ExcelWorkbook`** — xlsx 바이트/Blob 을 열거나 새 워크북을 만들 때. 사용 후 `close()` 필수.
7
- - **`ExcelWorksheet`** — 시트 단위로 셀/행/열 접근, 데이터테이블 입출력, 틀 고정/줌, 조건부 서식, 이미지 삽입.
8
- - **`ExcelCell` / `ExcelRow` / `ExcelCol`** — 단일 값·수식·스타일·병합, 행/열 전체 일괄 접근, 너비.
7
+ - **`ExcelWorkbook.setDefaultStyle`** — 워크북 전역(폰트·정렬·numFmt 등) 표준을 한번에 적용.
8
+ - **`ExcelWorksheet`** — 시트 단위접근의 진입점. 이름·범위 조회.
9
+ - **`getDataTable` / `setDataMatrix` / `setRecords`** — 시트와 레코드 배열(또는 2D 매트릭스) 간 입출력.
10
+ - **`copyCell` / `copyRow` / `copyCellStyle` / `copyRowStyle` / `insertCopyRow`** — 셀/행 복제·삽입(템플릿 시트 채울 때).
11
+ - **`setZoom` / `freezeAt`** — 시트 뷰 보기 설정(확대·틀 고정).
12
+ - **`setTabColor`** — 시트 탭 색 ARGB 지정.
13
+ - **`addConditionalFormat`** — 셀/범위에 조건부 서식 규칙 적용.
14
+ - **`addImage`** — 시트에 이미지(png/jpg 등) 삽입.
15
+ - **`ExcelCell`** — 단일 셀의 값·수식·스타일·병합.
16
+ - **`ExcelRow`** — 행 단위 셀 일괄 접근.
17
+ - **`ExcelCol`** — 열 단위 셀 접근 + 열 너비 설정.
9
18
  - **`ExcelWrapper`** — Zod 스키마로 헤더·타입을 정의해 레코드 배열로 read/write.
10
19
  - **`ExcelUtils`** — `"A1"`↔좌표, 범위 주소, Excel 직렬 날짜 ↔ 타임스탬프, numFmt 변환.
11
- - **타입 (`ExcelValueType`, `ExcelStyleOptions`, `ExcelFont`, `ExcelConditionalRule` 등)** 입력 옵션·반환값 정의.
20
+ - **`ExcelValueType`** 셀에 넣고 있는 값의 union (number/string/boolean/DateOnly/DateTime/Time/undefined).
21
+ - **`ExcelStyleOptions`** — `setStyle` / `setDefaultStyle` 입력 옵션 (배경·테두리·정렬·numFmt·폰트).
22
+ - **`ExcelFont`** — `ExcelStyleOptions.font` 의 폰트 속성(크기·family·bold·italic·underline·color·strike).
23
+ - **`ExcelConditionalRule` / `ExcelConditionalRuleStyle`** — `addConditionalFormat` 의 규칙·강조 스타일 타입.
24
+ - **`ExcelAddressPoint` / `ExcelAddressRangePoint`** — 0 기반 좌표 / 범위 좌표.
25
+ - **`ExcelNumberFormat` / `ExcelBorderPosition` / `ExcelHorizontalAlign` / `ExcelVerticalAlign` / `ExcelFontUnderline`** — 스타일 옵션의 enum literal 들.
12
26
 
13
27
  ## ExcelWorkbook
14
28
  ```typescript
@@ -16,7 +30,7 @@ new ExcelWorkbook(arg?: Blob | Bytes)
16
30
  getWorksheetNames(): Promise<string[]>
17
31
  addWorksheet(name): Promise<ExcelWorksheet>
18
32
  getWorksheet(nameOrIndex: string | number): Promise<ExcelWorksheet> // 인덱스 0 기반
19
- setDefaultStyle(opts: ExcelStyleOptions): Promise<void> // cellXfs[0] 덮어쓰기
33
+ setDefaultStyle(opts: ExcelStyleOptions): Promise<void> // fonts[0]/fills[0]/borders[0] 덮어쓰기, 모든 셀에 전역 적용
20
34
  toBytes(): Promise<Bytes>
21
35
  toBlob(): Promise<Blob> // xlsx MIME
22
36
  close(): Promise<void> // 멱등, 이후 모든 메서드는 throw
@@ -34,7 +48,7 @@ getDataTable(opt?: { headerRowIndex?; checkEndColIndex?; usableHeaderNameFn? })
34
48
  setDataMatrix(matrix: ExcelValueType[][]) // 0,0 부터
35
49
  setRecords(records: Record<string, ExcelValueType>[]) // 첫 행 헤더 자동
36
50
  copyCell / copyRow / copyCellStyle / copyRowStyle / insertCopyRow
37
- setZoom(percent) / freezeAt({ r?, c? })
51
+ setZoom(percent) / freezeAt({ r?, c? }) / setTabColor(color) // color: ARGB 8자리
38
52
  addConditionalFormat({ ref, rules: ExcelConditionalRule[] }) // 호출마다 priority 누적
39
53
  addImage({ bytes, ext, from, to? }) // ext 는 mime lookup. to 생략 시 from+1,+1
40
54
  ```
@@ -6,6 +6,15 @@ Simplysm 컨벤션용 ESLint 플러그인 패키지. 커스텀 규칙 묶음(`./
6
6
 
7
7
  - **`./eslint-recommended` (default export)** — 프로젝트 `eslint.config.{js,mjs,cjs}` 에서 그대로 spread 해 simplysm 표준 lint 규칙을 적용할 때.
8
8
  - **`./eslint-plugin` (default export)** — recommended 를 사용하지 않고 개별 규칙만 골라 쓰거나, 다른 flat config 에서 `@simplysm/<rule>` 로 참조할 때.
9
+ - **`ng-no-async-effect`** — Angular `effect()` 콜백을 async 로 작성하지 않게 막을 때.
10
+ - **`ng-template-no-strict-null-check`** — Angular 템플릿에서 `=== null|undefined` 대신 `== null` 로 통일시킬 때.
11
+ - **`ng-template-no-todo-comments`** — Angular 템플릿 내 `<!-- TODO: ... -->` 를 빌드 경고로 남길 때.
12
+ - **`ng-template-sd-require-binding-attrs`** — `sd-*` 컴포넌트에 plain attribute 못 쓰게 하고 property binding 으로 강제할 때.
13
+ - **`no-hard-private`** — `#field` 대신 TypeScript `private _field` 스타일을 강제할 때.
14
+ - **`no-subpath-imports-from-simplysm`** — `@simplysm/<pkg>/src/...` 직접 import 를 차단할 때.
15
+ - **`ts-no-throw-not-implemented-error`** — `NotImplementedError` 잔존을 빌드 경고로 표면화할 때.
16
+ - **`ts-no-unused-injects`** — Angular `inject()` 로 받은 미사용 필드를 정리할 때.
17
+ - **`ts-no-unused-protected-readonly`** — Angular 컴포넌트 인라인 템플릿/클래스 어느 쪽에서도 안 쓰는 `protected readonly` 필드를 정리할 때.
9
18
 
10
19
  ## `./eslint-recommended`
11
20
 
@@ -9,16 +9,41 @@ Dialect 독립 ORM 코어. `DbContext` 상속으로 테이블/뷰/프로시저
9
9
  - **`Queryable` / `queryable()`** — `DbContext` 에 등록된 테이블/뷰에서 SELECT/INSERT/UPDATE/DELETE/UPSERT 빌더 체이닝, JOIN/include/recursive CTE/UNION/search 할 때. 자세히: [queryable.md](./queryable.md)
10
10
  - **`Executable` / `executable()`** — 등록된 프로시저 호출 결과 받을 때. 자세히: [executable.md](./executable.md)
11
11
  - **`expr` namespace + `ExprUnit`/`WhereExprUnit`** — `where`/`select`/`groupBy`/`having`/`update` 콜백 안에서 비교·논리·문자열·날짜·집계·윈도우·CASE·subquery 등 SQL 표현식 만들 때. dialect 독립 AST. 자세히: [expr.md](./expr.md)
12
- - **`parseSearchQuery(text)`** — `Queryable.search()` 내부에서 쓰는 OR/`+`AND/`-`NOT/`"…"`/`*` 구문 파서. 직접 LIKE 패턴이 필요할 때만 외부 사용.
13
- - **`QueryBuilder` (`createQueryBuilder(dialect)`, `QueryBuilderBase`, `ExprRendererBase`, `*QueryBuilder`, `*ExprRenderer`)** executor 측에서 `QueryDef` dialect SQL 렌더할 때. 응용 코드는 직접 호출 X.
14
- - **`QueryDef` 타입군 (`./types/query-def`)**executor·테스트에서 빌더가 만든 AST 직접 다룰 때. `QueryDef`, `SelectQueryDef`, `InsertQueryDef`, ..., `QueryDefObjectName`, `DDL_TYPES`, `DdlType`.
15
- - **`Expr` 타입군 (`./types/expr`)**Expr AST 노드 타입(`ExprColumn`/`ExprValue`/`ExprRaw`/`ExprEq`/...`ExprWindow`/`ExprSubquery`). `DateUnit`. ExprRenderer 구현·검사에서 사용.
16
- - **`DataType` / `ColumnPrimitive*` (`./types/column`)** — SQL DataType union(`int`/`bigint`/`varchar`/`datetime`/`uuid`/...) TS 타입 매핑(`ColumnPrimitiveMap`/`ColumnPrimitiveStr`/`ColumnPrimitive`/`ColumnMeta`). `dataTypeStrToColumnPrimitiveStr` 상수, `InferColumnPrimitiveFromDataType<T>` / `inferColumnPrimitiveStr(value)` 런타임 추론.
17
- - **`Dialect` / `dialects` / `DataRecord` / `DbContextExecutor` / `ResultMeta` / `IsolationLevel` / `Migration` / `QueryBuildResult` (`./types/db`)**executor 구현·DbContext 외부 인터페이스. `Migration[]` DbContext 서브클래스의 `migrations` 프로퍼티로 오버라이드해 `initialize()` 에서 적용.
18
- - **`DbContextBase` / `DbContextStatus` / `DbContextDdlMethods` (`./types/db-context-def`)** — 외부에서 DbContext인터페이스로 다룰 때 (Queryable/Executable/ViewBuilder 의존).
19
- - **`DbTransactionError` / `DbErrorCode`**executor트랜잭션 에러를 표준화해 throw, 호출측은 `instanceof` 분기. 코드: `NO_ACTIVE_TRANSACTION`, `TRANSACTION_ALREADY_STARTED`, `DEADLOCK`, `LOCK_TIMEOUT`.
20
- - **`parseResults(rows, meta)` / `pickResultSets(rawResults, buildResult)` (`./utils/*`)** — executor raw 결과 가공. `parseResults` flat row 중첩 객체(JOIN 그룹핑 + 타입 파싱). `pickResultSets(raw, { resultSetIndex, resultSetStride })` 는 다중 결과 셋에서 필요한 셋만 추출 (예: MySQL 배치 INSERT 의 OUTPUT SELECT).
21
- - **`_Migration` / `SD_BUILDER`** 내부용. `_Migration` `_migration(code PK)` 시스템 테이블, `SD_BUILDER` 는 `queryable()`/`executable()` 팩토리 함수에 붙는 메타 심볼 (`initialize()` DbContext 프로퍼티에서 builder 회수할 사용).
12
+ - **`parseSearchQuery(text)`** — `Queryable.search()` 내부에서 쓰는 OR/`+`AND/`-`NOT/`"…"`/`*` 구문 파서. 직접 LIKE 패턴이 필요할 때만 외부 사용. (`ParsedSearchQuery` = `{ or, must, not }`)
13
+ - **`createQueryBuilder(dialect)`** — `Dialect` 문자열로 dialect QueryBuilder 인스턴스 받을 (executor 진입점).
14
+ - **`QueryBuilderBase` / `ExprRendererBase`**커스텀 dialect 구현을 위해 상속 베이스 필요할 때.
15
+ - **`MysqlQueryBuilder` / `MssqlQueryBuilder` / `PostgresqlQueryBuilder`** (와 대응 `*ExprRenderer`) — 특정 dialect 인스턴스를 직접 new 하거나 `instanceof` 분기할 때. 일반은 `createQueryBuilder` 사용.
16
+ - **`QueryDef` (union) + `QueryDefObjectName` (`./types/query-def`)** — executor 받는 query AST 의 union 타입 / 모든 DDL/DML 이 공통으로 쓰는 `{database?, schema?, name}` 형태의 DB 객체 식별자.
17
+ - **`SelectQueryDef`, `InsertQueryDef`, `InsertIfNotExistsQueryDef`, `InsertIntoQueryDef`, `UpdateQueryDef`, `DeleteQueryDef`, `UpsertQueryDef`, `SelectQueryDefJoin`, `CudOutputDef`**DML AST 노드를 직접 만들거나 검사할 (executor·테스트).
18
+ - **DDL QueryDef (`Create*` / `Drop*` / `Rename*` / `Add*` / `Modify*` / `Truncate*` / `Clear*` / `Schema*` / `ExecProc*` 등)** — 스키마 변경/프로시저 호출 AST 직접 다룰 때 (`getXxxQueryDef()` 반환 타입과 일치).
19
+ - **`DDL_TYPES` (배열) / `DdlType` (union)** queryDDL 인지 런타임/타입 레벨에서 검사할 때. 트랜잭션 DDL 차단 가드에서 사용.
20
+ - **`Expr` (union) / `WhereExpr` (union)** — SELECT·ORDER BY·SET 콜백이 모두 받는 일반 표현식 AST 와, WHERE·HAVING 전용 boolean 표현식 AST. ExprRenderer dispatch 하는 대상.
21
+ - **개별 Expr 노드 (`ExprColumn`, `ExprValue`, `ExprRaw`, `ExprEq`, `ExprLike`, `ExprConcat`, `ExprDateDiff`, `ExprSwitch`, `ExprCount`, `ExprWindow`, `ExprSubquery` )** Expr renderer 구현, AST 검사, 디버깅 개별 노드 타입 필요할 때. 응용 코드는 `expr.*` 헬퍼만 사용.
22
+ - **`WinFn` (union) / `WinSpec` / `WinFn*` 개별 노드** — Window 함수 AST 분기 (`rowNumber`, `rank`, `lag`, `sumOver` 등) 를 직접 처리할 때.
23
+ - **`DateUnit`** — `dateDiff`/`dateAdd` 의 단위 union (`"year" | "month" | "day" | "hour" | "minute" | "second"`). 동적으로 단위 선택할 때.
24
+ - **`DataType` (`./types/column`)** — SQL 타입 union (`{type:"int"}` / `{type:"varchar",length}` / `{type:"decimal",precision,scale?}` ...). DDL/cast 의 타입 인자.
25
+ - **`ColumnPrimitive` / `ColumnPrimitiveStr` / `ColumnPrimitiveMap`** — Column 값으로 허용되는 TS 타입 union (`string|number|boolean|DateTime|DateOnly|Time|Uuid|Bytes|undefined`), 그 키 이름 union, 키→타입 매핑. ExprUnit/ResultMeta 가 사용.
26
+ - **`ColumnMeta`** — `ColumnBuilder.meta` 의 형태 (`{type, dataType, autoIncrement?, nullable?, default?, description?}`). 외부에서 column 정의를 읽어 DDL 만들 때.
27
+ - **`dataTypeStrToColumnPrimitiveStr`** — `DataType.type` → `ColumnPrimitiveStr` 상수 매핑. cast 결과 dataType 추론에 사용.
28
+ - **`InferColumnPrimitiveFromDataType<T>`** — `DataType` 타입에서 TS 값 타입 추론 (제네릭 타입 유틸).
29
+ - **`inferColumnPrimitiveStr(value)`** — 런타임 값에서 `ColumnPrimitiveStr` 추론. NULL/unknown 이면 throw.
30
+ - **`Dialect`** — `"mysql" | "mssql" | "postgresql"` union. dialect 분기/`createQueryBuilder` 인자.
31
+ - **`dialects`** — `Dialect[]` 상수 배열. 테스트의 `it.each(dialects)` 또는 모든 dialect 순회용.
32
+ - **`DataRecord`** — query 결과 row 의 재귀 타입 (`{ [key]: ColumnPrimitive | DataRecord | DataRecord[] }`). Queryable/Executable 의 결과 제약.
33
+ - **`DbContextExecutor`** — 외부에서 DbContext 에 주입할 executor 인터페이스 (`connect`/`close`/`beginTransaction`/`commitTransaction`/`rollbackTransaction`/`executeDefs`). 신규 dialect/원격 executor 구현 시.
34
+ - **`ResultMeta`** — `executeDefs` 가 받는 `{columns: Record<string,ColumnPrimitiveStr>, joins: Record<string,{isSingle}>}`. raw row → 타입 변환·JOIN 그룹핑에 필요.
35
+ - **`IsolationLevel`** — `"READ_UNCOMMITTED" | "READ_COMMITTED" | "REPEATABLE_READ" | "SERIALIZABLE"`. `connect`/`transaction` 인자.
36
+ - **`Migration`** — `{name, up(db)}`. DbContext 서브클래스의 `migrations` 프로퍼티 타입. `initialize()` 가 적용.
37
+ - **`QueryBuildResult`** — `QueryBuilder.build()` 반환 (`{sql, resultSetIndex?, resultSetStride?}`). executor 가 `pickResultSets` 로 좁힐 때 필요.
38
+ - **`DbContextBase` (`./types/db-context-def`)** — DbContext 의 코어 인터페이스 (`status`/`database`/`schema`/`executeDefs`/`getNextAlias` 등). Queryable·Executable·ViewBuilder 가 의존하므로 mock/대체 구현 시 사용.
39
+ - **`DbContextStatus`** — `"ready" | "connect" | "transact"`. status 분기 시.
40
+ - **`DbContextDdlMethods`** — `createTable`/`addColumn`/`addForeignKey` 등 DDL 메서드 집합 인터페이스. `Migration.up` 의 db 인자 타입.
41
+ - **`DbTransactionError`** — executor 가 트랜잭션 에러를 표준화해 throw 하는 클래스. 호출측은 `instanceof DbTransactionError` 로 분기.
42
+ - **`DbErrorCode`** — `NO_ACTIVE_TRANSACTION` / `TRANSACTION_ALREADY_STARTED` / `DEADLOCK` / `LOCK_TIMEOUT` enum. `err.code === DbErrorCode.DEADLOCK` 같은 분기에 사용.
43
+ - **`parseQueryResult(rows, meta)` (`./utils/result-parser`)** — flat row 배열 + `ResultMeta` → 타입 변환 + JOIN 그룹핑된 중첩 객체 배열. async. 빈 결과면 undefined. executor 가 SELECT/OUTPUT 결과를 사용자 객체로 가공할 때.
44
+ - **`pickResultSets(rawResults, buildResult)` (`./utils/pick-result-sets`)** — `QueryBuildResult` 의 `resultSetIndex`/`resultSetStride` 따라 여러 결과 셋 중 필요한 셋만 추출/concat. MySQL 배치 INSERT 의 OUTPUT SELECT 만 모을 때.
45
+ - **`_Migration`** — `_migration(code PK varchar(255))` 시스템 테이블의 TableBuilder. DbContext 가 자동 등록, 사용자 직접 import 불필요.
46
+ - **`SD_BUILDER`** — `queryable()`/`executable()` 팩토리 함수에 builder 를 부착하는 심볼. `initialize()` 가 DbContext 의 프로퍼티에서 builder 를 회수할 때 사용. 사용자 코드 직접 사용 X.
22
47
 
23
48
  ## QueryBuilder (인라인)
24
49
 
@@ -4,13 +4,23 @@ Node.js 환경에서 `@simplysm/orm-common` 의 `DbContext` 를 실제 DB(MSSQL/
4
4
 
5
5
  ## 사용 트리거 인덱스
6
6
 
7
- - **`createOrm` / `Orm` / `OrmOptions`** — `DbContext` 서브클래스 + `DbConnConfig` 로 ORM 인스턴스를 만들고, 트랜잭션 유/무 콜백을 실행한다. 일반 ORM 사용의 진입점.
8
- - **`createDbConn`** — `DbConnConfig` 만으로 저수준 `DbConn` 인스턴스를 직접 만든다. `DbContext` 없이 raw SQL/bulk insert 필요할 때.
7
+ - **`createOrm`** — `DbContext` 서브클래스 + `DbConnConfig` 로 ORM 인스턴스 생성. 일반 ORM 사용의 진입점.
8
+ - **`Orm<T>`** — `createOrm` 반환 타입. 함수 시그니처·DI 토큰에서 참조하거나 `connect` / `connectWithoutTransaction` 호출 시.
9
+ - **`OrmOptions`** — `createOrm` 3번째 인자. `DbConnConfig` 의 `database` / `schema` 를 런타임에 덮어쓸 때.
10
+ - **`createDbConn`** — `DbConnConfig` 만으로 저수준 `DbConn` 인스턴스 직접 생성. `DbContext` 없이 raw SQL/bulk insert 가 필요할 때.
9
11
  - **`NodeDbContextExecutor`** — `DbContext` 의 executor 직접 주입이 필요할 때. 일반적으로는 `createOrm` 이 내부적으로 사용.
10
- - **`MysqlDbConn` / `MssqlDbConn` / `PostgresqlDbConn`** — dialect별 `DbConn` 구현. 직접 `new` 하지 말고 `createDbConn` 사용. 타입 참조용으로만 import.
11
- - **`DbConn` / `DbConnConfig` (+ `MysqlDbConnConfig` / `MssqlDbConnConfig` / `PostgresqlDbConnConfig`)** 설정/연결 타입. 함수 시그니처·DI 토큰 등에서 참조.
12
+ - **`MysqlDbConn`** — MySQL `DbConn` 구현 클래스. 직접 `new` 하지 말고 `createDbConn` 사용. 타입 참조용 import.
13
+ - **`MssqlDbConn`** — MSSQL/Azure SQL `DbConn` 구현 클래스. 직접 `new` 하지 말고 `createDbConn` 사용. 타입 참조용 import.
14
+ - **`PostgresqlDbConn`** — PostgreSQL 용 `DbConn` 구현 클래스. 직접 `new` 하지 말고 `createDbConn` 사용. 타입 참조용 import.
15
+ - **`DbConn`** — 저수준 연결 인터페이스. 모든 dialect 공통 메서드(`connect`/`close`/트랜잭션/`execute`/`executeParametrized`/`bulkInsert`) 와 `close` 이벤트.
16
+ - **`DbConnConfig`** — dialect 분기 union 타입. `createOrm`/`createDbConn` 입력.
17
+ - **`MysqlDbConnConfig`** — `dialect: "mysql"` 한정 설정 타입.
18
+ - **`MssqlDbConnConfig`** — `dialect: "mssql" | "mssql-azure"` 설정 타입. `schema?` 포함.
19
+ - **`PostgresqlDbConnConfig`** — `dialect: "postgresql"` 설정 타입. `schema?` 포함.
12
20
  - **`getDialectFromConfig`** — `DbConnConfig` → `Dialect` 변환(`mssql-azure` → `mssql`). 쿼리 빌더 선택 시.
13
- - **`DB_CONN_CONNECT_TIMEOUT` (10s) / `DB_CONN_DEFAULT_TIMEOUT` (10m) / `DB_CONN_ERRORS`** — 타임아웃·에러 메시지 상수.
21
+ - **`DB_CONN_CONNECT_TIMEOUT`** DB 연결 수립 타임아웃 상수 (10초).
22
+ - **`DB_CONN_DEFAULT_TIMEOUT`** — 쿼리/유휴 기본 타임아웃 상수 (10분).
23
+ - **`DB_CONN_ERRORS`** — `NOT_CONNECTED` / `ALREADY_CONNECTED` 에러 메시지 리터럴.
14
24
 
15
25
  ## createOrm
16
26
 
@@ -4,6 +4,6 @@ Claude Code 셋업 자산(`.claude/` 의 sd-* 스킬·룰·훅) 배포 및 `sd-c
4
4
 
5
5
  코드 API 없음 (npm 배포용). 외부에서 import 할 수 있는 라이브러리 심볼은 노출하지 않는다.
6
6
 
7
- - `bin`: `sd-claude` — `auth save` / `auth switch` (저장된 Claude 계정 전환).
8
- - `postinstall`: 설치 시 사용자 `~/.claude/` 로 자산 동기화.
9
- - `prepack`: 배포 전 `.claude/` → `packages/sd-claude/claude/` 증분 복사.
7
+ - `bin`: `sd-claude` — `auth save` (현재 Claude 계정 저장) / `auth switch` (저장된 계정 목록에서 선택해 전환).
8
+ - `postinstall`: 패키지 설치 시 `claude/` 의 sd-\* 에셋을 소비 프로젝트 루트의 `.claude/` 로 복사 (기존 sd-\* 항목은 정리 후 재복사, `settings.json`·`simplysm.json` 포함).
9
+ - `prepack`: 배포 전 워크스페이스의 `.claude/` → `packages/sd-claude/claude/` 증분 복사 (mtime+size 비교, `evals/`·`SKILL.eval.md`·`eval_*` 제외).
@@ -1,14 +1,44 @@
1
1
  # @simplysm/sd-cli
2
2
 
3
- 워크스페이스 빌드/배포 오케스트레이터. 라이브러리 export `sd.config.ts` 작성용 타입과 Vitest Angular 플러그인, 그리고 외부 도구가 재사용할 `SdTsCompiler` 다. CLI 서브커맨드는 이 문서 대상 아님 (`pnpm sd-cli --help`).
3
+ 워크스페이스 빌드/배포 오케스트레이터. 소비 표면은 갈래다 — `pnpm sd-cli <cmd>` 서브커맨드와 `sd.config.ts` 작성용 타입. 라이브러리 export 로는 Vitest Angular 플러그인과 외부 도구가 재사용할 `SdTsCompiler` 노출한다.
4
4
 
5
5
  ## 사용 트리거 인덱스
6
- - **`SdConfigFn` / `SdConfig` / `SdConfigParams`** — `sd.config.ts` 의 default export 타이핑. 자세히: [sd-config.md](./sd-config.md)
7
- - **패키지별 설정 타입 (`SdBuildPackageConfig`, `SdClientPackageConfig`, `SdServerPackageConfig`, `SdScriptsPackageConfig`)** — `SdConfig.packages` 값 타이핑. 자세히: [sd-config.md](./sd-config.md)
8
- - **`SdPublishConfig` / `SdPostPublishScriptConfig`** — `publish`·`postPublish` 항목 타이핑. 자세히: [sd-config.md](./sd-config.md)
9
- - **`SdCapacitorConfig` / `SdElectronConfig` / `SdPwaConfig` / `SdBrowserSupportConfig`** 클라이언트 패키지의 모바일/데스크톱/PWA/브라우저 지원 옵션. 자세히: [sd-config.md](./sd-config.md)
10
- - **`sdAngularPlugin(options)`** — Vitest `vite.config` (또는 `vitest.config`) 에서 Angular 패키지 AOT 컴파일이 필요할 때 plugin 으로 추가.
11
- - **`SdTsCompiler` (+ `ISdTsCompilerOptions`, `ISdTsCompilerResult`)** 사용자 코드에서 직접 호출할 일은 거의 없음. Angular/Non-Angular TS 패키지를 증분 컴파일·진단·lint·SCSS 통합 처리하는 엔진. `sd-cli` 내부 엔진(`engines/`, `orchestrators/`) `sdAngularPlugin` 에서 사용. 외부에서 동일한 엔진을 재사용해야 할 때만 직접 import.
6
+
7
+ ### 서브커맨드 (`pnpm sd-cli <cmd>`)
8
+
9
+ - **`check`** 타입체크와 lint 병렬 실행. 일반 검증 명령으로 가장 자주 호출됨.
10
+ - **`watch`** — 워크스페이스 전체 또는 일부 패키지를 watch 모드로 증분 빌드.
11
+ - **`dev`**server 패키지를 dev 모드로 실행 (`tsx` 핫리로드 + client 패키지의 dev http 서버 동반 기동).
12
+ - **`device`** — client 패키지를 안드로이드 디바이스 또는 Electron 데스크톱에서 실행. dev 서버가 떠 있어야 함.
13
+ - **`build`** — 프로덕션 빌드. `sd.config.ts` 의 `packages` 전 항목 또는 `-t` 지정 항목.
14
+ - **`publish`** — 빌드 후 `publish` 설정을 따라 배포 (npm / 로컬 디렉토리 / FTP·SFTP). `--no-build` 로 기존 산출물만 배포.
15
+ - **`replace-deps`** — `sd.config.ts.replaceDeps` 에 따라 `node_modules` 패키지를 로컬 소스로 심링크 교체.
16
+ - **`init`** — 인터랙티브 프롬프트로 SI 워크스페이스 골격 생성.
17
+
18
+ 공통 옵션:
19
+ - `-t / --target <pkg>` (반복 가능) — 대상 패키지. `sd.config.ts.packages` 키 (= `@simplysm/` 접두사 **제외**한 짧은 이름). 미지정 시 전체.
20
+ - `-o / --opt <val>` (반복 가능) — `sd.config.ts` 함수의 `params.opt[]` 로 전달. `check` 와 `init` 제외 전 커맨드에서 지원.
21
+ - `--debug` — 디버그 로그 출력 (모든 커맨드).
22
+ - `--help / -h` — 단독 호출 시 모든 서브커맨드 종합 도움말.
23
+
24
+ 커맨드별 고유 옵션:
25
+ - `check`: `--type typecheck|lint` (반복 가능, 기본 둘 다), `--fix` (lint 자동 수정).
26
+ - `device`: `--target <pkg>` (단수, 미지정 시 유일 client 자동 선택), `--url <devServerUrl>` (미지정 시 `sd.config.ts` 의 server 설정에서 자동 도출).
27
+ - `publish`: `--no-build` (빌드 생략), `--dry-run` (실제 배포 없이 시뮬레이션).
28
+
29
+ 진실 근거: `packages/sd-cli/src/sd-cli-entry.ts` (yargs 등록부), `packages/sd-cli/src/commands/<cmd>.ts`.
30
+
31
+ ### 설정 타입 (`sd.config.ts`)
32
+
33
+ - **`SdConfigFn` / `SdConfig` / `SdConfigParams`** — `sd.config.ts` 의 default export 함수와 그 반환 타입. 자세히: [sd-config.md](./sd-config.md)
34
+ - **`SdBuildPackageConfig` / `SdClientPackageConfig` / `SdServerPackageConfig` / `SdScriptsPackageConfig`** — `SdConfig.packages` 의 값 타입. 각각 라이브러리 / Frontend 앱 / Fastify 서버 / 유틸 패키지에 대응. 자세히: [sd-config.md](./sd-config.md)
35
+ - **`SdPublishConfig` / `SdPostPublishScriptConfig`** — 패키지의 `publish` 와 전역 `postPublish` 항목 타입. 자세히: [sd-config.md](./sd-config.md)
36
+ - **`SdCapacitorConfig` / `SdElectronConfig` / `SdPwaConfig` / `SdBrowserSupportConfig`** — client 패키지의 모바일·데스크톱·PWA·브라우저 지원 옵션. 자세히: [sd-config.md](./sd-config.md)
37
+
38
+ ### 라이브러리 export
39
+
40
+ - **`sdAngularPlugin(options)`** — Vitest 의 `vite.config` / `vitest.config` 에서 Angular 패키지 AOT 컴파일이 필요할 때 plugin 으로 추가.
41
+ - **`SdTsCompiler` (+ `ISdTsCompilerOptions`, `ISdTsCompilerResult`)** — Angular/Non-Angular TS 패키지를 증분 컴파일·진단·lint·SCSS 통합 처리하는 엔진. `sd-cli` 내부와 `sdAngularPlugin` 이 사용. 외부에서 동일한 엔진을 재사용할 때만 직접 import.
12
42
 
13
43
  ## sdAngularPlugin
14
44
 
@@ -3,28 +3,33 @@
3
3
  `@simplysm/service-server` 와 WebSocket 으로 통신하는 클라이언트. RPC 호출·이벤트 구독·파일 업/다운로드·원격 ORM 실행을 단일 `ServiceClient` 에서 제공한다 (Node/브라우저 공용).
4
4
 
5
5
  ## 사용 트리거 인덱스
6
- - **createServiceClient / ServiceConnectionOptions** — 클라이언트 인스턴스 생성·서버 접속/종료할 때.
7
- - **getService / send / ServiceProxy** — 서버 서비스 메서드를 타입 안전 RPC호출할 때.
8
- - **auth** — 서버 인증 토큰을 등록하고 재연결 자동 재인증되게 때.
9
- - **getEvent / addListener / removeListener / emitEvent** — 서버 사이드 이벤트 구독 또는 다른 클라이언트로 이벤트 발행할 때.
10
- - **uploadFile / downloadFileBuffer** — 서버에 파일을 올리거나 정적 경로에서 바이트로 받을 때.
11
- - **createOrmClientConnector / OrmConnectOptions** — 서버의 ORM 서비스를 통해 DbContext 트랜잭션을 원격 실행할 때.
12
- - **ServiceClient 이벤트 (`state`, `request-progress`, `response-progress`, `server-progress`)** 연결 상태와 전송/응답/서버 진행률을 구독할 때.
6
+
7
+ - **createServiceClient / ServiceConnectionOptions** — 서버 접속용 `ServiceClient` 만들고 `connect()`/`close()`연결을 열고 닫을 때.
8
+ - **getService / send / ServiceProxy** — 서버에 등록된 서비스의 메서드를 타입 안전 RPC 호출할 때 (Proxy 기반 메서드 호출 또는 저수준 `send`).
9
+ - **auth** — 서버 인증 토큰을 등록하고 재연결 자동 재인증되도록 토큰을 내부에 보관할 때.
10
+ - **getEvent / addListener / removeListener / emitEvent** — 서버 push 이벤트를 구독·해지하거나, 다른 클라이언트에게 이벤트를 발행할 때.
11
+ - **uploadFile / downloadFileBuffer** — 서버에 multipart 파일을 올리거나 정적 경로에서 바이트(`Uint8Array`)로 받을 때.
12
+ - **createOrmClientConnector / OrmConnectOptions** 서버 `"Orm"` 서비스를 통해 `DbContext` 트랜잭션을 원격 실행할 때.
13
+ - **ServiceClient 이벤트 (`state` / `request-progress` / `response-progress` / `server-progress`)** — 연결 상태 변화와 전송/응답/서버 진행률을 인스턴스 레벨에서 구독할 때.
14
+ - **BlobInput / FileCollection / isWorkerSupported 외** — Node/브라우저 양쪽 환경에서 동일한 코드를 쓰기 위해 DOM 의존 타입을 대체하거나 Worker 지원 여부를 미리 확인할 때.
13
15
 
14
16
  ## 연결/생성
17
+
15
18
  ```ts
16
19
  createServiceClient(name: string, options: ServiceConnectionOptions): ServiceClient
17
20
  interface ServiceConnectionOptions { port: number; host: string; ssl?: boolean; maxReconnectCount?: number; }
18
21
  client.connect(): Promise<void>
19
- client.close(): Promise<void>
22
+ client.close(): Promise<void> // protocol wrapper 의 worker 자원도 dispose
20
23
  client.connected: boolean
21
- client.hostUrl: string // `${ssl?https:http}://host:port`
24
+ client.hostUrl: string // `${ssl?https:http}://host:port`
22
25
  ```
23
- - WebSocket URL 은 `${ws|wss}://host:port/ws` 로 고정.
26
+
27
+ - WebSocket URL 은 `${ws|wss}://host:port/ws?ver=2&clientId=<uuid>&clientName=<name>` 으로 접속한다.
24
28
  - `maxReconnectCount` 기본 10, `0` 이면 재연결 비활성.
25
- - 5s ping / 30s 무응답 시 강제 재연결, 재연결 성공 시 인증 토큰과 이벤트 리스너가 자동 복구됨.
29
+ - 5s 마다 ping, 30s 무응답 시 강제 재연결. 재연결 성공 시 인증 토큰(`auth()`)과 이벤트 리스너(`addListener`)가 자동 복구된다.
26
30
 
27
31
  ## RPC 호출
32
+
28
33
  ```ts
29
34
  client.getService<TService>(serviceName): ServiceProxy<TService>
30
35
  client.send(serviceName, methodName, params, progress?): Promise<unknown>
@@ -32,18 +37,25 @@ type ServiceProxy<T> = { [K in keyof T]: T[K] extends (...a:infer P)=>infer R ?
32
37
  interface ServiceProgress { request?(s); response?(s); server?(s); }
33
38
  interface ServiceProgressState { uuid: string; totalSize: number; completedSize: number; }
34
39
  ```
35
- - `getService` 는 Proxy 라 임의 메서드명 호출 가능. 타입은 `TService` 로만 보장됨.
36
- - 메시지 이름은 `"<serviceName>.<methodName>"` 으로 전송.
37
- - 30KB 초과 또는 `Uint8Array`/큰 배열 페이로드는 Worker 에서 인코딩/디코딩.
40
+
41
+ - `getService` Proxy 라 임의 메서드명 호출 가능. 타입은 `TService` 로만 보장된다.
42
+ - 와이어 메시지 이름은 `"<serviceName>.<methodName>"`.
43
+ - 인코딩/디코딩의 Worker 오프로딩 임계값:
44
+ - **인코드**: body 가 `Uint8Array`, 30KB 초과 문자열, 길이 100 초과 배열, 또는 첫 요소가 `Uint8Array` 인 배열일 때 Worker 사용.
45
+ - **디코드**: 수신 바이트가 30KB 초과일 때 Worker 사용.
46
+ - Worker 미지원 환경(또는 초기화 실패)에선 메인 스레드 fallback.
38
47
 
39
48
  ## 인증
49
+
40
50
  ```ts
41
51
  client.auth(token: string): Promise<void>
42
52
  ```
53
+
43
54
  - 서버에 `auth` 메시지를 보내고 토큰을 내부 저장. 재연결 시 자동으로 같은 토큰으로 재인증.
44
- - `uploadFile` 은 인증 토큰이 없으면 에러를 던짐.
55
+ - `uploadFile` 은 인증 토큰이 없으면 에러를 던진다.
45
56
 
46
57
  ## 이벤트 (서버 push)
58
+
47
59
  ```ts
48
60
  client.getEvent<TEventDef>(eventName): ClientEventProxy<TEventDef>
49
61
  client.addListener<TEventDef>(eventName, info, cb): Promise<string> // key 반환
@@ -51,22 +63,26 @@ client.removeListener(key): Promise<void>
51
63
  client.emitEvent<TEventDef>(eventName, infoSelector, data): Promise<void>
52
64
  interface ClientEventProxy<T> { addListener(info, cb): Promise<string>; removeListener(key): Promise<void>; emit(infoSelector, data): Promise<void>; }
53
65
  ```
54
- - `addListener` 는 연결 상태에서만 가능. 로컬 맵에도 보관해 재연결 시 자동 재구독.
55
- - `emitEvent` 는 서버에 `evt:gets` 후보를 받아 `infoSelector` 통과분에만 `evt:emit` 호출.
56
- - 핸들러 내부 에러는 로깅만 되고 다른 핸들러 호출은 계속됨.
66
+
67
+ - `addListener` 는 연결 상태에서만 호출 가능 (`!connected` throw). 로컬 맵에도 보관해 재연결 시 자동 재구독.
68
+ - `emitEvent` 서버에 `evt:gets` 후보를 받아 `infoSelector` 통과분에만 `evt:emit` 호출. 대상이 0건이면 emit 생략.
69
+ - 핸들러 내부 에러는 로깅만 되고 다른 핸들러 호출은 계속 진행.
57
70
 
58
71
  ## 파일 업/다운로드
72
+
59
73
  ```ts
60
74
  client.uploadFile(files: File[] | FileCollection | { name: string; data: BlobInput }[]): Promise<ServiceUploadResult[]>
61
75
  client.downloadFileBuffer(relPath: string): Promise<Uint8Array>
62
76
  type BlobInput = Blob | Uint8Array<ArrayBuffer> | ArrayBuffer | string
63
77
  interface FileCollection { length; item(i); [i]; [Symbol.iterator]() } // 브라우저 FileList 호환
64
78
  ```
79
+
65
80
  - 업로드: `POST {hostUrl}/upload` (multipart). 헤더 `x-sd-client-name`, `Authorization: Bearer <token>`. 인증 필수.
66
- - 다운로드: `GET {hostUrl}/{relPath}` 의 응답 본문을 `Uint8Array` 로 반환.
81
+ - 다운로드: `GET {hostUrl}/{relPath}` 의 응답 본문을 `Uint8Array` 로 반환. `relPath` 가 `/` 로 시작하지 않으면 자동으로 붙임.
67
82
  - 브라우저 전용 `File`/`FileList` 대신 `BlobInput`/`FileCollection` 으로 Node 환경도 지원.
68
83
 
69
84
  ## ORM 클라이언트
85
+
70
86
  ```ts
71
87
  createOrmClientConnector(client: ServiceClient): OrmClientConnector
72
88
  interface OrmConnectOptions<T extends DbContext> {
@@ -77,16 +93,32 @@ interface OrmConnectOptions<T extends DbContext> {
77
93
  connector.connect(config, async db => ...) // 트랜잭션 래핑
78
94
  connector.connectWithoutTransaction(config, async db => ...)
79
95
  ```
80
- - 서버의 `"Orm"` 서비스에 RPC 를 걸어 `getInfo` → `connect` → `executeDefs` 등을 실행.
81
- - `dbContextOpt` 생략 서버가 알려준 `database`/`schema` 사용. 비면 에러.
82
- - 외래키 참조 위반 에러(`a parent row: a foreign key constraint` / `conflicted with the REFERENCE`)는 사용자 메시지로 변환되어 throw.
96
+
97
+ - 서버의 `"Orm"` 서비스에 RPC 걸어 `getInfo` `connect` `executeDefs`/`executeParametrized`/`bulkInsert` 등을 실행.
98
+ - `dbContextOpt` 생략 서버가 알려준 `database`/`schema` 사용. 최종 `database` 값이면 에러.
99
+ - 외래키 참조 위반 에러(`a parent row: a foreign key constraint` / `conflicted with the REFERENCE`)는 "경고! 연관된 작업으로 인해 작업이 거부되었습니다..." 사용자 메시지로 변환되어 throw (원본은 `cause`).
83
100
 
84
101
  ## 상태/진행률 이벤트
102
+
85
103
  ```ts
86
104
  client.on("state", (s: "connected" | "closed" | "reconnecting") => ...)
87
105
  client.on("request-progress", (s: ServiceProgressState) => ...) // 클라이언트 → 서버 전송 청크 진행
88
106
  client.on("response-progress", (s: ServiceProgressState) => ...) // 서버 → 클라이언트 응답 청크 진행
89
107
  client.on("server-progress", (s: ServiceProgressState) => ...) // 서버가 명시적으로 보내는 진행률
90
108
  ```
91
- - 단일 청크 메시지에는 progress 가 발행되지 않음(분할 메시지에서만).
92
- - `send` 호출 전달한 `progress?: ServiceProgress` 콜백은 인스턴스 이벤트와 별도로 호출됨.
109
+
110
+ - `request-progress` 인코드 결과 chunk 2개 이상일 때만 초기 0% 가 발행됨. 단일 청크는 progress 없음.
111
+ - `response-progress` 는 분할 수신 중에는 서버 progress 메시지로, 응답 완료 시 100% 보정값으로 발행됨.
112
+ - `send` 호출 시 전달한 `progress?: ServiceProgress` 콜백은 인스턴스 이벤트와 함께 호출된다.
113
+
114
+ ## 환경 호환 유틸
115
+
116
+ ```ts
117
+ import { BlobInput, FileCollection, BrowserWorker,
118
+ isBrowserWorkerSupported, isNodeWorkerSupported, isWorkerSupported }
119
+ from "@simplysm/service-client";
120
+ ```
121
+
122
+ - `BrowserWorker` — DOM `Worker` 의 구조적 호환 인터페이스. Node 환경 typecheck 통과용.
123
+ - `isBrowserWorkerSupported()` / `isNodeWorkerSupported()` / `isWorkerSupported()` — 현재 런타임에서 Worker 오프로딩이 가능한지 사전 확인.
124
+ - 보통 직접 호출할 필요 없음. `ServiceClient` 가 내부에서 분기하므로, 환경별 분기 로직을 사용자 코드에서 직접 짤 때만 사용.
@@ -7,7 +7,9 @@ FTP/FTPS/SFTP 원격 스토리지에 동일 인터페이스(`StorageClient`)로
7
7
  - **`StorageFactory.connect`** — FTP/FTPS/SFTP 어느 것이든 연결→작업→자동 종료를 한 번에 처리할 때 (권장 진입점).
8
8
  - **`StorageClient`** — 콜백 안에서 사용하는 공통 파일 작업 인터페이스(mkdir/list/readFile/put/uploadDir/remove/rename/exists).
9
9
  - **`FtpStorageClient` / `SftpStorageClient`** — 연결 생명주기를 직접 관리해야 할 때만 (장기 연결 풀 등). 그 외엔 `StorageFactory.connect` 사용.
10
- - **`StorageConnConfig`, `StorageProtocol`, `FileInfo`** API 호출 타입.
10
+ - **`StorageConnConfig`** `connect`/`StorageFactory.connect` 넘기는 접속 정보(host/port/user/password) 타입.
11
+ - **`StorageProtocol`** — `StorageFactory.connect` 의 `type` 인자로 쓰는 프로토콜 리터럴(`"ftp" | "ftps" | "sftp"`).
12
+ - **`FileInfo`** — `list` 결과 항목 타입(`{ name, isFile }`).
11
13
 
12
14
  ## StorageFactory.connect
13
15