@simplysm/sd-claude 14.0.76 → 14.0.77

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 (66) hide show
  1. package/claude/output-styles/sd-tone.md +128 -0
  2. package/claude/references/sd-simplysm14/apis/angular/README.md +28 -89
  3. package/claude/references/sd-simplysm14/apis/angular/app-structure.md +75 -32
  4. package/claude/references/sd-simplysm14/apis/angular/buttons.md +65 -29
  5. package/claude/references/sd-simplysm14/apis/angular/crud.md +86 -21
  6. package/claude/references/sd-simplysm14/apis/angular/forms.md +168 -42
  7. package/claude/references/sd-simplysm14/apis/angular/infrastructure.md +200 -49
  8. package/claude/references/sd-simplysm14/apis/angular/kanban.md +64 -20
  9. package/claude/references/sd-simplysm14/apis/angular/layout.md +75 -30
  10. package/claude/references/sd-simplysm14/apis/angular/modal.md +92 -40
  11. package/claude/references/sd-simplysm14/apis/angular/routing.md +86 -25
  12. package/claude/references/sd-simplysm14/apis/angular/selection-managers.md +72 -41
  13. package/claude/references/sd-simplysm14/apis/angular/shared-data.md +113 -21
  14. package/claude/references/sd-simplysm14/apis/angular/sheet.md +108 -33
  15. package/claude/references/sd-simplysm14/apis/angular/toast.md +81 -30
  16. package/claude/references/sd-simplysm14/apis/angular/visual.md +140 -32
  17. package/claude/references/sd-simplysm14/apis/capacitor-plugin-auto-update/README.md +46 -43
  18. package/claude/references/sd-simplysm14/apis/capacitor-plugin-intent/README.md +59 -48
  19. package/claude/references/sd-simplysm14/apis/capacitor-plugin-usb-storage/README.md +17 -7
  20. package/claude/references/sd-simplysm14/apis/core-common/README.md +43 -116
  21. package/claude/references/sd-simplysm14/apis/core-common/extensions.md +74 -109
  22. package/claude/references/sd-simplysm14/apis/core-common/features.md +40 -35
  23. package/claude/references/sd-simplysm14/apis/core-common/types.md +80 -106
  24. package/claude/references/sd-simplysm14/apis/core-common/utils.md +142 -111
  25. package/claude/references/sd-simplysm14/apis/core-node/README.md +7 -16
  26. package/claude/references/sd-simplysm14/apis/core-node/consola.md +33 -38
  27. package/claude/references/sd-simplysm14/apis/core-node/cpx.md +25 -33
  28. package/claude/references/sd-simplysm14/apis/core-node/fs-watcher.md +27 -38
  29. package/claude/references/sd-simplysm14/apis/core-node/fsx.md +32 -60
  30. package/claude/references/sd-simplysm14/apis/core-node/pathx.md +14 -45
  31. package/claude/references/sd-simplysm14/apis/core-node/worker.md +35 -81
  32. package/claude/references/sd-simplysm14/apis/excel/README.md +178 -80
  33. package/claude/references/sd-simplysm14/apis/lint/README.md +5 -0
  34. package/claude/references/sd-simplysm14/apis/orm-node/README.md +1 -1
  35. package/claude/references/sd-simplysm14/apis/sd-claude/README.md +28 -5
  36. package/claude/references/sd-simplysm14/apis/sd-cli/README.md +1 -1
  37. package/claude/references/sd-simplysm14/apis/service-client/README.md +57 -50
  38. package/claude/references/sd-simplysm14/apis/service-server/README.md +8 -15
  39. package/claude/references/sd-simplysm14/apis/service-server/auth.md +24 -16
  40. package/claude/references/sd-simplysm14/apis/service-server/builtin-services.md +55 -31
  41. package/claude/references/sd-simplysm14/apis/service-server/define-service.md +28 -44
  42. package/claude/references/sd-simplysm14/apis/service-server/internals.md +59 -18
  43. package/claude/references/sd-simplysm14/apis/service-server/server.md +37 -46
  44. package/claude/references/sd-simplysm14/manuals/client-component.md +3 -1
  45. package/claude/references/sd-simplysm14/manuals/logging.md +9 -8
  46. package/claude/rules/sd-base-rules.md +380 -219
  47. package/claude/settings.json +1 -0
  48. package/claude/skills/sd-commit/SKILL.md +31 -8
  49. package/claude/skills/sd-docs/SKILL.md +15 -10
  50. package/claude/skills/sd-docs/references/subagent-prompt.md +26 -8
  51. package/claude/skills/sd-impl/SKILL.md +1 -1
  52. package/claude/skills/sd-skill/references/skill-authoring.md +1 -1
  53. package/claude/skills/sd-spec/SKILL.md +22 -13
  54. package/claude/skills/sd-spec/references/spec-authoring.md +1 -1
  55. package/claude/skills/sd-unpack/SKILL.md +150 -26
  56. package/claude/skills/sd-unpack/scripts/handlers/__pycache__/_common.cpython-314.pyc +0 -0
  57. package/claude/skills/sd-unpack/scripts/handlers/__pycache__/eml_handler.cpython-314.pyc +0 -0
  58. package/claude/skills/sd-unpack/scripts/handlers/__pycache__/office_com.cpython-314.pyc +0 -0
  59. package/claude/skills/sd-unpack/scripts/handlers/__pycache__/pdf_handler.cpython-314.pyc +0 -0
  60. package/claude/skills/sd-unpack/scripts/handlers/_common.py +17 -2
  61. package/claude/skills/sd-unpack/scripts/handlers/eml_handler.py +100 -24
  62. package/claude/skills/sd-unpack/scripts/handlers/msg_handler.py +140 -27
  63. package/claude/skills/sd-unpack/scripts/handlers/office_com.py +698 -107
  64. package/claude/skills/sd-unpack/scripts/handlers/office_worker.py +34 -26
  65. package/claude/skills/sd-unpack/scripts/handlers/pdf_handler.py +130 -8
  66. package/package.json +1 -1
