oto-storage 0.3.2 → 0.4.1
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/LICENSE +1 -1
- package/README.md +63 -0
- package/package.json +10 -5
package/LICENSE
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
MIT License
|
|
2
2
|
|
|
3
|
-
Copyright (c) 2025 Diomari Madulara
|
|
3
|
+
Copyright (c) 2025 Diomari Madulara (https://diom.dev)
|
|
4
4
|
|
|
5
5
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
6
|
of this software and associated documentation files (the "Software"), to deal
|
package/README.md
CHANGED
|
@@ -23,6 +23,29 @@ Or with pnpm:
|
|
|
23
23
|
pnpm add oto-storage
|
|
24
24
|
```
|
|
25
25
|
|
|
26
|
+
### 📚 Documentation Site (VitePress)
|
|
27
|
+
|
|
28
|
+
This repo includes a VitePress documentation site in `/docs`.
|
|
29
|
+
Live documentation: [https://oto.diom.dev](https://oto.diom.dev)
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
# Run docs locally
|
|
33
|
+
npm run docs:dev
|
|
34
|
+
|
|
35
|
+
# Build static docs
|
|
36
|
+
npm run docs:build
|
|
37
|
+
|
|
38
|
+
# Preview built docs
|
|
39
|
+
npm run docs:preview
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Cloudflare Pages deployment settings:
|
|
43
|
+
|
|
44
|
+
- Project root: `/` (repo root)
|
|
45
|
+
- Build command: `npm run docs:build`
|
|
46
|
+
- Output directory: `docs/.vitepress/dist`
|
|
47
|
+
- Environment variable (optional analytics): `GA_MEASUREMENT_ID=G-XXXXXXXXXX`
|
|
48
|
+
|
|
26
49
|
### ⚡ The Problem
|
|
27
50
|
|
|
28
51
|
Working with browser storage usually involves repetitive `JSON.parse` and `JSON.stringify` calls, manual key prefixing to avoid collisions, and a total lack of Type Safety.
|
|
@@ -53,6 +76,8 @@ Oto storage uses the JavaScript Proxy API to let you interact with browser stora
|
|
|
53
76
|
|
|
54
77
|
- **TTL / Expiration**: Set automatic expiration for stored values.
|
|
55
78
|
|
|
79
|
+
- **Custom Encryption Hooks**: Encrypt/decrypt stored values with your own sync crypto callbacks.
|
|
80
|
+
|
|
56
81
|
### 🚀 Quick Start
|
|
57
82
|
|
|
58
83
|
**_1. Define your Schema_**
|
|
@@ -308,6 +333,44 @@ storage.user = { id: "1", name: "Alice" };
|
|
|
308
333
|
storage.user.name = "Bob"; // Updates are also TTL-protected
|
|
309
334
|
```
|
|
310
335
|
|
|
336
|
+
**Encryption**
|
|
337
|
+
|
|
338
|
+
Use custom synchronous `encrypt`/`decrypt` hooks to protect stored payloads at rest.
|
|
339
|
+
Security warning: `btoa`/`atob` is encoding, not cryptographic encryption. Use `encryption.encrypt`/`encryption.decrypt` with a real cipher (for example Web Crypto AES-GCM) in production.
|
|
340
|
+
|
|
341
|
+
```typescript
|
|
342
|
+
interface SecureStorage {
|
|
343
|
+
token: string;
|
|
344
|
+
profile: { id: string; name: string };
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
const keyPrefix = "my-secret-key:";
|
|
348
|
+
const secure = oto<SecureStorage>({
|
|
349
|
+
prefix: "secure-",
|
|
350
|
+
encryption: {
|
|
351
|
+
encrypt: (plainText) => btoa(`${keyPrefix}${plainText}`),
|
|
352
|
+
decrypt: (cipherText) => {
|
|
353
|
+
const decoded = atob(cipherText);
|
|
354
|
+
if (!decoded.startsWith(keyPrefix)) {
|
|
355
|
+
throw new Error("Invalid encryption key");
|
|
356
|
+
}
|
|
357
|
+
return decoded.slice(keyPrefix.length);
|
|
358
|
+
},
|
|
359
|
+
migrate: true, // Optional: auto-wrap existing plain JSON entries on read
|
|
360
|
+
},
|
|
361
|
+
});
|
|
362
|
+
|
|
363
|
+
secure.token = "abc123";
|
|
364
|
+
console.log(secure.token); // "abc123"
|
|
365
|
+
```
|
|
366
|
+
|
|
367
|
+
`encryption.migrate` helps adopt encryption without a one-time migration script by upgrading plain JSON entries as they are read.
|
|
368
|
+
Reserved keys note: `__oto_encrypted` and `__oto_payload` are used by the encryption envelope. If your stored object uses both keys with the same shape, it will be treated as encrypted data by `readStoredValue`/`isEncryptedWrapper`.
|
|
369
|
+
|
|
370
|
+
Encryption + TTL work together automatically. Expired encrypted entries are deleted on access, just like non-encrypted TTL values.
|
|
371
|
+
|
|
372
|
+
Security note: this feature protects data at rest in storage, but it does not protect against active XSS (malicious runtime code can access your encryption callbacks and decrypted values).
|
|
373
|
+
|
|
311
374
|
**Combining Defaults and TTL**
|
|
312
375
|
|
|
313
376
|
Use both features together for powerful patterns like session management:
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "oto-storage",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.1",
|
|
4
4
|
"description": "A lightweight, type-safe wrapper for localStorage and sessionStorage using the Proxy API.",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.mjs",
|
|
@@ -22,7 +22,10 @@
|
|
|
22
22
|
"test": "vitest run",
|
|
23
23
|
"test:watch": "vitest",
|
|
24
24
|
"lint": "tsc --noEmit",
|
|
25
|
-
"preview": "vite preview"
|
|
25
|
+
"preview": "vite preview",
|
|
26
|
+
"docs:dev": "vitepress dev docs",
|
|
27
|
+
"docs:build": "vitepress build docs && node scripts/inject-ga.mjs",
|
|
28
|
+
"docs:preview": "vitepress preview docs"
|
|
26
29
|
},
|
|
27
30
|
"keywords": [
|
|
28
31
|
"typescript",
|
|
@@ -33,17 +36,19 @@
|
|
|
33
36
|
"dx",
|
|
34
37
|
"storage-wrapper"
|
|
35
38
|
],
|
|
36
|
-
"author": "Diomari Madulara",
|
|
39
|
+
"author": "Diomari Madulara (https://diom.dev)",
|
|
37
40
|
"license": "MIT",
|
|
41
|
+
"homepage": "https://oto.diom.dev",
|
|
38
42
|
"repository": {
|
|
39
43
|
"type": "git",
|
|
40
|
-
"url": "https://github.com/diomari/oto-storage"
|
|
44
|
+
"url": "git+https://github.com/diomari/oto-storage.git"
|
|
41
45
|
},
|
|
42
46
|
"devDependencies": {
|
|
43
47
|
"typescript": "^5.3.3",
|
|
44
48
|
"vitest": "^1.2.2",
|
|
45
49
|
"jsdom": "^24.0.0",
|
|
46
50
|
"tsup": "^8.0.1",
|
|
47
|
-
"vite": "^5.1.0"
|
|
51
|
+
"vite": "^5.1.0",
|
|
52
|
+
"vitepress": "^1.6.4"
|
|
48
53
|
}
|
|
49
54
|
}
|