@dynlabs/react-native-immutable-file-cache 1.0.0-alpha.1 → 1.0.0-alpha.2
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/README.md +183 -261
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,19 +1,41 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
1
|
+
<p align="center">
|
|
2
|
+
<h1 align="center">react-native-immutable-file-cache</h1>
|
|
3
|
+
</p>
|
|
4
|
+
|
|
5
|
+
<p align="center">
|
|
6
|
+
<strong>Cross-platform immutable file cache for React Native and Web</strong>
|
|
7
|
+
</p>
|
|
8
|
+
|
|
9
|
+
<p align="center">
|
|
10
|
+
<a href="https://github.com/dienp/react-native-immutable-file-cache/actions/workflows/ci.yml">
|
|
11
|
+
<img src="https://github.com/dienp/react-native-immutable-file-cache/actions/workflows/ci.yml/badge.svg" alt="CI" />
|
|
12
|
+
</a>
|
|
13
|
+
<a href="https://www.npmjs.com/package/@dynlabs/react-native-immutable-file-cache">
|
|
14
|
+
<img src="https://img.shields.io/npm/v/@dynlabs/react-native-immutable-file-cache.svg" alt="npm version" />
|
|
15
|
+
</a>
|
|
16
|
+
<a href="https://opensource.org/licenses/MIT">
|
|
17
|
+
<img src="https://img.shields.io/badge/License-MIT-yellow.svg" alt="License: MIT" />
|
|
18
|
+
</a>
|
|
19
|
+
</p>
|
|
20
|
+
|
|
21
|
+
<p align="center">
|
|
22
|
+
<a href="#installation">Installation</a> •
|
|
23
|
+
<a href="#quick-start">Quick Start</a> •
|
|
24
|
+
<a href="#api">API</a> •
|
|
25
|
+
<a href="#adapters">Adapters</a> •
|
|
26
|
+
<a href="#contributing">Contributing</a>
|
|
27
|
+
</p>
|
|
28
|
+
|
|
29
|
+
---
|
|
8
30
|
|
|
9
31
|
## Features
|
|
10
32
|
|
|
11
|
-
- **Immutable entries**
|
|
12
|
-
- **Cross-platform**
|
|
13
|
-
- **Pluggable adapters**
|
|
14
|
-
- **TTL & LRU pruning**
|
|
15
|
-
- **Atomic writes**
|
|
16
|
-
- **TypeScript first**
|
|
33
|
+
- **Immutable entries** — Once cached, entries cannot be overwritten
|
|
34
|
+
- **Cross-platform** — iOS, Android, and Web support
|
|
35
|
+
- **Pluggable adapters** — Swap storage backends without code changes
|
|
36
|
+
- **TTL & LRU pruning** — Automatic cache management
|
|
37
|
+
- **Atomic writes** — Crash-safe file operations
|
|
38
|
+
- **TypeScript first** — Full type safety
|
|
17
39
|
|
|
18
40
|
## Installation
|
|
19
41
|
|
|
@@ -21,328 +43,222 @@ A cross-platform immutable file cache for React Native and Web with pluggable st
|
|
|
21
43
|
npm install @dynlabs/react-native-immutable-file-cache
|
|
22
44
|
```
|
|
23
45
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
Also install the filesystem dependency:
|
|
46
|
+
#### React Native
|
|
27
47
|
|
|
28
48
|
```bash
|
|
29
49
|
npm install react-native-fs
|
|
30
50
|
cd ios && pod install
|
|
31
51
|
```
|
|
32
52
|
|
|
33
|
-
|
|
53
|
+
#### Web
|
|
34
54
|
|
|
35
|
-
No additional dependencies required
|
|
55
|
+
No additional dependencies required — uses Cache Storage and IndexedDB.
|
|
36
56
|
|
|
37
57
|
## Quick Start
|
|
38
58
|
|
|
39
59
|
```typescript
|
|
40
60
|
import { createImmutableFileCache } from "@dynlabs/react-native-immutable-file-cache";
|
|
41
61
|
|
|
42
|
-
// Create cache instance
|
|
43
62
|
const cache = await createImmutableFileCache({
|
|
44
63
|
namespace: "images",
|
|
45
64
|
defaultTtlMs: 7 * 24 * 60 * 60 * 1000, // 7 days
|
|
46
65
|
maxSizeBytes: 100 * 1024 * 1024, // 100 MB
|
|
47
66
|
});
|
|
48
67
|
|
|
49
|
-
// Cache
|
|
50
|
-
const result = await cache.putFromUrl(
|
|
51
|
-
"avatar-123",
|
|
52
|
-
"https://example.com/avatar.jpg"
|
|
53
|
-
);
|
|
68
|
+
// Cache from URL
|
|
69
|
+
const result = await cache.putFromUrl("avatar-123", "https://example.com/avatar.jpg");
|
|
54
70
|
|
|
55
71
|
if (result.status === "created") {
|
|
56
|
-
console.log("Cached
|
|
57
|
-
} else {
|
|
58
|
-
console.log("Image already cached");
|
|
72
|
+
console.log("Cached:", result.entry.sizeBytes, "bytes");
|
|
59
73
|
}
|
|
60
74
|
|
|
61
|
-
// Retrieve
|
|
75
|
+
// Retrieve
|
|
62
76
|
const entry = await cache.get("avatar-123");
|
|
63
77
|
if (entry) {
|
|
64
|
-
// Use entry.uri in Image component
|
|
65
78
|
<Image source={{ uri: entry.uri }} />
|
|
66
79
|
}
|
|
67
80
|
```
|
|
68
81
|
|
|
69
|
-
##
|
|
70
|
-
|
|
71
|
-
The package uses a three-layer architecture:
|
|
72
|
-
|
|
73
|
-
```
|
|
74
|
-
src/
|
|
75
|
-
├── core/ # Platform-agnostic cache engine
|
|
76
|
-
├── adapters/ # Platform-specific storage adapters
|
|
77
|
-
└── index.*.ts # Platform entrypoints
|
|
78
|
-
```
|
|
79
|
-
|
|
80
|
-
### Core Layer
|
|
82
|
+
## API
|
|
81
83
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
### Adapters Layer
|
|
85
|
-
|
|
86
|
-
Platform-specific implementations of `IStorageAdapter`:
|
|
87
|
-
|
|
88
|
-
- **RNFS Adapter** - Uses `react-native-fs` for native platforms
|
|
89
|
-
- **Web Adapter** - Uses Cache Storage + IndexedDB for browsers
|
|
90
|
-
- **Memory Adapter** - In-memory storage for testing
|
|
91
|
-
|
|
92
|
-
### Public API
|
|
93
|
-
|
|
94
|
-
Platform entrypoints automatically select the appropriate adapter:
|
|
95
|
-
|
|
96
|
-
- `index.native.ts` - React Native (iOS/Android)
|
|
97
|
-
- `index.web.ts` - Web browsers
|
|
98
|
-
|
|
99
|
-
## Adapters
|
|
100
|
-
|
|
101
|
-
### Using the Default Adapter
|
|
102
|
-
|
|
103
|
-
```typescript
|
|
104
|
-
// React Native - automatically uses RNFS adapter
|
|
105
|
-
import { createImmutableFileCache } from "@dynlabs/react-native-immutable-file-cache";
|
|
106
|
-
|
|
107
|
-
// Web - automatically uses Web adapter
|
|
108
|
-
import { createImmutableFileCache } from "@dynlabs/react-native-immutable-file-cache/web";
|
|
109
|
-
```
|
|
110
|
-
|
|
111
|
-
### Injecting a Custom Adapter
|
|
84
|
+
### Configuration
|
|
112
85
|
|
|
113
86
|
```typescript
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
adapter: customAdapter,
|
|
87
|
+
createImmutableFileCache({
|
|
88
|
+
namespace: "default", // Cache isolation namespace
|
|
89
|
+
defaultTtlMs: undefined, // Default TTL (ms), undefined = no expiry
|
|
90
|
+
maxSizeBytes: undefined, // Max size, triggers LRU when exceeded
|
|
91
|
+
autoPruneExpired: true, // Auto-remove expired entries
|
|
92
|
+
adapter: undefined, // Custom storage adapter
|
|
93
|
+
hashFn: undefined, // Custom hash function (default: SHA-256)
|
|
94
|
+
onEvent: undefined, // Event handler for observability
|
|
123
95
|
});
|
|
124
96
|
```
|
|
125
97
|
|
|
126
|
-
### Building a Custom Adapter
|
|
127
|
-
|
|
128
|
-
Implement the `IStorageAdapter` interface:
|
|
129
|
-
|
|
130
|
-
```typescript
|
|
131
|
-
import type { IStorageAdapter, TBinarySource, IBinaryWriteResult } from "@dynlabs/react-native-immutable-file-cache";
|
|
132
|
-
|
|
133
|
-
const myAdapter: IStorageAdapter = {
|
|
134
|
-
kind: "my-storage",
|
|
135
|
-
rootId: "my-root",
|
|
136
|
-
|
|
137
|
-
async ensureDir(path) { /* Create directory */ },
|
|
138
|
-
async exists(path) { /* Check if exists */ },
|
|
139
|
-
async remove(path) { /* Remove file */ },
|
|
140
|
-
async removeDir(path) { /* Remove directory recursively */ },
|
|
141
|
-
async listDir(path) { /* List directory contents */ },
|
|
142
|
-
async readText(path, encoding) { /* Read text file */ },
|
|
143
|
-
async writeTextAtomic(path, content, encoding) { /* Write text atomically */ },
|
|
144
|
-
async stat(path) { /* Get file stats */ },
|
|
145
|
-
async writeBinaryAtomic(path, source, options) { /* Write binary atomically */ },
|
|
146
|
-
async getPublicUri(path) { /* Get URI for file */ },
|
|
147
|
-
};
|
|
148
|
-
```
|
|
149
|
-
|
|
150
|
-
### Supported Binary Sources by Adapter
|
|
151
|
-
|
|
152
|
-
| Source Type | RNFS Adapter | Web Adapter | Memory Adapter |
|
|
153
|
-
|-------------|--------------|-------------|----------------|
|
|
154
|
-
| `url` | ✅ | ✅ | ✅ |
|
|
155
|
-
| `file` | ✅ | ❌ | ✅ (simulated) |
|
|
156
|
-
| `blob` | ❌ | ✅ | ✅ |
|
|
157
|
-
| `bytes` | ✅ | ✅ | ✅ |
|
|
158
|
-
|
|
159
|
-
## API Reference
|
|
160
|
-
|
|
161
|
-
### `createImmutableFileCache(options?)`
|
|
162
|
-
|
|
163
|
-
Creates a new cache instance.
|
|
164
|
-
|
|
165
|
-
#### Options
|
|
166
|
-
|
|
167
|
-
| Option | Type | Default | Description |
|
|
168
|
-
|--------|------|---------|-------------|
|
|
169
|
-
| `namespace` | `string` | `"default"` | Cache namespace for isolation |
|
|
170
|
-
| `adapter` | `IStorageAdapter` | auto-detected | Custom storage adapter |
|
|
171
|
-
| `defaultTtlMs` | `number` | `undefined` | Default TTL for entries |
|
|
172
|
-
| `maxSizeBytes` | `number` | `undefined` | Max cache size (triggers LRU) |
|
|
173
|
-
| `autoPruneExpired` | `boolean` | `true` | Auto-prune on operations |
|
|
174
|
-
| `hashFn` | `(input: string) => string \| Promise<string>` | SHA-256 | Custom hash function |
|
|
175
|
-
|
|
176
98
|
### Put Operations
|
|
177
99
|
|
|
178
|
-
All put operations are immutable
|
|
179
|
-
|
|
180
|
-
#### `putFromUrl(key, url, options?)`
|
|
181
|
-
|
|
182
|
-
Cache content from a URL.
|
|
183
|
-
|
|
184
|
-
```typescript
|
|
185
|
-
const result = await cache.putFromUrl("image-key", "https://example.com/image.jpg", {
|
|
186
|
-
ttlMs: 86400000, // 1 day
|
|
187
|
-
ext: ".jpg",
|
|
188
|
-
metadata: { source: "cdn" },
|
|
189
|
-
onProgress: (pct) => console.log(`${pct}% downloaded`),
|
|
190
|
-
headers: { Authorization: "Bearer token" },
|
|
191
|
-
});
|
|
192
|
-
```
|
|
193
|
-
|
|
194
|
-
#### `putFromFile(key, filePath, options?)` (Native only)
|
|
195
|
-
|
|
196
|
-
Cache content from a local file.
|
|
100
|
+
All put operations are immutable — returns `{ status: "exists" }` if the key already exists.
|
|
197
101
|
|
|
198
102
|
```typescript
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
});
|
|
202
|
-
```
|
|
103
|
+
// From URL
|
|
104
|
+
await cache.putFromUrl(key, url, { ttlMs, ext, metadata, headers, onProgress });
|
|
203
105
|
|
|
204
|
-
|
|
106
|
+
// From file (Native only)
|
|
107
|
+
await cache.putFromFile(key, filePath, options);
|
|
205
108
|
|
|
206
|
-
|
|
109
|
+
// From Blob (Web only)
|
|
110
|
+
await cache.putFromBlob(key, blob, options);
|
|
207
111
|
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
const result = await cache.putFromBlob("data-key", blob);
|
|
211
|
-
```
|
|
212
|
-
|
|
213
|
-
#### `putFromBytes(key, bytes, options?)`
|
|
214
|
-
|
|
215
|
-
Cache raw bytes.
|
|
216
|
-
|
|
217
|
-
```typescript
|
|
218
|
-
const result = await cache.putFromBytes("raw-key", new Uint8Array([1, 2, 3]));
|
|
112
|
+
// From bytes
|
|
113
|
+
await cache.putFromBytes(key, new Uint8Array([...]), options);
|
|
219
114
|
```
|
|
220
115
|
|
|
221
116
|
### Get Operations
|
|
222
117
|
|
|
223
|
-
#### `get(key)`
|
|
224
|
-
|
|
225
|
-
Get entry with URI. Updates `lastAccessedAt`.
|
|
226
|
-
|
|
227
118
|
```typescript
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
console.log("Size:", result.entry.sizeBytes);
|
|
232
|
-
}
|
|
233
|
-
```
|
|
119
|
+
// Get with URI (updates lastAccessedAt)
|
|
120
|
+
const result = await cache.get(key);
|
|
121
|
+
// => { entry, uri } | null
|
|
234
122
|
|
|
235
|
-
|
|
123
|
+
// Check existence
|
|
124
|
+
const exists = await cache.has(key);
|
|
236
125
|
|
|
237
|
-
|
|
126
|
+
// Peek without updating access time
|
|
127
|
+
const entry = await cache.peek(key);
|
|
238
128
|
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
// Entry exists
|
|
242
|
-
}
|
|
243
|
-
```
|
|
129
|
+
// Get URI only
|
|
130
|
+
const uri = await cache.getUri(key);
|
|
244
131
|
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
132
|
+
// Read-through cache
|
|
133
|
+
const result = await cache.getOrPut(key, async (k) => ({
|
|
134
|
+
bytes: new Uint8Array([...]),
|
|
135
|
+
ttlMs: 86400000,
|
|
136
|
+
ext: ".json",
|
|
137
|
+
}));
|
|
251
138
|
```
|
|
252
139
|
|
|
253
|
-
### List
|
|
254
|
-
|
|
255
|
-
#### `list(options?)`
|
|
256
|
-
|
|
257
|
-
List entries with sorting, filtering, and pagination.
|
|
140
|
+
### List & Stats
|
|
258
141
|
|
|
259
142
|
```typescript
|
|
143
|
+
// List entries
|
|
260
144
|
const entries = await cache.list({
|
|
261
|
-
sortBy: "createdAt",
|
|
262
|
-
order: "desc",
|
|
145
|
+
sortBy: "createdAt", // "createdAt" | "lastAccessedAt" | "sizeBytes" | "key"
|
|
146
|
+
order: "desc", // "asc" | "desc"
|
|
263
147
|
limit: 10,
|
|
264
148
|
offset: 0,
|
|
265
|
-
filter: (
|
|
149
|
+
filter: (e) => e.sizeBytes > 1000,
|
|
266
150
|
});
|
|
267
|
-
```
|
|
268
151
|
|
|
269
|
-
|
|
152
|
+
// Get all keys
|
|
153
|
+
const keys = await cache.keys();
|
|
270
154
|
|
|
271
|
-
|
|
155
|
+
// Count entries
|
|
156
|
+
const count = await cache.count();
|
|
272
157
|
|
|
273
|
-
|
|
158
|
+
// Statistics
|
|
274
159
|
const stats = await cache.stats();
|
|
275
|
-
|
|
160
|
+
// => { entryCount, totalSizeBytes, oldestEntry?, newestEntry? }
|
|
276
161
|
```
|
|
277
162
|
|
|
278
|
-
###
|
|
163
|
+
### Cache Management
|
|
279
164
|
|
|
280
|
-
|
|
165
|
+
```typescript
|
|
166
|
+
// Remove single entry
|
|
167
|
+
await cache.remove(key);
|
|
281
168
|
|
|
282
|
-
Remove
|
|
169
|
+
// Remove expired entries
|
|
170
|
+
await cache.removeExpired();
|
|
171
|
+
// => { removedCount, freedBytes, removedKeys }
|
|
283
172
|
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
```
|
|
173
|
+
// LRU prune to size limit
|
|
174
|
+
await cache.pruneLru(50 * 1024 * 1024);
|
|
287
175
|
|
|
288
|
-
|
|
176
|
+
// Clear all
|
|
177
|
+
await cache.clear();
|
|
289
178
|
|
|
290
|
-
|
|
179
|
+
// Validate & repair index
|
|
180
|
+
await cache.validateAndRepair();
|
|
291
181
|
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
182
|
+
// TTL management
|
|
183
|
+
await cache.touch(key); // Refresh access time
|
|
184
|
+
await cache.setTtl(key, 86400000); // Set new TTL
|
|
185
|
+
await cache.extendTtl(key, 3600000); // Extend TTL
|
|
295
186
|
```
|
|
296
187
|
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
Prune to fit size limit using LRU.
|
|
188
|
+
### Lifecycle
|
|
300
189
|
|
|
301
190
|
```typescript
|
|
302
|
-
|
|
191
|
+
// Flush pending writes (when using debounce)
|
|
192
|
+
await cache.flush();
|
|
193
|
+
|
|
194
|
+
// Destroy and release resources
|
|
195
|
+
await cache.destroy();
|
|
303
196
|
```
|
|
304
197
|
|
|
305
|
-
|
|
198
|
+
## Adapters
|
|
306
199
|
|
|
307
|
-
|
|
200
|
+
The library uses a pluggable adapter architecture:
|
|
308
201
|
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
202
|
+
| Adapter | Platform | Storage |
|
|
203
|
+
|---------|----------|---------|
|
|
204
|
+
| **RNFS** | iOS/Android | `react-native-fs` |
|
|
205
|
+
| **Web** | Browser | Cache Storage + IndexedDB |
|
|
206
|
+
| **Memory** | All | In-memory (testing) |
|
|
312
207
|
|
|
313
|
-
###
|
|
208
|
+
### Default Adapter (Auto-selected)
|
|
314
209
|
|
|
315
|
-
|
|
210
|
+
```typescript
|
|
211
|
+
// React Native — uses RNFS adapter
|
|
212
|
+
import { createImmutableFileCache } from "@dynlabs/react-native-immutable-file-cache";
|
|
316
213
|
|
|
317
|
-
|
|
214
|
+
// Web — uses Web adapter
|
|
215
|
+
import { createImmutableFileCache } from "@dynlabs/react-native-immutable-file-cache/web";
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
### Custom Adapter
|
|
318
219
|
|
|
319
220
|
```typescript
|
|
320
|
-
|
|
321
|
-
if (result.repaired) {
|
|
322
|
-
console.log("Fixed issues:", result.issues);
|
|
323
|
-
}
|
|
324
|
-
```
|
|
221
|
+
import { createImmutableFileCache, createRnfsAdapter } from "@dynlabs/react-native-immutable-file-cache";
|
|
325
222
|
|
|
326
|
-
|
|
223
|
+
const cache = await createImmutableFileCache({
|
|
224
|
+
adapter: createRnfsAdapter({ baseDir: "/custom/path", namespace: "my-app" }),
|
|
225
|
+
});
|
|
226
|
+
```
|
|
327
227
|
|
|
328
|
-
|
|
228
|
+
### Supported Sources
|
|
329
229
|
|
|
330
|
-
|
|
331
|
-
|
|
230
|
+
| Source | RNFS | Web | Memory |
|
|
231
|
+
|--------|------|-----|--------|
|
|
232
|
+
| `url` | ✓ | ✓ | ✓ |
|
|
233
|
+
| `file` | ✓ | — | ✓ |
|
|
234
|
+
| `blob` | — | ✓ | ✓ |
|
|
235
|
+
| `bytes` | ✓ | ✓ | ✓ |
|
|
332
236
|
|
|
333
|
-
|
|
237
|
+
### Implementing Custom Adapters
|
|
334
238
|
|
|
335
|
-
|
|
336
|
-
|
|
239
|
+
```typescript
|
|
240
|
+
import type { IStorageAdapter } from "@dynlabs/react-native-immutable-file-cache";
|
|
337
241
|
|
|
338
|
-
|
|
339
|
-
|
|
242
|
+
const myAdapter: IStorageAdapter = {
|
|
243
|
+
kind: "my-storage",
|
|
244
|
+
rootId: "my-root",
|
|
245
|
+
supportedSources: new Set(["url", "bytes"]),
|
|
246
|
+
|
|
247
|
+
async ensureDir(path) { /* ... */ },
|
|
248
|
+
async exists(path) { /* ... */ },
|
|
249
|
+
async remove(path) { /* ... */ },
|
|
250
|
+
async removeDir(path) { /* ... */ },
|
|
251
|
+
async listDir(path) { /* ... */ },
|
|
252
|
+
async readText(path, encoding) { /* ... */ },
|
|
253
|
+
async writeTextAtomic(path, content, encoding) { /* ... */ },
|
|
254
|
+
async stat(path) { /* ... */ },
|
|
255
|
+
async writeBinaryAtomic(path, source, options) { /* ... */ },
|
|
256
|
+
async getPublicUri(path) { /* ... */ },
|
|
257
|
+
};
|
|
340
258
|
```
|
|
341
259
|
|
|
342
260
|
## Error Handling
|
|
343
261
|
|
|
344
|
-
The package provides typed errors:
|
|
345
|
-
|
|
346
262
|
```typescript
|
|
347
263
|
import {
|
|
348
264
|
CacheError,
|
|
@@ -362,23 +278,32 @@ try {
|
|
|
362
278
|
}
|
|
363
279
|
```
|
|
364
280
|
|
|
365
|
-
##
|
|
366
|
-
|
|
367
|
-
The adapter architecture makes it easy to add support for:
|
|
368
|
-
|
|
369
|
-
- `react-native-blob-util`
|
|
370
|
-
- `expo-file-system`
|
|
371
|
-
- S3-backed remote cache
|
|
372
|
-
- SQLite-based storage
|
|
373
|
-
- Custom encrypted storage
|
|
281
|
+
## Observability
|
|
374
282
|
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
283
|
+
```typescript
|
|
284
|
+
const cache = await createImmutableFileCache({
|
|
285
|
+
onEvent: (event) => {
|
|
286
|
+
switch (event.type) {
|
|
287
|
+
case "cache_hit":
|
|
288
|
+
console.log(`HIT: ${event.key} (${event.ageMs}ms old)`);
|
|
289
|
+
break;
|
|
290
|
+
case "cache_miss":
|
|
291
|
+
console.log(`MISS: ${event.key} (${event.reason})`);
|
|
292
|
+
break;
|
|
293
|
+
case "cache_write":
|
|
294
|
+
console.log(`WRITE: ${event.key} (${event.sizeBytes} bytes)`);
|
|
295
|
+
break;
|
|
296
|
+
case "cache_prune":
|
|
297
|
+
console.log(`PRUNE: removed ${event.removedCount} entries`);
|
|
298
|
+
break;
|
|
299
|
+
}
|
|
300
|
+
},
|
|
301
|
+
});
|
|
302
|
+
```
|
|
378
303
|
|
|
379
304
|
## Testing
|
|
380
305
|
|
|
381
|
-
|
|
306
|
+
Use the memory adapter for unit tests:
|
|
382
307
|
|
|
383
308
|
```typescript
|
|
384
309
|
import { CacheEngine, createMemoryAdapter } from "@dynlabs/react-native-immutable-file-cache";
|
|
@@ -389,27 +314,24 @@ await cache.init();
|
|
|
389
314
|
|
|
390
315
|
// Run tests...
|
|
391
316
|
|
|
392
|
-
// Clean up
|
|
393
|
-
adapter._reset();
|
|
317
|
+
adapter._reset(); // Clean up
|
|
394
318
|
```
|
|
395
319
|
|
|
396
320
|
## Contributing
|
|
397
321
|
|
|
398
|
-
Contributions are welcome! Please read our [Contributing Guide](CONTRIBUTING.md) for details.
|
|
399
|
-
|
|
400
322
|
```bash
|
|
401
|
-
# Clone and install
|
|
402
323
|
git clone https://github.com/dienp/react-native-immutable-file-cache.git
|
|
403
324
|
cd react-native-immutable-file-cache
|
|
404
325
|
npm install
|
|
405
326
|
|
|
406
|
-
# Development
|
|
407
327
|
npm run typecheck # Type check
|
|
408
328
|
npm run lint # Lint
|
|
409
329
|
npm test # Run tests
|
|
410
330
|
npm run build # Build
|
|
411
331
|
```
|
|
412
332
|
|
|
333
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md) for details.
|
|
334
|
+
|
|
413
335
|
## License
|
|
414
336
|
|
|
415
|
-
MIT
|
|
337
|
+
[MIT](LICENSE)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dynlabs/react-native-immutable-file-cache",
|
|
3
|
-
"version": "1.0.0-alpha.
|
|
3
|
+
"version": "1.0.0-alpha.2",
|
|
4
4
|
"description": "Cross-platform immutable file cache with pluggable storage adapters for React Native and Web",
|
|
5
5
|
"author": "dienp",
|
|
6
6
|
"license": "MIT",
|