@@ -1,72 +1,71 @@
1
1
  # @simplysm/capacitor-plugin-auto-update
2
2
 
3
- Android Capacitor 앱의 APK 자동 업데이트 플러그인 (서버 또는 외부 저장소 기반).
3
+ Android Capacitor 앱의 APK 자동 업데이트 흐름(버전 비교 다운로드 → 권한 확인 → 설치)과 APK 설치 네이티브 플러그인 래퍼.
4
4
 
5
5
  ## 사용 트리거 인덱스
6
6
 
7
- - **AutoUpdate** — 앱 부팅 최신 APK 확인·다운로드·설치 과정을 한 번에 실행할 때.
8
- - **ApkInstaller**APK 설치 권한 체크/요청, 임의 APK 파일 설치, 현재 앱 버전 조회 저수준 단위 동작이 필요할 때.
9
- - **VersionInfo / ApkInstallerPlugin** API 호출 결과 타입을 참조할 때.
7
+ - **`AutoUpdate`** — 앱 부팅 직후 서버 또는 외부 저장소에서 최신 APK 버전을 확인·다운로드·설치하는 전체 흐름을 한 번에 실행할 때.
8
+ - **`ApkInstaller`**자체 UI/흐름을 만들면서 APK 설치 권한·설치·현재 앱 버전 조회를 개별로 호출할 때.
9
+ - **`ApkInstallerPlugin`, `VersionInfo`**Capacitor 플러그인 인터페이스 타입을 참조하거나 모킹할 때.
10
10
 
11
- ## AutoUpdate
12
-
13
- `abstract class AutoUpdate` (static 메서드만). Android 전용. 호출 시 권한 확인 → 버전 비교 → 다운로드 → 설치 → 무한 대기(freeze)까지 자동 처리. 오류는 catch 후 `log` 로 메시지 노출 후 freeze.
11
+ ## `AutoUpdate`
14
12
 
15
13
  ```ts
16
- AutoUpdate.run(opt: {
17
- log: (messageHtml: string) => void;
18
- serviceClient: ServiceClient; // @simplysm/service-client
19
- }): Promise<void>
14
+ abstract class AutoUpdate {
15
+ static run(opt: { log: (messageHtml: string) => void; serviceClient: ServiceClient }): Promise<void>;
16
+ static runByExternalStorage(opt: { log: (messageHtml: string) => void; dirPath: string }): Promise<void>;
17
+ }
20
18
  ```
21
- 서버의 `AutoUpdateService` 에 `getLastVersion("android")` 호출 → `{ version, downloadPath }` 수신 → `serviceClient.hostUrl + downloadPath` 에서 APK 다운로드 → `appCache/latest.apk` 로 저장 후 설치. 다운로드 진행률은 `log` 로 갱신.
22
19
 
