@simplysm/sd-claude 14.0.89 → 14.0.90

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 (79) hide show
  1. package/claude/references/sd-simplysm14/README.md +16 -17
  2. package/claude/references/sd-simplysm14/apis/angular/README.md +52 -30
  3. package/claude/references/sd-simplysm14/apis/angular/controls.md +200 -38
  4. package/claude/references/sd-simplysm14/apis/angular/crud.md +41 -53
  5. package/claude/references/sd-simplysm14/apis/angular/directives.md +66 -22
  6. package/claude/references/sd-simplysm14/apis/angular/features.md +127 -40
  7. package/claude/references/sd-simplysm14/apis/angular/infra.md +60 -43
  8. package/claude/references/sd-simplysm14/apis/angular/layout.md +56 -20
  9. package/claude/references/sd-simplysm14/apis/angular/overlay.md +74 -74
  10. package/claude/references/sd-simplysm14/apis/angular/routing-appstructure.md +50 -40
  11. package/claude/references/sd-simplysm14/apis/angular/selection-managers.md +55 -15
  12. package/claude/references/sd-simplysm14/apis/angular/shared-data.md +59 -42
  13. package/claude/references/sd-simplysm14/apis/angular/sheet.md +77 -62
  14. package/claude/references/sd-simplysm14/apis/capacitor-plugin-auto-update/README.md +8 -7
  15. package/claude/references/sd-simplysm14/apis/capacitor-plugin-file-system/README.md +71 -43
  16. package/claude/references/sd-simplysm14/apis/capacitor-plugin-intent/README.md +22 -14
  17. package/claude/references/sd-simplysm14/apis/capacitor-plugin-usb-storage/README.md +19 -19
  18. package/claude/references/sd-simplysm14/apis/core-browser/README.md +17 -17
  19. package/claude/references/sd-simplysm14/apis/core-browser/dom-element.md +28 -28
  20. package/claude/references/sd-simplysm14/apis/core-browser/indexed-db.md +37 -37
  21. package/claude/references/sd-simplysm14/apis/core-common/README.md +87 -219
  22. package/claude/references/sd-simplysm14/apis/core-common/array-ext.md +54 -98
  23. package/claude/references/sd-simplysm14/apis/core-common/async-runtime.md +57 -99
  24. package/claude/references/sd-simplysm14/apis/core-common/datetime.md +60 -103
  25. package/claude/references/sd-simplysm14/apis/core-common/errors.md +42 -47
  26. package/claude/references/sd-simplysm14/apis/core-common/obj.md +42 -88
  27. package/claude/references/sd-simplysm14/apis/core-common/serialization.md +55 -0
  28. package/claude/references/sd-simplysm14/apis/core-node/README.md +6 -7
  29. package/claude/references/sd-simplysm14/apis/core-node/consola.md +17 -12
  30. package/claude/references/sd-simplysm14/apis/core-node/cpx.md +14 -13
  31. package/claude/references/sd-simplysm14/apis/core-node/fs-watcher.md +9 -8
  32. package/claude/references/sd-simplysm14/apis/core-node/fsx.md +14 -13
  33. package/claude/references/sd-simplysm14/apis/core-node/pathx.md +4 -8
  34. package/claude/references/sd-simplysm14/apis/core-node/worker.md +14 -12
  35. package/claude/references/sd-simplysm14/apis/excel/README.md +22 -22
  36. package/claude/references/sd-simplysm14/apis/excel/cell.md +37 -29
  37. package/claude/references/sd-simplysm14/apis/excel/conditional-format.md +29 -15
  38. package/claude/references/sd-simplysm14/apis/excel/style.md +33 -27
  39. package/claude/references/sd-simplysm14/apis/excel/utils.md +29 -19
  40. package/claude/references/sd-simplysm14/apis/excel/workbook-worksheet.md +78 -55
  41. package/claude/references/sd-simplysm14/apis/excel/wrapper.md +42 -45
  42. package/claude/references/sd-simplysm14/apis/orm-common/README.md +6 -8
  43. package/claude/references/sd-simplysm14/apis/orm-common/db-context.md +118 -67
  44. package/claude/references/sd-simplysm14/apis/orm-common/expr.md +83 -86
  45. package/claude/references/sd-simplysm14/apis/orm-common/queryable.md +102 -93
  46. package/claude/references/sd-simplysm14/apis/orm-common/schema.md +138 -81
  47. package/claude/references/sd-simplysm14/apis/orm-common/types.md +49 -44
  48. package/claude/references/sd-simplysm14/apis/orm-node/README.md +42 -42
  49. package/claude/references/sd-simplysm14/apis/orm-node/db-conn.md +44 -33
  50. package/claude/references/sd-simplysm14/apis/sd-cli/README.md +11 -10
  51. package/claude/references/sd-simplysm14/apis/service-client/README.md +56 -52
  52. package/claude/references/sd-simplysm14/apis/service-client/orm.md +33 -28
  53. package/claude/references/sd-simplysm14/apis/service-client/transport.md +23 -21
  54. package/claude/references/sd-simplysm14/apis/service-common/README.md +83 -48
  55. package/claude/references/sd-simplysm14/apis/service-common/app-structure.md +126 -34
  56. package/claude/references/sd-simplysm14/apis/service-common/protocol.md +109 -54
  57. package/claude/references/sd-simplysm14/apis/service-server/README.md +69 -81
  58. package/claude/references/sd-simplysm14/apis/service-server/service-authoring.md +46 -43
  59. package/claude/references/sd-simplysm14/apis/service-server/transport-internals.md +63 -37
  60. package/claude/references/sd-simplysm14/apis/service-server/v1-legacy.md +40 -30
  61. package/claude/references/sd-simplysm14/apis/storage/README.md +17 -17
  62. package/claude/references/sd-simplysm14/manuals/client-app-structure.md +142 -140
  63. package/claude/references/sd-simplysm14/manuals/client-orm.md +1 -1
  64. package/claude/references/sd-simplysm14/manuals/client-service.md +19 -7
  65. package/claude/references/sd-simplysm14/manuals/client-shared-data.md +2 -2
  66. package/claude/references/sd-simplysm14/manuals/client-system-log.md +11 -3
  67. package/claude/references/sd-simplysm14/manuals/data-log.md +0 -1
  68. package/claude/references/sd-simplysm14/manuals/orm.md +16 -0
  69. package/claude/rules/sd-design-rules.md +10 -0
  70. package/claude/skills/sd-demo/SKILL.md +0 -6
  71. package/claude/skills/sd-docs/SKILL.md +58 -0
  72. package/claude/{workflows/sd-docs.rules.md → skills/sd-docs/references/subagent-prompt.md} +103 -103
  73. package/claude/skills/sd-impl/SKILL.md +7 -4
  74. package/claude/skills/sd-spec/SKILL.md +842 -15
  75. package/claude/skills/sd-spec/references/example-spec.md +26 -36
  76. package/package.json +1 -1
  77. package/claude/references/sd-simplysm14/apis/core-common/json-transfer.md +0 -53
  78. package/claude/skills/sd-spec/references/spec-authoring.md +0 -519
  79. package/claude/workflows/sd-docs.js +0 -84
