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.
Files changed (115) hide show
  1. package/AI-INTEGRATION-GUIDE.md +46 -2
  2. package/LICENSE +21 -35
  3. package/README.md +15 -13
  4. package/dist/LICENSE +21 -35
  5. package/dist/README.md +15 -13
  6. package/dist/adapters/capacitor/FilesystemAdapter.d.ts +0 -1
  7. package/dist/adapters/capacitor/PreferencesAdapter.d.ts +0 -1
  8. package/dist/adapters/capacitor/SecureAdapter.d.ts +0 -1
  9. package/dist/adapters/capacitor/SqliteAdapter.d.ts +0 -1
  10. package/dist/adapters/capacitor/index.d.ts +0 -1
  11. package/dist/adapters/web/CacheAdapter.d.ts +0 -1
  12. package/dist/adapters/web/CacheAdapter.js +20 -5
  13. package/dist/adapters/web/CookieAdapter.d.ts +0 -1
  14. package/dist/adapters/web/CookieAdapter.js +27 -3
  15. package/dist/adapters/web/IndexedDBAdapter.d.ts +0 -1
  16. package/dist/adapters/web/IndexedDBAdapter.js +5 -1
  17. package/dist/adapters/web/LocalStorageAdapter.d.ts +0 -1
  18. package/dist/adapters/web/LocalStorageAdapter.js +15 -1
  19. package/dist/adapters/web/MemoryAdapter.d.ts +7 -1
  20. package/dist/adapters/web/MemoryAdapter.js +22 -5
  21. package/dist/adapters/web/SessionStorageAdapter.d.ts +0 -1
  22. package/dist/adapters/web/SessionStorageAdapter.js +14 -1
  23. package/dist/adapters/web/URLAdapter.d.ts +0 -1
  24. package/dist/adapters/web/index.d.ts +0 -1
  25. package/dist/capacitor.d.ts +0 -1
  26. package/dist/config/support.d.ts +0 -1
  27. package/dist/core/AdapterRegistry.d.ts +0 -1
  28. package/dist/core/BaseAdapter.d.ts +0 -1
  29. package/dist/core/Strata.d.ts +12 -1
  30. package/dist/core/Strata.js +119 -21
  31. package/dist/features/compression/index.d.ts +0 -1
  32. package/dist/features/compression.d.ts +23 -9
  33. package/dist/features/compression.js +164 -77
  34. package/dist/features/encryption/index.d.ts +0 -1
  35. package/dist/features/encryption.d.ts +0 -1
  36. package/dist/features/integrity.d.ts +0 -1
  37. package/dist/features/migration.d.ts +0 -1
  38. package/dist/features/migration.js +7 -2
  39. package/dist/features/observer/index.d.ts +0 -1
  40. package/dist/features/observer.d.ts +0 -1
  41. package/dist/features/query/index.d.ts +0 -1
  42. package/dist/features/query.d.ts +1 -1
  43. package/dist/features/query.js +29 -6
  44. package/dist/features/sync/index.d.ts +0 -1
  45. package/dist/features/sync.d.ts +0 -1
  46. package/dist/features/sync.js +18 -3
  47. package/dist/features/ttl/index.d.ts +0 -1
  48. package/dist/features/ttl.d.ts +0 -1
  49. package/dist/features/ttl.js +4 -2
  50. package/dist/firebase.d.ts +0 -1
  51. package/dist/firebase.js +39 -2
  52. package/dist/index.d.ts +2 -3
  53. package/dist/integrations/angular/index.d.ts +0 -1
  54. package/dist/integrations/index.d.ts +0 -1
  55. package/dist/integrations/react/index.d.ts +0 -1
  56. package/dist/integrations/vue/index.d.ts +0 -1
  57. package/dist/package.json +9 -4
  58. package/dist/plugin/definitions.d.ts +0 -1
  59. package/dist/plugin/index.d.ts +0 -1
  60. package/dist/plugin/web.d.ts +0 -1
  61. package/dist/types/index.d.ts +0 -1
  62. package/dist/utils/errors.d.ts +0 -1
  63. package/dist/utils/index.d.ts +0 -1
  64. package/dist/utils/logger.d.ts +0 -1
  65. package/package.json +15 -5
  66. package/scripts/build.js +30 -13
  67. package/android/AGENTS.md +0 -66
  68. package/android/CLAUDE.md +0 -122
  69. package/dist/adapters/capacitor/FilesystemAdapter.d.ts.map +0 -1
  70. package/dist/adapters/capacitor/PreferencesAdapter.d.ts.map +0 -1
  71. package/dist/adapters/capacitor/SecureAdapter.d.ts.map +0 -1
  72. package/dist/adapters/capacitor/SqliteAdapter.d.ts.map +0 -1
  73. package/dist/adapters/capacitor/index.d.ts.map +0 -1
  74. package/dist/adapters/web/CacheAdapter.d.ts.map +0 -1
  75. package/dist/adapters/web/CookieAdapter.d.ts.map +0 -1
  76. package/dist/adapters/web/IndexedDBAdapter.d.ts.map +0 -1
  77. package/dist/adapters/web/LocalStorageAdapter.d.ts.map +0 -1
  78. package/dist/adapters/web/MemoryAdapter.d.ts.map +0 -1
  79. package/dist/adapters/web/SessionStorageAdapter.d.ts.map +0 -1
  80. package/dist/adapters/web/URLAdapter.d.ts.map +0 -1
  81. package/dist/adapters/web/index.d.ts.map +0 -1
  82. package/dist/capacitor.d.ts.map +0 -1
  83. package/dist/config/support.d.ts.map +0 -1
  84. package/dist/core/AdapterRegistry.d.ts.map +0 -1
  85. package/dist/core/BaseAdapter.d.ts.map +0 -1
  86. package/dist/core/Strata.d.ts.map +0 -1
  87. package/dist/features/compression/index.d.ts.map +0 -1
  88. package/dist/features/compression.d.ts.map +0 -1
  89. package/dist/features/encryption/index.d.ts.map +0 -1
  90. package/dist/features/encryption.d.ts.map +0 -1
  91. package/dist/features/integrity.d.ts.map +0 -1
  92. package/dist/features/migration.d.ts.map +0 -1
  93. package/dist/features/observer/index.d.ts.map +0 -1
  94. package/dist/features/observer.d.ts.map +0 -1
  95. package/dist/features/query/index.d.ts.map +0 -1
  96. package/dist/features/query.d.ts.map +0 -1
  97. package/dist/features/sync/index.d.ts.map +0 -1
  98. package/dist/features/sync.d.ts.map +0 -1
  99. package/dist/features/ttl/index.d.ts.map +0 -1
  100. package/dist/features/ttl.d.ts.map +0 -1
  101. package/dist/firebase.d.ts.map +0 -1
  102. package/dist/index.d.ts.map +0 -1
  103. package/dist/integrations/angular/index.d.ts.map +0 -1
  104. package/dist/integrations/index.d.ts.map +0 -1
  105. package/dist/integrations/react/index.d.ts.map +0 -1
  106. package/dist/integrations/vue/index.d.ts.map +0 -1
  107. package/dist/plugin/definitions.d.ts.map +0 -1
  108. package/dist/plugin/index.d.ts.map +0 -1
  109. package/dist/plugin/web.d.ts.map +0 -1
  110. package/dist/types/index.d.ts.map +0 -1
  111. package/dist/utils/errors.d.ts.map +0 -1
  112. package/dist/utils/index.d.ts.map +0 -1
  113. package/dist/utils/logger.d.ts.map +0 -1
  114. package/ios/AGENTS.md +0 -59
  115. package/ios/CLAUDE.md +0 -106