23
- ```ts
24
- AutoUpdate.runByExternalStorage(opt: {
25
- log: (messageHtml: string) => void;
26
- dirPath: string; // external 스토리지 기준 상대 경로
27
- }): Promise<void>
28
- ```
29
- 외부 저장소 `external/<dirPath>` 폴더의 `<semver>.apk` 파일 중 가장 높은 버전을 골라 설치. 파일명이 semver 가 아니거나 없으면 조용히 반환.
20
+ - `run` — `serviceClient.getService<AutoUpdateService>("AutoUpdate").getLastVersion("android")` 호출 → semver 비교 후 더 큰 버전이면 `serviceClient.hostUrl + downloadPath` 에서 APK 다운로드 → `appCache/latest.apk` 저장 → 설치. 서버 기반 배포용.
21
+ - `runByExternalStorage` — `FileSystem.getStoragePath("external")` 하위 `dirPath` 폴더에서 파일명이 `^[0-9.]*$` 인 `.apk` 들을 후보로 모아 semver 최댓값을 골라 설치. 서버 없이 사이드로드 배포용.
22
+ - `opt.log` 진행/오류를 HTML 문자열로 받는 콜백. 다운로드 버튼·재시도 버튼 등 HTML 마크업이 포함되므로 호출측이 innerHTML 로 렌더해야 함.
23
+ - `opt.serviceClient` `@simplysm/service-client` `ServiceClient` 연결 인스턴스. 서버에 `AutoUpdateService` 가 등록되어 있어야 함.
24
+ - `opt.dirPath` — external 저장소 루트 기준 상대 경로.
30
25
 
31
- 공통:
32
- - 현재 앱 버전(`ApkInstaller.getVersionInfo().versionName`) 보다 높은 버전만 설치.
33
- - semver 유효성 실패 시 업데이트 스킵.
34
- - 설치 권한이 없으면 설정 화면 이동 + "재시도" 버튼 HTML 을 `log` 로 표시하고 최대 5분 대기.
35
- - 설치 후 `_freezeApp()` 으로 무한 대기 — 호출측에서 별도 후속 처리 불필요.
36
- - `log` 인자에는 HTML 문자열이 전달됨 (innerHTML 로 렌더링하도록 구성할 것).
26
+ 동작 주의:
37
27
 
38
- ## ApkInstaller
28
+ - UA 가 android 가 아니면 throw.
29
+ - 현재 또는 비교 대상 버전이 invalid semver 이거나 서버에서 버전 정보를 못 받으면 silent return (로그만 남김).
30
+ - 권한 미부여 시 `ApkInstaller.requestPermissions()` 호출 후 1초 간격 최대 300회(5분) polling.
31
+ - manifest 에 `REQUEST_INSTALL_PACKAGES` 미선언이거나 권한 확인 자체가 실패하면 "APK 재다운로드/재설치" 안내를 throw — `run` 의 경우 다운로드 링크 버튼 HTML 을 메시지에 포함.
32
+ - try/catch 종료 후 항상 `_freezeApp()`(무한 await) — 정상 경로·에러 경로 모두 호출부의 후속 코드는 실행되지 않음 전제로 사용.
39
33
 
40
- `abstract class ApkInstaller` (static 메서드만). Capacitor 플러그인 `"ApkInstaller"` 래퍼. Web 환경에서는 알림만 표시 후 정상 반환.
34
+ 사용 예:
41
35
 
42
36
  ```ts
43
- ApkInstaller.checkPermissions(): Promise<{ granted: boolean; manifest: boolean }>
37
+ await AutoUpdate.run({ log: (h) => (document.body.innerHTML = h), serviceClient });
44
38
  ```
45
- `granted` = REQUEST_INSTALL_PACKAGES 승인 여부, `manifest` = AndroidManifest 에 권한 선언 여부. `manifest=false` 면 APK 재설치 필요.
46
39
 
47
- ```ts
48
- ApkInstaller.requestPermissions(): Promise<void>
49
- ```
50
- 설정 화면으로 이동시켜 사용자에게 권한 요청. 사용자 응답을 await 하지 않으므로 호출측에서 polling 필요 (`checkPermissions` 반복).
40
+ ## `ApkInstaller`
51
41
 
52
42
  ```ts
53
- ApkInstaller.install(apkUri: string): Promise<void>
43
+ abstract class ApkInstaller {
44
+ static checkPermissions(): Promise<{ granted: boolean; manifest: boolean }>;
45
+ static requestPermissions(): Promise<void>;
46
+ static install(apkUri: string): Promise<void>;
47
+ static getVersionInfo(): Promise<VersionInfo>;
48
+ }
54
49
  ```
