strata-storage 2.7.0 → 2.8.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.
- package/AI-INTEGRATION-GUIDE.md +46 -2
- package/LICENSE +21 -35
- package/README.md +15 -13
- package/dist/LICENSE +21 -35
- package/dist/README.md +15 -13
- package/dist/adapters/capacitor/FilesystemAdapter.d.ts +0 -1
- package/dist/adapters/capacitor/PreferencesAdapter.d.ts +0 -1
- package/dist/adapters/capacitor/SecureAdapter.d.ts +0 -1
- package/dist/adapters/capacitor/SqliteAdapter.d.ts +0 -1
- package/dist/adapters/capacitor/index.d.ts +0 -1
- package/dist/adapters/web/CacheAdapter.d.ts +0 -1
- package/dist/adapters/web/CacheAdapter.js +20 -5
- package/dist/adapters/web/CookieAdapter.d.ts +0 -1
- package/dist/adapters/web/CookieAdapter.js +27 -3
- package/dist/adapters/web/IndexedDBAdapter.d.ts +0 -1
- package/dist/adapters/web/IndexedDBAdapter.js +5 -1
- package/dist/adapters/web/LocalStorageAdapter.d.ts +0 -1
- package/dist/adapters/web/LocalStorageAdapter.js +15 -1
- package/dist/adapters/web/MemoryAdapter.d.ts +7 -1
- package/dist/adapters/web/MemoryAdapter.js +22 -5
- package/dist/adapters/web/SessionStorageAdapter.d.ts +0 -1
- package/dist/adapters/web/SessionStorageAdapter.js +14 -1
- package/dist/adapters/web/URLAdapter.d.ts +0 -1
- package/dist/adapters/web/index.d.ts +0 -1
- package/dist/capacitor.d.ts +0 -1
- package/dist/config/support.d.ts +0 -1
- package/dist/core/AdapterRegistry.d.ts +0 -1
- package/dist/core/BaseAdapter.d.ts +0 -1
- package/dist/core/Strata.d.ts +12 -1
- package/dist/core/Strata.js +119 -21
- package/dist/features/compression/index.d.ts +0 -1
- package/dist/features/compression.d.ts +23 -9
- package/dist/features/compression.js +164 -77
- package/dist/features/encryption/index.d.ts +0 -1
- package/dist/features/encryption.d.ts +0 -1
- package/dist/features/integrity.d.ts +0 -1
- package/dist/features/migration.d.ts +0 -1
- package/dist/features/migration.js +7 -2
- package/dist/features/observer/index.d.ts +0 -1
- package/dist/features/observer.d.ts +0 -1
- package/dist/features/query/index.d.ts +0 -1
- package/dist/features/query.d.ts +1 -1
- package/dist/features/query.js +29 -6
- package/dist/features/sync/index.d.ts +0 -1
- package/dist/features/sync.d.ts +0 -1
- package/dist/features/sync.js +18 -3
- package/dist/features/ttl/index.d.ts +0 -1
- package/dist/features/ttl.d.ts +0 -1
- package/dist/features/ttl.js +4 -2
- package/dist/firebase.d.ts +0 -1
- package/dist/firebase.js +39 -2
- package/dist/index.d.ts +2 -3
- package/dist/integrations/angular/index.d.ts +0 -1
- package/dist/integrations/index.d.ts +0 -1
- package/dist/integrations/react/index.d.ts +0 -1
- package/dist/integrations/vue/index.d.ts +0 -1
- package/dist/package.json +9 -4
- package/dist/plugin/definitions.d.ts +0 -1
- package/dist/plugin/index.d.ts +0 -1
- package/dist/plugin/web.d.ts +0 -1
- package/dist/types/index.d.ts +0 -1
- package/dist/utils/errors.d.ts +0 -1
- package/dist/utils/index.d.ts +0 -1
- package/dist/utils/logger.d.ts +0 -1
- package/package.json +15 -5
- package/scripts/build.js +30 -13
- package/android/AGENTS.md +0 -66
- package/android/CLAUDE.md +0 -122
- package/dist/adapters/capacitor/FilesystemAdapter.d.ts.map +0 -1
- package/dist/adapters/capacitor/PreferencesAdapter.d.ts.map +0 -1
- package/dist/adapters/capacitor/SecureAdapter.d.ts.map +0 -1
- package/dist/adapters/capacitor/SqliteAdapter.d.ts.map +0 -1
- package/dist/adapters/capacitor/index.d.ts.map +0 -1
- package/dist/adapters/web/CacheAdapter.d.ts.map +0 -1
- package/dist/adapters/web/CookieAdapter.d.ts.map +0 -1
- package/dist/adapters/web/IndexedDBAdapter.d.ts.map +0 -1
- package/dist/adapters/web/LocalStorageAdapter.d.ts.map +0 -1
- package/dist/adapters/web/MemoryAdapter.d.ts.map +0 -1
- package/dist/adapters/web/SessionStorageAdapter.d.ts.map +0 -1
- package/dist/adapters/web/URLAdapter.d.ts.map +0 -1
- package/dist/adapters/web/index.d.ts.map +0 -1
- package/dist/capacitor.d.ts.map +0 -1
- package/dist/config/support.d.ts.map +0 -1
- package/dist/core/AdapterRegistry.d.ts.map +0 -1
- package/dist/core/BaseAdapter.d.ts.map +0 -1
- package/dist/core/Strata.d.ts.map +0 -1
- package/dist/features/compression/index.d.ts.map +0 -1
- package/dist/features/compression.d.ts.map +0 -1
- package/dist/features/encryption/index.d.ts.map +0 -1
- package/dist/features/encryption.d.ts.map +0 -1
- package/dist/features/integrity.d.ts.map +0 -1
- package/dist/features/migration.d.ts.map +0 -1
- package/dist/features/observer/index.d.ts.map +0 -1
- package/dist/features/observer.d.ts.map +0 -1
- package/dist/features/query/index.d.ts.map +0 -1
- package/dist/features/query.d.ts.map +0 -1
- package/dist/features/sync/index.d.ts.map +0 -1
- package/dist/features/sync.d.ts.map +0 -1
- package/dist/features/ttl/index.d.ts.map +0 -1
- package/dist/features/ttl.d.ts.map +0 -1
- package/dist/firebase.d.ts.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/integrations/angular/index.d.ts.map +0 -1
- package/dist/integrations/index.d.ts.map +0 -1
- package/dist/integrations/react/index.d.ts.map +0 -1
- package/dist/integrations/vue/index.d.ts.map +0 -1
- package/dist/plugin/definitions.d.ts.map +0 -1
- package/dist/plugin/index.d.ts.map +0 -1
- package/dist/plugin/web.d.ts.map +0 -1
- package/dist/types/index.d.ts.map +0 -1
- package/dist/utils/errors.d.ts.map +0 -1
- package/dist/utils/index.d.ts.map +0 -1
- package/dist/utils/logger.d.ts.map +0 -1
- package/ios/AGENTS.md +0 -59
- package/ios/CLAUDE.md +0 -106
package/AI-INTEGRATION-GUIDE.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# AI Integration Guide - strata-storage
|
|
2
2
|
|
|
3
|
-
Quick reference for AI development agents (Claude Code, Cursor, Copilot, etc.) to integrate `strata-storage` into web and mobile projects. Current version: **2.7.
|
|
3
|
+
Quick reference for AI development agents (Claude Code, Cursor, Copilot, etc.) to integrate `strata-storage` into web and mobile projects. Current version: **2.7.1**.
|
|
4
4
|
|
|
5
5
|
## Installation
|
|
6
6
|
|
|
@@ -81,7 +81,7 @@ await storage.set('key', value, {
|
|
|
81
81
|
ttl: 3_600_000, // expire in 1 hour (ms)
|
|
82
82
|
encrypt: true, // async only — requires encryption config + password
|
|
83
83
|
compress: true, // async only
|
|
84
|
-
tags: ['user-data'], //
|
|
84
|
+
tags: ['user-data'], // grouping; filter with clear({ tags })
|
|
85
85
|
metadata: { version: 1 },
|
|
86
86
|
verify: true, // store + check an integrity checksum (2.5.0)
|
|
87
87
|
durable: true, // read back and verify the write (2.5.0)
|
|
@@ -90,6 +90,27 @@ await storage.set('key', value, {
|
|
|
90
90
|
const value = await storage.get('key', { storage: 'indexedDB' });
|
|
91
91
|
```
|
|
92
92
|
|
|
93
|
+
## Query data model
|
|
94
|
+
|
|
95
|
+
`query(condition, options?)` matches the condition against the **stored value's own
|
|
96
|
+
bare fields** (the decoded user value) using MongoDB-style operators
|
|
97
|
+
(`$eq $ne $gt $gte $lt $lte $in $nin $regex $exists $type $and $or $not`):
|
|
98
|
+
|
|
99
|
+
```typescript
|
|
100
|
+
// matches stored values whose own `status` === 'active' AND `score` >= 10
|
|
101
|
+
const rows = await storage.query<{ status: string; score: number }>({
|
|
102
|
+
status: 'active',
|
|
103
|
+
score: { $gte: 10 },
|
|
104
|
+
}); // => Array<{ key: string; value: T }>
|
|
105
|
+
|
|
106
|
+
// sort/skip/limit/select use bare value field names (no `value.` prefix)
|
|
107
|
+
await storage.query({ status: 'active' }, { sort: { score: -1 }, limit: 20 });
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
The wrapper fields `key`, `tags`, `created`, `updated`, `expires`, and `metadata`
|
|
111
|
+
are **NOT** queryable via `query()` — they return nothing. Filter by tag with
|
|
112
|
+
`clear({ tags })`, not `query()`.
|
|
113
|
+
|
|
93
114
|
## Synchronous API (2.5.0)
|
|
94
115
|
|
|
95
116
|
No `await`. Works only on sync-capable adapters: `memory`, `localStorage`, `sessionStorage`, `cookies`, `url`.
|
|
@@ -270,6 +291,25 @@ const storage = defineStorage({
|
|
|
270
291
|
| `getTTL`/`extendTTL`/`persist` | TTL management |
|
|
271
292
|
| `registerAdapter(adapter)` | `void` |
|
|
272
293
|
|
|
294
|
+
## Notes for AI agents
|
|
295
|
+
|
|
296
|
+
- **Error handling** — every library error class (`QuotaExceededError`,
|
|
297
|
+
`EncryptionError`, `ValidationError`, `NotFoundError`, `IntegrityError`, etc.)
|
|
298
|
+
extends `StrataError`. Catch any of them with `catch (e) { if (e instanceof StrataError) … }`.
|
|
299
|
+
- **Server / SSR durability** — the default `storage` singleton uses web adapters and
|
|
300
|
+
**falls back to non-persistent `memory` on Node/SSR** (no localStorage/IndexedDB there).
|
|
301
|
+
For durable server storage register `sqlite`/`filesystem` or a custom adapter and
|
|
302
|
+
target it with `{ storage: '…' }`.
|
|
303
|
+
- **Browser encryption** — `crypto.subtle` requires a **secure context**
|
|
304
|
+
(HTTPS or `localhost`); encryption throws on insecure-origin pages. Node 20+ is fine.
|
|
305
|
+
- **Sync API limits** — `getSync`/`setSync`/… throw on async-only adapters
|
|
306
|
+
(indexedDB, cache, sqlite, filesystem, secure, preferences); `setSync` throws if
|
|
307
|
+
`encrypt`/`compress` is requested, and `getSync` throws on an encrypted/compressed
|
|
308
|
+
stored value. Use the async API there.
|
|
309
|
+
- **`useStorage` value is `T | null`** — element `[0]` is `null` during initial load
|
|
310
|
+
and when the key is absent with no default, *even when a defaultValue is passed*.
|
|
311
|
+
Null-guard before use.
|
|
312
|
+
|
|
273
313
|
## Troubleshooting
|
|
274
314
|
|
|
275
315
|
| Issue | Solution |
|
|
@@ -293,3 +333,7 @@ Full documentation lives at **https://stratastorage-docs.aoneahsan.com**:
|
|
|
293
333
|
- [Recovery & Integrity](https://stratastorage-docs.aoneahsan.com/api/features/recovery)
|
|
294
334
|
- [Changelog](https://stratastorage-docs.aoneahsan.com/reference/changelog)
|
|
295
335
|
- Machine-readable: [`/llms.txt`](https://stratastorage-docs.aoneahsan.com/llms.txt) · [`/llms-full.txt`](https://stratastorage-docs.aoneahsan.com/llms-full.txt)
|
|
336
|
+
|
|
337
|
+
---
|
|
338
|
+
|
|
339
|
+
Developed with ❤️ by the **Strata Storage Team** — maintained by [Ahsan Mahmood](https://aoneahsan.com). Questions or integration help: **aoneahsan@gmail.com**.
|
package/LICENSE
CHANGED
|
@@ -1,35 +1,21 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
1. Attribution Requirement:
|
|
24
|
-
You must retain all copyright notices and this license in any distribution.
|
|
25
|
-
|
|
26
|
-
2. Contribution Agreement:
|
|
27
|
-
Any contributions submitted for inclusion shall be under the same license.
|
|
28
|
-
|
|
29
|
-
3. Name and Trademark:
|
|
30
|
-
"Strata Storage" name may not be used for derivative works without permission.
|
|
31
|
-
|
|
32
|
-
4. Patent Grant:
|
|
33
|
-
This license includes express patent grants from contributors.
|
|
34
|
-
|
|
35
|
-
For the complete license terms and plain English explanation, see LICENSE.md
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024-2026 Ahsan Mahmood
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -5,12 +5,12 @@
|
|
|
5
5
|
- **[AI Integration Guide](./AI-INTEGRATION-GUIDE.md)** — quick reference for AI development agents (Claude Code, Cursor, Copilot).
|
|
6
6
|
|
|
7
7
|
[](https://www.npmjs.com/package/strata-storage)
|
|
8
|
-
[](LICENSE)
|
|
9
9
|
[](https://www.typescriptlang.org/)
|
|
10
10
|
[](https://stratastorage.aoneahsan.com)
|
|
11
11
|
|
|
12
|
-
- **Version:** `2.
|
|
13
|
-
- **License:**
|
|
12
|
+
- **Version:** `2.8.0`
|
|
13
|
+
- **License:** MIT
|
|
14
14
|
- **Node.js:** `>= 24.13.0`
|
|
15
15
|
- **Module format:** ESM only
|
|
16
16
|
|
|
@@ -478,24 +478,24 @@ Optional peer dependencies (install only the ones you use): `react >= 19.2.3`, `
|
|
|
478
478
|
|
|
479
479
|
## Documentation
|
|
480
480
|
|
|
481
|
-
📚 **
|
|
482
|
-
🤖 **For AI agents
|
|
481
|
+
📚 **Docs:** browse in-repo in [`./docs`](./docs/intro.md) · hosted at [stratastorage-docs.aoneahsan.com](https://stratastorage-docs.aoneahsan.com)
|
|
482
|
+
🤖 **For AI agents:** [`AI-INTEGRATION-GUIDE.md`](./AI-INTEGRATION-GUIDE.md) · hosted [/ai](https://stratastorage-docs.aoneahsan.com/ai) · [`/llms.txt`](https://stratastorage-docs.aoneahsan.com/llms.txt)
|
|
483
483
|
|
|
484
484
|
### Getting Started
|
|
485
|
-
- [Installation](
|
|
485
|
+
- [Introduction](./docs/intro.md) · [Installation](./docs/installation.md) · [Quick Start](./docs/quick-start.md) · [Configuration](./docs/configuration.md)
|
|
486
486
|
|
|
487
487
|
### API
|
|
488
|
-
- [API Reference](
|
|
489
|
-
- [All adapters](
|
|
488
|
+
- [API Reference](./docs/api/README.md) · [Core (`Strata`)](./docs/api/core/strata.md) · [Types](./docs/api/core/types.md) · [Errors](./docs/api/core/errors.md)
|
|
489
|
+
- [All adapters](./docs/api/adapters/README.md) — web (localStorage, IndexedDB, cookies, Cache, URL, …) + Capacitor (Preferences, Secure, SQLite, Filesystem) + remote (Firebase)
|
|
490
490
|
|
|
491
491
|
### Features
|
|
492
|
-
- [Encryption](
|
|
492
|
+
- [Encryption](./docs/guides/features/encryption.md) · [Compression](./docs/guides/features/compression.md) · [TTL](./docs/api/features/ttl.md) · [Sync](./docs/guides/features/sync.md) · [Queries](./docs/guides/features/queries.md) · [Migrations](./docs/guides/features/migrations.md) · [Recovery & Integrity](./docs/api/features/recovery.md)
|
|
493
493
|
|
|
494
494
|
### Platforms
|
|
495
|
-
- [Web](
|
|
495
|
+
- [Web](./docs/guides/platforms/web.md) · [iOS](./docs/guides/platforms/ios.md) · [Android](./docs/guides/platforms/android.md) · [Capacitor](./docs/guides/platforms/capacitor.md) · [Firebase](./docs/guides/platforms/firebase.md)
|
|
496
496
|
|
|
497
497
|
### Examples & Reference
|
|
498
|
-
- [Examples](
|
|
498
|
+
- [Examples](./docs/examples/README.md) · [Changelog](./docs/reference/changelog.md) · [FAQ](./docs/reference/faq.md) · [Troubleshooting](./docs/reference/troubleshooting.md) · [Migration](./docs/migration.md)
|
|
499
499
|
|
|
500
500
|
## Contributing
|
|
501
501
|
|
|
@@ -503,7 +503,7 @@ Contributions are welcome — please read the [Contributing Guide](./.github/CON
|
|
|
503
503
|
|
|
504
504
|
## License
|
|
505
505
|
|
|
506
|
-
|
|
506
|
+
MIT License — see [LICENSE](LICENSE). Free for commercial and non-commercial use, modification, distribution, and sublicensing; the only condition is keeping the copyright and license notice; provided without warranty.
|
|
507
507
|
|
|
508
508
|
## Author
|
|
509
509
|
|
|
@@ -529,7 +529,9 @@ Apache License 2.0 — see [LICENSE](LICENSE). Free for commercial use, modifica
|
|
|
529
529
|
|
|
530
530
|
---
|
|
531
531
|
|
|
532
|
-
|
|
532
|
+
Developed with ❤️ by the **Strata Storage Team** — maintained by [Ahsan Mahmood](https://aoneahsan.com) · aoneahsan@gmail.com.
|
|
533
|
+
|
|
534
|
+
**One API. Every Storage. Everywhere.**
|
|
533
535
|
|
|
534
536
|
<!-- project-links:start -->
|
|
535
537
|
## Links
|
package/dist/LICENSE
CHANGED
|
@@ -1,35 +1,21 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
1. Attribution Requirement:
|
|
24
|
-
You must retain all copyright notices and this license in any distribution.
|
|
25
|
-
|
|
26
|
-
2. Contribution Agreement:
|
|
27
|
-
Any contributions submitted for inclusion shall be under the same license.
|
|
28
|
-
|
|
29
|
-
3. Name and Trademark:
|
|
30
|
-
"Strata Storage" name may not be used for derivative works without permission.
|
|
31
|
-
|
|
32
|
-
4. Patent Grant:
|
|
33
|
-
This license includes express patent grants from contributors.
|
|
34
|
-
|
|
35
|
-
For the complete license terms and plain English explanation, see LICENSE.md
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024-2026 Ahsan Mahmood
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/dist/README.md
CHANGED
|
@@ -5,12 +5,12 @@
|
|
|
5
5
|
- **[AI Integration Guide](./AI-INTEGRATION-GUIDE.md)** — quick reference for AI development agents (Claude Code, Cursor, Copilot).
|
|
6
6
|
|
|
7
7
|
[](https://www.npmjs.com/package/strata-storage)
|
|
8
|
-
[](LICENSE)
|
|
9
9
|
[](https://www.typescriptlang.org/)
|
|
10
10
|
[](https://stratastorage.aoneahsan.com)
|
|
11
11
|
|
|
12
|
-
- **Version:** `2.
|
|
13
|
-
- **License:**
|
|
12
|
+
- **Version:** `2.8.0`
|
|
13
|
+
- **License:** MIT
|
|
14
14
|
- **Node.js:** `>= 24.13.0`
|
|
15
15
|
- **Module format:** ESM only
|
|
16
16
|
|
|
@@ -478,24 +478,24 @@ Optional peer dependencies (install only the ones you use): `react >= 19.2.3`, `
|
|
|
478
478
|
|
|
479
479
|
## Documentation
|
|
480
480
|
|
|
481
|
-
📚 **
|
|
482
|
-
🤖 **For AI agents
|
|
481
|
+
📚 **Docs:** browse in-repo in [`./docs`](./docs/intro.md) · hosted at [stratastorage-docs.aoneahsan.com](https://stratastorage-docs.aoneahsan.com)
|
|
482
|
+
🤖 **For AI agents:** [`AI-INTEGRATION-GUIDE.md`](./AI-INTEGRATION-GUIDE.md) · hosted [/ai](https://stratastorage-docs.aoneahsan.com/ai) · [`/llms.txt`](https://stratastorage-docs.aoneahsan.com/llms.txt)
|
|
483
483
|
|
|
484
484
|
### Getting Started
|
|
485
|
-
- [Installation](
|
|
485
|
+
- [Introduction](./docs/intro.md) · [Installation](./docs/installation.md) · [Quick Start](./docs/quick-start.md) · [Configuration](./docs/configuration.md)
|
|
486
486
|
|
|
487
487
|
### API
|
|
488
|
-
- [API Reference](
|
|
489
|
-
- [All adapters](
|
|
488
|
+
- [API Reference](./docs/api/README.md) · [Core (`Strata`)](./docs/api/core/strata.md) · [Types](./docs/api/core/types.md) · [Errors](./docs/api/core/errors.md)
|
|
489
|
+
- [All adapters](./docs/api/adapters/README.md) — web (localStorage, IndexedDB, cookies, Cache, URL, …) + Capacitor (Preferences, Secure, SQLite, Filesystem) + remote (Firebase)
|
|
490
490
|
|
|
491
491
|
### Features
|
|
492
|
-
- [Encryption](
|
|
492
|
+
- [Encryption](./docs/guides/features/encryption.md) · [Compression](./docs/guides/features/compression.md) · [TTL](./docs/api/features/ttl.md) · [Sync](./docs/guides/features/sync.md) · [Queries](./docs/guides/features/queries.md) · [Migrations](./docs/guides/features/migrations.md) · [Recovery & Integrity](./docs/api/features/recovery.md)
|
|
493
493
|
|
|
494
494
|
### Platforms
|
|
495
|
-
- [Web](
|
|
495
|
+
- [Web](./docs/guides/platforms/web.md) · [iOS](./docs/guides/platforms/ios.md) · [Android](./docs/guides/platforms/android.md) · [Capacitor](./docs/guides/platforms/capacitor.md) · [Firebase](./docs/guides/platforms/firebase.md)
|
|
496
496
|
|
|
497
497
|
### Examples & Reference
|
|
498
|
-
- [Examples](
|
|
498
|
+
- [Examples](./docs/examples/README.md) · [Changelog](./docs/reference/changelog.md) · [FAQ](./docs/reference/faq.md) · [Troubleshooting](./docs/reference/troubleshooting.md) · [Migration](./docs/migration.md)
|
|
499
499
|
|
|
500
500
|
## Contributing
|
|
501
501
|
|
|
@@ -503,7 +503,7 @@ Contributions are welcome — please read the [Contributing Guide](./.github/CON
|
|
|
503
503
|
|
|
504
504
|
## License
|
|
505
505
|
|
|
506
|
-
|
|
506
|
+
MIT License — see [LICENSE](LICENSE). Free for commercial and non-commercial use, modification, distribution, and sublicensing; the only condition is keeping the copyright and license notice; provided without warranty.
|
|
507
507
|
|
|
508
508
|
## Author
|
|
509
509
|
|
|
@@ -529,7 +529,9 @@ Apache License 2.0 — see [LICENSE](LICENSE). Free for commercial use, modifica
|
|
|
529
529
|
|
|
530
530
|
---
|
|
531
531
|
|
|
532
|
-
|
|
532
|
+
Developed with ❤️ by the **Strata Storage Team** — maintained by [Ahsan Mahmood](https://aoneahsan.com) · aoneahsan@gmail.com.
|
|
533
|
+
|
|
534
|
+
**One API. Every Storage. Everywhere.**
|
|
533
535
|
|
|
534
536
|
<!-- project-links:start -->
|
|
535
537
|
## Links
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* Provides network-aware storage for offline support
|
|
4
4
|
*/
|
|
5
5
|
import { BaseAdapter } from "../../core/BaseAdapter.js";
|
|
6
|
-
import { getObjectSize } from "../../utils/index.js";
|
|
6
|
+
import { getObjectSize, serialize, deserialize } from "../../utils/index.js";
|
|
7
7
|
import { StorageError, QuotaExceededError, NotSupportedError } from "../../utils/errors.js";
|
|
8
8
|
import { logger } from "../../utils/logger.js";
|
|
9
9
|
/**
|
|
@@ -84,7 +84,7 @@ export class CacheAdapter extends BaseAdapter {
|
|
|
84
84
|
const response = await cache.match(url);
|
|
85
85
|
if (!response)
|
|
86
86
|
return null;
|
|
87
|
-
const data = (await response.
|
|
87
|
+
const data = deserialize(await response.text());
|
|
88
88
|
// Check TTL
|
|
89
89
|
if (this.isExpired(data)) {
|
|
90
90
|
await this.remove(key);
|
|
@@ -105,8 +105,9 @@ export class CacheAdapter extends BaseAdapter {
|
|
|
105
105
|
const url = this.keyToUrl(key);
|
|
106
106
|
const oldValue = await this.get(key);
|
|
107
107
|
try {
|
|
108
|
-
// Create Response with the data
|
|
109
|
-
|
|
108
|
+
// Create Response with the data (shared serialize preserves Date/Map/Set
|
|
109
|
+
// etc., matching the other adapters instead of raw JSON).
|
|
110
|
+
const response = new Response(serialize(value), {
|
|
110
111
|
headers: {
|
|
111
112
|
'Content-Type': 'application/json',
|
|
112
113
|
'X-Strata-Created': value.created.toString(),
|
|
@@ -130,7 +131,21 @@ export class CacheAdapter extends BaseAdapter {
|
|
|
130
131
|
async remove(key) {
|
|
131
132
|
const cache = await this.openCache();
|
|
132
133
|
const url = this.keyToUrl(key);
|
|
133
|
-
|
|
134
|
+
// Read raw via cache.match — NOT via get(), which deletes an expired entry
|
|
135
|
+
// by awaiting remove(), recursing here and never resolving. Only read when
|
|
136
|
+
// a listener needs the old value.
|
|
137
|
+
let oldValue = null;
|
|
138
|
+
if (this.hasChangeListeners()) {
|
|
139
|
+
const response = await cache.match(url);
|
|
140
|
+
if (response) {
|
|
141
|
+
try {
|
|
142
|
+
oldValue = deserialize(await response.text());
|
|
143
|
+
}
|
|
144
|
+
catch {
|
|
145
|
+
oldValue = null;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
134
149
|
const deleted = await cache.delete(url);
|
|
135
150
|
if (deleted && oldValue) {
|
|
136
151
|
this.emitChange(key, oldValue.value, undefined, 'local');
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
* Provides limited storage with 4KB per cookie limit
|
|
4
4
|
*/
|
|
5
5
|
import { BaseAdapter } from "../../core/BaseAdapter.js";
|
|
6
|
+
import { serialize, deserialize } from "../../utils/index.js";
|
|
6
7
|
import { StorageError, QuotaExceededError } from "../../utils/errors.js";
|
|
7
8
|
import { logger } from "../../utils/logger.js";
|
|
8
9
|
/**
|
|
@@ -92,7 +93,7 @@ export class CookieAdapter extends BaseAdapter {
|
|
|
92
93
|
return null;
|
|
93
94
|
try {
|
|
94
95
|
const decoded = decodeURIComponent(value);
|
|
95
|
-
const parsed =
|
|
96
|
+
const parsed = deserialize(decoded);
|
|
96
97
|
// Check TTL
|
|
97
98
|
if (this.isExpired(parsed)) {
|
|
98
99
|
this.removeSync(key);
|
|
@@ -118,7 +119,7 @@ export class CookieAdapter extends BaseAdapter {
|
|
|
118
119
|
const cookieKey = this.prefix + key;
|
|
119
120
|
const oldValue = this.getSync(key);
|
|
120
121
|
try {
|
|
121
|
-
const serialized =
|
|
122
|
+
const serialized = serialize(value);
|
|
122
123
|
const encoded = encodeURIComponent(serialized);
|
|
123
124
|
// Check size limit
|
|
124
125
|
if (encoded.length > this.maxCookieSize) {
|
|
@@ -153,8 +154,21 @@ export class CookieAdapter extends BaseAdapter {
|
|
|
153
154
|
* Remove a value from cookies (synchronous)
|
|
154
155
|
*/
|
|
155
156
|
removeSync(key) {
|
|
156
|
-
const oldValue = this.getSync(key);
|
|
157
157
|
const cookieKey = this.prefix + key;
|
|
158
|
+
// Read raw — NOT via getSync(), which deletes expired cookies by calling
|
|
159
|
+
// removeSync() and would recurse here forever. Only read with a listener.
|
|
160
|
+
let oldValue = null;
|
|
161
|
+
if (this.hasChangeListeners()) {
|
|
162
|
+
const raw = this.getCookie(cookieKey);
|
|
163
|
+
if (raw) {
|
|
164
|
+
try {
|
|
165
|
+
oldValue = deserialize(decodeURIComponent(raw));
|
|
166
|
+
}
|
|
167
|
+
catch {
|
|
168
|
+
oldValue = null;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
158
172
|
this.deleteCookie(cookieKey);
|
|
159
173
|
if (oldValue) {
|
|
160
174
|
this.emitChange(key, oldValue.value, undefined, 'local');
|
|
@@ -289,6 +303,16 @@ export class CookieAdapter extends BaseAdapter {
|
|
|
289
303
|
setCookie(name, value, options = {}) {
|
|
290
304
|
if (typeof document === 'undefined')
|
|
291
305
|
return;
|
|
306
|
+
// The value is percent-encoded by the caller, but the NAME is written raw —
|
|
307
|
+
// reject cookie-control characters in it so a crafted key cannot inject
|
|
308
|
+
// extra attributes (`; Path=/`) or additional cookies (`; evil=1`).
|
|
309
|
+
const hasControlChar = [...name].some((ch) => {
|
|
310
|
+
const code = ch.charCodeAt(0);
|
|
311
|
+
return code < 0x20 || code === 0x7f;
|
|
312
|
+
});
|
|
313
|
+
if (/[;=,\s]/.test(name) || hasControlChar) {
|
|
314
|
+
throw new StorageError(`Invalid cookie name "${name}": contains forbidden characters`);
|
|
315
|
+
}
|
|
292
316
|
let cookie = `${name}=${value}`;
|
|
293
317
|
if (options.maxAge !== undefined) {
|
|
294
318
|
cookie += `; max-age=${options.maxAge}`;
|
|
@@ -139,7 +139,11 @@ export class IndexedDBAdapter extends BaseAdapter {
|
|
|
139
139
|
*/
|
|
140
140
|
async remove(key) {
|
|
141
141
|
const db = await this.openDatabase();
|
|
142
|
-
|
|
142
|
+
// Only read the old value when a listener needs it. get() on an expired key
|
|
143
|
+
// fire-and-forgets remove(), so an unconditional read here spawns redundant
|
|
144
|
+
// remove→get cycles; gating also drops the read for this observable:false
|
|
145
|
+
// adapter.
|
|
146
|
+
const oldValue = this.hasChangeListeners() ? await this.get(key) : null;
|
|
143
147
|
const { promise, resolve, reject } = createDeferred();
|
|
144
148
|
const transaction = db.transaction([this.storeName], 'readwrite');
|
|
145
149
|
const store = transaction.objectStore(this.storeName);
|
|
@@ -132,7 +132,21 @@ export class LocalStorageAdapter extends BaseAdapter {
|
|
|
132
132
|
* Remove a value from localStorage (synchronous)
|
|
133
133
|
*/
|
|
134
134
|
removeSync(key) {
|
|
135
|
-
|
|
135
|
+
// Read the raw stored value directly — NOT via getSync(), which deletes an
|
|
136
|
+
// expired entry by calling removeSync(), recursing here forever (stack
|
|
137
|
+
// overflow). Only read when a listener actually needs the old value.
|
|
138
|
+
let oldValue = null;
|
|
139
|
+
if (this.hasChangeListeners()) {
|
|
140
|
+
const item = this.getStorage().getItem(this.prefix + key);
|
|
141
|
+
if (item) {
|
|
142
|
+
try {
|
|
143
|
+
oldValue = deserialize(item);
|
|
144
|
+
}
|
|
145
|
+
catch {
|
|
146
|
+
oldValue = null;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
136
150
|
this.getStorage().removeItem(this.prefix + key);
|
|
137
151
|
if (oldValue) {
|
|
138
152
|
this.emitChange(key, oldValue.value, undefined, 'local');
|
|
@@ -27,6 +27,13 @@ export declare class MemoryAdapter extends BaseAdapter {
|
|
|
27
27
|
* Get a value from memory
|
|
28
28
|
*/
|
|
29
29
|
get<T = unknown>(key: string): Promise<StorageValue<T> | null>;
|
|
30
|
+
/**
|
|
31
|
+
* Clone a stored value to isolate it from external mutation. Prefers
|
|
32
|
+
* structuredClone (preserves Map/Set/Date/TypedArray/ArrayBuffer — so the
|
|
33
|
+
* advertised `binary: true` capability holds), falling back to deepClone where
|
|
34
|
+
* structuredClone is unavailable or the value isn't structured-cloneable.
|
|
35
|
+
*/
|
|
36
|
+
private clone;
|
|
30
37
|
/**
|
|
31
38
|
* Get a value from memory (synchronous)
|
|
32
39
|
*/
|
|
@@ -90,4 +97,3 @@ export declare class MemoryAdapter extends BaseAdapter {
|
|
|
90
97
|
*/
|
|
91
98
|
close(): Promise<void>;
|
|
92
99
|
}
|
|
93
|
-
//# sourceMappingURL=MemoryAdapter.d.ts.map
|
|
@@ -43,6 +43,23 @@ export class MemoryAdapter extends BaseAdapter {
|
|
|
43
43
|
async get(key) {
|
|
44
44
|
return this.getSync(key);
|
|
45
45
|
}
|
|
46
|
+
/**
|
|
47
|
+
* Clone a stored value to isolate it from external mutation. Prefers
|
|
48
|
+
* structuredClone (preserves Map/Set/Date/TypedArray/ArrayBuffer — so the
|
|
49
|
+
* advertised `binary: true` capability holds), falling back to deepClone where
|
|
50
|
+
* structuredClone is unavailable or the value isn't structured-cloneable.
|
|
51
|
+
*/
|
|
52
|
+
clone(value) {
|
|
53
|
+
if (typeof structuredClone === 'function') {
|
|
54
|
+
try {
|
|
55
|
+
return structuredClone(value);
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
58
|
+
// Fall through to deepClone (e.g. value carries a non-cloneable field).
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return deepClone(value);
|
|
62
|
+
}
|
|
46
63
|
/**
|
|
47
64
|
* Get a value from memory (synchronous)
|
|
48
65
|
*/
|
|
@@ -55,8 +72,8 @@ export class MemoryAdapter extends BaseAdapter {
|
|
|
55
72
|
this.removeSync(key);
|
|
56
73
|
return null;
|
|
57
74
|
}
|
|
58
|
-
// Return a
|
|
59
|
-
return
|
|
75
|
+
// Return a clone to prevent external modifications
|
|
76
|
+
return this.clone(value);
|
|
60
77
|
}
|
|
61
78
|
/**
|
|
62
79
|
* Set a value in memory
|
|
@@ -83,8 +100,8 @@ export class MemoryAdapter extends BaseAdapter {
|
|
|
83
100
|
});
|
|
84
101
|
}
|
|
85
102
|
}
|
|
86
|
-
// Store a
|
|
87
|
-
const clonedValue =
|
|
103
|
+
// Store a clone to prevent external modifications
|
|
104
|
+
const clonedValue = this.clone(value);
|
|
88
105
|
this.storage.set(key, clonedValue);
|
|
89
106
|
// Update size tracking
|
|
90
107
|
if (oldValue) {
|
|
@@ -214,7 +231,7 @@ export class MemoryAdapter extends BaseAdapter {
|
|
|
214
231
|
if (matches) {
|
|
215
232
|
results.push({
|
|
216
233
|
key,
|
|
217
|
-
value:
|
|
234
|
+
value: this.clone(item.value),
|
|
218
235
|
});
|
|
219
236
|
}
|
|
220
237
|
}
|