@@ -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.0**.
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'], // for queries
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
- Copyright 2024 Ahsan Mahmood
2
-
3
- Licensed under the Apache License, Version 2.0 (the "License");
4
- you may not use this file except in compliance with the License.
5
- You may obtain a copy of the License at
6
-
7
- http://www.apache.org/licenses/LICENSE-2.0
8
-
9
- Unless required by applicable law or agreed to in writing, software
10
- distributed under the License is distributed on an "AS IS" BASIS,
11
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
- See the License for the specific language governing permissions and
13
- limitations under the License.
14
-
15
- ================================================================================
16
-
17
- Full Apache License 2.0 text: https://www.apache.org/licenses/LICENSE-2.0.txt
18
-
19
- ================================================================================
20
-
21
- Additional Terms:
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
  [![npm version](https://img.shields.io/npm/v/strata-storage.svg)](https://www.npmjs.com/package/strata-storage)
8
- [![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](LICENSE)
8
+ [![License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
9
9
  [![TypeScript](https://img.shields.io/badge/TypeScript-strict-blue.svg)](https://www.typescriptlang.org/)
10
10
  [![Platform](https://img.shields.io/badge/platform-Web%20%7C%20iOS%20%7C%20Android-lightgrey.svg)](https://stratastorage.aoneahsan.com)
11
11
 
12
- - **Version:** `2.7.0`
13
- - **License:** Apache-2.0
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
- 📚 **Full documentation: [stratastorage-docs.aoneahsan.com](https://stratastorage-docs.aoneahsan.com)**
482
- 🤖 **For AI agents: [stratastorage-docs.aoneahsan.com/ai](https://stratastorage-docs.aoneahsan.com/ai)** (plus [`/llms.txt`](https://stratastorage-docs.aoneahsan.com/llms.txt) and [`/llms-full.txt`](https://stratastorage-docs.aoneahsan.com/llms-full.txt))
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](https://stratastorage-docs.aoneahsan.com/installation) · [Quick Start](https://stratastorage-docs.aoneahsan.com/quick-start) · [Configuration](https://stratastorage-docs.aoneahsan.com/configuration)
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](https://stratastorage-docs.aoneahsan.com/api) · [Core (`Strata`)](https://stratastorage-docs.aoneahsan.com/api/core/strata) · [Types](https://stratastorage-docs.aoneahsan.com/api/core/types) · [Errors](https://stratastorage-docs.aoneahsan.com/api/core/errors)
489
- - [All adapters](https://stratastorage-docs.aoneahsan.com/api/adapters) — web (localStorage, IndexedDB, cookies, Cache, URL, …) + Capacitor (Preferences, Secure, SQLite, Filesystem) + remote (Firebase)
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](https://stratastorage-docs.aoneahsan.com/guides/features/encryption) · [Compression](https://stratastorage-docs.aoneahsan.com/guides/features/compression) · [TTL](https://stratastorage-docs.aoneahsan.com/api/features/ttl) · [Sync](https://stratastorage-docs.aoneahsan.com/guides/features/sync) · [Queries](https://stratastorage-docs.aoneahsan.com/guides/features/queries) · [Migrations](https://stratastorage-docs.aoneahsan.com/guides/features/migrations) · [Recovery & Integrity](https://stratastorage-docs.aoneahsan.com/api/features/recovery)
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](https://stratastorage-docs.aoneahsan.com/guides/platforms/web) · [iOS](https://stratastorage-docs.aoneahsan.com/guides/platforms/ios) · [Android](https://stratastorage-docs.aoneahsan.com/guides/platforms/android) · [Capacitor](https://stratastorage-docs.aoneahsan.com/guides/platforms/capacitor) · [Firebase](https://stratastorage-docs.aoneahsan.com/guides/platforms/firebase)
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](https://stratastorage-docs.aoneahsan.com/examples) · [Changelog](https://stratastorage-docs.aoneahsan.com/reference/changelog) · [FAQ](https://stratastorage-docs.aoneahsan.com/reference/faq) · [Troubleshooting](https://stratastorage-docs.aoneahsan.com/reference/troubleshooting) · [Migration](https://stratastorage-docs.aoneahsan.com/migration)
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
- Apache License 2.0 — see [LICENSE](LICENSE). Free for commercial use, modification, and distribution with patent protection; attribution required; provided without warranty.
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
- Made by [Ahsan Mahmood](https://aoneahsan.com). **One API. Every Storage. Everywhere.**
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
- Copyright 2024 Ahsan Mahmood
2
-
3
- Licensed under the Apache License, Version 2.0 (the "License");
4
- you may not use this file except in compliance with the License.
5
- You may obtain a copy of the License at
6
-
7
- http://www.apache.org/licenses/LICENSE-2.0
8
-
9
- Unless required by applicable law or agreed to in writing, software
10
- distributed under the License is distributed on an "AS IS" BASIS,
11
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
- See the License for the specific language governing permissions and
13
- limitations under the License.
14
-
15
- ================================================================================
16
-
17
- Full Apache License 2.0 text: https://www.apache.org/licenses/LICENSE-2.0.txt
18
-
19
- ================================================================================
20
-
21
- Additional Terms:
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
  [![npm version](https://img.shields.io/npm/v/strata-storage.svg)](https://www.npmjs.com/package/strata-storage)
8
- [![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](LICENSE)
8
+ [![License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
9
9
  [![TypeScript](https://img.shields.io/badge/TypeScript-strict-blue.svg)](https://www.typescriptlang.org/)
10
10
  [![Platform](https://img.shields.io/badge/platform-Web%20%7C%20iOS%20%7C%20Android-lightgrey.svg)](https://stratastorage.aoneahsan.com)
11
11
 
12
- - **Version:** `2.7.0`
13
- - **License:** Apache-2.0
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
- 📚 **Full documentation: [stratastorage-docs.aoneahsan.com](https://stratastorage-docs.aoneahsan.com)**
482
- 🤖 **For AI agents: [stratastorage-docs.aoneahsan.com/ai](https://stratastorage-docs.aoneahsan.com/ai)** (plus [`/llms.txt`](https://stratastorage-docs.aoneahsan.com/llms.txt) and [`/llms-full.txt`](https://stratastorage-docs.aoneahsan.com/llms-full.txt))
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](https://stratastorage-docs.aoneahsan.com/installation) · [Quick Start](https://stratastorage-docs.aoneahsan.com/quick-start) · [Configuration](https://stratastorage-docs.aoneahsan.com/configuration)
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](https://stratastorage-docs.aoneahsan.com/api) · [Core (`Strata`)](https://stratastorage-docs.aoneahsan.com/api/core/strata) · [Types](https://stratastorage-docs.aoneahsan.com/api/core/types) · [Errors](https://stratastorage-docs.aoneahsan.com/api/core/errors)
489
- - [All adapters](https://stratastorage-docs.aoneahsan.com/api/adapters) — web (localStorage, IndexedDB, cookies, Cache, URL, …) + Capacitor (Preferences, Secure, SQLite, Filesystem) + remote (Firebase)
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](https://stratastorage-docs.aoneahsan.com/guides/features/encryption) · [Compression](https://stratastorage-docs.aoneahsan.com/guides/features/compression) · [TTL](https://stratastorage-docs.aoneahsan.com/api/features/ttl) · [Sync](https://stratastorage-docs.aoneahsan.com/guides/features/sync) · [Queries](https://stratastorage-docs.aoneahsan.com/guides/features/queries) · [Migrations](https://stratastorage-docs.aoneahsan.com/guides/features/migrations) · [Recovery & Integrity](https://stratastorage-docs.aoneahsan.com/api/features/recovery)
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](https://stratastorage-docs.aoneahsan.com/guides/platforms/web) · [iOS](https://stratastorage-docs.aoneahsan.com/guides/platforms/ios) · [Android](https://stratastorage-docs.aoneahsan.com/guides/platforms/android) · [Capacitor](https://stratastorage-docs.aoneahsan.com/guides/platforms/capacitor) · [Firebase](https://stratastorage-docs.aoneahsan.com/guides/platforms/firebase)
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](https://stratastorage-docs.aoneahsan.com/examples) · [Changelog](https://stratastorage-docs.aoneahsan.com/reference/changelog) · [FAQ](https://stratastorage-docs.aoneahsan.com/reference/faq) · [Troubleshooting](https://stratastorage-docs.aoneahsan.com/reference/troubleshooting) · [Migration](https://stratastorage-docs.aoneahsan.com/migration)
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
- Apache License 2.0 — see [LICENSE](LICENSE). Free for commercial use, modification, and distribution with patent protection; attribution required; provided without warranty.
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
- Made by [Ahsan Mahmood](https://aoneahsan.com). **One API. Every Storage. Everywhere.**
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
@@ -43,4 +43,3 @@ export declare class FilesystemAdapter extends BaseAdapter {
43
43
  */
44
44
  size(detailed?: boolean): Promise<SizeInfo>;
45
45
  }
46
- //# sourceMappingURL=FilesystemAdapter.d.ts.map
@@ -43,4 +43,3 @@ export declare class PreferencesAdapter extends BaseAdapter {
43
43
  */
44
44
  size(detailed?: boolean): Promise<SizeInfo>;
45
45
  }
46
- //# sourceMappingURL=PreferencesAdapter.d.ts.map
@@ -66,4 +66,3 @@ export declare class SecureAdapter extends BaseAdapter {
66
66
  */
67
67
  getEncryptedPreference(key: string, fileName?: string): Promise<unknown>;
68
68
  }
69
- //# sourceMappingURL=SecureAdapter.d.ts.map
@@ -86,4 +86,3 @@ export declare class SqliteAdapter extends BaseAdapter {
86
86
  */
87
87
  transaction(): Promise<Transaction>;
88
88
  }
89
- //# sourceMappingURL=SqliteAdapter.d.ts.map
@@ -6,4 +6,3 @@ export { PreferencesAdapter } from "./PreferencesAdapter.js";
6
6
  export { SqliteAdapter } from "./SqliteAdapter.js";
7
7
  export { SecureAdapter } from "./SecureAdapter.js";
8
8
  export { FilesystemAdapter } from "./FilesystemAdapter.js";
9
- //# sourceMappingURL=index.d.ts.map
@@ -88,4 +88,3 @@ export declare class CacheAdapter extends BaseAdapter {
88
88
  */
89
89
  private isQuotaError;
90
90
  }
91
- //# sourceMappingURL=CacheAdapter.d.ts.map
@@ -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.json());
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
- const response = new Response(JSON.stringify(value), {
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
- const oldValue = await this.get(key);
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');
@@ -110,4 +110,3 @@ export declare class CookieAdapter extends BaseAdapter {
110
110
  private getAllCookies;
111
111
  }
112
112
  export {};
113
- //# sourceMappingURL=CookieAdapter.d.ts.map
@@ -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 = JSON.parse(decoded);
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 = JSON.stringify(value);
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}`;
@@ -82,4 +82,3 @@ export declare class IndexedDBAdapter extends BaseAdapter {
82
82
  */
83
83
  private isQuotaError;
84
84
  }
85
- //# sourceMappingURL=IndexedDBAdapter.d.ts.map
@@ -139,7 +139,11 @@ export class IndexedDBAdapter extends BaseAdapter {
139
139
  */
140
140
  async remove(key) {
141
141
  const db = await this.openDatabase();
142
- const oldValue = await this.get(key);
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);
@@ -91,4 +91,3 @@ export declare class LocalStorageAdapter extends BaseAdapter {
91
91
  */
92
92
  protected isQuotaError(error: unknown): boolean;
93
93
  }
94
- //# sourceMappingURL=LocalStorageAdapter.d.ts.map
@@ -132,7 +132,21 @@ export class LocalStorageAdapter extends BaseAdapter {
132
132
  * Remove a value from localStorage (synchronous)
133
133
  */
134
134
  removeSync(key) {
135
- const oldValue = this.getSync(key);
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 deep clone to prevent external modifications
59
- return deepClone(value);
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 deep clone to prevent external modifications
87
- const clonedValue = deepClone(value);
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: deepClone(item.value),
234
+ value: this.clone(item.value),
218
235
  });
219
236
  }
220
237
  }