55
- `apkUri` 는 FileProvider 의 `content://` URI. `@simplysm/capacitor-plugin-file-system` 의 `FileSystem.getUri(path)` 로 변환해 전달.
50
+
51
+ - `checkPermissions` — `granted` 는 사용자의 `REQUEST_INSTALL_PACKAGES` 승인 여부, `manifest` 는 AndroidManifest 에 권한이 선언돼 있는지. `manifest=false` 면 APK 자체를 재빌드/재설치 해야 함.
52
+ - `requestPermissions` — 시스템 설정의 "알 수 없는 앱 설치" 화면으로 이동. 결과를 await 하지 않으므로 호출측에서 `checkPermissions` polling 필요.
53
+ - `install` — `apkUri` 는 `content://` FileProvider URI. `@simplysm/capacitor-plugin-file-system` 의 `FileSystem.getUri(path)` 로 변환해 넘김. 설치 인텐트 실행 후 즉시 반환 — 실제 설치 완료를 await 하지 않음.
54
+ - `getVersionInfo` — 현재 설치된 앱 자체의 `versionName`/`versionCode` 반환.
55
+ - 웹(비-android) 환경에서는 `ApkInstallerWeb` 폴백이 알림만 표시하고 정상 반환(no-op).
56
+
57
+ 사용 예:
56
58
 
57
59
  ```ts
58
- ApkInstaller.getVersionInfo(): Promise<VersionInfo>
60
+ const { granted } = await ApkInstaller.checkPermissions();
61
+ if (!granted) await ApkInstaller.requestPermissions();
62
+ await ApkInstaller.install(await FileSystem.getUri(apkFilePath));
59
63
  ```
60
- 현재 설치된 앱 자체의 버전을 반환.
61
64
 
62
- ## 타입
65
+ ## `ApkInstallerPlugin`, `VersionInfo`
63
66
 
64
67
  ```ts
65
- interface VersionInfo {
66
- versionName: string; // 예: "1.2.3"
67
- versionCode: string;
68
- }
69
-
68
+ interface VersionInfo { versionName: string; versionCode: string }
70
69
  interface ApkInstallerPlugin {
71
70
  install(options: { uri: string }): Promise<void>;
72
71
  checkPermissions(): Promise<{ granted: boolean; manifest: boolean }>;
@@ -74,3 +73,7 @@ interface ApkInstallerPlugin {
74
73
  getVersionInfo(): Promise<VersionInfo>;
75
74
  }
76
75
  ```
76
+
77
+ - `VersionInfo.versionName` — `build.gradle` 의 versionName 문자열. `AutoUpdate` 가 semver 비교에 사용하므로 semver 형식 권장.
78
+ - `VersionInfo.versionCode` — versionCode 를 문자열로 반환(정수 증가값).
79
+ - `ApkInstallerPlugin` — `registerPlugin<ApkInstallerPlugin>("ApkInstaller", ...)` 의 타입 파라미터. 직접 호출하지 말고 `ApkInstaller` 정적 메서드 사용. 타입 참조/모킹 시에만 import.
@@ -1,32 +1,42 @@
1
1
  # @simplysm/capacitor-plugin-intent
2
2
 
3
- Android 인텐트(브로드캐스트 송수신, 실행 인텐트 조회, startActivityForResult) Capacitor 플러그인. 산업용 디바이스 연동(바코드 스캐너, PDA 등) 용도. 환경에서는 no-op + 경고 로그.
3
+ Android 인텐트 송수신·외부 Activity 실행용 Capacitor 플러그인. 산업용 디바이스 연동(바코드 스캐너·PDA 등). 웹은 stub(경고 로그 + no-op).
4
4
 
5
5
  ## 사용 트리거 인덱스
6
- - **`Intent.subscribe` / `Intent.unsubscribeAll`** — 특정 액션 브로드캐스트 수신.
7
- - **`Intent.send`** — 외부 앱에 브로드캐스트 송신(예: DataWedge 트리거).
8
- - **`Intent.getLaunchIntent`** — 앱이 인텐트로 기동될 때 초기 데이터 조회.
9
- - **`Intent.addListener("newIntent", ...)` / `Intent.removeAllListeners`** — 앱 실행 중 새 인텐트 수신.
10
- - **`Intent.startActivityForResult`** — 외부 Activity 실행 후 결과 수신(결제·인증 모듈 등).
11
- - **`IntentResult` / `StartActivityForResultOptions` / `StartActivityForResultResult`** — 타입 정의.
12
6
 
13
- ## Intent (abstract class, static only)
7
+ - **`Intent.subscribe` / `Intent.unsubscribeAll`** — 외부 앱이 보내는 브로드캐스트 액션을 앱에서 수신할 때 (스캐너 RESULT ).
8
+ - **`Intent.send`** — 외부 앱(DataWedge 등)에 브로드캐스트 명령을 송신할 때.
9
+ - **`Intent.getLaunchIntent`** — 앱을 기동시킨 인텐트의 action/extras 를 읽을 때.
10
+ - **`Intent.addListener("newIntent", …)` / `Intent.removeAllListeners`** — 이미 실행 중인 앱에 들어오는 새 인텐트를 받을 때 (`singleTask`/`singleTop` launchMode 필요).
11
+ - **`Intent.startActivityForResult`** — 외부 Activity 를 실행하고 결과 코드/데이터를 받을 때 (결제·인증 모듈 등).
12
+
13
+ ## `Intent` (abstract class, static only)
14
+
15
+ `new` 금지, 정적 메서드만 호출.
16
+
17
+ ### `subscribe(filters, callback): Promise<() => Promise<void>>`
18
+
19
+ - `filters: string[]` — 수신할 Intent action 문자열 배열.
20
+ - `callback: (result: IntentResult) => void` — 매 수신마다 호출. 등록 직후의 빈 resolve(`action == null`)는 내부 필터로 콜백 호출 X.
21
+ - 반환: 해당 구독만 해제하는 함수.
14
22
 
