ac-storage 0.14.0 → 0.15.0

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.
@@ -0,0 +1,57 @@
1
+ # 모호한 테스트 보고서
2
+
3
+ ## 1. electron-ipc-simulation.test.ts
4
+
5
+ ### 제거 권장 (버그 재현용):
6
+ - **라인 240-305**: `test('CRITICAL: 동시 save() 호출로 인한 race condition')`
7
+ - 50번 반복하여 손상 재현 시도
8
+ - json-accessor v0.7에서 이미 해결됨
9
+
10
+ - **라인 631-690**: `test('CRITICAL: 빠른 IPC 요청으로 동시 writeFile 유발')`
11
+ - 100번 반복하여 파일 손상 재현 시도
12
+ - 이미 해결된 문제
13
+
14
+ - **라인 784-820**: `test('문서화: IPC 환경 특유의 문제점')`
15
+ - 단순 console.log만 출력
16
+ - `expect(true).toBe(true)` - 의미 없는 검증
17
+ - 코드 주석이나 문서로 대체 가능
18
+
19
+ ### 판단: 3개 테스트 제거하고 나머지 유지
20
+
21
+ ---
22
+
23
+ ## 2. storage-move.test.ts
24
+
25
+ ### 제거 권장:
26
+ - **라인 97-99**: `test('copy 123')`
27
+ ```typescript
28
+ test(`copy 123`, async () => {
29
+ await storage.access('text1:index.txt', 'text');
30
+ });
31
+ ```
32
+ - 의미 없는 테스트명
33
+ - 불완전한 구현 (access만 하고 아무것도 검증 안 함)
34
+ - 작성 중 방치된 것으로 보임
35
+
36
+ ### 판단: 해당 테스트 제거
37
+
38
+ ---
39
+
40
+ ## 3. idempotent-operations.test.ts
41
+ - **명확함**: 멱등성 검증, 유지 권장
42
+
43
+ ## 4. 나머지 테스트들
44
+ - **명확함**: 정상적인 기능 테스트
45
+
46
+ ---
47
+
48
+ ## 요약
49
+
50
+ ### 제거 대상 (총 4개 테스트):
51
+ 1. `electron-ipc-simulation.test.ts` 내 3개 CRITICAL/문서화 테스트
52
+ 2. `storage-move.test.ts` 내 'copy 123' 테스트
53
+
54
+ ### 제거 후:
55
+ - 더 명확한 테스트 스위트
56
+ - 실제 기능 검증에 집중
57
+ - 유지보수 부담 감소
package/CLAUDE.md ADDED
@@ -0,0 +1,415 @@
1
+ # AC-Storage - Developer Documentation
2
+
3
+ ## Project Overview
4
+
5
+ **AC-Storage** is a TypeScript library that provides a structured, access-controlled file storage management system. It allows developers to define file access permissions upfront and manage JSON, text, and binary files in a type-safe manner with transactional semantics.
6
+
7
+ ### Key Features
8
+
9
+ - **Access Control**: Pre-register file paths and access types before use
10
+ - **Multiple File Formats**: Built-in support for JSON, Text, and Binary files
11
+ - **Custom Accessors**: Extensible system for custom file formats
12
+ - **Transactional Semantics**: Commit changes explicitly to filesystem
13
+ - **Caching System**: Optimized access type validation through `.acstorage` cache
14
+ - **Sub-Storage**: Create isolated storage spaces for directory-based operations
15
+ - **Dependency Tracking**: Automatic management of file dependencies
16
+
17
+ ## Directory Structure
18
+
19
+ ```
20
+ ac-storage/
21
+ ├── src/
22
+ │ ├── features/ # Core feature implementations
23
+ │ │ ├── accessors/ # File accessor implementations
24
+ │ │ │ ├── BinaryAccessor/ # Binary file handling
25
+ │ │ │ ├── TextAccessor/ # Text file handling
26
+ │ │ │ ├── JSONAccessor/ # JSON file handling
27
+ │ │ │ ├── CustomAccessor/ # Custom format support
28
+ │ │ │ └── MetaAccessor/ # Directory and root accessors
29
+ │ │ ├── storage/ # Storage management
30
+ │ │ │ ├── ACStorage.ts # Main storage class
31
+ │ │ │ ├── ACSubStorage.ts # Sub-storage implementation
32
+ │ │ │ ├── MemACStorage.ts # In-memory storage
33
+ │ │ │ └── test/ # Storage tests
34
+ │ │ ├── StorageAccessControl/ # Access control logic
35
+ │ │ │ ├── StorageAccessControl.ts
36
+ │ │ │ └── StorageAccessControl.test.ts
37
+ │ │ └── StorageAccess/ # Access type definitions
38
+ │ │ └── StorageAccess.ts
39
+ │ ├── types/ # TypeScript type definitions
40
+ │ ├── errors/ # Error classes
41
+ │ ├── utils/ # Utility functions
42
+ │ └── data/ # Test data
43
+ ├── dist/ # Build output
44
+ ├── _TESTPATH/ # Test runtime directory
45
+ ├── jest.config.ts # Jest test configuration
46
+ ├── tsconfig.json # TypeScript configuration
47
+ ├── rollup.config.js # Build configuration
48
+ └── package.json # Package metadata
49
+ ```
50
+
51
+ ## Architecture
52
+
53
+ ### Core Components
54
+
55
+ 1. **ACStorage** (`src/features/storage/ACStorage.ts`)
56
+ - Main entry point for storage operations
57
+ - Manages accessor lifecycle and dependencies
58
+ - Handles caching and filesystem synchronization
59
+ - Provides memory management through release/drop operations
60
+
61
+ 2. **StorageAccessControl** (`src/features/StorageAccessControl/`)
62
+ - Enforces access permissions
63
+ - Validates file access against registered tree
64
+ - Manages file operations (copy, move)
65
+ - Handles destroy operations for memory cleanup
66
+
67
+ 3. **Accessors** (`src/features/accessors/`)
68
+ - Abstract file operations for different formats
69
+ - Each type has a Manager and Accessor class
70
+ - Manager handles lifecycle, Accessor provides API
71
+
72
+ 4. **StorageAccess** (`src/features/StorageAccess/`)
73
+ - Factory for creating access type definitions
74
+ - Used in `register()` to define file permissions
75
+
76
+ ### Data Flow
77
+
78
+ ```
79
+ User Code
80
+
81
+ ACStorage.register() → Define access tree
82
+
83
+ ACStorage.create*() / open*() / access*() → Request file access
84
+
85
+ StorageAccessControl → Validate permissions
86
+
87
+ AccessorManager → Create/load accessor
88
+
89
+ Accessor API → Read/write operations
90
+
91
+ ACStorage.commit() → Persist to filesystem
92
+
93
+ ACStorage.release() → Save and unload from memory (optional)
94
+ ACStorage.drop() → Delete file and unload (alternative)
95
+ ```
96
+
97
+ ### File Access Methods
98
+
99
+ AC-Storage provides three distinct methods for accessing files, each with different semantics:
100
+
101
+ #### 1. **create()** - Create Only
102
+ - **Creates** a new file
103
+ - **Throws error** if file already exists (on disk or in memory)
104
+ - Use when you want to ensure you're creating a new file
105
+
106
+ #### 2. **open()** - Load Only
107
+ - **Loads** an existing file
108
+ - **Throws error** if file does not exist
109
+ - Use when you expect the file to already exist
110
+
111
+ #### 3. **access()** - Create or Load (Default)
112
+ - **Creates** file if it doesn't exist
113
+ - **Loads** file if it already exists
114
+ - **Never throws** for existence checks
115
+ - Use for flexible access (most common)
116
+
117
+ #### Access Methods Comparison
118
+
119
+ | Method | Creates if Missing | Loads if Exists | Error if Missing | Error if Exists |
120
+ |--------|-------------------|-----------------|------------------|-----------------|
121
+ | `create()` | ✅ | ❌ | N/A | ✅ |
122
+ | `open()` | ❌ | ✅ | ✅ | N/A |
123
+ | `access()` | ✅ | ✅ | ❌ | ❌ |
124
+
125
+ **Example:**
126
+ ```typescript
127
+ // Create only - explicit file creation
128
+ const config = await storage.createAsJSON('config.json');
129
+ config.setOne('version', '1.0');
130
+
131
+ // Open only - explicit file loading
132
+ const existing = await storage.openAsJSON('config.json');
133
+ console.log(existing.getOne('version'));
134
+
135
+ // Access - flexible (creates or loads)
136
+ const flexible = await storage.accessAsJSON('settings.json');
137
+ ```
138
+
139
+ **Available methods for each approach:**
140
+ ```typescript
141
+ // CREATE methods
142
+ await storage.create(identifier, accessType)
143
+ await storage.createAsJSON(identifier)
144
+ await storage.createAsText(identifier)
145
+ await storage.createAsBinary(identifier)
146
+
147
+ // OPEN methods
148
+ await storage.open(identifier, accessType)
149
+ await storage.openAsJSON(identifier)
150
+ await storage.openAsText(identifier)
151
+ await storage.openAsBinary(identifier)
152
+
153
+ // ACCESS methods (backward compatible)
154
+ await storage.access(identifier, accessType)
155
+ await storage.accessAsJSON(identifier)
156
+ await storage.accessAsText(identifier)
157
+ await storage.accessAsBinary(identifier)
158
+ ```
159
+
160
+ ### Memory Management
161
+
162
+ AC-Storage provides two approaches for unloading files from memory:
163
+
164
+ #### 1. **release()** - Save and Unload
165
+ - Commits changes to filesystem
166
+ - Removes accessor from memory
167
+ - **Keeps file on disk**
168
+ - Use when you want to free memory but preserve data
169
+
170
+ #### 2. **drop()** - Delete and Unload
171
+ - **Does NOT commit changes** (uncommitted changes are lost)
172
+ - Removes accessor from memory
173
+ - **Deletes file from disk**
174
+ - Use when you want to completely remove the file
175
+
176
+ #### Comparison Table
177
+
178
+ | Operation | Commits Changes | Removes from Memory | Deletes File |
179
+ |-----------|----------------|---------------------|--------------|
180
+ | `commit()` | ✅ | ❌ | ❌ |
181
+ | `release()` | ✅ | ✅ | ❌ |
182
+ | `drop()` | ❌ | ✅ | ✅ |
183
+
184
+ **Example:**
185
+ ```typescript
186
+ // Save and unload from memory (file persists)
187
+ await storage.accessAsJSON('config.json');
188
+ await storage.release('config.json');
189
+
190
+ // Delete file and unload
191
+ await storage.accessAsJSON('temp.json');
192
+ await storage.drop('temp.json');
193
+ ```
194
+
195
+ ### Internal Events
196
+
197
+ The library uses an internal event system for lifecycle management:
198
+
199
+ - **`'access'` event**: Fired when a file is accessed
200
+ - **`'destroy'` event**: Fired when a file is dropped (deleted)
201
+ - **Note**: `release()` does NOT trigger destroy event (it's a safe unload)
202
+
203
+ **Usage:**
204
+ ```typescript
205
+ storage.addListener('access', (identifier) => {
206
+ console.log(`Accessed: ${identifier}`);
207
+ });
208
+
209
+ storage.addListener('destroy', (identifier) => {
210
+ console.log(`Destroyed: ${identifier}`);
211
+ });
212
+ ```
213
+
214
+ ## Testing
215
+
216
+ ### Test Configuration
217
+
218
+ - **Framework**: Jest with ts-jest
219
+ - **Location**: Tests are colocated with source code
220
+ - **Pattern**: `**/*.(spec|test).ts`
221
+ - **Environment**: Node.js
222
+
223
+ ### Test Files
224
+
225
+ #### Accessor Tests
226
+ - `src/features/accessors/BinaryAccessor/binary-accessor.test.ts` - Binary file operations
227
+ - `src/features/accessors/TextAccessor/text-accessor.test.ts` - Text file operations
228
+ - `src/features/accessors/JSONAccessor/json-accesssor.test.ts` - JSON file operations
229
+
230
+ #### Storage Tests
231
+ - `src/features/storage/test/storage.test.ts` - Core storage functionality
232
+ - `src/features/storage/test/storage-accessor.test.ts` - Accessor lifecycle
233
+ - `src/features/storage/test/storage-fs.test.ts` - Filesystem operations
234
+ - `src/features/storage/test/storage-move.test.ts` - Move/copy operations
235
+ - `src/features/storage/test/ac-drop.test.ts` - Drop/destroy operations (memory cleanup)
236
+ - `src/features/storage/test/release.test.ts` - Release operations (save & unload)
237
+ - `src/features/storage/test/access-separation.test.ts` - Create/Open/Access API separation
238
+ - `src/features/storage/test/custom-accessor.test.ts` - Custom accessor support
239
+ - `src/features/storage/test/substorage.test.ts` - Sub-storage functionality
240
+
241
+ #### Access Control Tests
242
+ - `src/features/StorageAccessControl/StorageAccessControl.test.ts` - Access control logic
243
+
244
+ ### Running Tests
245
+
246
+ ```bash
247
+ # Run all tests
248
+ npm test
249
+
250
+ # Run tests in watch mode
251
+ npm test -- --watch
252
+
253
+ # Run tests with coverage
254
+ npm test -- --coverage
255
+
256
+ # Run specific test file
257
+ npm test -- storage.test.ts
258
+ ```
259
+
260
+ ### Test Output Location
261
+
262
+ Test artifacts and temporary files are created in:
263
+ - `_TESTPATH/` - Runtime test directory (gitignored)
264
+ - Individual tests may create temporary subdirectories
265
+
266
+ ## Building
267
+
268
+ ### Build Configuration
269
+
270
+ - **Bundler**: Rollup
271
+ - **Output Formats**:
272
+ - CommonJS: `dist/bundle.cjs`
273
+ - ES Module: `dist/bundle.mjs`
274
+ - TypeScript Declarations: `dist/index.d.ts`
275
+
276
+ ### Build Commands
277
+
278
+ ```bash
279
+ # Build the library
280
+ npm run build
281
+
282
+ # Run playground example
283
+ npm run playground
284
+
285
+ # Publish to npm
286
+ npm run publish-public
287
+ ```
288
+
289
+ ### Path Aliases
290
+
291
+ The project uses TypeScript path aliases for cleaner imports:
292
+
293
+ ```typescript
294
+ @/* → src/*
295
+ types → src/types/index
296
+ errors → src/errors/index
297
+ features/* → src/features/*
298
+ data/* → src/data/*
299
+ utils → src/utils/index
300
+ ```
301
+
302
+ Both `tsconfig.json` and `jest.config.ts` must be kept in sync for these aliases.
303
+
304
+ ## Development Guidelines
305
+
306
+ ### Adding New Accessor Types
307
+
308
+ 1. Create accessor directory under `src/features/accessors/`
309
+ 2. Implement `IAccessorManager` and accessor interface
310
+ 3. Add tests in the same directory
311
+ 4. Export from `src/features/accessors/index.ts`
312
+
313
+ ### Adding Tests
314
+
315
+ 1. Place tests near the code they test
316
+ 2. Use `.test.ts` suffix
317
+ 3. Follow existing test patterns
318
+ 4. Ensure all async operations are properly awaited
319
+ 5. Clean up test artifacts in `_TESTPATH/`
320
+
321
+ ### Code Style
322
+
323
+ - TypeScript strict mode enabled (with some relaxations)
324
+ - No implicit any allowed for complex types
325
+ - Explicit method overrides required
326
+ - Property access from index signatures restricted
327
+
328
+ ## Common Issues
329
+
330
+ ### Cache-Related Issues
331
+
332
+ If tests fail due to cache conflicts:
333
+ ```bash
334
+ # Clear test cache
335
+ rm -rf _TESTPATH/
336
+ ```
337
+
338
+ ### Build Issues
339
+
340
+ If build fails:
341
+ ```bash
342
+ # Clean and rebuild
343
+ rm -rf dist/
344
+ npm run build
345
+ ```
346
+
347
+ ### Test Failures
348
+
349
+ If tests hang or fail inconsistently:
350
+ - Check for uncommitted accessors
351
+ - Ensure proper cleanup in test teardown
352
+ - Verify `_TESTPATH/` is empty between runs
353
+
354
+ ## Dependencies
355
+
356
+ ### Runtime Dependencies
357
+ - `@hve/json-accessor` - JSON manipulation
358
+ - `fast-deep-equal` - Deep equality checks
359
+ - `tree-navigate` - Tree structure navigation
360
+
361
+ ### Development Dependencies
362
+ - `typescript` - TypeScript compiler
363
+ - `jest` / `ts-jest` - Testing framework
364
+ - `rollup` - Module bundler
365
+ - `tsx` - TypeScript execution for playground
366
+
367
+ ## Version
368
+
369
+ Current version: **0.15.0** (unreleased)
370
+
371
+ Last updated: 2025-12-07
372
+
373
+ ## Recent Changes
374
+
375
+ ### v0.15.0 - Access API Separation & Release API (2025-12-07)
376
+
377
+ **Breaking Changes:**
378
+ - Renamed internal event `'release'` → `'destroy'` (v0.14.1)
379
+ - `storage.addListener('release', ...)` → `storage.addListener('destroy', ...)`
380
+
381
+ **New Features:**
382
+
383
+ 1. **File Access Method Separation**
384
+ - `create()` / `createAsJSON()` / `createAsText()` / `createAsBinary()` - Create new files only (error if exists)
385
+ - `open()` / `openAsJSON()` / `openAsText()` / `openAsBinary()` - Load existing files only (error if missing)
386
+ - `access()` / `accessAsJSON()` / `accessAsText()` / `accessAsBinary()` - Flexible access (create or load)
387
+
388
+ 2. **Memory Management APIs** (v0.14.1+)
389
+ - `release(identifier)` - Save changes and unload file from memory (file persists)
390
+ - `releaseDir(identifier)` - Save and unload directory from memory
391
+ - `releaseAll()` - Save and unload all files from memory
392
+
393
+ **Internal Changes:**
394
+ - Refactored `getOrCreateAccessor()` to support three access modes: `'create'`, `'open'`, `'access'`
395
+ - Added `getOrCreateAccessorFromAccess()` helper method
396
+ - Added `validateAccess()` to `StorageAccessControl` for permission validation without accessor creation
397
+ - Updated all internal event listeners to use `'destroy'` terminology
398
+
399
+ **Backward Compatibility:**
400
+ - All existing `access*()` methods continue to work with the same behavior
401
+ - No breaking changes to public API (except event name change in v0.14.1)
402
+
403
+ **Example:**
404
+ ```typescript
405
+ // New explicit methods
406
+ const config = await storage.createAsJSON('config.json'); // Create only
407
+ const existing = await storage.openAsJSON('config.json'); // Load only
408
+
409
+ // Existing flexible method (backward compatible)
410
+ const flexible = await storage.accessAsJSON('settings.json'); // Create or load
411
+
412
+ // Memory management
413
+ await storage.release('config.json'); // Save and unload (v0.14.1+)
414
+ await storage.drop('temp.json'); // Delete and unload
415
+ ```