@@ -1,18 +1,18 @@
1
1
  # @simplysm/core-browser
2
2
 
3
- 브라우저 전용 유틸리티. `Element`/`HTMLElement` 프로토타입 확장(사이드 이펙트)과 파일 다운로드·업로드, IndexedDB 래퍼를 제공.
3
+ 브라우저 전용 유틸리티 묶음. DOM 요소 탐색·위치 계산·가시성 판정 확장, IndexedDB 영속화 및 그 위의 가상 파일시스템, 파일 다운로드·선택 헬퍼를 제공.
4
4
 
5
- > 패키지의 어떤 심볼이든 import 하면 `index.ts` 가 `import "./extensions/..."` 를 실행해 프로토타입 확장이 자동 등록됨(`element-ext`, `html-element-ext` 사이드 이펙트). 별도 초기화 호출 없이 `el.findAll(...)` 식으로 사용 가능.
5
+ > 패키지의 어떤 심볼이든 import 하면 `index.ts` 가 `import "./extensions/element-ext"`·`"./extensions/html-element-ext"` 를 실행해 `Element`/`HTMLElement` 프로토타입 확장이 사이드 이펙트로 자동 등록됨. 별도 초기화 없이 `el.findAll(...)` 식으로 호출 가능.
6
6
 
7
7
  ## 사용 트리거 인덱스
8
8
 
9
- - **DOM 요소 확장** — DOM 조회(`findAll`/`findFirst`), 부모/탭이동 가능 요소 탐색, 가시성·offset 판정, 부모 기준 상대 좌표 계산, 가림 보정 스크롤, 강제 리페인트, 클립보드 복사/붙여넣기 핸들러, 다중 요소 경계 측정이 필요할 때. 자세히: [dom-element.md](./dom-element.md)
10
- - **IndexedDB 저장소/가상 파일시스템** (`IndexedDbStore`, `IndexedDbVirtualFs`) — 브라우저 IndexedDB 에 KV 영구 저장하거나, 그 위에 경로 키 기반 가상 파일트리를 올릴 때. 자세히: [indexed-db.md](./indexed-db.md)
11
- - **파일 다운로드/업로드** (`downloadBlob`, `fetchUrlBytes`/`DownloadProgress`, `openFileDialog`) — Blob 을 파일로 내려받거나, URL 바이너리를 진행률과 함께 받거나, 파일 선택 대화상자를 코드에서 띄울 때. (아래 인라인 섹션)
9
+ - **DOM 요소 확장·헬퍼** — DOM 조회(`findAll`/`findFirst`), 조상/탭 이동 가능 요소 탐색, offset·가시성 판정, 부모 기준 상대 좌표 계산, 가림 보정 스크롤, 강제 리페인트, 클립보드 복사/붙여넣기 핸들러, 다중 요소 경계 측정이 필요할 때. 자세히: [dom-element.md](./dom-element.md)
10
+ - **IndexedDB 영속화** (`IndexedDbStore`, `IndexedDbVirtualFs`) — 브라우저 IndexedDB 에 KV 영구 저장하거나, 그 위에 경로 키 기반 가상 파일트리(파일/디렉터리)를 올릴 때. 자세히: [indexed-db.md](./indexed-db.md)
11
+ - **downloadBlob / fetchUrlBytes / openFileDialog**생성한 Blob 을 파일로 저장하거나, 진행률을 보며 URL 바이너리를 받거나, 파일 선택 대화상자를 코드로 때. (아래 인라인 섹션)
12
12
 
13
- ## 파일 다운로드/업로드
13
+ ## 파일·다운로드 유틸
14
14
 