15
- ### `subscribe(filters, callback) → Promise<() => Promise<void>>`
16
- `filters`: 수신할 action 문자열 배열. `callback`: 매 수신마다 호출. 반환값은 구독 해제 함수.
17
23
  ```ts
18
24
  const unsub = await Intent.subscribe(
19
25
  ["com.symbol.datawedge.api.RESULT_ACTION"],
20
- (result) => console.log(result.extras),
26
+ (r) => console.log(r.extras),
21
27
  );
22
28
  await unsub();
23
29
  ```
24
30
 
25
- ### `unsubscribeAll() Promise<void>`
26
- 프로세스 내 모든 `subscribe` 구독 해제.
31
+ ### `unsubscribeAll(): Promise<void>`
32
+
33
+ `subscribe` 로 등록된 모든 수신기 해제.
34
+
35
+ ### `send({ action, extras? }): Promise<void>`
36
+
37
+ - `action: string` — 송신할 브로드캐스트 action.
38
+ - `extras?: Record<string, unknown>` — 함께 보낼 키/값.
27
39
 
28
- ### `send({ action, extras? }) → Promise<void>`
29
- 브로드캐스트 송신.
30
40
  ```ts
31
41
  await Intent.send({
32
42
  action: "com.symbol.datawedge.api.ACTION",
@@ -34,47 +44,48 @@ await Intent.send({
34
44
  });
35
45
  ```
36
46
 
37
- ### `getLaunchIntent() Promise<IntentResult>`
38
- 현재 앱을 실행시킨 인텐트의 action/extras 조회. 웹은 `{}` 반환.
47
+ ### `getLaunchIntent(): Promise<IntentResult>`
39
48
 
40
- ### `addListener("newIntent", callback) Promise<PluginListenerHandle>`
41
- 앱 실행 중 수신되는 새 인텐트(`onNewIntent`)에 대한 리스너 등록. `handle.remove()` 로 개별 해제.
49
+ 앱을 기동시킨 인텐트의 action/extras 반환. 웹은 `{}`.
42
50
 
43
- ### `removeAllListeners() Promise<void>`
44
- `addListener` 로 등록된 모든 리스너 제거.
51
+ ### `addListener("newIntent", callback): Promise<PluginListenerHandle>`
45
52
 
46
- ### `startActivityForResult(options) Promise<StartActivityForResultResult>`
47
- 외부 Activity 실행 후 결과 수신. `resultCode === -1` 이 `RESULT_OK`.
48
- ```ts
49
- const result = await Intent.startActivityForResult({
50
- action: "com.example.PAY",
51
- extras: { amount: 1000 },
52
- });
53
- if (result.resultCode === -1) { /* OK */ }
54
- ```
53
+ - `eventName: "newIntent"` — 고정 리터럴. Android `onNewIntent` 수신 시점에 호출.
54
+ - 반환 핸들의 `handle.remove()` 개별 해제.
55
55
 
56
- ## 타입
56
+ ### `removeAllListeners(): Promise<void>`
57
+
58
+ `addListener` 등록 전체 제거.
59
+
60
+ ### `startActivityForResult(options): Promise<StartActivityForResultResult>`
61
+
62
+ `StartActivityForResultOptions` (모두 선택, 최소 1개로 대상 결정):
63
+
64
+ - `action?: string` — Intent action.
65
+ - `uri?: string` — `setData()` URI.
66
+ - `extras?: Record<string, unknown>` — 전달 extras.
67
+ - `type?: string` — MIME type (`setType()`).
68
+ - `packageName?: string` — 대상 앱 패키지 한정.
69
+ - `className?: string` — 대상 Activity FQCN 한정.
70
+ - `flags?: number` — Intent flags 비트마스크 (Android `Intent.FLAG_*`).
57
71
 
58
- ### `IntentResult`
59
- - `action?: string` — 브로드캐스트 액션.
60
- - `extras?: Record<string, unknown>` — 추가 데이터.
72
+ 반환 `StartActivityForResultResult`:
61
73
 
