@simplysm/sd-claude 14.0.41 → 14.0.43
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-simplysm14/angular/docs/directives.md +74 -3
- package/claude/references/sd-simplysm14/angular/docs/features.md +64 -14
- package/claude/references/sd-simplysm14/angular/docs/plugins.md +2 -90
- package/claude/references/sd-simplysm14/angular/docs/providers.md +2 -2
- package/claude/references/sd-simplysm14/angular/docs/type-utilities.md +1 -2
- package/claude/references/sd-simplysm14/angular/docs/ui-data.md +103 -23
- package/claude/references/sd-simplysm14/angular/docs/ui-form.md +173 -28
- package/claude/references/sd-simplysm14/angular/docs/ui-layout.md +19 -4
- package/claude/references/sd-simplysm14/angular/docs/ui-navigation.md +20 -2
- package/claude/references/sd-simplysm14/angular/docs/ui-overlay.md +23 -14
- package/claude/references/sd-simplysm14/angular/docs/ui-visual.md +15 -7
- package/claude/references/sd-simplysm14/angular/docs/utils.md +1 -1
- package/claude/references/sd-simplysm14/angular/usage.md +16 -15
- package/claude/references/sd-simplysm14/capacitor-plugin-auto-update/usage.md +1 -1
- package/claude/references/sd-simplysm14/capacitor-plugin-file-system/docs/file-operations.md +154 -0
- package/claude/references/sd-simplysm14/capacitor-plugin-file-system/docs/permissions.md +84 -0
- package/claude/references/sd-simplysm14/capacitor-plugin-file-system/docs/storage-paths.md +107 -0
- package/claude/references/sd-simplysm14/capacitor-plugin-file-system/docs/types.md +83 -0
- package/claude/references/sd-simplysm14/capacitor-plugin-file-system/usage.md +83 -128
- package/claude/references/sd-simplysm14/capacitor-plugin-usb-storage/usage.md +99 -1
- package/claude/references/sd-simplysm14/core-node/docs/child-process.md +182 -0
- package/claude/references/sd-simplysm14/core-node/docs/features.md +1 -1
- package/claude/references/sd-simplysm14/core-node/docs/file-system.md +509 -0
- package/claude/references/sd-simplysm14/core-node/docs/file-watching.md +139 -0
- package/claude/references/sd-simplysm14/core-node/docs/logging.md +180 -0
- package/claude/references/sd-simplysm14/core-node/docs/path.md +176 -0
- package/claude/references/sd-simplysm14/core-node/docs/worker-threads.md +334 -0
- package/claude/references/sd-simplysm14/core-node/usage.md +192 -96
- package/claude/references/sd-simplysm14/excel/docs/core-classes.md +33 -14
- package/claude/references/sd-simplysm14/excel/usage.md +47 -45
- package/claude/references/sd-simplysm14/lint/usage.md +3 -2
- package/claude/references/sd-simplysm14/orm-common/docs/queryable-executable.md +30 -35
- package/claude/references/sd-simplysm14/orm-common/usage.md +9 -8
- package/claude/references/sd-simplysm14/sd-claude/docs/assets.md +43 -34
- package/claude/references/sd-simplysm14/sd-claude/docs/cli.md +1 -1
- package/claude/references/sd-simplysm14/sd-claude/docs/hooks.md +20 -2
- package/claude/references/sd-simplysm14/sd-claude/docs/scripts.md +5 -18
- package/claude/references/sd-simplysm14/sd-claude/usage.md +6 -5
- package/claude/references/sd-simplysm14/sd-cli/usage.md +176 -1
- package/claude/references/sd-simplysm14/service-client/usage.md +126 -61
- package/claude/references/sd-simplysm14/service-common/usage.md +28 -28
- package/claude/references/sd-simplysm14/storage/usage.md +123 -30
- package/claude/references/sd-testing.md +100 -4
- package/claude/rules/sd-claude-rules.md +19 -4
- package/claude/sd-check-write.py +1 -1
- package/claude/skills/sd-check/SKILL.md +7 -4
- package/claude/skills/sd-claude-docs/SKILL.md +7 -4
- package/claude/skills/sd-claude-docs/references/package-doc-gen.md +30 -7
- package/claude/skills/sd-commit/SKILL.md +2 -0
- package/claude/skills/sd-debug/SKILL.md +1 -1
- package/claude/skills/sd-deliverable/SKILL.md +2 -0
- package/claude/skills/sd-dev/SKILL.md +1 -1
- package/claude/skills/sd-doc-extract/SKILL.md +2 -0
- package/claude/{references/sd-debug.md → skills/sd-inner-debug/SKILL.md} +16 -20
- package/claude/{references/sd-review.md → skills/sd-inner-review/SKILL.md} +9 -4
- package/claude/skills/sd-issue/SKILL.md +2 -0
- package/claude/skills/sd-outlook/SKILL.md +2 -0
- package/claude/skills/sd-plan/SKILL.md +1 -1
- package/claude/skills/sd-prompt/SKILL.md +2 -2
- package/claude/skills/sd-refactor/SKILL.md +2 -2
- package/claude/skills/sd-review/SKILL.md +1 -1
- package/claude/skills/sd-tdd/SKILL.md +7 -7
- package/claude/skills/sd-use/SKILL.md +2 -0
- package/claude/skills/sd-wbs/SKILL.md +41 -18
- package/package.json +1 -1
- /package/claude/{rules → references}/sd-simplysm14.md +0 -0
- /package/claude/{references → rules}/sd-clarify.md +0 -0
|
@@ -265,7 +265,7 @@ function setupModelHook<T, S extends WritableSignal<T>>(
|
|
|
265
265
|
function setupCanDeactivate(fn: () => boolean): void
|
|
266
266
|
```
|
|
267
267
|
|
|
268
|
-
모달 내부이면 `SdActivatedModalProvider.
|
|
268
|
+
모달 내부이면 `SdActivatedModalProvider.canDeactivateFn`에 설정, 라우트 내부이면 `routeConfig.canDeactivate`에 추가.
|
|
269
269
|
|
|
270
270
|
### `setupCumulateSelectedKeys`
|
|
271
271
|
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
Angular 21 기반 UI 컴포넌트 라이브러리. Zoneless, signal-based, standalone 컴포넌트로 구성된다.
|
|
4
4
|
|
|
5
|
+
> **NOTE:** 이 문서는 `@simplysm/angular` 라이브러리의 사용법만 다룬다. Angular 프레임워크 자체의 사용법(컴포넌트 작성, DI, 라우팅, signal 등)은 `angular-cli` MCP를 활용한다.
|
|
6
|
+
|
|
5
7
|
## Installation
|
|
6
8
|
|
|
7
9
|
```bash
|
|
@@ -49,7 +51,6 @@ npm install @simplysm/angular
|
|
|
49
51
|
|
|
50
52
|
| API | Type | Description |
|
|
51
53
|
|-----|------|-------------|
|
|
52
|
-
| `AppStructureItem` | type | 앱 구조 항목 (그룹 또는 리프) |
|
|
53
54
|
| `SdMenu` | interface | 메뉴 트리 노드 |
|
|
54
55
|
| `SdFlatMenu` | interface | 플랫 메뉴 항목 |
|
|
55
56
|
| `SdPermission` | interface | 권한 트리 노드 |
|
|
@@ -82,6 +83,11 @@ npm install @simplysm/angular
|
|
|
82
83
|
| `SdItemOfTemplate` | directive | `ng-template[itemOf]` 항목 반복 템플릿 타입 가드 |
|
|
83
84
|
| `SdItemOfTemplateContext` | interface | itemOf 템플릿 컨텍스트 (`$implicit`, `item`, `index`, `depth`) |
|
|
84
85
|
| `SdRouterLink` | directive | `[sdRouterLink]` 라우터 네비게이션 (Ctrl+클릭 새 창) |
|
|
86
|
+
| `SdCommandDirective` | directive | `[sdSaveCommand]`, `[sdRefreshCommand]`, `[sdInsertCommand]` 키보드 단축키 output 이벤트 디렉티브 |
|
|
87
|
+
| `SdResizeDirective` | directive | `[sdResize]` ResizeObserver 기반 resize output 이벤트 디렉티브 |
|
|
88
|
+
| `SdResizeEvent` | interface | resize 이벤트 데이터 (`heightChanged`, `widthChanged`, `target`, `contentRect`) |
|
|
89
|
+
| `SdIntersectionDirective` | directive | `[sdIntersection]` IntersectionObserver 기반 intersection output 이벤트 디렉티브 |
|
|
90
|
+
| `SdIntersectionEvent` | interface | intersection 이벤트 데이터 (`entry`) |
|
|
85
91
|
|
|
86
92
|
-> See [docs/directives.md](./docs/directives.md) for details.
|
|
87
93
|
|
|
@@ -89,14 +95,7 @@ npm install @simplysm/angular
|
|
|
89
95
|
|
|
90
96
|
| API | Type | Description |
|
|
91
97
|
|-----|------|-------------|
|
|
92
|
-
| `
|
|
93
|
-
| `SdRefreshCommandEventPlugin` | class | `(sdRefreshCommand)` Ctrl+Alt+L 이벤트 플러그인 |
|
|
94
|
-
| `SdInsertCommandEventPlugin` | class | `(sdInsertCommand)` Ctrl+Insert 이벤트 플러그인 |
|
|
95
|
-
| `SdResizeEventPlugin` | class | `(sdResize)` ResizeObserver 이벤트 플러그인 |
|
|
96
|
-
| `SdResizeEvent` | interface | resize 이벤트 데이터 |
|
|
97
|
-
| `SdIntersectionEventPlugin` | class | `(sdIntersection)` IntersectionObserver 이벤트 플러그인 |
|
|
98
|
-
| `SdIntersectionEvent` | interface | intersection 이벤트 데이터 |
|
|
99
|
-
| `SdOptionEventPlugin` | class | `.capture`, `.passive`, `.once` 이벤트 옵션 플러그인 |
|
|
98
|
+
| `SdOptionEventPlugin` | class | `.capture`, `.passive`, `.once` 이벤트 옵션 플러그인 (`provideSdAngular`에서 자동 등록) |
|
|
100
99
|
| `SdGlobalErrorHandlerPlugin` | class | 글로벌 에러 핸들러 (PromiseRejection, ErrorEvent 등) |
|
|
101
100
|
|
|
102
101
|
-> See [docs/plugins.md](./docs/plugins.md) for details.
|
|
@@ -161,7 +160,7 @@ npm install @simplysm/angular
|
|
|
161
160
|
| `SdBaseContainer` | component | 페이지/모달/뷰 공통 레이아웃 컨테이너 |
|
|
162
161
|
| `SdAddressSearchModal` | component | Daum Postcode 주소 검색 모달 |
|
|
163
162
|
| `Address` | interface | 주소 검색 결과 |
|
|
164
|
-
| `SdPermissionTable` | component | 권한 매트릭스 테이블 |
|
|
163
|
+
| `SdPermissionTable` | component | 권한 매트릭스 테이블 (items, value) |
|
|
165
164
|
| `SdDataSheetBase` | class | 데이터 시트 CRUD 추상 클래스 |
|
|
166
165
|
| `SdDataSheet` | component | 데이터 시트 presentation 컴포넌트 |
|
|
167
166
|
| `SdDataSheetColumn` | directive | 데이터 시트 컬럼 (edit 추가) |
|
|
@@ -171,7 +170,7 @@ npm install @simplysm/angular
|
|
|
171
170
|
| `SdDataSelectButton` | component | 선택 버튼 presentation 컴포넌트 |
|
|
172
171
|
| `SdSharedDataSelect` | component | 공유 데이터 드롭다운 선택 |
|
|
173
172
|
| `SdSharedDataSelectButton` | component | 공유 데이터 모달 선택 버튼 |
|
|
174
|
-
| `SdSharedDataSelectList` | component | 공유 데이터 목록형 선택 |
|
|
173
|
+
| `SdSharedDataSelectList` | component | 공유 데이터 목록형 선택 (selectedItem model) |
|
|
175
174
|
| `matchesSearchText` | function | 공백 구분 AND 조건 텍스트 검색 매칭 |
|
|
176
175
|
| `getOrmDataEditToastErrorMessage` | function | ORM 편집 에러 메시지 변환 (FK 위반 등 DB 에러를 한국어 메시지로) |
|
|
177
176
|
|
|
@@ -195,7 +194,7 @@ npm install @simplysm/angular
|
|
|
195
194
|
| `SdDockContainer` | component | 도킹 레이아웃 컨테이너 |
|
|
196
195
|
| `SdDock` | component | 도킹 영역 (top/bottom/left/right) |
|
|
197
196
|
| `SdGap` | component | 간격 (gap) 컴포넌트 |
|
|
198
|
-
| `SdKanbanBoard` | component | 칸반 보드 (
|
|
197
|
+
| `SdKanbanBoard` | component | 칸반 보드 (드래그앤드롭, selectedValues) |
|
|
199
198
|
| `SdKanbanBoardDropInfo` | interface | 칸반 보드 드롭 이벤트 정보 |
|
|
200
199
|
| `SdKanbanDragRef` | interface | 칸반 드래그 참조 인터페이스 |
|
|
201
200
|
| `SdKanbanDropTarget` | interface | 칸반 드롭 타겟 인터페이스 |
|
|
@@ -224,7 +223,7 @@ npm install @simplysm/angular
|
|
|
224
223
|
| `SdCheckboxGroup` | component | 체크박스 그룹 |
|
|
225
224
|
| `SdCheckboxGroupItem` | component | 체크박스 그룹 항목 |
|
|
226
225
|
| `SdTiptapEditor` | component | TipTap 리치 텍스트 에디터 |
|
|
227
|
-
| `SdSelect` | component | 드롭다운 선택 (single/multi
|
|
226
|
+
| `SdSelect` | component | 드롭다운 선택 (single/multi) |
|
|
228
227
|
| `SdSelectItem` | component | 드롭다운 선택 항목 |
|
|
229
228
|
| `SdSelectButton` | component | 버튼 스타일 선택 |
|
|
230
229
|
| `SdForm` | component | 폼 래퍼 (submit 이벤트, busy 관리) |
|
|
@@ -261,8 +260,10 @@ npm install @simplysm/angular
|
|
|
261
260
|
|-----|------|-------------|
|
|
262
261
|
| `SdList` | component | 리스트 |
|
|
263
262
|
| `SdListItem` | component | 리스트 항목 |
|
|
264
|
-
| `SdSheet` | component | 스프레드시트 (정렬, 고정, 리사이즈) |
|
|
265
|
-
| `SdSheetColumn` | directive | 시트 컬럼 정의 |
|
|
263
|
+
| `SdSheet` | component | 스프레드시트 (정렬, 고정, 리사이즈). `key`로 설정 저장 |
|
|
264
|
+
| `SdSheetColumn` | directive | 시트 컬럼 정의 (헤더, 너비, 고정, 정렬 등) |
|
|
265
|
+
| `SdSheetColumnCellTemplate` | directive | 시트 컬럼 셀 내용 정의 (`ng-template[cell]`), `SdSheetCellContext` 타입 가드 제공 |
|
|
266
|
+
| `SdSheetCellContext` | interface | 시트 셀 템플릿 컨텍스트 (`$implicit`, `item`, `index`, `depth`, `edit`) |
|
|
266
267
|
| `SdSheetConfigModal` | component | 시트 설정 모달 |
|
|
267
268
|
| `SdSheetColumnDef` | interface | 시트 컬럼 정의 데이터 |
|
|
268
269
|
| `SdSheetConfig` | interface | 시트 설정 데이터 |
|
|
@@ -66,7 +66,7 @@ export interface ApkInstallerPlugin {
|
|
|
66
66
|
|
|
67
67
|
## `ApkInstaller`
|
|
68
68
|
|
|
69
|
-
APK 설치 플러그인 정적 파사드 클래스. Android에서는 네이티브 플러그인을 실행하고, 브라우저 환경에서는 `ApkInstallerWeb`으로
|
|
69
|
+
APK 설치 플러그인 정적 파사드 클래스. Android에서는 네이티브 플러그인을 실행하고, 브라우저 환경에서는 `ApkInstallerWeb`으로 폴백한다. 브라우저 폴백: `install()`은 `alert()` 표시 후 반환, `checkPermissions()`는 항상 `{ granted: true, manifest: true }` 반환, `requestPermissions()`는 무동작, `getVersionInfo()`는 `env("__VER__") ?? "0.0.0"`을 `versionName`으로 반환.
|
|
70
70
|
|
|
71
71
|
```typescript
|
|
72
72
|
export abstract class ApkInstaller {
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
# File Operations
|
|
2
|
+
|
|
3
|
+
## `FileSystem.readdir`
|
|
4
|
+
|
|
5
|
+
디렉토리의 파일과 폴더 목록을 조회합니다.
|
|
6
|
+
|
|
7
|
+
```typescript
|
|
8
|
+
static async readdir(dirPath: string): Promise<FileInfo[]>
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
| Parameter | Type | Description |
|
|
12
|
+
|-----------|------|-------------|
|
|
13
|
+
| `dirPath` | string | 조회할 디렉토리의 절대 경로 |
|
|
14
|
+
|
|
15
|
+
**Return**: 디렉토리 내 파일/폴더 목록 (각 항목은 name과 isDirectory 포함)
|
|
16
|
+
|
|
17
|
+
**Throws**: 디렉토리가 존재하지 않거나 허용되지 않는 경로일 경우 Error
|
|
18
|
+
|
|
19
|
+
```typescript
|
|
20
|
+
const files = await FileSystem.readdir("/storage/emulated/0/Documents");
|
|
21
|
+
for (const file of files) {
|
|
22
|
+
console.log(`${file.name} ${file.isDirectory ? "[DIR]" : ""}`);
|
|
23
|
+
}
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## `FileSystem.writeFile`
|
|
27
|
+
|
|
28
|
+
파일을 작성합니다. 문자열 또는 Bytes(Uint8Array) 데이터를 지원합니다.
|
|
29
|
+
|
|
30
|
+
```typescript
|
|
31
|
+
static async writeFile(filePath: string, data: string | Bytes): Promise<void>
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
| Parameter | Type | Description |
|
|
35
|
+
|-----------|------|-------------|
|
|
36
|
+
| `filePath` | string | 쓸 파일의 절대 경로 |
|
|
37
|
+
| `data` | string \| Bytes | 파일 내용 (문자열 또는 Uint8Array) |
|
|
38
|
+
|
|
39
|
+
**Behavior**:
|
|
40
|
+
- 문자열인 경우: UTF-8 인코딩으로 저장 (encoding: "utf8")
|
|
41
|
+
- Bytes인 경우: Base64 인코딩으로 저장 (encoding: "base64")
|
|
42
|
+
- 상위 디렉토리가 없으면 자동 생성 (웹 환경에서만)
|
|
43
|
+
|
|
44
|
+
**Throws**: 쓰기 권한 없을 경우 Error
|
|
45
|
+
|
|
46
|
+
```typescript
|
|
47
|
+
// 문자열 쓰기
|
|
48
|
+
await FileSystem.writeFile("/storage/emulated/0/Documents/notes.txt", "Hello, World!");
|
|
49
|
+
|
|
50
|
+
// Bytes 쓰기 (예: PNG 이미지)
|
|
51
|
+
const pngData = new Uint8Array([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]);
|
|
52
|
+
await FileSystem.writeFile("/storage/emulated/0/Pictures/image.png", pngData);
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## `FileSystem.readFile`
|
|
56
|
+
|
|
57
|
+
파일을 읽습니다. 기본적으로 Bytes를 반환하며, encoding 파라미터로 문자열 반환을 지정할 수 있습니다.
|
|
58
|
+
|
|
59
|
+
```typescript
|
|
60
|
+
static async readFile(filePath: string): Promise<Bytes>;
|
|
61
|
+
static async readFile(filePath: string, encoding: "utf8"): Promise<string>;
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
| Parameter | Type | Description |
|
|
65
|
+
|-----------|------|-------------|
|
|
66
|
+
| `filePath` | string | 읽을 파일의 절대 경로 |
|
|
67
|
+
| `encoding` | "utf8" (optional) | "utf8"일 경우 string 반환, 생략 시 Bytes 반환 |
|
|
68
|
+
|
|
69
|
+
**Return**:
|
|
70
|
+
- encoding 생략: `Promise<Bytes>` (Uint8Array)
|
|
71
|
+
- encoding="utf8": `Promise<string>`
|
|
72
|
+
|
|
73
|
+
**Throws**: 파일이 없거나 읽기 권한이 없을 경우 Error
|
|
74
|
+
|
|
75
|
+
```typescript
|
|
76
|
+
// Bytes로 읽기 (기본)
|
|
77
|
+
const imageData = await FileSystem.readFile("/storage/emulated/0/Pictures/photo.jpg");
|
|
78
|
+
console.log(imageData instanceof Uint8Array); // true
|
|
79
|
+
|
|
80
|
+
// 문자열로 읽기
|
|
81
|
+
const config = await FileSystem.readFile("/storage/emulated/0/Documents/config.json", "utf8");
|
|
82
|
+
const obj = JSON.parse(config);
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## `FileSystem.remove`
|
|
86
|
+
|
|
87
|
+
파일 또는 디렉토리를 삭제합니다. 디렉토리인 경우 재귀적으로 삭제됩니다.
|
|
88
|
+
|
|
89
|
+
```typescript
|
|
90
|
+
static async remove(targetPath: string): Promise<void>
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
| Parameter | Type | Description |
|
|
94
|
+
|-----------|------|-------------|
|
|
95
|
+
| `targetPath` | string | 삭제할 파일/디렉토리의 절대 경로 |
|
|
96
|
+
|
|
97
|
+
**Behavior**:
|
|
98
|
+
- 파일: 즉시 삭제
|
|
99
|
+
- 디렉토리: 하위의 모든 파일/폴더 포함하여 재귀 삭제
|
|
100
|
+
- 웹 환경: 경로 프리픽스로 모든 관련 항목 삭제
|
|
101
|
+
|
|
102
|
+
**Throws**: 대상이 존재하지 않거나 권한 없을 경우 Error
|
|
103
|
+
|
|
104
|
+
```typescript
|
|
105
|
+
// 파일 삭제
|
|
106
|
+
await FileSystem.remove("/storage/emulated/0/Documents/temp.txt");
|
|
107
|
+
|
|
108
|
+
// 디렉토리 재귀 삭제
|
|
109
|
+
await FileSystem.remove("/storage/emulated/0/Documents/old_backup");
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
## `FileSystem.mkdir`
|
|
113
|
+
|
|
114
|
+
디렉토리를 생성합니다. 상위 경로가 없는 경우 자동으로 생성됩니다 (재귀 생성).
|
|
115
|
+
|
|
116
|
+
```typescript
|
|
117
|
+
static async mkdir(targetPath: string): Promise<void>
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
| Parameter | Type | Description |
|
|
121
|
+
|-----------|------|-------------|
|
|
122
|
+
| `targetPath` | string | 생성할 디렉토리의 절대 경로 |
|
|
123
|
+
|
|
124
|
+
**Behavior**:
|
|
125
|
+
- 중간 경로가 없어도 자동 생성
|
|
126
|
+
- 이미 존재하면 아무 동작 없음
|
|
127
|
+
|
|
128
|
+
**Throws**: 권한 없을 경우 Error
|
|
129
|
+
|
|
130
|
+
```typescript
|
|
131
|
+
// 중간 경로 자동 생성
|
|
132
|
+
await FileSystem.mkdir("/storage/emulated/0/Documents/projects/2025/Q1");
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
## `FileSystem.exists`
|
|
136
|
+
|
|
137
|
+
파일 또는 디렉토리의 존재 여부를 확인합니다.
|
|
138
|
+
|
|
139
|
+
```typescript
|
|
140
|
+
static async exists(targetPath: string): Promise<boolean>
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
| Parameter | Type | Description |
|
|
144
|
+
|-----------|------|-------------|
|
|
145
|
+
| `targetPath` | string | 확인할 파일/디렉토리의 절대 경로 |
|
|
146
|
+
|
|
147
|
+
**Return**: true (존재), false (존재하지 않음)
|
|
148
|
+
|
|
149
|
+
```typescript
|
|
150
|
+
const exists = await FileSystem.exists("/storage/emulated/0/Documents/config.json");
|
|
151
|
+
if (!exists) {
|
|
152
|
+
await FileSystem.writeFile("/storage/emulated/0/Documents/config.json", "{}");
|
|
153
|
+
}
|
|
154
|
+
```
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# Permissions
|
|
2
|
+
|
|
3
|
+
## `FileSystem.checkPermissions`
|
|
4
|
+
|
|
5
|
+
파일 시스템 접근 권한 여부를 확인합니다.
|
|
6
|
+
|
|
7
|
+
```typescript
|
|
8
|
+
static async checkPermissions(): Promise<boolean>
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
**Return**: true (권한 허용), false (권한 거부)
|
|
12
|
+
|
|
13
|
+
**플랫폼별 동작**:
|
|
14
|
+
- **Android**: 현재 권한 상태 확인 (MANAGE_EXTERNAL_STORAGE 또는 READ/WRITE_EXTERNAL_STORAGE)
|
|
15
|
+
- **Web**: 항상 true (권한 개념 없음)
|
|
16
|
+
|
|
17
|
+
```typescript
|
|
18
|
+
const hasPermission = await FileSystem.checkPermissions();
|
|
19
|
+
if (hasPermission) {
|
|
20
|
+
// 파일 접근 가능
|
|
21
|
+
const files = await FileSystem.readdir("/storage/emulated/0/Documents");
|
|
22
|
+
} else {
|
|
23
|
+
// 권한 요청 필요
|
|
24
|
+
await FileSystem.requestPermissions();
|
|
25
|
+
}
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## `FileSystem.requestPermissions`
|
|
29
|
+
|
|
30
|
+
파일 시스템 접근 권한을 요청합니다.
|
|
31
|
+
|
|
32
|
+
```typescript
|
|
33
|
+
static async requestPermissions(): Promise<void>
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
**플랫폼별 동작**:
|
|
37
|
+
- **Android 11+ (API 30+)**:
|
|
38
|
+
- `MANAGE_EXTERNAL_STORAGE` 권한 요청
|
|
39
|
+
- 설정 화면으로 이동하여 사용자가 수동으로 허용
|
|
40
|
+
- 권한 대화상자가 표시되지 않음
|
|
41
|
+
- **Android 10 이하 (API 29-)**:
|
|
42
|
+
- `READ_EXTERNAL_STORAGE` + `WRITE_EXTERNAL_STORAGE` 요청
|
|
43
|
+
- 표준 권한 대화상자 표시
|
|
44
|
+
- **Web**: 아무 동작 없음
|
|
45
|
+
|
|
46
|
+
```typescript
|
|
47
|
+
async function ensureFileSystemAccess() {
|
|
48
|
+
const hasPermission = await FileSystem.checkPermissions();
|
|
49
|
+
|
|
50
|
+
if (!hasPermission) {
|
|
51
|
+
try {
|
|
52
|
+
await FileSystem.requestPermissions();
|
|
53
|
+
console.log("Permission granted");
|
|
54
|
+
} catch (error) {
|
|
55
|
+
console.error("Permission request failed:", error);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// 앱 시작 시 권한 확인
|
|
61
|
+
await ensureFileSystemAccess();
|
|
62
|
+
|
|
63
|
+
// 외부 저장소 접근
|
|
64
|
+
const externalPath = await FileSystem.getStoragePath("external");
|
|
65
|
+
const files = await FileSystem.readdir(externalPath);
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## 권한 관련 주의사항
|
|
69
|
+
|
|
70
|
+
### Android 11+ (Scoped Storage)
|
|
71
|
+
|
|
72
|
+
- `MANAGE_EXTERNAL_STORAGE` 권한은 특수 권한이며, 일반 권한 대화상자로 요청할 수 없습니다.
|
|
73
|
+
- 권한 요청 시 설정 앱으로 이동하므로 사용자가 직접 허용/거부를 선택해야 합니다.
|
|
74
|
+
- AndroidManifest.xml에 `android.permission.MANAGE_EXTERNAL_STORAGE`를 선언해야 합니다.
|
|
75
|
+
|
|
76
|
+
### Android 10 이하
|
|
77
|
+
|
|
78
|
+
- `READ_EXTERNAL_STORAGE`, `WRITE_EXTERNAL_STORAGE` 권한이 필요합니다.
|
|
79
|
+
- 이 권한들은 위험한(Dangerous) 권한으로 분류되어 런타임 권한 요청이 필요합니다.
|
|
80
|
+
|
|
81
|
+
### 웹 환경
|
|
82
|
+
|
|
83
|
+
- 권한 개념이 없으며, IndexedDB 기반 가상 파일 시스템을 사용합니다.
|
|
84
|
+
- 사용자는 브라우저 저장소 한도에만 제한됩니다.
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
# Storage & Paths
|
|
2
|
+
|
|
3
|
+
## `FileSystem.getStoragePath`
|
|
4
|
+
|
|
5
|
+
저장소 유형별로 기기의 실제 경로(Android) 또는 가상 경로(웹)를 반환합니다.
|
|
6
|
+
|
|
7
|
+
```typescript
|
|
8
|
+
static async getStoragePath(type: StorageType): Promise<string>
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
| Parameter | Type | Description |
|
|
12
|
+
|-----------|------|-------------|
|
|
13
|
+
| `type` | StorageType | 저장소 유형 |
|
|
14
|
+
|
|
15
|
+
**Return**: 절대 경로 문자열
|
|
16
|
+
|
|
17
|
+
**StorageType 종류**:
|
|
18
|
+
|
|
19
|
+
| Type | Android Path | Web Path | 설명 |
|
|
20
|
+
|------|--------------|----------|------|
|
|
21
|
+
| `external` | `Environment.getExternalStorageDirectory()` | `/webfs/external` | 외부 저장소 루트 (공유 저장소) |
|
|
22
|
+
| `externalFiles` | `getExternalFilesDir(null)` | `/webfs/externalFiles` | 앱 전용 외부 파일 디렉토리 |
|
|
23
|
+
| `externalCache` | `externalCacheDir` | `/webfs/externalCache` | 앱 전용 외부 캐시 디렉토리 |
|
|
24
|
+
| `externalMedia` | `externalMediaDirs[0]` | `/webfs/externalMedia` | 앱 전용 외부 미디어 디렉토리 |
|
|
25
|
+
| `appData` | `applicationInfo.dataDir` | `/webfs/appData` | 앱 데이터 디렉토리 (내부) |
|
|
26
|
+
| `appFiles` | `filesDir` | `/webfs/appFiles` | 앱 파일 디렉토리 (내부) |
|
|
27
|
+
| `appCache` | `cacheDir` | `/webfs/appCache` | 앱 캐시 디렉토리 (내부) |
|
|
28
|
+
|
|
29
|
+
```typescript
|
|
30
|
+
// 앱 캐시 디렉토리에 임시 파일 작성
|
|
31
|
+
const cachePath = await FileSystem.getStoragePath("appCache");
|
|
32
|
+
await FileSystem.writeFile(cachePath + "/temp.dat", "temporary data");
|
|
33
|
+
|
|
34
|
+
// 외부 파일 디렉토리에 문서 저장
|
|
35
|
+
const filesPath = await FileSystem.getStoragePath("externalFiles");
|
|
36
|
+
await FileSystem.mkdir(filesPath + "/documents");
|
|
37
|
+
await FileSystem.writeFile(filesPath + "/documents/report.pdf", pdfBytes);
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## `FileSystem.getUri`
|
|
41
|
+
|
|
42
|
+
파일의 URI를 조회합니다. 주로 Blob URL(웹) 또는 FileProvider URI(Android)로 반환됩니다.
|
|
43
|
+
|
|
44
|
+
```typescript
|
|
45
|
+
static async getUri(filePath: string): Promise<string>
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
| Parameter | Type | Description |
|
|
49
|
+
|-----------|------|-------------|
|
|
50
|
+
| `filePath` | string | 파일의 절대 경로 |
|
|
51
|
+
|
|
52
|
+
**Return**: URI 문자열
|
|
53
|
+
- Android: `content://` scheme의 FileProvider URI
|
|
54
|
+
- Web: `blob://` scheme의 Blob URL
|
|
55
|
+
|
|
56
|
+
**Web 환경 주의사항**:
|
|
57
|
+
반환된 Blob URL은 사용 후 반드시 `URL.revokeObjectURL(uri)`로 해제해야 합니다. 해제하지 않으면 메모리 누수가 발생할 수 있습니다.
|
|
58
|
+
|
|
59
|
+
```typescript
|
|
60
|
+
// 웹 환경: Blob URL 사용 후 해제
|
|
61
|
+
const imagePath = await FileSystem.getStoragePath("appFiles");
|
|
62
|
+
const imageFile = imagePath + "/photo.jpg";
|
|
63
|
+
|
|
64
|
+
const uri = await FileSystem.getUri(imageFile);
|
|
65
|
+
|
|
66
|
+
const img = document.createElement("img");
|
|
67
|
+
img.src = uri;
|
|
68
|
+
img.onload = () => {
|
|
69
|
+
URL.revokeObjectURL(uri); // 메모리 해제
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
// Android 환경: FileProvider URI를 다른 앱과 공유
|
|
73
|
+
const documentPath = await FileSystem.getStoragePath("externalFiles");
|
|
74
|
+
const documentFile = documentPath + "/report.pdf";
|
|
75
|
+
const contentUri = await FileSystem.getUri(documentFile);
|
|
76
|
+
|
|
77
|
+
// contentUri를 Intent의 data로 사용하여 다른 앱 실행
|
|
78
|
+
const intent = new Intent(Intent.ACTION_VIEW);
|
|
79
|
+
intent.setDataAndType(Uri.parse(contentUri), "application/pdf");
|
|
80
|
+
startActivity(intent);
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## `StorageType`
|
|
84
|
+
|
|
85
|
+
저장소 유형을 나타내는 union type입니다.
|
|
86
|
+
|
|
87
|
+
```typescript
|
|
88
|
+
type StorageType =
|
|
89
|
+
| "external"
|
|
90
|
+
| "externalFiles"
|
|
91
|
+
| "externalCache"
|
|
92
|
+
| "externalMedia"
|
|
93
|
+
| "appData"
|
|
94
|
+
| "appFiles"
|
|
95
|
+
| "appCache";
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
**사용 가이드**:
|
|
99
|
+
- **내부 저장소 (앱 전용)**:
|
|
100
|
+
- `appData`: 앱 상태 데이터 (자동 백업 대상)
|
|
101
|
+
- `appFiles`: 일반 파일 저장
|
|
102
|
+
- `appCache`: 임시 캐시 (시스템이 필요 시 삭제 가능)
|
|
103
|
+
- **외부 저장소 (공유 또는 앱 전용)**:
|
|
104
|
+
- `external`: 전체 외부 저장소 (권한 필요)
|
|
105
|
+
- `externalFiles`: 앱 전용 외부 파일 (권한 필요)
|
|
106
|
+
- `externalCache`: 앱 전용 외부 캐시 (권한 필요)
|
|
107
|
+
- `externalMedia`: 앱 전용 외부 미디어 (권한 필요)
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# Types
|
|
2
|
+
|
|
3
|
+
## `FileInfo`
|
|
4
|
+
|
|
5
|
+
파일 또는 디렉토리의 정보를 나타내는 인터페이스입니다.
|
|
6
|
+
|
|
7
|
+
```typescript
|
|
8
|
+
interface FileInfo {
|
|
9
|
+
name: string;
|
|
10
|
+
isDirectory: boolean;
|
|
11
|
+
}
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
| Field | Type | Description |
|
|
15
|
+
|-------|------|-------------|
|
|
16
|
+
| `name` | string | 파일 또는 디렉토리의 이름 (경로 제외, 확장자 포함) |
|
|
17
|
+
| `isDirectory` | boolean | true일 경우 디렉토리, false일 경우 파일 |
|
|
18
|
+
|
|
19
|
+
```typescript
|
|
20
|
+
// 디렉토리 읽기 결과
|
|
21
|
+
const files = await FileSystem.readdir("/storage/emulated/0/Documents");
|
|
22
|
+
|
|
23
|
+
// FileInfo 배열 처리
|
|
24
|
+
for (const file of files) {
|
|
25
|
+
if (file.isDirectory) {
|
|
26
|
+
console.log(`📁 ${file.name} (directory)`);
|
|
27
|
+
} else {
|
|
28
|
+
console.log(`📄 ${file.name} (file)`);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## `FileSystemPlugin`
|
|
34
|
+
|
|
35
|
+
Capacitor 플러그인 인터페이스입니다. 일반적으로 `FileSystem` 파사드를 통해 간접적으로 사용됩니다.
|
|
36
|
+
|
|
37
|
+
```typescript
|
|
38
|
+
interface FileSystemPlugin {
|
|
39
|
+
checkPermissions(): Promise<{ granted: boolean }>;
|
|
40
|
+
requestPermissions(): Promise<void>;
|
|
41
|
+
readdir(options: { path: string }): Promise<{ files: FileInfo[] }>;
|
|
42
|
+
getStoragePath(options: { type: StorageType }): Promise<{ path: string }>;
|
|
43
|
+
getUri(options: { path: string }): Promise<{ uri: string }>;
|
|
44
|
+
writeFile(options: { path: string; data: string; encoding?: "utf8" | "base64" }): Promise<void>;
|
|
45
|
+
readFile(options: { path: string; encoding?: "utf8" | "base64" }): Promise<{ data: string }>;
|
|
46
|
+
remove(options: { path: string }): Promise<void>;
|
|
47
|
+
mkdir(options: { path: string }): Promise<void>;
|
|
48
|
+
exists(options: { path: string }): Promise<{ exists: boolean }>;
|
|
49
|
+
}
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
**참고**: 이 인터페이스는 내부 플러그인 구현용이며, 외부 사용자는 `FileSystem` 파사드의 정적 메서드를 사용합니다.
|
|
53
|
+
|
|
54
|
+
## `Bytes`
|
|
55
|
+
|
|
56
|
+
이 패키지에서는 `@simplysm/core-common`의 `Bytes` 타입(Uint8Array의 별칭)을 사용합니다.
|
|
57
|
+
|
|
58
|
+
```typescript
|
|
59
|
+
import type { Bytes } from "@simplysm/core-common";
|
|
60
|
+
import { bytes } from "@simplysm/core-common";
|
|
61
|
+
|
|
62
|
+
// Bytes = Uint8Array
|
|
63
|
+
const data: Bytes = new Uint8Array([0x89, 0x50, 0x4e, 0x47]);
|
|
64
|
+
|
|
65
|
+
// Base64 변환 유틸리티
|
|
66
|
+
const base64Str = bytes.toBase64(data); // Bytes → Base64 문자열
|
|
67
|
+
const bytesData = bytes.fromBase64(base64Str); // Base64 문자열 → Bytes
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## `StorageType`
|
|
71
|
+
|
|
72
|
+
저장소 유형 union type입니다. 자세한 설명은 [storage-paths.md](./storage-paths.md)를 참조하세요.
|
|
73
|
+
|
|
74
|
+
```typescript
|
|
75
|
+
type StorageType =
|
|
76
|
+
| "external"
|
|
77
|
+
| "externalFiles"
|
|
78
|
+
| "externalCache"
|
|
79
|
+
| "externalMedia"
|
|
80
|
+
| "appData"
|
|
81
|
+
| "appFiles"
|
|
82
|
+
| "appCache";
|
|
83
|
+
```
|