15
- 브라우저에서 파일을 내려받거나, URL 에서 바이너리를 받거나, 사용자가 파일을 고르게 할 때 쓰는 독립 함수 묶음.
15
+ 생성한 데이터를 파일로 내보내거나, 외부 바이너리를 받거나, 사용자에게 파일을 고르게 할 때 쓰는 단발성 함수들.
16
16
 
17
17
  ### downloadBlob
18
18
 
@@ -20,10 +20,10 @@
20
20
  function downloadBlob(blob: Blob, fileName: string): void;
21
21
  ```
22
22
 
23
- Blob 을 objectURL 로 만들어 동적 `a[download]` 클릭으로 저장. objectURL 은 1초 뒤 revoke. 화면 다운로드 버튼 핸들러에서 즉시 저장할 때.
23
+ Blob 을 object URL 로 만들어 동적 `a[download]` 클릭으로 저장하고, object URL 은 1초 뒤 revoke. 클릭 직후 함수가 반환됨(다운로드 완료를 기다리지 않음). 화면 다운로드 버튼 핸들러에서 즉시 저장할 때.
24
24
 
25
- - `blob: Blob` — 저장할 데이터.
26
- - `fileName: string` — 저장 파일명. `sanitize-filename` 으로 OS 금지 문자·예약어를 제거한 뒤 추가로 `[`·`]` 도 제거하며, 결과가 빈 문자열이면 `"download"` 로 대체. 사용자 입력 파일명을 그대로 넣어도 안전.
25
+ - blob: Blob — 저장할 데이터. 엑셀·이미지·텍스트 등 메모리에서 만든 Blob 을 그대로 전달.
26
+ - fileName: string — 저장 파일명. `sanitize-filename` 으로 OS 금지 문자·예약어를 제거한 뒤 추가로 `[`·`]` 도 제거하며, 결과가 빈 문자열이면 `"download"` 로 대체. 확장자 포함, 사용자 입력 파일명을 그대로 넣어도 안전.
27
27
 
28
28
  ```ts
29
29
  downloadBlob(new Blob([buf], { type: "application/pdf" }), "보고서[2026].pdf");
@@ -39,12 +39,12 @@ function fetchUrlBytes(
39
39
  ): Promise<Uint8Array>;
40
40
  ```
41
41
 
42
- URL 바이너리를 스트림 reader 로 다운로드. 큰 파일을 진행률과 함께 받을 때.
42
+ URL 바이너리를 스트림 reader 로 다운로드하며 진행률을 보고. 큰 파일을 진행 바와 함께 받을 때.
43
43
 
44
- - `url: string` — 다운로드 대상 URL. `response.ok` 가 아니면 `Error("다운로드 실패: <status> <statusText>")`, 본문 reader 가 없으면 `Error("응답 본문을 읽을 수 없습니다")` throw.
45
- - `options.onProgress: (progress: DownloadProgress) => void` — 청크 수신마다 호출되는 진행 콜백. `Content-Length` 헤더가 있는 경로에서만 호출됨(없으면 청크를 모아 `bytes.concat` 으로 마지막에 한 번에 병합 → chunked encoding 이라 중간 보고 없음). 진행 바 갱신에.
46
- - `DownloadProgress.receivedLength: number` — 누적 수신 바이트 수.
47
- - `DownloadProgress.contentLength: number` — 전체 바이트(`Content-Length` 헤더 값, 없으면 0). 헤더가 있으면 그 크기로 버퍼를 사전 할당하고, 수신량이 헤더 값을 초과하거나 미달하면 무결성 위반으로 Error throw.
44
+ - url: string — 다운로드 대상 URL. `response.ok` 가 아니면 `Error("다운로드 실패: <status> <statusText>")`, 본문 reader 가 없으면 `Error("응답 본문을 읽을 수 없습니다")` throw.
45
+ - options.onProgress: (progress: DownloadProgress) => void — 청크 수신마다 호출되는 진행 콜백. `Content-Length` 헤더가 있는 경로에서만 호출됨(헤더가 없으면 청크를 모아 `bytes.concat` 으로 마지막에 한 병합 → chunked encoding 이라 중간 보고 없음). 진행 바 갱신이 필요할 때만 전달.
46
+ - DownloadProgress.receivedLength: number — 지금까지 받은 누적 바이트 수.
47
+ - DownloadProgress.contentLength: number — 전체 바이트(`Content-Length` 헤더 값, 없으면 0). 헤더가 있으면 그 크기로 버퍼를 사전 할당하고, 수신량이 헤더 값을 초과·미달하면 무결성 위반으로 Error throw.
48
48
 
49
49
  ```ts