62
- ### `StartActivityForResultOptions`
63
- - `action?: string`
64
- - `uri?: string`
65
- - `extras?: Record<string, unknown>`
66
- - `type?: string` — MIME type.
67
- - `packageName?: string` — 특정 앱 지정.
68
- - `className?: string` — 특정 Activity 지정.
69
- - `flags?: number` — Intent flags.
74
+ - `resultCode: number` — Android 결과 코드. `-1` = `RESULT_OK`, `0` = `RESULT_CANCELED`, 그 외 앱 정의 값.
75
+ - `data?: { action?, uri?, extras? }` — 결과 Intent 의 action/uri/extras.
70
76
 
71
- ### `StartActivityForResultResult`
72
- - `resultCode: number` Android `RESULT_*` 코드 (`-1` = OK, `0` = CANCELED).
73
- - `data?: { action?: string; uri?: string; extras?: Record<string, unknown> }`
77
+ ```ts
78
+ const r = await Intent.startActivityForResult({ action: "com.example.PAY", extras: { amount: 1000 } });
79
+ if (r.resultCode === -1) { /* OK */ }
80
+ ```
74
81
 
75
- ### `IntentPlugin`
76
- 저수준 Capacitor 플러그인 인터페이스. 일반적으로 직접 사용하지 않고 `Intent` static API 사용. 커스텀 래핑이 필요할 때만 참조.
82
+ ## 타입
83
+
84
+ - `IntentResult { action?: string; extras?: Record<string, unknown> }` — 수신/조회 결과 공통 형태.
85
+ - `StartActivityForResultOptions` / `StartActivityForResultResult` — 위 메서드 시그니처 참조.
86
+ - `IntentPlugin` — Capacitor `registerPlugin` 용 저수준 인터페이스. 커스텀 래핑이 필요할 때만 참조, 일반 사용은 `Intent` static API.
77
87
 
78
88
  ## 플랫폼 동작
89
+
79
90
  - Android: 네이티브 구현.
