@simplysm/sd-claude 14.0.82 → 14.0.84
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/claude/references/sd-requirement-source-handling.md +20 -20
- package/claude/references/sd-simplysm14/README.md +13 -13
- package/claude/references/sd-simplysm14/manuals/client-component.md +92 -92
- package/claude/references/sd-simplysm14/manuals/client-crud.md +11 -11
- package/claude/references/sd-simplysm14/manuals/client-demo.md +28 -28
- package/claude/references/sd-simplysm14/manuals/client-rules.md +1 -1
- package/claude/references/sd-simplysm14/manuals/client-setup.md +21 -21
- package/claude/references/sd-simplysm14/manuals/client-tab.md +3 -3
- package/claude/references/sd-simplysm14/manuals/logging.md +15 -15
- package/claude/references/sd-simplysm14/manuals/orm-union.md +6 -6
- package/claude/references/sd-simplysm14/manuals/orm.md +19 -19
- package/claude/references/sd-simplysm14/manuals/test.md +33 -33
- package/claude/rules/sd-design-rules.md +18 -18
- package/claude/sd-system-prompt.md +369 -0
- package/claude/skills/sd-commit/SKILL.md +10 -10
- package/claude/skills/sd-config/SKILL.md +2 -2
- package/claude/skills/sd-demo/SKILL.md +45 -45
- package/claude/skills/sd-dev/SKILL.md +15 -15
- package/claude/skills/sd-docs/SKILL.md +7 -7
- package/claude/skills/sd-docs/references/subagent-prompt.md +33 -33
- package/claude/skills/sd-impl/SKILL.md +60 -60
- package/claude/skills/sd-review/SKILL.md +9 -9
- package/claude/skills/sd-skill/SKILL.md +74 -74
- package/claude/skills/sd-skill/evals/fixtures/existing-skill/.claude/skills/todo-format/SKILL.md +1 -1
- package/claude/skills/sd-spec/SKILL.md +354 -319
- package/claude/skills/sd-spec/references/example-spec.md +104 -104
- package/claude/skills/sd-unpack/SKILL.md +34 -34
- package/claude/skills/sd-unpack/scripts/handlers/__pycache__/office_com.cpython-314.pyc +0 -0
- package/claude/skills/sd-unpack/scripts/handlers/office_com.py +234 -159
- package/claude/skills/sd-use/SKILL.md +4 -4
- package/package.json +1 -1
- package/claude/references/sd-simplysm14/apis/angular/README.md +0 -37
- package/claude/references/sd-simplysm14/apis/angular/app-structure.md +0 -92
- package/claude/references/sd-simplysm14/apis/angular/buttons.md +0 -88
- package/claude/references/sd-simplysm14/apis/angular/crud.md +0 -100
- package/claude/references/sd-simplysm14/apis/angular/forms.md +0 -200
- package/claude/references/sd-simplysm14/apis/angular/infrastructure.md +0 -231
- package/claude/references/sd-simplysm14/apis/angular/kanban.md +0 -80
- package/claude/references/sd-simplysm14/apis/angular/layout.md +0 -92
- package/claude/references/sd-simplysm14/apis/angular/modal.md +0 -115
- package/claude/references/sd-simplysm14/apis/angular/routing.md +0 -107
- package/claude/references/sd-simplysm14/apis/angular/select-dropdown.md +0 -35
- package/claude/references/sd-simplysm14/apis/angular/selection-managers.md +0 -82
- package/claude/references/sd-simplysm14/apis/angular/shared-data.md +0 -134
- package/claude/references/sd-simplysm14/apis/angular/sheet.md +0 -127
- package/claude/references/sd-simplysm14/apis/angular/toast.md +0 -97
- package/claude/references/sd-simplysm14/apis/angular/visual.md +0 -167
- package/claude/references/sd-simplysm14/apis/capacitor-plugin-auto-update/README.md +0 -79
- package/claude/references/sd-simplysm14/apis/capacitor-plugin-file-system/README.md +0 -83
- package/claude/references/sd-simplysm14/apis/capacitor-plugin-intent/README.md +0 -91
- package/claude/references/sd-simplysm14/apis/capacitor-plugin-usb-storage/README.md +0 -49
- package/claude/references/sd-simplysm14/apis/core-browser/README.md +0 -143
- package/claude/references/sd-simplysm14/apis/core-common/README.md +0 -58
- package/claude/references/sd-simplysm14/apis/core-common/extensions.md +0 -88
- package/claude/references/sd-simplysm14/apis/core-common/features.md +0 -51
- package/claude/references/sd-simplysm14/apis/core-common/types.md +0 -88
- package/claude/references/sd-simplysm14/apis/core-common/utils.md +0 -189
- package/claude/references/sd-simplysm14/apis/core-node/README.md +0 -12
- package/claude/references/sd-simplysm14/apis/core-node/consola.md +0 -59
- package/claude/references/sd-simplysm14/apis/core-node/cpx.md +0 -44
- package/claude/references/sd-simplysm14/apis/core-node/fs-watcher.md +0 -42
- package/claude/references/sd-simplysm14/apis/core-node/fsx.md +0 -53
- package/claude/references/sd-simplysm14/apis/core-node/pathx.md +0 -24
- package/claude/references/sd-simplysm14/apis/core-node/worker.md +0 -65
- package/claude/references/sd-simplysm14/apis/excel/README.md +0 -193
- package/claude/references/sd-simplysm14/apis/lint/README.md +0 -94
- package/claude/references/sd-simplysm14/apis/orm-common/README.md +0 -58
- package/claude/references/sd-simplysm14/apis/orm-common/db-context.md +0 -77
- package/claude/references/sd-simplysm14/apis/orm-common/executable.md +0 -20
- package/claude/references/sd-simplysm14/apis/orm-common/expr.md +0 -92
- package/claude/references/sd-simplysm14/apis/orm-common/queryable.md +0 -98
- package/claude/references/sd-simplysm14/apis/orm-common/schema-builders.md +0 -128
- package/claude/references/sd-simplysm14/apis/orm-node/README.md +0 -69
- package/claude/references/sd-simplysm14/apis/sd-claude/README.md +0 -32
- package/claude/references/sd-simplysm14/apis/sd-cli/README.md +0 -80
- package/claude/references/sd-simplysm14/apis/sd-cli/sd-config.md +0 -155
- package/claude/references/sd-simplysm14/apis/service-client/README.md +0 -131
- package/claude/references/sd-simplysm14/apis/service-common/README.md +0 -29
- package/claude/references/sd-simplysm14/apis/service-common/app-structure.md +0 -63
- package/claude/references/sd-simplysm14/apis/service-common/messages.md +0 -56
- package/claude/references/sd-simplysm14/apis/service-common/protocol.md +0 -64
- package/claude/references/sd-simplysm14/apis/service-common/service-types.md +0 -43
- package/claude/references/sd-simplysm14/apis/service-server/README.md +0 -13
- package/claude/references/sd-simplysm14/apis/service-server/auth.md +0 -39
- package/claude/references/sd-simplysm14/apis/service-server/builtin-services.md +0 -71
- package/claude/references/sd-simplysm14/apis/service-server/define-service.md +0 -55
- package/claude/references/sd-simplysm14/apis/service-server/internals.md +0 -82
- package/claude/references/sd-simplysm14/apis/service-server/server.md +0 -57
- package/claude/references/sd-simplysm14/apis/storage/README.md +0 -71
- package/claude/rules/sd-base-rules.md +0 -306
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
# @simplysm/capacitor-plugin-auto-update
|
|
2
|
-
|
|
3
|
-
Android Capacitor 앱의 APK 자동 업데이트 흐름(버전 비교 → 다운로드 → 권한 확인 → 설치)과 APK 설치 네이티브 플러그인 래퍼.
|
|
4
|
-
|
|
5
|
-
## 사용 트리거 인덱스
|
|
6
|
-
|
|
7
|
-
- **`AutoUpdate`** — 앱 부팅 직후 서버 또는 외부 저장소에서 최신 APK 버전을 확인·다운로드·설치하는 전체 흐름을 한 번에 실행할 때.
|
|
8
|
-
- **`ApkInstaller`** — 자체 UI/흐름을 만들면서 APK 설치 권한·설치·현재 앱 버전 조회를 개별로 호출할 때.
|
|
9
|
-
- **`ApkInstallerPlugin`, `VersionInfo`** — Capacitor 플러그인 인터페이스 타입을 참조하거나 모킹할 때.
|
|
10
|
-
|
|
11
|
-
## `AutoUpdate`
|
|
12
|
-
|
|
13
|
-
```ts
|
|
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
|
-
}
|
|
18
|
-
```
|
|
19
|
-
|
|
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 저장소 루트 기준 상대 경로.
|
|
25
|
-
|
|
26
|
-
동작 주의:
|
|
27
|
-
|
|
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) — 정상 경로·에러 경로 모두 호출부의 후속 코드는 실행되지 않음 전제로 사용.
|
|
33
|
-
|
|
34
|
-
사용 예:
|
|
35
|
-
|
|
36
|
-
```ts
|
|
37
|
-
await AutoUpdate.run({ log: (h) => (document.body.innerHTML = h), serviceClient });
|
|
38
|
-
```
|
|
39
|
-
|
|
40
|
-
## `ApkInstaller`
|
|
41
|
-
|
|
42
|
-
```ts
|
|
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
|
-
}
|
|
49
|
-
```
|
|
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
|
-
사용 예:
|
|
58
|
-
|
|
59
|
-
```ts
|
|
60
|
-
const { granted } = await ApkInstaller.checkPermissions();
|
|
61
|
-
if (!granted) await ApkInstaller.requestPermissions();
|
|
62
|
-
await ApkInstaller.install(await FileSystem.getUri(apkFilePath));
|
|
63
|
-
```
|
|
64
|
-
|
|
65
|
-
## `ApkInstallerPlugin`, `VersionInfo`
|
|
66
|
-
|
|
67
|
-
```ts
|
|
68
|
-
interface VersionInfo { versionName: string; versionCode: string }
|
|
69
|
-
interface ApkInstallerPlugin {
|
|
70
|
-
install(options: { uri: string }): Promise<void>;
|
|
71
|
-
checkPermissions(): Promise<{ granted: boolean; manifest: boolean }>;
|
|
72
|
-
requestPermissions(): Promise<void>;
|
|
73
|
-
getVersionInfo(): Promise<VersionInfo>;
|
|
74
|
-
}
|
|
75
|
-
```
|
|
76
|
-
|
|
77
|
-
- `VersionInfo.versionName` — `build.gradle` 의 versionName 문자열. `AutoUpdate` 가 semver 비교에 사용하므로 semver 형식 권장.
|
|
78
|
-
- `VersionInfo.versionCode` — versionCode 를 문자열로 반환(정수 증가값).
|
|
79
|
-
- `ApkInstallerPlugin` — `registerPlugin<ApkInstallerPlugin>("ApkInstaller", ...)` 의 타입 파라미터. 직접 호출하지 말고 `ApkInstaller` 정적 메서드 사용. 타입 참조/모킹 시에만 import.
|
|
@@ -1,83 +0,0 @@
|
|
|
1
|
-
# @simplysm/capacitor-plugin-file-system
|
|
2
|
-
|
|
3
|
-
Capacitor 기반 파일 시스템 접근 플러그인. Android(11+ MANAGE_EXTERNAL_STORAGE, 10- READ/WRITE_EXTERNAL_STORAGE) 네이티브, Web 은 IndexedDB 에뮬레이션.
|
|
4
|
-
|
|
5
|
-
## 사용 트리거 인덱스
|
|
6
|
-
|
|
7
|
-
- **`FileSystem`** — 모바일/웹에서 파일·디렉토리 읽기/쓰기/삭제, 저장소 경로·URI 조회, 권한 처리 필요 시.
|
|
8
|
-
- **`FileInfo`, `StorageType`** — `readdir` 결과 처리, `getStoragePath` 호출 시 타입.
|
|
9
|
-
- **`FileSystemPlugin`** — 저수준 Capacitor 플러그인 인터페이스 직접 호출 필요 시(정상적으론 `FileSystem` 정적 메서드 사용).
|
|
10
|
-
|
|
11
|
-
## FileSystem
|
|
12
|
-
|
|
13
|
-
`abstract class` — 정적 메서드만 호출.
|
|
14
|
-
|
|
15
|
-
```ts
|
|
16
|
-
// 권한
|
|
17
|
-
await FileSystem.checkPermissions(): Promise<boolean>
|
|
18
|
-
await FileSystem.requestPermissions(): Promise<void> // Android 11+: 설정 화면 이동, 10-: 권한 대화상자
|
|
19
|
-
|
|
20
|
-
// 경로/URI
|
|
21
|
-
await FileSystem.getStoragePath(type: StorageType): Promise<string>
|
|
22
|
-
await FileSystem.getUri(filePath: string): Promise<string> // 네이티브: FileProvider URI / Web: Blob URL (사용 후 `URL.revokeObjectURL` 필수)
|
|
23
|
-
|
|
24
|
-
// 디렉토리
|
|
25
|
-
await FileSystem.readdir(dirPath: string): Promise<FileInfo[]>
|
|
26
|
-
await FileSystem.mkdir(targetPath: string): Promise<void> // 재귀
|
|
27
|
-
|
|
28
|
-
// 파일
|
|
29
|
-
await FileSystem.writeFile(filePath: string, data: string | Bytes): Promise<void>
|
|
30
|
-
await FileSystem.readFile(filePath: string): Promise<Bytes>
|
|
31
|
-
await FileSystem.readFile(filePath: string, encoding: "utf8"): Promise<string>
|
|
32
|
-
|
|
33
|
-
// 공통
|
|
34
|
-
await FileSystem.remove(targetPath: string): Promise<void> // 파일/디렉토리 재귀 삭제
|
|
35
|
-
await FileSystem.exists(targetPath: string): Promise<boolean>
|
|
36
|
-
```
|
|
37
|
-
|
|
38
|
-
`writeFile`: `string` 은 utf8, `Bytes`(=`Uint8Array`, `@simplysm/core-common`) 는 base64 로 전달. cross-realm 안전.
|
|
39
|
-
`readFile`: encoding 미지정 시 `Bytes`, `"utf8"` 지정 시 `string`.
|
|
40
|
-
|
|
41
|
-
사용 예:
|
|
42
|
-
|
|
43
|
-
```ts
|
|
44
|
-
if (!(await FileSystem.checkPermissions())) await FileSystem.requestPermissions();
|
|
45
|
-
const root = await FileSystem.getStoragePath("externalFiles");
|
|
46
|
-
await FileSystem.mkdir(`${root}/logs`);
|
|
47
|
-
await FileSystem.writeFile(`${root}/logs/a.txt`, "hello");
|
|
48
|
-
const files = await FileSystem.readdir(`${root}/logs`);
|
|
49
|
-
```
|
|
50
|
-
|
|
51
|
-
## FileInfo / StorageType
|
|
52
|
-
|
|
53
|
-
```ts
|
|
54
|
-
interface FileInfo { name: string; isDirectory: boolean; }
|
|
55
|
-
|
|
56
|
-
type StorageType =
|
|
57
|
-
| "external" // 외부 저장소 루트 (Environment.getExternalStorageDirectory)
|
|
58
|
-
| "externalFiles" // 앱 전용 외부 파일
|
|
59
|
-
| "externalCache" // 앱 전용 외부 캐시
|
|
60
|
-
| "externalMedia" // 앱 전용 외부 미디어
|
|
61
|
-
| "appData" // 앱 데이터
|
|
62
|
-
| "appFiles" // 앱 파일
|
|
63
|
-
| "appCache"; // 앱 캐시
|
|
64
|
-
```
|
|
65
|
-
|
|
66
|
-
## FileSystemPlugin
|
|
67
|
-
|
|
68
|
-
저수준 Capacitor 인터페이스. `FileSystem` 의 모든 정적 메서드가 위임 대상. 직접 사용 시 `writeFile`/`readFile` 의 `encoding` 은 `"utf8" | "base64"`, `data` 는 항상 `string`.
|
|
69
|
-
|
|
70
|
-
```ts
|
|
71
|
-
interface FileSystemPlugin {
|
|
72
|
-
checkPermissions(): Promise<{ granted: boolean }>;
|
|
73
|
-
requestPermissions(): Promise<void>;
|
|
74
|
-
readdir(options: { path: string }): Promise<{ files: FileInfo[] }>;
|
|
75
|
-
getStoragePath(options: { type: StorageType }): Promise<{ path: string }>;
|
|
76
|
-
getUri(options: { path: string }): Promise<{ uri: string }>;
|
|
77
|
-
writeFile(options: { path: string; data: string; encoding?: "utf8" | "base64" }): Promise<void>;
|
|
78
|
-
readFile(options: { path: string; encoding?: "utf8" | "base64" }): Promise<{ data: string }>;
|
|
79
|
-
remove(options: { path: string }): Promise<void>;
|
|
80
|
-
mkdir(options: { path: string }): Promise<void>;
|
|
81
|
-
exists(options: { path: string }): Promise<{ exists: boolean }>;
|
|
82
|
-
}
|
|
83
|
-
```
|
|
@@ -1,91 +0,0 @@
|
|
|
1
|
-
# @simplysm/capacitor-plugin-intent
|
|
2
|
-
|
|
3
|
-
Android 인텐트 송수신·외부 Activity 실행용 Capacitor 플러그인. 산업용 디바이스 연동(바코드 스캐너·PDA 등). 웹은 stub(경고 로그 + no-op).
|
|
4
|
-
|
|
5
|
-
## 사용 트리거 인덱스
|
|
6
|
-
|
|
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
|
-
- 반환: 해당 구독만 해제하는 함수.
|
|
22
|
-
|
|
23
|
-
```ts
|
|
24
|
-
const unsub = await Intent.subscribe(
|
|
25
|
-
["com.symbol.datawedge.api.RESULT_ACTION"],
|
|
26
|
-
(r) => console.log(r.extras),
|
|
27
|
-
);
|
|
28
|
-
await unsub();
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
### `unsubscribeAll(): Promise<void>`
|
|
32
|
-
|
|
33
|
-
`subscribe` 로 등록된 모든 수신기 해제.
|
|
34
|
-
|
|
35
|
-
### `send({ action, extras? }): Promise<void>`
|
|
36
|
-
|
|
37
|
-
- `action: string` — 송신할 브로드캐스트 action.
|
|
38
|
-
- `extras?: Record<string, unknown>` — 함께 보낼 키/값.
|
|
39
|
-
|
|
40
|
-
```ts
|
|
41
|
-
await Intent.send({
|
|
42
|
-
action: "com.symbol.datawedge.api.ACTION",
|
|
43
|
-
extras: { "com.symbol.datawedge.api.SOFT_SCAN_TRIGGER": "TOGGLE_SCANNING" },
|
|
44
|
-
});
|
|
45
|
-
```
|
|
46
|
-
|
|
47
|
-
### `getLaunchIntent(): Promise<IntentResult>`
|
|
48
|
-
|
|
49
|
-
앱을 기동시킨 인텐트의 action/extras 반환. 웹은 `{}`.
|
|
50
|
-
|
|
51
|
-
### `addListener("newIntent", callback): Promise<PluginListenerHandle>`
|
|
52
|
-
|
|
53
|
-
- `eventName: "newIntent"` — 고정 리터럴. Android `onNewIntent` 수신 시점에 호출.
|
|
54
|
-
- 반환 핸들의 `handle.remove()` 로 개별 해제.
|
|
55
|
-
|
|
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_*`).
|
|
71
|
-
|
|
72
|
-
반환 `StartActivityForResultResult`:
|
|
73
|
-
|
|
74
|
-
- `resultCode: number` — Android 결과 코드. `-1` = `RESULT_OK`, `0` = `RESULT_CANCELED`, 그 외 앱 정의 값.
|
|
75
|
-
- `data?: { action?, uri?, extras? }` — 결과 Intent 의 action/uri/extras.
|
|
76
|
-
|
|
77
|
-
```ts
|
|
78
|
-
const r = await Intent.startActivityForResult({ action: "com.example.PAY", extras: { amount: 1000 } });
|
|
79
|
-
if (r.resultCode === -1) { /* OK */ }
|
|
80
|
-
```
|
|
81
|
-
|
|
82
|
-
## 타입
|
|
83
|
-
|
|
84
|
-
- `IntentResult { action?: string; extras?: Record<string, unknown> }` — 수신/조회 결과 공통 형태.
|
|
85
|
-
- `StartActivityForResultOptions` / `StartActivityForResultResult` — 위 메서드 시그니처 참조.
|
|
86
|
-
- `IntentPlugin` — Capacitor `registerPlugin` 용 저수준 인터페이스. 커스텀 래핑이 필요할 때만 참조, 일반 사용은 `Intent` static API.
|
|
87
|
-
|
|
88
|
-
## 플랫폼 동작
|
|
89
|
-
|
|
90
|
-
- Android: 네이티브 구현.
|
|
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.
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
# @simplysm/capacitor-plugin-usb-storage
|
|
2
|
-
|
|
3
|
-
USB Mass Storage 접근용 Capacitor 플러그인 (Android: libaums, Browser: IndexedDB 가상 USB 에뮬레이션).
|
|
4
|
-
|
|
5
|
-
## 사용 트리거 인덱스
|
|
6
|
-
|
|
7
|
-
- **`UsbStorage`** — 정적 메서드로 장치 목록·권한·디렉토리·파일 읽기. USB 저장 장치에서 데이터를 가져올 때.
|
|
8
|
-
- **`UsbDeviceInfo` / `UsbDeviceFilter` / `UsbFileInfo`** — 인자·반환 타입. 호출부 타입 선언에.
|
|
9
|
-
- **`UsbStoragePlugin`** — 원시 Capacitor 플러그인 인터페이스. `UsbStorage` 래퍼로 충분하면 직접 사용 X.
|
|
10
|
-
|
|
11
|
-
## UsbStorage
|
|
12
|
-
|
|
13
|
-
모든 메서드 `static async`. 장치 식별은 `{ vendorId, productId }` (`UsbDeviceFilter`) 로 한다.
|
|
14
|
-
|
|
15
|
-
```ts
|
|
16
|
-
import { UsbStorage } from "@simplysm/capacitor-plugin-usb-storage";
|
|
17
|
-
|
|
18
|
-
const devices = await UsbStorage.getDevices(); // UsbDeviceInfo[]
|
|
19
|
-
const filter = { vendorId: devices[0].vendorId, productId: devices[0].productId };
|
|
20
|
-
|
|
21
|
-
if (!(await UsbStorage.checkPermissions(filter))) {
|
|
22
|
-
if (!(await UsbStorage.requestPermissions(filter))) return; // boolean
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
const files = await UsbStorage.readdir(filter, "/"); // UsbFileInfo[]
|
|
26
|
-
const data = await UsbStorage.readFile(filter, "/a.txt"); // Bytes | undefined
|
|
27
|
-
```
|
|
28
|
-
|
|
29
|
-
- `getDevices()` — 연결된 USB 장치 전체 반환.
|
|
30
|
-
- `requestPermissions(filter)` — 해당 장치 접근 권한 요청. `true` = 사용자가 승인, `false` = 거부. 사용자 인터랙션 유발.
|
|
31
|
-
- `checkPermissions(filter)` — 현재 권한 보유 여부 조회. 인터랙션 없음. `true` 면 곧바로 read 호출 가능.
|
|
32
|
-
- `readdir(filter, dirPath)` — 디렉토리 항목 목록 (`UsbFileInfo[]`).
|
|
33
|
-
- `readFile(filter, filePath)` — 파일 바이트. 없으면 `undefined`. 내부에서 base64 → `Bytes`(@simplysm/core-common) 변환.
|
|
34
|
-
|
|
35
|
-
## 타입
|
|
36
|
-
|
|
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,143 +0,0 @@
|
|
|
1
|
-
# @simplysm/core-browser
|
|
2
|
-
|
|
3
|
-
브라우저 전용 보강 — `Element`/`HTMLElement` 프로토타입 확장(import 사이드 이펙트) + DOM/파일/네트워크/IndexedDB 헬퍼.
|
|
4
|
-
|
|
5
|
-
> 이 패키지를 import 만 해도 `Element`/`HTMLElement` 프로토타입이 확장된다. SSR 환경에서는 import 자체를 피한다.
|
|
6
|
-
|
|
7
|
-
## 사용 트리거 인덱스
|
|
8
|
-
|
|
9
|
-
DOM 탐색/가시성 — `Element` 확장:
|
|
10
|
-
|
|
11
|
-
- **`findAll`** — `el` 하위에서 선택자 일치 요소 전부 배열로 받을 때.
|
|
12
|
-
- **`findFirst`** — `el` 하위에서 선택자 일치 첫 요소만 받을 때 (`querySelector` 의 `null` 대신 `undefined`).
|
|
13
|
-
- **`prependChild`** — 자식 목록의 맨 앞으로 삽입할 때.
|
|
14
|
-
- **`getParents`** — 가까운 부모부터 위로 거슬러 올라가는 조상 배열이 필요할 때.
|
|
15
|
-
- **`isOffsetElement`** — 어떤 요소가 자식 absolute 의 기준이 되는지(`position: relative/absolute/fixed/sticky`) 판정할 때.
|
|
16
|
-
- **`isVisible`** — 화면에 실제로 보이는지(클라이언트 영역 + `visibility` + `opacity`) 판정할 때.
|
|
17
|
-
|
|
18
|
-
포커스/탭 이동 — `Element` 확장:
|
|
19
|
-
|
|
20
|
-
- **`findTabbableParent`** — 현재 요소를 감싸는 가장 가까운 tabbable 부모를 찾을 때 (모달·툴팁의 포커스 트랩 호스트 추적).
|
|
21
|
-
- **`findFirstTabbableChild`** — 컨테이너에 진입했을 때 처음 포커스할 자식을 찾을 때.
|
|
22
|
-
|
|
23
|
-
레이아웃/스크롤 — `HTMLElement` 확장:
|
|
24
|
-
|
|
25
|
-
- **`repaint`** — 스타일 변경 후 즉시 동기 reflow 가 필요할 때.
|
|
26
|
-
- **`getRelativeOffset`** — 드롭다운/팝업을 부모 기준 absolute 좌표로 띄울 때 (스크롤·border·transform 보정 포함).
|
|
27
|
-
- **`scrollIntoViewIfNeeded`** — 고정 헤더/컬럼에 가려진 셀을 위/왼쪽으로만 보정 스크롤할 때.
|
|
28
|
-
|
|
29
|
-
클립보드/측정 헬퍼:
|
|
30
|
-
|
|
31
|
-
- **`copyElement`** — `<el @copy>` 이벤트 핸들러로 내부 첫 input/textarea 값을 클립보드로 보낼 때.
|
|
32
|
-
- **`pasteToElement`** — `<el @paste>` 이벤트 핸들러로 클립보드 값을 내부 첫 input/textarea 에 전체 교체할 때.
|
|
33
|
-
- **`getBounds`** / **`ElementBounds`** — 다수 요소의 뷰포트 경계를 `IntersectionObserver` 로 한 번에 측정할 때 (입력 순서 유지·타임아웃 보장).
|
|
34
|
-
|
|
35
|
-
파일 다이얼로그/다운로드:
|
|
36
|
-
|
|
37
|
-
- **`openFileDialog`** — 사용자에게 파일 선택 UI 를 띄워 `File[]` 을 받을 때 (취소·빈 선택은 `undefined`).
|
|
38
|
-
- **`downloadBlob`** — 메모리 상의 `Blob` 을 사용자 다운로드로 흘려보낼 때 (파일명 sanitize).
|
|
39
|
-
|
|
40
|
-
진행률 fetch:
|
|
41
|
-
|
|
42
|
-
- **`fetchUrlBytes`** / **`DownloadProgress`** — 큰 바이너리를 `Uint8Array` 로 받으며 진행률 콜백을 받을 때.
|
|
43
|
-
|
|
44
|
-
IndexedDB:
|
|
45
|
-
|
|
46
|
-
- **`IndexedDbStore`** / **`StoreConfig`** — 브라우저 영속 키/값 저장소가 필요할 때 (트랜잭션·재진입 안전 `open`).
|
|
47
|
-
- **`IndexedDbVirtualFs`** / **`VirtualFsEntry`** — 위 저장소 위에 경로(`/a/b/c`) 기반 파일/디렉토리 트리를 올릴 때.
|
|
48
|
-
|
|
49
|
-
## DOM 탐색/가시성 — `Element` 확장
|
|
50
|
-
|
|
51
|
-
```ts
|
|
52
|
-
el.findAll<T extends Element = Element>(selector: string): T[] // 빈 선택자 → []
|
|
53
|
-
el.findFirst<T extends Element = Element>(selector: string): T | undefined // 빈 선택자 → undefined
|
|
54
|
-
el.prependChild<T extends Element>(child: T): T // 첫 자식으로 삽입
|
|
55
|
-
el.getParents(): Element[] // 가까운 순서
|
|
56
|
-
el.isOffsetElement(): boolean // position: relative/absolute/fixed/sticky
|
|
57
|
-
el.isVisible(): boolean // clientRects 존재 + visibility != hidden + opacity != "0"
|
|
58
|
-
```
|
|
59
|
-
|
|
60
|
-
## 포커스/탭 이동 — `Element` 확장
|
|
61
|
-
|
|
62
|
-
```ts
|
|
63
|
-
el.findTabbableParent(): HTMLElement | undefined // tabbable 라이브러리 사용
|
|
64
|
-
el.findFirstTabbableChild(): HTMLElement | undefined // TreeWalker로 첫 매치
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
## 레이아웃/스크롤 — `HTMLElement` 확장
|
|
68
|
-
|
|
69
|
-
```ts
|
|
70
|
-
el.repaint(): void // offsetHeight 접근으로 강제 reflow
|
|
71
|
-
el.getRelativeOffset(parent: HTMLElement | string): { top; left } // CSS top/left 즉시 사용 가능. transform/border/스크롤 보정. 못 찾으면 ArgumentError
|
|
72
|
-
el.scrollIntoViewIfNeeded(target: { top; left }, offset?): void // 상단/좌측 가림만 보정. 하단/우측은 브라우저 기본
|
|
73
|
-
```
|
|
74
|
-
|
|
75
|
-
`getRelativeOffset` 은 드롭다운/팝업의 absolute 위치 지정 표준 경로. `parent` 는 가장 가까운 offset parent 또는 selector.
|
|
76
|
-
|
|
77
|
-
## 클립보드/측정 헬퍼
|
|
78
|
-
|
|
79
|
-
```ts
|
|
80
|
-
function copyElement(event: ClipboardEvent): void // 대상 내 첫 input/textarea.value → clipboard
|
|
81
|
-
function pasteToElement(event: ClipboardEvent): void // clipboard → 첫 input/textarea.value 교체 + input 이벤트 dispatch
|
|
82
|
-
function getBounds(els: Element[], timeout = 5000): Promise<ElementBounds[]> // IntersectionObserver 기반. 입력 순서 유지. timeout 초과 시 TimeoutError
|
|
83
|
-
|
|
84
|
-
interface ElementBounds { target: Element; top: number; left: number; width: number; height: number; }
|
|
85
|
-
```
|
|
86
|
-
|
|
87
|
-
`copyElement`/`pasteToElement` 는 `<element @copy=... @paste=...>` 이벤트 핸들러로 직결. 커서/선택 영역은 무시하고 전체 값 교체.
|
|
88
|
-
|
|
89
|
-
## 파일 다이얼로그/다운로드
|
|
90
|
-
|
|
91
|
-
```ts
|
|
92
|
-
function openFileDialog(options?: { accept?: string; multiple?: boolean }): Promise<File[] | undefined>
|
|
93
|
-
// 취소 시 undefined, 빈 선택 시 undefined.
|
|
94
|
-
function downloadBlob(blob: Blob, fileName: string): void
|
|
95
|
-
// 파일명: sanitize-filename + 대괄호 제거. 빈 결과는 "download". ObjectURL 1초 후 해제.
|
|
96
|
-
```
|
|
97
|
-
|
|
98
|
-
## 진행률 fetch
|
|
99
|
-
|
|
100
|
-
```ts
|
|
101
|
-
interface DownloadProgress { receivedLength: number; contentLength: number; }
|
|
102
|
-
function fetchUrlBytes(url: string, options?: { onProgress?: (p: DownloadProgress) => void }): Promise<Uint8Array>
|
|
103
|
-
```
|
|
104
|
-
|
|
105
|
-
`Content-Length` 가 있으면 사전 할당(메모리 효율) + 초과/부족 검출, 없으면 청크 수집 후 `bytes.concat`. HTTP 오류·본문 없음·길이 불일치는 모두 throw.
|
|
106
|
-
|
|
107
|
-
## IndexedDB 저장소 — `IndexedDbStore`
|
|
108
|
-
|
|
109
|
-
```ts
|
|
110
|
-
interface StoreConfig { name: string; keyPath: string; }
|
|
111
|
-
|
|
112
|
-
class IndexedDbStore {
|
|
113
|
-
constructor(dbName: string, dbVersion: number, storeConfigs: StoreConfig[]);
|
|
114
|
-
open(): Promise<IDBDatabase>; // versionchange/close 시 자동 무효화
|
|
115
|
-
withStore<R>(name, mode: IDBTransactionMode, fn: (s: IDBObjectStore) => Promise<R>): Promise<R>; // fn throw 시 tx.abort
|
|
116
|
-
get<T>(name, key: IDBValidKey): Promise<T | undefined>;
|
|
117
|
-
put(name, value): Promise<void>;
|
|
118
|
-
delete(name, key: IDBValidKey): Promise<void>;
|
|
119
|
-
getAll<T>(name): Promise<T[]>;
|
|
120
|
-
close(): void;
|
|
121
|
-
}
|
|
122
|
-
```
|
|
123
|
-
|
|
124
|
-
`open()` 은 중복 호출 안전(병행 호출 단일화). `withStore` 의 `fn` 내부 에러는 트랜잭션 abort 후 원본 에러로 reject.
|
|
125
|
-
|
|
126
|
-
## IndexedDB 가상 파일시스템 — `IndexedDbVirtualFs`
|
|
127
|
-
|
|
128
|
-
`IndexedDbStore` 위에 경로 키(`/a/b/c`) 기반 파일/디렉토리 모델. 데이터는 base64 문자열로 저장.
|
|
129
|
-
|
|
130
|
-
```ts
|
|
131
|
-
interface VirtualFsEntry { kind: "file" | "dir"; dataBase64?: string; }
|
|
132
|
-
|
|
133
|
-
class IndexedDbVirtualFs {
|
|
134
|
-
constructor(db: IndexedDbStore, storeName: string, keyField: string);
|
|
135
|
-
getEntry(fullKey: string): Promise<VirtualFsEntry | undefined>;
|
|
136
|
-
putEntry(fullKey: string, kind: "file" | "dir", dataBase64?: string): Promise<void>;
|
|
137
|
-
deleteByPrefix(keyPrefix: string): Promise<boolean>; // 자기 자신 + "/" 하위 재귀 삭제
|
|
138
|
-
listChildren(prefix: string): Promise<{ name: string; isDirectory: boolean }[]>; // 직속 자식만, 중간 경로도 dir 로 노출
|
|
139
|
-
ensureDir(fullKeyBuilder: (path: string) => string, dirPath: string): Promise<void>; // 중간 디렉토리 모두 생성
|
|
140
|
-
}
|
|
141
|
-
```
|
|
142
|
-
|
|
143
|
-
`fullKey`/`keyField`/`fullKeyBuilder` 분리로 멀티 테넌트(예: 사용자별 prefix) 키 스킴을 호출 측에서 결정.
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
# @simplysm/core-common
|
|
2
|
-
브라우저·Node 공통 유틸·타입·에러·확장 메서드 패키지. import 시 Array/Map/Set 프로토타입 확장이 자동 적용됨.
|
|
3
|
-
|
|
4
|
-
## 사용 트리거 인덱스
|
|
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으로 치환 (라이브러리 빌드에선 미치환)
|
|
20
|
-
```
|
|
21
|
-
- `env(key)`: `process.env[key]` 우선, 없으면 `import.meta.env[key]`. 둘 다 없으면 `undefined`. Node/브라우저 양쪽 안전.
|
|
22
|
-
|
|
23
|
-
## 에러 클래스
|
|
24
|
-
|
|
25
|
-
모두 `SdError` 상속. ES2024 `cause` 사용. V8에서 `captureStackTrace` + cause stack 결합.
|
|
26
|
-
|
|
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]"
|
|
34
|
-
```
|
|
35
|
-
- `cause`: 원인 Error. 메시지·stack이 결합되어 디버깅 가능.
|
|
36
|
-
- `messages`: 가변 인자, **역순으로** ` => ` join (상위 컨텍스트가 앞).
|
|
37
|
-
- `ArgumentError.argObj`: 검사 실패한 인자 객체. `yaml` 라이브러리로 YAML 렌더되어 메시지 끝에 첨부.
|
|
38
|
-
|
|
39
|
-
## 공통 타입 유틸 (`common.types.ts`)
|
|
40
|
-
|
|
41
|
-
```ts
|
|
42
|
-
type Bytes = Uint8Array // 바이너리 표준 타입 (Buffer 대체)
|
|
43
|
-
interface Type<T> extends Function { new (...args: unknown[]): T } // 클래스 생성자 타입
|
|
44
|
-
type DeepPartial<T> // 재귀 Partial (원시타입은 그대로)
|
|
45
|
-
|
|
46
|
-
type PrimitiveTypeMap = { // 원시 타입 ↔ 문자열 키 매핑
|
|
47
|
-
string, number, boolean, DateTime, DateOnly, Time, Uuid, Bytes
|
|
48
|
-
}
|
|
49
|
-
type PrimitiveTypeStr = keyof PrimitiveTypeMap // "string"|"number"|...
|
|
50
|
-
type PrimitiveType = PrimitiveTypeMap[PrimitiveTypeStr] | undefined // 값 union
|
|
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)` 런타임 추론과 한 쌍.
|
|
55
|
-
|
|
56
|
-
## 부수 효과 (import 시 자동 적용)
|
|
57
|
-
|
|
58
|
-
`@simplysm/core-common`을 한 번이라도 import하면 `Array.prototype`·`Map.prototype`·`Set.prototype`에 확장 메서드가 enumerable=false로 추가됨. 글로벌 인터페이스(`Array<T>`, `ReadonlyArray<T>`, `Map<K,V>`, `Set<T>`)도 ambient declare됨.
|
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
# @simplysm/core-common — extensions
|
|
2
|
-
|
|
3
|
-
`@simplysm/core-common` import 시 자동 적용. 글로벌 `Array`/`ReadonlyArray`/`Map`/`Set` 인터페이스에 ambient declare.
|
|
4
|
-
|
|
5
|
-
## ReadonlyArray<T> (비파괴)
|
|
6
|
-
|
|
7
|
-
```ts
|
|
8
|
-
single(predicate?): T | undefined // 0~1개만 통과. 2개+ → ArgumentError
|
|
9
|
-
first(predicate?): T | undefined // 첫 요소 (predicate 시 find와 동일)
|
|
10
|
-
last(predicate?): T | undefined // 마지막 요소
|
|
11
|
-
filterAsync(predicate: async): Promise<T[]> // 비동기 필터 (순차)
|
|
12
|
-
filterExists(): NonNullable<T>[] // null/undefined 제거 + 타입 좁힘
|
|
13
|
-
ofType(type: PrimitiveTypeStr | Type<N>): N[] // 원시 타입명 또는 생성자로 필터
|
|
14
|
-
mapAsync(selector: async): Promise<R[]> // 비동기 매핑 (순차)
|
|
15
|
-
mapMany(selector?): R[] // flat + filterExists
|
|
16
|
-
mapManyAsync(selector?: async): Promise<R[]>
|
|
17
|
-
parallelAsync(fn: async): Promise<R[]> // Promise.all (하나 reject 시 전체 reject)
|
|
18
|
-
|
|
19
|
-
groupBy(keySelector, valueSelector?): { key, values }[]
|
|
20
|
-
// 원시 key: O(n) Map 최적화. 객체 key: equal() 비교로 O(n²)
|
|
21
|
-
toMap(keySelector, valueSelector?): Map<K, V> // 중복 key → ArgumentError
|
|
22
|
-
toMapAsync(keySelector: async, valueSelector?: async): Promise<Map>
|
|
23
|
-
toArrayMap(keySelector, valueSelector?): Map<K, V[]> // 중복 허용, array로 누적 (O(n))
|
|
24
|
-
toSetMap(keySelector, valueSelector?): Map<K, Set<V>>
|
|
25
|
-
toMapValues(keySelector, valueSelector(items)): Map<K, V> // value는 그룹 전체로 계산
|
|
26
|
-
toObject(keySelector: → string, valueSelector?): Record<string, V>
|
|
27
|
-
toTree(keyProp, parentKey): TreeArray<T>[] // 평면 → 트리 (parentKey null이면 root)
|
|
28
|
-
|
|
29
|
-
distinct(options?: bool | { matchAddress?, keyFn? }): T[]
|
|
30
|
-
// matchAddress=true: Set 참조 비교. keyFn: 커스텀 키 O(n). 둘 다 없이 객체: O(n²) equal
|
|
31
|
-
orderBy(selector?): T[] // 오름차순 (불변, 새 array)
|
|
32
|
-
orderByDesc(selector?): T[]
|
|
33
|
-
|
|
34
|
-
diffs(target, options?: { keys?, excludes? }): ArrayDiffsResult<T, P>[]
|
|
35
|
-
// 전체 일치 우선, 없으면 keys 일치(update 후보). 결과: INSERT|DELETE|UPDATE
|
|
36
|
-
oneWayDiffs(orgItems: T[] | Map<TKey, T>, keyPropNameOrGetValFn, options?):
|
|
37
|
-
ArrayOneWayDiffResult<T>[] // type: 'create'|'update'|'same'
|
|
38
|
-
merge(target, options?): (T | P | T&P)[] // diffs 후 update는 obj.merge, insert는 append
|
|
39
|
-
|
|
40
|
-
sum(selector?): number // 숫자 아니면 ArgumentError
|
|
41
|
-
min(selector?): number | string | undefined // 숫자/문자열만
|
|
42
|
-
max(selector?): number | string | undefined
|
|
43
|
-
shuffle(): T[] // Fisher-Yates, 새 array
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
## Array<T> (파괴, @mutates)
|
|
47
|
-
|
|
48
|
-
```ts
|
|
49
|
-
distinctThis(options?) // distinct를 in-place로
|
|
50
|
-
orderByThis(selector?) // Array.prototype.sort 위임 (in-place)
|
|
51
|
-
orderByDescThis(selector?)
|
|
52
|
-
insert(index, ...items) // splice 삽입, this 반환
|
|
53
|
-
remove(item | selector) // 역순 순회 splice 제거
|
|
54
|
-
toggle(item) // 있으면 remove, 없으면 push
|
|
55
|
-
clear() // 전체 비우기
|
|
56
|
-
```
|
|
57
|
-
|
|
58
|
-
## 익스포트 타입
|
|
59
|
-
|
|
60
|
-
```ts
|
|
61
|
-
type ArrayDiffsResult<TOrig, TOther> =
|
|
62
|
-
| { source: undefined; target: TOther } // INSERT
|
|
63
|
-
| { source: TOrig; target: undefined } // DELETE
|
|
64
|
-
| { source: TOrig; target: TOther } // UPDATE
|
|
65
|
-
type ArrayOneWayDiffResult<T> =
|
|
66
|
-
| { type: 'create'; item: T; orgItem: undefined }
|
|
67
|
-
| { type: 'update'; item: T; orgItem: T }
|
|
68
|
-
| { type: 'same'; item: T; orgItem: T }
|
|
69
|
-
type TreeArray<TNode> = TNode & { children: TreeArray<TNode>[] }
|
|
70
|
-
type ComparableType = string | number | boolean | DateTime | DateOnly | Time | undefined
|
|
71
|
-
```
|
|
72
|
-
|
|
73
|
-
## Map<K, V>
|
|
74
|
-
|
|
75
|
-
```ts
|
|
76
|
-
getOrCreate(key, newValue: V): V
|
|
77
|
-
getOrCreate(key, newValueFn: () => V): V // 함수면 팩토리로 호출하여 lazy 생성
|
|
78
|
-
update(key, updateFn: (v: V | undefined) => V): void // key 없어도 fn 호출
|
|
79
|
-
```
|
|
80
|
-
- **주의**: `Map<K, () => void>` 같이 V가 함수 타입이면 두 번째 인자가 팩토리로 인식됨. 함수 값을 저장하려면 `getOrCreate(k, () => myFn)`.
|
|
81
|
-
|
|
82
|
-
## Set<T>
|
|
83
|
-
|
|
84
|
-
```ts
|
|
85
|
-
adds(...values: T[]): this // 다중 add
|
|
86
|
-
toggle(value, addOrDel?: "add" | "del"): this
|
|
87
|
-
// 인자 없으면 자동 토글, "add"=강제 추가, "del"=강제 삭제
|
|
88
|
-
```
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
# @simplysm/core-common — features
|
|
2
|
-
|
|
3
|
-
## EventEmitter<TEvents>
|
|
4
|
-
|
|
5
|
-
EventTarget 기반의 타입 안전 이벤트 이미터. 브라우저·Node 공통.
|
|
6
|
-
|
|
7
|
-
```ts
|
|
8
|
-
class EventEmitter<TEvents extends { [K in keyof TEvents]: unknown } = Record<string, unknown>> {
|
|
9
|
-
on<E extends keyof TEvents & string>(type: E, listener: (data: TEvents[E]) => void): void
|
|
10
|
-
off<E>(type: E, listener: ...): void
|
|
11
|
-
emit<E>(type: E, ...args: TEvents[E] extends void ? [] : [data: TEvents[E]]): void
|
|
12
|
-
listenerCount(type): number
|
|
13
|
-
dispose(): void // 모든 리스너 제거
|
|
14
|
-
}
|
|
15
|
-
```
|
|
16
|
-
- `TEvents`: `{ eventName: dataType }` 맵. `void` 타입이면 `emit("done")` 인자 생략.
|
|
17
|
-
- 같은 `(type, listener)` 쌍 중복 등록 시 무시.
|
|
18
|
-
- 내부적으로 `CustomEvent.detail`로 데이터 전송. listener는 wrapper로 감싸져 등록되며, listenerMap이 원본 ↔ wrapper 매핑 보관.
|
|
19
|
-
|
|
20
|
-
```ts
|
|
21
|
-
interface MyEvents { data: string; done: void }
|
|
22
|
-
class M extends EventEmitter<MyEvents> {}
|
|
23
|
-
const m = new M();
|
|
24
|
-
m.on("data", s => ...);
|
|
25
|
-
m.emit("data", "hi");
|
|
26
|
-
m.emit("done");
|
|
27
|
-
```
|
|
28
|
-
|
|
29
|
-
## DebounceQueue extends EventEmitter<{ error: SdError }>
|
|
30
|
-
|
|
31
|
-
마지막 요청만 실행. 짧은 시간 내 다중 호출 → 마지막 1건만 처리.
|
|
32
|
-
|
|
33
|
-
```ts
|
|
34
|
-
new DebounceQueue(delay?: number) // ms. 생략 시 다음 이벤트 루프 (setTimeout(_, undefined))
|
|
35
|
-
run(fn: () => void | Promise<void>): void
|
|
36
|
-
dispose(): void // 타이머·pending 정리
|
|
37
|
-
```
|
|
38
|
-
- `delay` ms 지난 뒤 가장 최근 `fn` 실행. 실행 중 도착한 추가 `run()`은 디바운스 지연 없이 현재 실행 직후 즉시 처리 (요청 누락 방지).
|
|
39
|
-
- fn throw 시 `SdError`로 감싸 `"error"` 이벤트 발행. 리스너 없으면 `consola` 로그.
|
|
40
|
-
|
|
41
|
-
## SerialQueue extends EventEmitter<{ error: SdError }>
|
|
42
|
-
|
|
43
|
-
큐에 추가된 함수들을 순차 실행.
|
|
44
|
-
|
|
45
|
-
```ts
|
|
46
|
-
new SerialQueue(gap: number = 0) // 각 작업 사이 ms 간격
|
|
47
|
-
run(fn: () => void | Promise<void>): void
|
|
48
|
-
dispose(): void // 대기 큐 비우기 (실행 중은 완료됨)
|
|
49
|
-
```
|
|
50
|
-
- 하나 완료 후 다음 시작. 에러 발생해도 후속 작업 계속 실행. throw는 `SdError` 감싸서 `"error"` 이벤트 (리스너 없으면 `consola.error`).
|
|
51
|
-
- `gap>0` 이면 작업 간 `wait.time(gap)` 대기.
|