50
50
  const data = await fetchUrlBytes("/api/file", {
@@ -60,8 +60,8 @@ function openFileDialog(options?: { accept?: string; multiple?: boolean }): Prom
60
60
 
61
61
  동적 `input[type=file]` 을 만들어 클릭, 파일 선택 대화상자를 표시. 업로드 버튼 핸들러에서 호출.
62
62
 
63
- - `options.accept: string` — 허용 MIME/확장자 필터(input `accept` 에 그대로 전달). 미지정 시 제한 없음. 특정 형식만 받을 때(예: `".png,.jpg"`, `"image/*"`).
64
- - `options.multiple: boolean` — 다중 선택 허용. true 면 여러 파일 선택 가능, 기본 `false`(단일). 여러 파일 업로드 화면이면 true.
63
+ - options.accept: string — 허용 MIME/확장자 필터(input `accept` 에 그대로 전달, 예: `".png,.jpg"`, `"image/*"`). 미지정 시 제한 없음.
64
+ - options.multiple: boolean — 다중 선택 허용. true 면 여러 파일 선택 가능, 기본 `false`(단일). 여러 파일을 번에 받을 화면이면 true.
65
65
  - 반환: 선택 파일이 있으면 `File[]`, 사용자가 취소하거나(`cancel` 이벤트) 0개 선택이면 `undefined`. 결측을 빈 배열로 뭉개지 않으므로 `== null` 로 취소를 구분.
66
66
 
67
67
  ```ts
@@ -1,4 +1,4 @@
1
- # @simplysm/core-browser — DOM 요소 확장
1
+ # @simplysm/core-browser — DOM 요소 확장·헬퍼
2
2
 
3
3
  DOM 요소를 다룰 때 함께 읽히는 묶음. `Element.prototype`/`HTMLElement.prototype` 에 등록되는 확장 메서드와, 이벤트 핸들러·다중 요소용 정적 함수(`copyElement`/`pasteToElement`/`getBounds`)로 구성. 패키지를 import 하면 프로토타입 메서드가 자동 등록되므로 별도 초기화 불필요.
4
4
 
@@ -6,14 +6,14 @@ DOM 요소를 다룰 때 함께 읽히는 묶음. `Element.prototype`/`HTMLEleme
6
6
 
7
7
  `Element.prototype` 에 등록. import 만으로 활성화.
8
8
 
9
- - `findAll<TEl>(selector: string): TEl[]` — 선택자 일치 하위 요소를 배열로 반환. 선택자를 trim 한 결과가 빈 문자열이면 `[]`. `querySelectorAll` 결과를 NodeList 대신 배열로 받고 빈 선택자 예외를 회피할 때.
10
- - `findFirst<TEl>(selector: string): TEl | undefined` — 첫 일치 하위 요소 또는 `undefined`. 빈 선택자도 `undefined`, 미일치도 `undefined`. `querySelector` 의 `null` 을 `undefined` 로 정규화한 형태.
11
- - `prependChild<TEl>(child: TEl): TEl` — 자식을 첫 번째 위치(`insertBefore(child, firstElementChild)`)에 삽입하고 그 요소 반환. 맨 앞에 끼울 때.
12
- - `getParents(): Element[]` — 모든 조상 요소를 가까운 것부터 먼 순서로 배열 반환. 조상 체인 순회·특정 조상 포함 판정에.
13
- - `findTabbableParent(): HTMLElement | undefined` — `tabbable` 라이브러리 기준 첫 탭 이동 가능 조상. 없으면 `undefined`. 포커스 위임 대상을 위로 탐색할 때.
14
- - `findFirstTabbableChild(): HTMLElement | undefined` — TreeWalker 로 순회한 첫 탭 이동 가능 하위 요소. 없으면 `undefined`. 컨테이너 진입 시 자동 포커스 대상을 찾을 때.
15
- - `isOffsetElement(): boolean` — `getComputedStyle().position` 이 relative/absolute/fixed/sticky 중 하나면 true, 아니면 false. offset parent(절대배치 기준) 역할 여부 판정에.
16
- - `isVisible(): boolean` — `getClientRects().length > 0` 이고 `visibility !== "hidden"` 이고 `opacity !== "0"` 를 모두 만족하면 true. 화면 표시 여부 판정에(display:none 은 clientRects 가 비어 false).
9
+ - findAll<TEl>(selector: string): TEl[] — 선택자 일치 하위 요소를 배열로 반환. 선택자를 trim 한 결과가 빈 문자열이면 `[]`. `querySelectorAll` 결과를 NodeList 대신 배열로 받고 빈 선택자 예외를 회피할 때.
10
+ - findFirst<TEl>(selector: string): TEl | undefined — 첫 일치 하위 요소 또는 `undefined`. 빈 선택자도 `undefined`, 미일치도 `undefined`. `querySelector` 의 `null` 을 `undefined` 로 정규화한 형태.
11
+ - prependChild<TEl>(child: TEl): TEl — 자식을 첫 번째 위치(`insertBefore(child, firstElementChild)`)에 삽입하고 그 요소 반환. 맨 앞에 끼울 때.
12
+ - getParents(): Element[] — 모든 조상 요소를 가까운 것부터 먼 순서로 배열 반환. 조상 체인 순회·특정 조상 포함 판정에.
13
+ - findTabbableParent(): HTMLElement | undefined — `tabbable` 라이브러리 기준 첫 탭 이동 가능 조상. 없으면 `undefined`. 포커스 위임 대상을 위로 탐색할 때.
14
+ - findFirstTabbableChild(): HTMLElement | undefined — TreeWalker 로 순회한 첫 탭 이동 가능 하위 요소. 없으면 `undefined`. 컨테이너 진입 시 자동 포커스 대상을 찾을 때.
15
+ - isOffsetElement(): boolean — `getComputedStyle().position` 이 relative/absolute/fixed/sticky 중 하나면 true, 아니면 false. offset parent(절대배치 기준) 역할 여부 판정에.
16
+ - isVisible(): boolean — `getClientRects().length > 0` 이고 `visibility !== "hidden"` 이고 `opacity !== "0"` 를 모두 만족하면 true. 화면 표시 여부 판정에(display:none 은 clientRects 가 비어 false).
17
17
 
18
18
  ```ts
19
19
  import "@simplysm/core-browser";
@@ -25,12 +25,12 @@ const first = containerEl.findFirstTabbableChild();
25
25
 
26
26
  `HTMLElement.prototype` 에 등록. 위와 동일하게 import 만으로 활성화.
27
27
 
28
- - `repaint(): void` — `offsetHeight` 접근으로 강제 동기 레이아웃(reflow)을 유발해 즉시 리페인트. 스타일 변경 직후 즉각 반영을 강제할 때.
29
- - `getRelativeOffset(parent: HTMLElement | string): { top: number; left: number }` — 부모 기준 CSS `top`/`left` 좌표 계산. 뷰포트 위치(getBoundingClientRect)·부모 내부 스크롤(scrollTop/Left)·중간 요소 border 두께·CSS transform 까지 반영해, 드롭다운/팝업 위치 지정에 바로 쓸 수 있는 좌표 반환. 부모를 못 찾으면 `ArgumentError` throw.
30
- - `parent: HTMLElement | string` — 기준 부모. 문자열이면 `this.closest(parent)` 로 조상 탐색, 요소면 직접 사용. `document.body` `".container"` 식으로 지정.
31
- - `scrollIntoViewIfNeeded(target, offset?): void` — 대상이 스크롤 영역의 상단/좌측 경계를 벗어났을 때만 그쪽으로 스크롤해 보이게 함. 하단/우측 방향은 처리하지 않고 브라우저 기본 포커스 스크롤에 위임. 고정 헤더/컬럼이 있는 테이블의 포커스 처리에.
32
- - `target: { top: number; left: number }` — 컨테이너 내 대상 위치(offsetTop/offsetLeft 기준).
33
- - `offset: { top: number; left: number }` — 가려지면 안 되는 영역 크기(고정 헤더 높이·고정 컬럼 너비). 기본 `{ top: 0, left: 0 }`.
28
+ - repaint(): void — `offsetHeight` 접근으로 강제 동기 레이아웃(reflow)을 유발해 즉시 리페인트. 스타일 변경 직후 즉각 반영을 강제할 때.
29
+ - getRelativeOffset(parent: HTMLElement | string): { top: number; left: number } — 부모 기준 CSS `top`/`left` 좌표 계산. 뷰포트 위치(getBoundingClientRect)·부모 내부 스크롤(scrollTop/Left)·중간 요소 border 두께·CSS transform 까지 반영해, 드롭다운/팝업 위치 지정에 바로 쓸 수 있는 좌표 반환. 부모를 못 찾으면(`HTMLElement` 아님) `ArgumentError` throw.
30
+ - parent: HTMLElement | string — 기준 부모. 문자열이면 `this.closest(parent)` 로 조상 탐색, 요소면 직접 사용(예: `document.body`, `".container"`).
31
+ - scrollIntoViewIfNeeded(target, offset?): void — 대상이 스크롤 영역의 상단/좌측 경계를 벗어났을 때만 그쪽으로 스크롤해 보이게 함. 하단/우측 방향은 처리하지 않고 브라우저 기본 포커스 스크롤에 위임. 고정 헤더/컬럼이 있는 테이블의 포커스 처리에.
32
+ - target: { top: number; left: number } — 컨테이너 내 대상 위치(offsetTop/offsetLeft 기준).
33
+ - offset: { top: number; left: number } — 가려지면 안 되는 영역 크기(고정 헤더 높이·고정 컬럼 너비). 기본 `{ top: 0, left: 0 }`.
34
34
 
35
35
  ```ts
36
36
  const { top, left } = popupEl.getRelativeOffset(".container");
@@ -41,19 +41,19 @@ scrollEl.scrollIntoViewIfNeeded({ top: cellTop, left: cellLeft }, { top: headerH
41
41
 
42
42
  이벤트 핸들러로 붙이거나 다중 요소를 한 번에 처리하는 함수. 프로토타입 확장이 아니라 named export 이므로 직접 import.
43
43
 
44
- - `copyElement(event: ClipboardEvent): void` — copy 이벤트 핸들러용. 이벤트 타겟 내 첫 `input/textarea` 의 `value` 를 클립보드 `text/plain` 으로 기록하고 `preventDefault`. clipboardData 가 없거나 타겟이 Element 가 아니거나 input 이 없으면 무동작.
45
- - `event: ClipboardEvent` — copy 이벤트 객체. `el.addEventListener("copy", copyElement)` 로 등록.
46
- - `pasteToElement(event: ClipboardEvent): void` — paste 이벤트 핸들러용. 타겟 내 첫 `input/textarea` 의 전체 `value` 를 클립보드 텍스트로 교체하고 `input` 이벤트 dispatch(bubbles: true) 후 `preventDefault`. 커서 위치·선택 영역은 무시하고 전체를 치환.
47
- - `event: ClipboardEvent` — paste 이벤트 객체. `el.addEventListener("paste", pasteToElement)` 로 등록.
48
- - `getBounds(els: Element[], timeout?: number): Promise<ElementBounds[]>` — `IntersectionObserver` 로 여러 요소의 뷰포트 기준 경계를 한 번에 측정. 중복은 제거하고 입력 순서대로 정렬해 반환. 빈 배열이면 즉시 `[]`. 모든 요소 관측 완료 시 resolve, 제한시간 초과 시 `TimeoutError` throw(어느 경우든 finally 에서 observer disconnect).
49
- - `els: Element[]` — 측정 대상. 중복은 제거되고 결과는 입력 순서로 정렬됨.
50
- - `timeout: number` — 제한시간(ms). 기본 `5000`. 초과 시 `TimeoutError`.
51
- - `ElementBounds` (반환 항목 타입):
52
- - `target: Element` — 측정된 요소.
53
- - `top: number` — 뷰포트 기준 상단 위치(boundingClientRect.top).
54
- - `left: number` — 뷰포트 기준 좌측 위치(boundingClientRect.left).
55
- - `width: number` — 요소 너비(boundingClientRect.width).
56
- - `height: number` — 요소 높이(boundingClientRect.height).
44
+ - copyElement(event: ClipboardEvent): void — copy 이벤트 핸들러용. 이벤트 타겟 내 첫 `input/textarea` 의 `value` 를 클립보드 `text/plain` 으로 기록하고 `preventDefault`. clipboardData 가 없거나 타겟이 Element 가 아니거나 input 이 없으면 무동작.
45
+ - event: ClipboardEvent — copy 이벤트 객체. `el.addEventListener("copy", copyElement)` 로 등록.
46
+ - pasteToElement(event: ClipboardEvent): void — paste 이벤트 핸들러용. 타겟 내 첫 `input/textarea` 의 전체 `value` 를 클립보드 텍스트로 교체하고 `input` 이벤트 dispatch(`bubbles: true`) 후 `preventDefault`. 커서 위치·선택 영역은 무시하고 전체를 치환.
47
+ - event: ClipboardEvent — paste 이벤트 객체. `el.addEventListener("paste", pasteToElement)` 로 등록.
48
+ - getBounds(els: Element[], timeout?: number): Promise<ElementBounds[]> — `IntersectionObserver` 로 여러 요소의 뷰포트 기준 경계를 한 번에 측정. 중복은 제거하고 입력 순서대로 정렬해 반환. 빈 배열이면 즉시 `[]`. 모든 요소 관측 완료 시 resolve, 제한시간 초과 시 `TimeoutError` throw(어느 경우든 finally 에서 observer disconnect).
49
+ - els: Element[] — 측정 대상. 중복은 제거되고 결과는 입력 순서로 정렬됨.
50
+ - timeout: number — 제한시간(ms). 기본 `5000`. 초과 시 `TimeoutError`.
51
+ - ElementBounds (반환 항목 타입):
52
+ - target: Element — 측정된 요소.
53
+ - top: number — 뷰포트 기준 상단 위치(boundingClientRect.top).
54
+ - left: number — 뷰포트 기준 좌측 위치(boundingClientRect.left).
55
+ - width: number — 요소 너비(boundingClientRect.width).
56
+ - height: number — 요소 높이(boundingClientRect.height).
57
57
 
58
58
  ```ts
59
59
  inputEl.addEventListener("copy", copyElement);
@@ -1,4 +1,4 @@
1
- # @simplysm/core-browser — IndexedDB 저장소/가상 파일시스템
1
+ # @simplysm/core-browser — IndexedDB 영속화
2
2
 
3
3
  브라우저 IndexedDB 를 다룰 때 함께 읽히는 묶음. `IndexedDbStore` 는 연결·트랜잭션·KV CRUD 를 담당하고, `IndexedDbVirtualFs` 는 그 위에 경로 키 기반 가상 파일트리(entry put/get, prefix 삭제, 자식 나열, 디렉터리 보장)를 얹음.
4
4
 
@@ -17,23 +17,23 @@ store.close();
17
17
 
18
18
  시그니처:
19
19
 
20
- - `new IndexedDbStore(dbName: string, dbVersion: number, storeConfigs: StoreConfig[])` — DB 이름·버전·스토어 설정으로 생성(연결은 지연, 첫 작업 시 오픈).
21
- - dbName: `string` — IndexedDB 데이터베이스 이름.
22
- - dbVersion: `number` — DB 버전. 올리면 `onupgradeneeded` 에서 누락 스토어를 생성. 스키마(스토어 추가) 변경 시 증가.
23
- - storeConfigs: `StoreConfig[]` — 생성할 오브젝트 스토어 목록.
24
- - `StoreConfig` — 스토어 설정 항목.
25
- - name: `string` — 오브젝트 스토어 이름. upgrade 시 미존재면 `createObjectStore` 로 생성.
26
- - keyPath: `string` — 스토어 keyPath(레코드에서 키로 쓸 속성명).
27
- - `open(): Promise<IDBDatabase>` — 연결을 열어 반환. 이미 열렸으면 캐시 반환, 진행 중이면 같은 Promise 공유(중복 오픈 방지). `onupgradeneeded` 시 없는 스토어만 생성. `onversionchange`/`onclose` 시 내부 캐시(`_db`/`_opening`)를 해제해 다음 호출에 재오픈. `onblocked` 면 `Error("다른 연결에 의해 데이터베이스가 차단되었습니다")`, `onerror` 면 원본 에러로 reject. CRUD 가 자동 호출하므로 직접 호출 불필요.
28
- - `withStore<TResult>(storeName, mode, fn): Promise<TResult>` — 트랜잭션 1건 안에서 `fn(store)` 실행 후 완료까지 대기. `fn` 이 throw 하면 `tx.abort()` 후 그 에러로 reject(롤백), 정상이면 `oncomplete` 시 결과 resolve, `onerror` 면 `tx.error` 로 reject. 커서 등 저수준 IDB 작업을 감쌀 때.
29
- - storeName: `string` — 트랜잭션 대상 스토어.
30
- - mode: `IDBTransactionMode` — `"readonly"`(읽기 전용) | `"readwrite"`(읽기·쓰기) | `"versionchange"`. 쓰기 작업이면 `"readwrite"`.
31
- - fn: `(store: IDBObjectStore) => Promise<TResult>` — 스토어를 받아 작업하는 콜백.
32
- - `get<TValue>(storeName, key): Promise<TValue | undefined>` — 키로 단건 조회. 미존재 시 `undefined`(결측 그대로 반환).
33
- - `put(storeName, value): Promise<void>` — 레코드 upsert. value 에 keyPath 속성이 포함돼야 함.
34
- - `delete(storeName, key): Promise<void>` — 키로 단건 삭제.
35
- - `getAll<TItem>(storeName): Promise<TItem[]>` — 스토어 전체 레코드 배열 반환.
36
- - `close(): void` — 연결을 닫고 내부 캐시 해제. 다음 작업 시 재오픈. 페이지 정리 시 호출.
20
+ - new IndexedDbStore(dbName: string, dbVersion: number, storeConfigs: StoreConfig[]) — DB 이름·버전·스토어 설정으로 생성(연결은 지연, 첫 작업 시 오픈).
21
+ - dbName: string — IndexedDB 데이터베이스 이름.
22
+ - dbVersion: number — DB 버전. 올리면 `onupgradeneeded` 에서 누락 스토어를 생성. 스키마(스토어 추가) 변경 시 증가.
23
+ - storeConfigs: StoreConfig[] — 생성할 오브젝트 스토어 목록.
24
+ - StoreConfig — 스토어 설정 항목.
25
+ - name: string — 오브젝트 스토어 이름. upgrade 시 미존재면 `createObjectStore` 로 생성.
26
+ - keyPath: string — 스토어 keyPath(레코드에서 키로 쓸 속성명).
27
+ - open(): Promise<IDBDatabase> — 연결을 열어 반환. 이미 열렸으면 캐시 반환, 진행 중이면 같은 Promise 공유(중복 오픈 방지). `onupgradeneeded` 시 없는 스토어만 생성. `onversionchange`/`onclose` 시 내부 캐시(`_db`/`_opening`)를 해제해 다음 호출에 재오픈. `onblocked` 면 `Error("다른 연결에 의해 데이터베이스가 차단되었습니다")`, `onerror` 면 원본 에러로 reject. CRUD 가 자동 호출하므로 직접 호출 불필요.
28
+ - withStore<TResult>(storeName, mode, fn): Promise<TResult> — 트랜잭션 1건 안에서 `fn(store)` 실행 후 완료까지 대기. `fn` 이 throw 하면 `tx.abort()` 후 그 에러로 reject(롤백), 정상이면 `oncomplete` 시 결과 resolve, `onerror` 면 `tx.error` 로 reject. 커서 등 저수준 IDB 작업을 감쌀 때.
29
+ - storeName: string — 트랜잭션 대상 스토어.
30
+ - mode: IDBTransactionMode — `"readonly"`(읽기 전용) | `"readwrite"`(읽기·쓰기) | `"versionchange"`. 쓰기 작업이면 `"readwrite"`.
31
+ - fn: (store: IDBObjectStore) => Promise<TResult> — 스토어를 받아 작업하는 콜백.
32
+ - get<TValue>(storeName, key): Promise<TValue | undefined> — 키로 단건 조회. 미존재 시 `undefined`(결측 그대로 반환).
33
+ - put(storeName, value): Promise<void> — 레코드 upsert. value 에 keyPath 속성이 포함돼야 함.
34
+ - delete(storeName, key): Promise<void> — 키로 단건 삭제.
35
+ - getAll<TItem>(storeName): Promise<TItem[]> — 스토어 전체 레코드 배열 반환.
36
+ - close(): void — 연결을 닫고 내부 캐시 해제. 다음 작업 시 재오픈. 페이지 정리 시 호출.
37
37
 
38
38
  주의:
39
39
 
@@ -54,25 +54,25 @@ const ok = await fs.deleteByPrefix("/root/a"); // 하위 전체 삭제, 삭제
54
54
 
55
55
  시그니처:
56
56
 
57
- - `new IndexedDbVirtualFs(db: IndexedDbStore, storeName: string, keyField: string)` — 백엔드 store·스토어 이름·키 필드명으로 생성.
58
- - db: `IndexedDbStore` — 백엔드 저장소.
59
- - storeName: `string` — 사용할 오브젝트 스토어 이름.
60
- - keyField: `string` — 레코드에서 경로 키를 담는 속성명(스토어 keyPath 와 일치해야 함).
61
- - `VirtualFsEntry` — 저장 엔트리 타입.
62
- - kind: `"file" | "dir"` — 엔트리 종류. `"file"` = 파일, `"dir"` = 디렉터리. 자식 나열·디렉터리 판정에 사용.
63
- - dataBase64: `string` — 파일 내용 base64. 디렉터리거나 빈 파일이면 생략(undefined).
64
- - `getEntry(fullKey): Promise<VirtualFsEntry | undefined>` — 전체 경로 키로 단건 조회. 미존재 시 `undefined`.
65
- - `putEntry(fullKey, kind, dataBase64?): Promise<void>` — 엔트리 저장. `keyField` 에 `fullKey`, 그리고 `kind`/`dataBase64` 를 함께 기록.
66
- - fullKey: `string` — 저장할 전체 경로 키.
67
- - kind: `"file" | "dir"` — 저장할 엔트리 종류.
68
- - dataBase64: `string` — 파일 데이터(base64). 디렉터리면 생략.
69
- - `deleteByPrefix(keyPrefix): Promise<boolean>` — 커서로 키가 `keyPrefix` 자신이거나 `keyPrefix + "/"` 로 시작하는 엔트리 전부 삭제(같은 접두어를 가진 다른 형제 경로 오삭제 방지). 하나라도 지웠으면 `true`, 없으면 `false`. 디렉터리 트리 통째 삭제에.
70
- - `listChildren(prefix): Promise<{ name: string; isDirectory: boolean }[]>` — `prefix` 직계 자식만 집계. 키에서 prefix 제거 후 첫 세그먼트를 이름으로 삼고, 하위 세그먼트가 더 있거나 엔트리 `kind === "dir"` 면 디렉터리로 판정. 디렉터리 목록 표시용(재귀 아님).
71
- - 반환 항목 name: `string` — 직계 자식 이름(첫 경로 세그먼트).
72
- - 반환 항목 isDirectory: `boolean` — 디렉터리 여부.
73
- - `ensureDir(fullKeyBuilder, dirPath): Promise<void>` — `dirPath` 상의 각 중간 디렉터리를 부모부터 누적 경로마다 없으면 생성. `dirPath === "/"` 면 루트 1건만 생성. 단일 `withStore("readwrite")` 트랜잭션으로 처리(원자적). 파일 쓰기 전 상위 디렉터리 보장에.
74
- - fullKeyBuilder: `(path: string) => string` — 누적 경로(예: `/a`, `/a/b`)를 실제 저장 key 로 변환하는 콜백.
75
- - dirPath: `string` — 보장할 디렉터리 경로(`/` 구분). 빈 세그먼트는 무시.
57
+ - new IndexedDbVirtualFs(db: IndexedDbStore, storeName: string, keyField: string) — 백엔드 store·스토어 이름·키 필드명으로 생성.
58
+ - db: IndexedDbStore — 백엔드 저장소.
59
+ - storeName: string — 사용할 오브젝트 스토어 이름.
60
+ - keyField: string — 레코드에서 경로 키를 담는 속성명(스토어 keyPath 와 일치해야 함).
61
+ - VirtualFsEntry — 저장 엔트리 타입.
62
+ - kind: "file" | "dir" — 엔트리 종류. `"file"` = 파일, `"dir"` = 디렉터리. 자식 나열·디렉터리 판정에 사용.
63
+ - dataBase64: string — 파일 내용 base64. 디렉터리거나 빈 파일이면 생략(undefined).
64
+ - getEntry(fullKey): Promise<VirtualFsEntry | undefined> — 전체 경로 키로 단건 조회. 미존재 시 `undefined`.
65
+ - putEntry(fullKey, kind, dataBase64?): Promise<void> — 엔트리 저장. `keyField` 에 `fullKey`, 그리고 `kind`/`dataBase64` 를 함께 기록.
66
+ - fullKey: string — 저장할 전체 경로 키.
67
+ - kind: "file" | "dir" — 저장할 엔트리 종류.
68
+ - dataBase64: string — 파일 데이터(base64). 디렉터리면 생략.
69
+ - deleteByPrefix(keyPrefix): Promise<boolean> — 커서로 키가 `keyPrefix` 자신이거나 `keyPrefix + "/"` 로 시작하는 엔트리 전부 삭제(같은 접두어를 가진 다른 형제 경로 오삭제 방지). 하나라도 지웠으면 `true`, 없으면 `false`. 디렉터리 트리 통째 삭제에.
70
+ - listChildren(prefix): Promise<{ name: string; isDirectory: boolean }[]> — `prefix` 직계 자식만 집계. 키에서 prefix 제거 후 첫 세그먼트를 이름으로 삼고, 하위 세그먼트가 더 있거나 엔트리 `kind === "dir"` 면 디렉터리로 판정. 디렉터리 목록 표시용(재귀 아님).
71
+ - 반환 항목 name: string — 직계 자식 이름(첫 경로 세그먼트).
72
+ - 반환 항목 isDirectory: boolean — 디렉터리 여부.
73
+ - ensureDir(fullKeyBuilder, dirPath): Promise<void> — `dirPath` 상의 각 중간 디렉터리를 부모부터 누적 경로마다 없으면 생성. `dirPath === "/"` 면 루트 1건만 생성. 단일 `withStore("readwrite")` 트랜잭션으로 처리(원자적). 파일 쓰기 전 상위 디렉터리 보장에.
74
+ - fullKeyBuilder: (path: string) => string — 누적 경로(예: `/a`, `/a/b`)를 실제 저장 key 로 변환하는 콜백.
75
+ - dirPath: string — 보장할 디렉터리 경로(`/` 구분). 빈 세그먼트는 무시.
76
76
 
77
77
  주의:
78
78