80
- - Web: 모든 변경 메서드(`subscribe`/`send`/`startActivityForResult`)는 `console.warn` 후 stub 반환. `getLaunchIntent`/`unsubscribe*` 는 조용히 no-op.
91
+ - Web(`IntentWeb`): `subscribe`/`send`/`startActivityForResult` 는 `consola.withTag("capacitor:intent").warn("웹 환경에서는 지원하지 않습니다.")` 후 stub 반환 (`subscribe` `{ id: "web-stub" }`, `startActivityForResult` → `{ resultCode: 0 }`, `send` → void). `getLaunchIntent``{}`, `unsubscribe`/`unsubscribeAll` 은 조용히 no-op.
@@ -10,7 +10,7 @@ USB Mass Storage 접근용 Capacitor 플러그인 (Android: libaums, Browser: In
10
10
 
11
11
  ## UsbStorage
12
12
 
13
- 모든 메서드 `static async`. 장치 식별은 `{ vendorId, productId }` (`UsbDeviceFilter`)로 한다.
13
+ 모든 메서드 `static async`. 장치 식별은 `{ vendorId, productId }` (`UsbDeviceFilter`) 로 한다.
14
14
 
15
15
  ```ts
16
16
  import { UsbStorage } from "@simplysm/capacitor-plugin-usb-storage";
@@ -27,13 +27,23 @@ const data = await UsbStorage.readFile(filter, "/a.txt"); // Bytes | undefi
27
27
  ```
28
28
 
29
29
  - `getDevices()` — 연결된 USB 장치 전체 반환.
30
- - `requestPermissions(filter)` / `checkPermissions(filter)` 권한 승인/보유 여부 `boolean`.
31
- - `readdir(filter, dirPath)` — 디렉토리 항목 목록 (`name`, `isDirectory`).
30
+ - `requestPermissions(filter)` 해당 장치 접근 권한 요청. `true` = 사용자가 승인, `false` = 거부. 사용자 인터랙션 유발.
31
+ - `checkPermissions(filter)` — 현재 권한 보유 여부 조회. 인터랙션 없음. `true` 면 곧바로 read 호출 가능.
32
+ - `readdir(filter, dirPath)` — 디렉토리 항목 목록 (`UsbFileInfo[]`).
32
33
  - `readFile(filter, filePath)` — 파일 바이트. 없으면 `undefined`. 내부에서 base64 → `Bytes`(@simplysm/core-common) 변환.
33
34
 
34
35
  ## 타입
35
36
 
36
- - `UsbDeviceInfo` — `deviceName`, `manufacturerName`, `productName`, `vendorId`, `productId`.
37
- - `UsbDeviceFilter` — `vendorId`, `productId`.
38
- - `UsbFileInfo` — `name`, `isDirectory`.
39
- - `UsbStoragePlugin` — Capacitor `registerPlugin` 원시 인터페이스. 메서드 반환이 `{ devices }`/`{ granted }`/`{ files }`/`{ data: string | null }` 형태의 base64 raw 응답.
37
+ `UsbDeviceInfo` — `getDevices()` 반환 원소.
38
+ - `deviceName` — OS 가 부여한 장치 노드 이름 (예: `/dev/bus/usb/001/002`).
39
+ - `manufacturerName` — 제조사 문자열.
40
+ - `productName` — 제품명 문자열.
41
+ - `vendorId` / `productId` — USB VID/PID 정수. 다른 메서드의 `filter` 로 그대로 사용.
42
+
43
+ `UsbDeviceFilter` — 장치 식별 인자. `vendorId`, `productId` 두 정수만.
44
+
45
+ `UsbFileInfo` — `readdir` 반환 원소.
46
+ - `name` — 항목 이름 (디렉토리 내 상대명, 경로 X).
47
+ - `isDirectory` — `true` = 하위 디렉토리(다시 `readdir` 호출 대상), `false` = 파일(`readFile` 호출 대상).
48
+
49
+ `UsbStoragePlugin` — Capacitor `registerPlugin` 원시 인터페이스. 메서드 반환이 `{ devices }`/`{ granted }`/`{ files }`/`{ data: string | null }` 형태의 base64 raw 응답. `UsbStorage` 가 이를 풀어 `Bytes`·`boolean` 등으로 변환해 노출.
@@ -1,131 +1,58 @@
1
1
  # @simplysm/core-common
2
-
3
- 공통 유틸리티(타입·에러·큐·이벤트·변환·확장 메서드·환경변수). simplysm 모든 패키지의 공용 기반.
2
+ 브라우저·Node 공통 유틸·타입·에러·확장 메서드 패키지. import 시 Array/Map/Set 프로토타입 확장이 자동 적용됨.
4
3
 
5
4
  ## 사용 트리거 인덱스
6
-
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·팩토리 패턴).
53
-
54
- ## 에러 클래스
55
-
56
- ```typescript
57
- new SdError(cause: Error, ...messages: string[])
58
- new SdError(...messages: string[])
59
- // 메시지는 역순 결합: "상위 => 하위 => 원인". cause stack을 현재 stack에 append.
60
-
61
- new ArgumentError(argObj)
62
- new ArgumentError(message, argObj)
63
- // 인자 객체를 YAML 형식으로 메시지에 포함.
64
-
65
- new NotImplementedError(message?) // "미구현: <message>"
66
- new TimeoutError(count?, message?) // "대기 시간 초과(N회 시도): <message>". wait.until 에서 자동 throw.
67
- ```
68
-
69
- 모두 `SdError` 상속. `name` 자동 설정.
70
-
71
- ## 환경변수
72
-
73
- ```typescript
74
- env("PORT") // string | undefined (process.env → import.meta.env)
75
- env("PORT", "3000") // void (process.env 에 기록, process 없으면 무시)
76
- parseBoolEnv(v) // "true"|"1"|"yes"|"on" → true (대소문자 무시)
5
+ - **`env`, `parseBoolEnv`, `__DEV__`** — 환경변수 읽기/쓰기 또는 빌드 시점 dev 플래그 분기. (인라인)
6
+ - **에러 클래스 (`SdError`, `ArgumentError`, `NotImplementedError`, `TimeoutError`)** 도메인별 에러 throw 또는 instanceof 분기. (인라인)
7
+ - **공통 타입 유틸 (`Bytes`, `Type<T>`, `DeepPartial<T>`, `PrimitiveType*`)** 타입 시그니처 작성, 생성자/원시타입 타입화. (인라인)
8
+ - **날짜·시간·UUID·LazyGcMap 클래스** 도메인 객체 생성/파싱/연산. 자세히: [types.md](./types.md)
9
+ - **이벤트·큐 클래스 (`EventEmitter`, `DebounceQueue`, `SerialQueue`)** 입력 디바운싱, 작업 직렬화, 타입 안전 이벤트 발행. 자세히: [features.md](./features.md)
10
+ - **Array/Map/Set 확장 메서드** `single`/`first`/`groupBy`/`toMap`/`distinct`/`orderBy`/`diffs`/`merge`/`toTree`, `Map.getOrCreate`/`update`, `Set.adds`/`toggle` 등. 자세히: [extensions.md](./extensions.md)
11
+ - **`obj`/`str`/`num`/`bytes`/`path`/`json`/`xml`/`wait`/`transfer`/`err`/`dt`/`primitive` 네임스페이스 + `js`/`ts`/`html`/`tsql`/`mysql`/`pgsql` 태그, `ZipArchive`** — 객체 복제·동등성·병합, 문자열 파싱·casing, JSON/XML 직렬화, Worker 전송, 날짜 포맷팅 등. 자세히: [utils.md](./utils.md)
12
+
13
+ ## env
14
+
15
+ ```ts
16
+ env(key: string): string | undefined
17
+ env(key: string, value: string): void // process.env에 set
18
+ parseBoolEnv(value: unknown): boolean // "true"|"1"|"yes"|"on" (대소문자 무시) true
19
+ declare const __DEV__: boolean // 빌드 define으로 치환 (라이브러리 빌드에선 미치환)
77
20
  ```
21
+ - `env(key)`: `process.env[key]` 우선, 없으면 `import.meta.env[key]`. 둘 다 없으면 `undefined`. Node/브라우저 양쪽 안전.
78
22
 
79
- ## 템플릿 문자열 태그
23
+ ## 에러 클래스
80
24
 
81
- ```typescript
82
- import { js, ts, html, tsql, mysql, pgsql } from "@simplysm/core-common";
25
+ 모두 `SdError` 상속. ES2024 `cause` 사용. V8에서 `captureStackTrace` + cause stack 결합.
83
26
 
84
- const code = ts`
85
- interface User { name: string; }
86
- `;
87
- // "interface User { name: string; }" (앞뒤 빈 줄·공통 들여쓰기 제거)
27
+ ```ts
28
+ new SdError(cause: Error, ...messages: string[]) // "상위msg => ... => cause.message"
29
+ new SdError(...messages: string[]) // 메시지 가변 인자, 역순 " => " join
30
+ new ArgumentError(argObj) // "잘못된 인자입니다.\n\n<YAML>"
31
+ new ArgumentError(message, argObj) // message + YAML 첨부
32
+ new NotImplementedError(message?) // "미구현[: message]"
33
+ new TimeoutError(count?, message?) // "대기 시간 초과[(N회 시도)][: message]"
88
34
  ```
35
+ - `cause`: 원인 Error. 메시지·stack이 결합되어 디버깅 가능.
36
+ - `messages`: 가변 인자, **역순으로** ` => ` join (상위 컨텍스트가 앞).
37
+ - `ArgumentError.argObj`: 검사 실패한 인자 객체. `yaml` 라이브러리로 YAML 렌더되어 메시지 끝에 첨부.
89
38
 
90
- 모두 동일 함수, IDE 하이라이팅 차별화 목적.
39
+ ## 공통 타입 유틸 (`common.types.ts`)
91
40
 
92
- ## ZIP 처리
41
+ ```ts
42
+ type Bytes = Uint8Array // 바이너리 표준 타입 (Buffer 대체)
43
+ interface Type<T> extends Function { new (...args: unknown[]): T } // 클래스 생성자 타입
44
+ type DeepPartial<T> // 재귀 Partial (원시타입은 그대로)
93
45
 
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(); // 필수
46
+ type PrimitiveTypeMap = { // 원시 타입 ↔ 문자열 키 매핑
47
+ string, number, boolean, DateTime, DateOnly, Time, Uuid, Bytes
105
48
  }
106
-
107
- // 쓰기
108
- const archive = new ZipArchive();
109
- archive.write("file.txt", bytes);
110
- const zipBytes = await archive.compress(); // 내부적으로 extractAll → 전체 메모리 로드
111
- await archive.close();
49
+ type PrimitiveTypeStr = keyof PrimitiveTypeMap // "string"|"number"|...
50
+ type PrimitiveType = PrimitiveTypeMap[PrimitiveTypeStr] | undefined // 값 union
112
51
  ```
52
+ - `Type<T>`: DI/팩토리/instanceof 체크용. `new ctor()` 호출 가능.
53
+ - `DeepPartial<T>`: 객체·array는 재귀 Partial. 원시·`DateTime`/`DateOnly`/`Time`/`Uuid`/`Bytes`는 leaf로 유지.
54
+ - `PrimitiveType*`: `@simplysm/orm-common`과 공유. `primitive.typeStr(value)` 런타임 추론과 한 쌍.
113
55
 
114
- `extractAll` 진행률 콜백: `{ fileName, totalSize, extractedSize }`. `compress()` 는 전체 파일을 메모리에 로드하므로 대용량 ZIP 주의.
56
+ ## 부수 효과 (import 자동 적용)
115
57
 
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
- ```
58
+ `@simplysm/core-common`을 번이라도 import하면 `Array.prototype`·`Map.prototype`·`Set.prototype`에 확장 메서드가 enumerable=false로 추가됨. 글로벌 인터페이스(`Array<T>`, `ReadonlyArray<T>`, `Map<K,V>`, `Set<T>`)도 ambient declare됨.