strata-storage 2.8.3 → 2.8.5

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 CHANGED
@@ -1,60 +1,191 @@
1
- # Strata Storage
1
+ <div align="center">
2
2
 
3
- > Zero-dependency universal storage for the web, iOS, and Android. One API for `localStorage`, IndexedDB, cookies, the URL, native Keychain/Keystore, SQLite, and more — with optional React, Vue, Angular, Capacitor, and Firebase surfaces.
3
+ <img src="https://raw.githubusercontent.com/aoneahsan/strata-storage/main/assets/logo.svg" alt="Strata Storage logo" width="120" />
4
4
 
5
- - **[AI Integration Guide](./AI-INTEGRATION-GUIDE.md)** — quick reference for AI development agents (Claude Code, Cursor, Copilot).
5
+ <h1>strata-storage</h1>
6
6
 
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-MIT-blue.svg)](LICENSE)
9
- [![TypeScript](https://img.shields.io/badge/TypeScript-strict-blue.svg)](https://www.typescriptlang.org/)
10
- [![Platform](https://img.shields.io/badge/platform-Web%20%7C%20iOS%20%7C%20Android-lightgrey.svg)](https://stratastorage.aoneahsan.com)
11
-
12
- - **Version:** `2.8.3`
13
- - **License:** MIT
14
- - **Node.js:** `>= 24.13.0`
15
- - **Module format:** ESM only
16
-
17
- ## Why Strata Storage
7
+ <p><strong>One storage API across web, iOS and Android — zero runtime dependencies.</strong></p>
18
8
 
19
- Every product re-solves the same storage problem: pick a backend per platform, learn its quirks, wrap it for your framework, and bolt on encryption, expiry, and cross-tab sync by hand. Strata Storage replaces that with one adapter-based API that runs everywhere and keeps the runtime package free of dependencies.
20
-
21
- - **Zero runtime dependencies.** The core is pure TypeScript. React, Vue, Angular, and `@capacitor/core` are optional peer dependencies — install only what you use.
22
- - **One API, every backend.** `get`/`set`/`remove`/`query`/`subscribe` behave the same whether the value lives in `localStorage`, IndexedDB, the URL, or the iOS Keychain.
23
- - **Provider-free.** `defineStorage()` returns a ready-to-use instance you create once and import anywhere — no React context, Vue plugin, or Angular module required (the Provider/Plugin/Module styles still work if you prefer them).
24
- - **Opt-in power features.** Encryption, compression, TTL, queries, cross-tab sync, integrity checksums, durable writes, mirroring, and snapshots are all off by default and added per call or per instance.
25
-
26
- ## Installation
9
+ [![npm version](https://img.shields.io/npm/v/strata-storage.svg)](https://www.npmjs.com/package/strata-storage)
10
+ [![downloads](https://img.shields.io/npm/dm/strata-storage.svg)](https://www.npmjs.com/package/strata-storage)
11
+ [![license](https://img.shields.io/npm/l/strata-storage.svg)](https://github.com/aoneahsan/strata-storage/blob/main/LICENSE)
12
+ [![types](https://img.shields.io/npm/types/strata-storage.svg)](https://www.npmjs.com/package/strata-storage)
13
+ [![bundle size](https://img.shields.io/bundlephobia/minzip/strata-storage.svg)](https://bundlephobia.com/package/strata-storage)
14
+ [![CI](https://github.com/aoneahsan/strata-storage/actions/workflows/ci.yml/badge.svg)](https://github.com/aoneahsan/strata-storage/actions/workflows/ci.yml)
15
+ [![node](https://img.shields.io/node/v/strata-storage.svg)](https://nodejs.org)
16
+
17
+ [Docs](https://stratastorage-docs.aoneahsan.com) · [npm](https://www.npmjs.com/package/strata-storage) · [GitHub](https://github.com/aoneahsan/strata-storage) · [Changelog](https://github.com/aoneahsan/strata-storage/blob/main/CHANGELOG.md) · [AI Guide](https://github.com/aoneahsan/strata-storage/blob/main/AI-INTEGRATION-GUIDE.md) · [Support](https://github.com/aoneahsan/strata-storage/issues)
18
+
19
+ </div>
20
+
21
+ > [!IMPORTANT]
22
+ > In a Capacitor app, run **`npx cap sync`** after installing. Without it the native module is never
23
+ > copied into your iOS/Android projects and the native adapters — `secure`, `sqlite`, `preferences`,
24
+ > `filesystem` — fail silently on device while working fine in the browser.
25
+
26
+ Strata Storage gives you one `get`/`set`/`remove`/`query`/`subscribe` API over every storage backend a
27
+ cross-platform app touches: `localStorage`, `sessionStorage`, IndexedDB, cookies, the Cache API, the page
28
+ URL, and — through Capacitor — the iOS Keychain, Android EncryptedSharedPreferences, native SQLite and the
29
+ filesystem. The core is pure TypeScript with **no runtime dependencies**; React, Vue, Angular, Capacitor and
30
+ Firebase are optional peers you install only if you use them. Encryption, compression, TTL, cross-tab sync,
31
+ integrity checksums and mirrored backups are opt-in per call or per instance.
32
+
33
+ | | |
34
+ |---|---|
35
+ | **Version** | `2.8.5` |
36
+ | **License** | MIT |
37
+ | **Node** | `>=24.13.0` |
38
+ | **Platforms** | Web · iOS · Android (via Capacitor) |
39
+ | **Module format** | ESM only — no CommonJS build |
40
+ | **Install size** | 155 kB packed · 660 kB unpacked, of which 130 kB is iOS + Android native source |
41
+ | **Types** | Bundled `.d.ts` for every entry point |
42
+ | **Status** | Stable · actively maintained |
43
+
44
+ <a id="table-of-contents"></a>
45
+ ## 🧭 Table of Contents&nbsp;[#](#table-of-contents)
46
+
47
+ - [💡 Why strata-storage](#why-strata-storage)
48
+ - [✨ Features](#features)
49
+ - [📱 Platform Support](#platform-support)
50
+ - [📋 Requirements](#requirements)
51
+ - [📦 Installation](#installation)
52
+ - [🚀 Quick Start](#quick-start)
53
+ - [🛠️ Usage](#usage)
54
+ - [⚙️ Configuration](#configuration)
55
+ - [🔧 API Reference](#api-reference)
56
+ - [🧩 Types](#types)
57
+ - [💻 Command Line](#command-line)
58
+ - [🧪 Examples](#examples)
59
+ - [🎛️ Advanced Features](#advanced-features)
60
+ - [🚑 Recovery & Troubleshooting](#recovery-troubleshooting)
61
+ - [🚧 Limitations](#limitations)
62
+ - [📚 Documentation](#documentation)
63
+ - [🔄 Changelog](#changelog)
64
+ - [🤝 Contributing](#contributing)
65
+ - [🗂️ Repository](#repository)
66
+ - [💬 Support](#support)
67
+ - [📄 License](#license)
68
+ - [👤 Author](#author)
69
+ - [🔗 Links](#links)
70
+ - [🏷️ Keywords](#keywords)
71
+
72
+ <a id="why-strata-storage"></a>
73
+ ## 💡 Why strata-storage&nbsp;[#](#why-strata-storage)
74
+
75
+ Every cross-platform product re-solves the same problem: pick a storage backend per platform, learn each
76
+ one's quirks, wrap it for your framework, then bolt on encryption, expiry and cross-tab sync by hand. The
77
+ result is a per-platform layer nobody wants to own. Strata Storage replaces it with one adapter-based API
78
+ that behaves identically everywhere, and keeps the runtime package dependency-free so it adds nothing to
79
+ your dependency tree.
80
+
81
+ | | `strata-storage` | Rolling your own per platform |
82
+ |---|---|---|
83
+ | Backends | 11 adapters behind one API | one integration per backend, written twice |
84
+ | Runtime dependencies | none | whatever each wrapper pulls in |
85
+ | Framework binding | optional sub-path imports, no provider required | hand-written hooks per framework |
86
+ | Encryption · TTL · sync · queries | opt-in flags | built and maintained by you |
87
+ | Native iOS/Android | ships as a Capacitor plugin | a separate native module to maintain |
88
+ | Automated test suite | **none** — typecheck, lint and build are the gates | yours to write |
89
+
90
+ **Not the right tool when** — you only need `localStorage` in one web app (use it directly); you need a
91
+ CommonJS build or Node below 24.13 (this package is ESM-only); you need a server-side or multi-user
92
+ database (this is client-side key-value storage); or you need cryptographic tamper-proofing from the
93
+ integrity feature specifically — its checksums are non-cryptographic, so use the encryption feature instead.
94
+
95
+ <a id="features"></a>
96
+ ## ✨ Features&nbsp;[#](#features)
97
+
98
+ - **One API, every backend** — the same calls whether the value lives in `localStorage`, IndexedDB, the URL
99
+ or the iOS Keychain.
100
+ - **Zero runtime dependencies** — the core is pure TypeScript; every framework and platform binding is an
101
+ optional peer.
102
+ - **Provider-free by default** — create one instance and import it anywhere. No React context, Vue plugin or
103
+ Angular module is required, though all three styles are still supported.
104
+ - **Synchronous API alongside the async one** — for initial render and event handlers, on the backends that
105
+ are genuinely synchronous.
106
+ - **Opt-in encryption and compression** — AES-GCM via Web Crypto, size-thresholded compression, both off by
107
+ default.
108
+ - **TTL and expiry** — absolute or sliding, with expiry inspection and a cleanup sweep.
109
+ - **Queries and tags** — MongoDB-style conditions over stored values and their tags.
110
+ - **Cross-tab synchronisation** — subscribe to changes made in other tabs of the same origin.
111
+ - **Recovery features** — integrity checksums, durable writes, mirrored read-repair, portable snapshots and
112
+ scheduled backups.
113
+ - **Native adapters with no plugin dependencies** — SQLite is hand-rolled and the filesystem adapter uses
114
+ the platform's own `FileManager` / `java.io.File`.
115
+ - **Typed end to end** — bundled declarations for every entry point, including each framework sub-path.
116
+
117
+ <a id="platform-support"></a>
118
+ ## 📱 Platform Support&nbsp;[#](#platform-support)
119
+
120
+ | Platform | Supported | Notes |
121
+ |---|---|---|
122
+ | Browsers | ✅ | All seven web adapters: `memory`, `localStorage`, `sessionStorage`, `indexedDB`, `cookies`, `cache`, `url`. |
123
+ | iOS | ✅ | Via Capacitor. Requires `npx cap sync`. Keychain, UserDefaults, SQLite, FileManager. |
124
+ | Android | ✅ | Via Capacitor. Requires `npx cap sync`. EncryptedSharedPreferences, SharedPreferences, SQLite, `java.io.File`. |
125
+ | Node / SSR | ⚠️ | Imports and runs, but only the `memory` adapter is available — there is no DOM storage. Browser-only adapters report `isAvailable() === false` instead of throwing. |
126
+ | Firebase | ✅ | Optional cloud sync through the `strata-storage/firebase` sub-path. |
127
+
128
+ <a id="requirements"></a>
129
+ ## 📋 Requirements&nbsp;[#](#requirements)
130
+
131
+ | Requirement | Version | Why |
132
+ |---|---|---|
133
+ | Node | `>=24.13.0` | Matches `.nvmrc`; the package is ESM-only and relies on modern Node resolution. |
134
+ | TypeScript | `moduleResolution: "bundler"` or `"nodenext"` | Older `node`/`node10` resolution cannot see the typed sub-path exports. |
135
+ | `@capacitor/core` | `>=8.0.0` | Optional peer — only for the native iOS/Android adapters. |
136
+ | `react` | `>=19.2.3` | Optional peer — only for `strata-storage/react`. |
137
+ | `vue` | `>=3.5.26` | Optional peer — only for `strata-storage/vue`. |
138
+ | `@angular/core`, `@angular/forms` | `>=21.0.6` | Optional peers — only for `strata-storage/angular`. |
139
+ | `firebase` | `>=10.0.0` | Optional peer — only for `strata-storage/firebase`. |
140
+
141
+ <a id="installation"></a>
142
+ ## 📦 Installation&nbsp;[#](#installation)
27
143
 
28
144
  ```bash
29
145
  yarn add strata-storage
30
146
  ```
31
147
 
32
- Framework adapters import from sub-paths; no extra install beyond the framework itself:
148
+ Nothing else is needed for web use. Install only the optional peer you actually import:
33
149
 
34
150
  ```bash
35
- # React / Vue / Angular peers are optional — install the one you use
36
- yarn add react # for strata-storage/react
37
- yarn add vue # for strata-storage/vue
151
+ yarn add react # for strata-storage/react
152
+ yarn add vue # for strata-storage/vue
38
153
  yarn add @angular/core @angular/forms # for strata-storage/angular
39
154
  yarn add @capacitor/core # for strata-storage/capacitor
155
+ yarn add firebase # for strata-storage/firebase
40
156
  ```
41
157
 
42
- ## Quick Start
158
+ **Capacitor apps must then sync the native module**, or the native adapters will not work on device:
159
+
160
+ ```bash
161
+ npx cap sync
162
+ ```
163
+
164
+ An optional interactive wizard can scaffold a configuration file for you — see
165
+ [Command Line](#command-line).
166
+
167
+ <a id="quick-start"></a>
168
+ ## 🚀 Quick Start&nbsp;[#](#quick-start)
43
169
 
44
- The shortest path is the default `storage` instance. It registers the standard web adapters and initializes lazily on first use, so importing the package does no I/O.
170
+ The default `storage` instance registers the standard web adapters and initialises lazily on first use, so
171
+ importing the package performs no I/O.
45
172
 
46
173
  ```typescript
47
174
  import { storage } from 'strata-storage';
48
175
 
49
- // No setup, no Provider, no initialize() call — works immediately.
50
- await storage.set('user', { id: 123, name: 'John Doe' });
176
+ await storage.set('user', { id: 123, name: 'Ada Lovelace' });
51
177
  const user = await storage.get<{ id: number; name: string }>('user');
52
178
 
53
179
  await storage.remove('user');
54
- await storage.clear();
55
180
  ```
56
181
 
57
- Need your own configured instance? Use `defineStorage()` — it is the same factory the default instance is built from.
182
+ <a id="usage"></a>
183
+ ## 🛠️ Usage&nbsp;[#](#usage)
184
+
185
+ ### Your own configured instance
186
+
187
+ `defineStorage()` is the same factory the default instance is built from. Create one at module scope and
188
+ import it anywhere — no provider needed.
58
189
 
59
190
  ```typescript
60
191
  import { defineStorage } from 'strata-storage';
@@ -64,29 +195,15 @@ export const storage = defineStorage({
64
195
  encryption: { enabled: true, password: process.env.STORAGE_KEY! },
65
196
  });
66
197
 
67
- await storage.set('token', '...', { encrypt: true });
198
+ await storage.set('token', '', { encrypt: true });
68
199
  ```
69
200
 
70
- `defineStorage()` registers memory, `localStorage`, `sessionStorage`, IndexedDB, cookies, and the Cache API. Add the URL adapter or native adapters yourself when you need them (see below).
71
-
72
- ## Provider-Free Usage
73
-
74
- The recommended pattern across all frameworks: create one instance and bind to it. No Provider, plugin, or module is required. The Provider-based styles remain available and are documented in the [examples](https://stratastorage-docs.aoneahsan.com/examples).
75
-
76
- ### Vanilla JavaScript / TypeScript
77
-
78
- ```typescript
79
- import { defineStorage } from 'strata-storage';
80
-
81
- export const storage = defineStorage();
82
-
83
- await storage.set('theme', 'dark');
84
- const theme = await storage.get<string>('theme');
85
- ```
201
+ It registers `memory`, `localStorage`, `sessionStorage`, `indexedDB`, `cookies` and `cache`. Register the
202
+ URL adapter and the native adapters yourself when you need them.
86
203
 
87
204
  ### React
88
205
 
89
- Bind the hooks to an instance once at module scope with `createStrataHooks`, then use them in any component — no `<StrataProvider>` needed.
206
+ Bind the hooks to an instance once, then use them in any component.
90
207
 
91
208
  ```tsx
92
209
  // storage.ts
@@ -102,36 +219,19 @@ export const { useStorage, useStorageQuery, useStorageTTL } = createStrataHooks(
102
219
  import { useStorage } from './storage';
103
220
 
104
221
  function Settings() {
105
- // [value, setValue, loading]
106
222
  const [theme, setTheme, loading] = useStorage<string>('theme', 'light');
107
-
108
223
  if (loading) return <p>Loading…</p>;
109
-
110
224
  return (
111
- <button onClick={() => setTheme(theme === 'light' ? 'dark' : 'light')}>
112
- Theme: {theme}
113
- </button>
225
+ <button onClick={() => setTheme(theme === 'light' ? 'dark' : 'light')}>Theme: {theme}</button>
114
226
  );
115
227
  }
116
228
  ```
117
229
 
118
- Prefer context? `<StrataProvider>` still works and now accepts an `instance` prop so it can wrap an instance you created yourself:
119
-
120
- ```tsx
121
- import { StrataProvider, useStorage } from 'strata-storage/react';
122
- import { storage } from './storage';
123
-
124
- <StrataProvider instance={storage}>
125
- <App />
126
- </StrataProvider>;
127
- ```
230
+ `<StrataProvider instance={storage}>` still works if you prefer context.
128
231
 
129
232
  ### Vue
130
233
 
131
- `createStrataComposables` binds the composables to an instance. Each built-in composable also accepts an optional instance as its last argument, and the classic `StrataPlugin` still works.
132
-
133
234
  ```typescript
134
- // storage.ts
135
235
  import { defineStorage } from 'strata-storage';
136
236
  import { createStrataComposables } from 'strata-storage/vue';
137
237
 
@@ -139,87 +239,54 @@ export const storage = defineStorage();
139
239
  export const { useStorage, useStorageQuery, useStorageTTL } = createStrataComposables(storage);
140
240
  ```
141
241
 
142
- ```vue
143
- <script setup lang="ts">
144
- import { useStorage } from './storage';
145
-
146
- const { value: theme, update } = useStorage<string>('theme', 'light');
147
- </script>
148
-
149
- <template>
150
- <button @click="update(theme === 'light' ? 'dark' : 'light')">Theme: {{ theme }}</button>
151
- </template>
152
- ```
242
+ The classic `StrataPlugin` remains available, and each built-in composable also accepts an instance as its
243
+ last argument.
153
244
 
154
245
  ### Angular
155
246
 
156
- `provideStrata` accepts either a pre-created instance or a config object, and registers `StrataService` for injection. It works in `bootstrapApplication` (standalone) or a component's `providers`. The `STRATA_INSTANCE` token holds the instance; `StrataModule.forRoot(config)` remains for NgModule apps.
157
-
158
247
  ```typescript
159
- // main.ts
160
248
  import { bootstrapApplication } from '@angular/platform-browser';
161
249
  import { defineStorage } from 'strata-storage';
162
250
  import { provideStrata } from 'strata-storage/angular';
163
251
  import { AppComponent } from './app/app.component';
164
252
 
165
- const storage = defineStorage();
166
-
167
- bootstrapApplication(AppComponent, {
168
- providers: [provideStrata(storage)], // or provideStrata({ defaultStorages: ['indexedDB'] })
169
- });
253
+ bootstrapApplication(AppComponent, { providers: [provideStrata(defineStorage())] });
170
254
  ```
171
255
 
172
- ```typescript
173
- // any.component.ts
174
- import { Component } from '@angular/core';
175
- import { StrataService } from 'strata-storage/angular';
176
-
177
- @Component({ /* ... */ })
178
- export class AnyComponent {
179
- constructor(private storage: StrataService) {}
180
-
181
- save() {
182
- // StrataService methods return RxJS Observables
183
- this.storage.set('theme', 'dark').subscribe();
184
- }
185
- }
186
- ```
187
-
188
- ## Synchronous API
256
+ `StrataService` is then injectable and returns RxJS Observables. `StrataModule.forRoot(config)` remains for
257
+ NgModule applications.
189
258
 
190
- For UI code that must read or write without `await` — initial render, event handlers, synchronous state hydration — Strata exposes a synchronous API alongside the async one:
259
+ ### Native adapters (iOS and Android)
191
260
 
192
261
  ```typescript
193
262
  import { defineStorage } from 'strata-storage';
263
+ import { registerCapacitorAdapters } from 'strata-storage/capacitor';
194
264
 
195
265
  const storage = defineStorage();
266
+ await registerCapacitorAdapters(storage);
196
267
 
197
- storage.setSync('lastTab', 'inbox');
198
- const tab = storage.getSync<string>('lastTab'); // 'inbox'
199
- storage.hasSync('lastTab'); // true
200
- storage.keysSync(); // string[]
201
- storage.removeSync('lastTab');
202
- storage.clearSync();
268
+ await storage.set('token', value, { storage: 'secure' }); // Keychain / EncryptedSharedPreferences
203
269
  ```
204
270
 
205
- ### Limitations (read these)
271
+ `PreferencesAdapter`, `SecureAdapter`, `SqliteAdapter` and `FilesystemAdapter` are also exported
272
+ individually when you need per-adapter configuration. Each `SqliteAdapter` binds to one `(database, table)`
273
+ pair, so separate logical stores map to separate physical files and cannot collide.
206
274
 
207
- The sync API only works on adapters that are genuinely synchronous: **`memory`, `localStorage`, `sessionStorage`, `cookies`, and `url`**. It does not paper over async backends, and it cannot do work that is inherently asynchronous:
208
-
209
- - Targeting an async-only adapter (`indexedDB`, `cache`, `sqlite`, `filesystem`, `secure`, `preferences`) throws a `StorageError` telling you to use the async API.
210
- - `setSync` with `{ encrypt: true }` or `{ compress: true }` throws — Web Crypto and compression are async, so use `await storage.set(...)`.
211
- - `getSync` on a value that was stored encrypted or compressed throws — read it with `await storage.get(...)`.
212
-
213
- TTL, tags, and metadata work with the sync API; encryption and compression do not.
275
+ ### The synchronous API
214
276
 
215
277
  ```typescript
216
- // Pick a sync-capable backend explicitly when needed:
217
- storage.setSync('filters', { status: 'open' }, { storage: 'localStorage', ttl: 60_000 });
278
+ storage.setSync('lastTab', 'inbox');
279
+ const tab = storage.getSync<string>('lastTab');
280
+ storage.removeSync('lastTab');
218
281
  ```
219
282
 
220
- ## URL Adapter
283
+ Available on `memory`, `localStorage`, `sessionStorage`, `cookies` and `url` only, and it cannot encrypt or
284
+ compress — see [Limitations](#limitations).
285
+
286
+ ### The URL adapter
221
287
 
222
- The `URLAdapter` (storage type `'url'`) persists state in the page URL so it survives reloads and round-trips through shareable/bookmarkable links — filters, the active tab, pagination, and other small UI state. It is inherently synchronous and emits change events on `popstate`/`hashchange`, so back/forward navigation and manual URL edits notify subscribers.
288
+ Persists small UI state in the page URL so it survives reloads and shareable links, and emits change events
289
+ on `popstate`/`hashchange`.
223
290
 
224
291
  ```typescript
225
292
  import { defineStorage, URLAdapter } from 'strata-storage';
@@ -227,317 +294,271 @@ import { defineStorage, URLAdapter } from 'strata-storage';
227
294
  const storage = defineStorage();
228
295
  storage.registerAdapter(new URLAdapter());
229
296
 
230
- // Write to the URL (no await needed — URL access is synchronous)
231
297
  storage.setSync('tab', 'pending', { storage: 'url' });
232
- storage.setSync('page', 3, { storage: 'url' });
233
-
234
- // Read it back (e.g. on reload)
235
298
  const tab = storage.getSync<string>('tab', { storage: 'url' });
236
-
237
- // React to back/forward navigation or manual edits
238
- storage.subscribe((change) => {
239
- if (change.key === 'tab') applyTab(change.newValue);
240
- }, { storage: 'url' });
241
- ```
242
-
243
- ### Configuration
244
-
245
- Pass `URLAdapterConfig` when constructing the adapter:
246
-
247
- ```typescript
248
- new URLAdapter(); // defaults below
249
- ```
250
-
251
- | Option | Type | Default | Meaning |
252
- |--------|------|---------|---------|
253
- | `mode` | `'query'` \| `'hash'` | `'query'` | Store params in the query string (`?strata.tab=...`) or the hash fragment (`#strata.tab=...`). |
254
- | `prefix` | `string` | `'strata.'` | Prefix on every param name to avoid collisions with your own query params. |
255
- | `history` | `'push'` \| `'replace'` | `'replace'` | Whether each write adds a browser history entry or replaces the current one. |
256
- | `maxLength` | `number` | `2000` | Soft warning threshold (chars) for total URL length. |
257
-
258
- The adapter is configured through `StrataConfig.adapters.url` when you let Strata manage it:
259
-
260
- ```typescript
261
- const storage = defineStorage({ adapters: { url: { mode: 'hash', history: 'push' } } });
262
- storage.registerAdapter(new URLAdapter());
263
- ```
264
-
265
- ### Limitations (read these)
266
-
267
- - **Length limits.** URLs have practical limits (~2000 chars in some browsers and servers). This adapter is for small, simple, serializable state — not bulk data. Writes past `maxLength` are allowed but logged as a warning.
268
- - **Server visibility.** In `'query'` mode the data is sent to the server on every navigation and appears in server/proxy logs. Use `'hash'` mode to keep it client-only (the fragment is never sent to the server).
269
- - **Browser only.** Outside a browser (SSR/Node) the adapter reports unavailable; `isAvailable()` returns `false`.
270
- - **Not persistent.** State lives only as long as the URL does — it is not durable storage.
271
-
272
- ## Disaster Recovery
273
-
274
- Strata includes opt-in recovery features for data you cannot afford to silently lose. **Everything here is off by default** — enable only what you need, since each adds overhead.
275
-
276
- ### Integrity checksums
277
-
278
- Set `integrity: true` (or per call `{ verify: true }`) to compute and store an FNV-1a checksum with each value and verify it on read. On corruption, Strata first attempts mirror read-repair (below); otherwise it honors `{ ignoreCorruption: true }` (returns `null`) or throws a typed `IntegrityError`.
279
-
280
- ```typescript
281
- import { defineStorage } from 'strata-storage';
282
-
283
- const storage = defineStorage({ integrity: true });
284
-
285
- await storage.set('config', settings); // checksum stored
286
- const config = await storage.get('config'); // verified; throws IntegrityError if corrupted
287
- ```
288
-
289
- > **Honest note:** checksums are **FNV-1a, non-cryptographic**. They cheaply detect *accidental* corruption (truncated writes, bit flips, partial storage). They do **not** resist tampering — for tamper resistance use the encryption feature.
290
-
291
- ### Durable writes
292
-
293
- `durableWrites: true` (or per call `{ durable: true }`) reads each value back after writing and retries on mismatch, throwing `StorageError` if it cannot confirm the write after a few attempts. This adds one read per write.
294
-
295
- ```typescript
296
- const storage = defineStorage({ durableWrites: true });
297
- await storage.set('order', order); // confirmed written, or throws
298
299
  ```
299
300
 
300
- ### Mirroring (read-repair)
301
-
302
- `mirror: [...]` copies every write/remove to backup storage types. On a primary read miss or corruption, Strata recovers the value from a mirror and repairs the primary in place.
301
+ <a id="configuration"></a>
302
+ ## ⚙️ Configuration&nbsp;[#](#configuration)
303
+
304
+ Passed to `defineStorage(config)` or `new Strata(config)`:
305
+
306
+ | Option | Type | Default | What it does |
307
+ |---|---|---|---|
308
+ | `defaultStorages` | `StorageType[]` | `['localStorage', 'indexedDB', 'sessionStorage', 'memory']` | Preference order for picking the default adapter. |
309
+ | `adapters` | `object` | `{}` | Per-adapter settings, or `false` to skip one. `localStorage`/`sessionStorage` take `{ prefix }`; `indexedDB` takes `{ dbName, version }`; `cookies` takes `{ secure, sameSite }`; `cache` takes `{ cacheName }`. |
310
+ | `encryption` | `{ enabled, password }` | disabled | AES-GCM encryption on every write. Async path only. |
311
+ | `compression` | `{ enabled, threshold }` | disabled | Compress values above `threshold` bytes. Async path only. |
312
+ | `sync` | `{ enabled }` | disabled | Cross-tab change notifications. |
313
+ | `integrity` | `boolean` | `false` | Store an FNV-1a checksum with each value and verify it on read. |
314
+ | `durableWrites` | `boolean` | `false` | Read each write back and retry on mismatch. Costs one extra read per write. |
315
+ | `mirror` | `StorageType[]` | `[]` | Copy every write to backup storages, and read-repair the primary from them. |
316
+ | `autoBackup` | `{ interval, storage }` | disabled | Take periodic snapshots into a durable adapter. |
317
+ | `debug` | `boolean` | `false` | Raise the internal log level from `warn` to `debug`. |
318
+
319
+ The `URLAdapter` takes its own options: `mode` (`'query'` \| `'hash'`, default `'query'`), `prefix`
320
+ (default `'strata.'`), `history` (`'push'` \| `'replace'`, default `'replace'`) and `maxLength` (default
321
+ `2000`).
322
+
323
+ Full reference: [Configuration](https://stratastorage-docs.aoneahsan.com/configuration).
324
+
325
+ <a id="api-reference"></a>
326
+ ## 🔧 API Reference&nbsp;[#](#api-reference)
327
+
328
+ An index of the main surface. Full signatures and behaviour live on the docs site.
329
+
330
+ | Export | Signature | Docs |
331
+ |---|---|---|
332
+ | `storage` | the default `Strata` instance | [→](https://stratastorage-docs.aoneahsan.com/quick-start) |
333
+ | `defineStorage` | `(config?: StrataConfig) => Strata` | [→](https://stratastorage-docs.aoneahsan.com/configuration) |
334
+ | `Strata` | `new (config?: StrataConfig)` | [→](https://stratastorage-docs.aoneahsan.com/api/core/strata) |
335
+ | `.get` / `.set` | `get<T>(key, opts?) => Promise<T \| null>` · `set<T>(key, value, opts?) => Promise<void>` | [→](https://stratastorage-docs.aoneahsan.com/api/core/strata) |
336
+ | `.remove` / `.clear` / `.has` / `.keys` | `(key?, opts?) => Promise<…>` | [→](https://stratastorage-docs.aoneahsan.com/api/core/strata) |
337
+ | `.getSync` / `.setSync` / `.removeSync` / `.hasSync` / `.keysSync` / `.clearSync` | synchronous equivalents, sync-capable adapters only | [→](https://stratastorage-docs.aoneahsan.com/api/core/strata) |
338
+ | `.query` | `(condition, opts?) => Promise<Array<{ key, value }>>` | [→](https://stratastorage-docs.aoneahsan.com/guides/features/queries) |
339
+ | `.subscribe` | `(cb, opts?) => UnsubscribeFunction` | [→](https://stratastorage-docs.aoneahsan.com/guides/features/sync) |
340
+ | `.getTTL` / `.extendTTL` / `.persist` / `.getExpiring` / `.cleanupExpired` | TTL inspection and maintenance | [→](https://stratastorage-docs.aoneahsan.com/api/features/ttl) |
341
+ | `.snapshot` / `.restore` / `.export` / `.import` | portable backup and transfer | [→](https://stratastorage-docs.aoneahsan.com/api/features/recovery) |
342
+ | `.size` / `.getCapabilities` / `.getAvailableStorageTypes` | introspection | [→](https://stratastorage-docs.aoneahsan.com/api/core/strata) |
343
+ | `.registerAdapter` / `.refreshAdapters` / `.close` | lifecycle | [→](https://stratastorage-docs.aoneahsan.com/api/adapters) |
344
+ | `computeChecksum` / `verifyChecksum` | `(data) => string` · `(data, sum) => boolean` | [→](https://stratastorage-docs.aoneahsan.com/api/features/recovery) |
345
+ | `URLAdapter` and the six web adapters | `new (config?)` | [→](https://stratastorage-docs.aoneahsan.com/api/adapters) |
346
+ | `registerCapacitorAdapters` | `(strata) => Promise<void>` — `strata-storage/capacitor` | [→](https://stratastorage-docs.aoneahsan.com/guides/platforms/capacitor) |
347
+ | `enableFirebaseSync` | `(strata, config) => Promise<void>` — `strata-storage/firebase` | [→](https://stratastorage-docs.aoneahsan.com/guides/platforms/firebase) |
348
+ | Error classes | `StrataError`, `StorageError`, `IntegrityError`, `QuotaExceededError`, `EncryptionError`, `CompressionError`, `SerializationError`, `ValidationError`, `NotSupportedError`, `AdapterNotAvailableError` | [→](https://stratastorage-docs.aoneahsan.com/api/core/errors) |
349
+
350
+ <a id="types"></a>
351
+ ## 🧩 Types&nbsp;[#](#types)
352
+
353
+ The types a consumer touches directly. Full definitions:
354
+ [Types](https://stratastorage-docs.aoneahsan.com/api/core/types).
303
355
 
304
356
  ```typescript
305
- const storage = defineStorage({
306
- defaultStorages: ['localStorage'],
307
- integrity: true,
308
- mirror: ['indexedDB'], // localStorage is primary; indexedDB backs it up
309
- });
310
- ```
311
-
312
- ### Snapshots and scheduled backups
313
-
314
- `snapshot()` produces a portable, integrity-verified backup string (embedding a checksum manifest); `restore()` validates that checksum and throws `IntegrityError` on a corrupted backup. `autoBackup` schedules periodic snapshots to a durable adapter.
315
-
316
- ```typescript
317
- const backup = await storage.snapshot(); // store/download this string
318
- await storage.restore(backup); // validates, then restores
319
-
320
- // Scheduled, every 5 minutes, into indexedDB
321
- const storage = defineStorage({
322
- autoBackup: { interval: 5 * 60_000, storage: 'indexedDB' },
323
- });
324
- ```
325
-
326
- Integrity helpers and error classes are exported for direct use:
327
-
328
- ```typescript
329
- import { computeChecksum, verifyChecksum, IntegrityError } from 'strata-storage';
330
- ```
331
-
332
- ## Advanced Features
333
-
334
- ### Encryption (async only)
335
-
336
- ```typescript
337
- const storage = defineStorage({ encryption: { enabled: true, password: 'secret' } });
338
- await storage.set('secret', { token: 'abc' }); // encrypted with AES-GCM
339
- await storage.set('one-off', data, { encrypt: true }); // per-call override
340
- ```
341
-
342
- ### TTL / expiration
343
-
344
- ```typescript
345
- await storage.set('session', data, { ttl: 3_600_000 }); // expires in 1 hour
346
- await storage.set('cache', data, { ttl: 600_000, sliding: true }); // reset on access
347
- const ms = await storage.getTTL('session');
348
- await storage.persist('session'); // remove expiry
349
- ```
350
-
351
- ### Compression (async only)
352
-
353
- ```typescript
354
- const storage = defineStorage({ compression: { enabled: true, threshold: 1024 } });
355
- await storage.set('largePayload', bigObject); // compressed above 1KB
356
- ```
357
-
358
- ### Cross-tab sync
359
-
360
- ```typescript
361
- const storage = defineStorage({ sync: { enabled: true } });
362
- storage.subscribe((change) => {
363
- console.log(`${change.key} changed`, change.newValue);
364
- });
365
- ```
366
-
367
- ### Queries
368
-
369
- ```typescript
370
- await storage.set('user:1', user, { tags: ['users', 'active'] });
371
- const active = await storage.query({
372
- tags: { $in: ['active'] },
373
- 'value.age': { $gte: 18 },
374
- });
375
- ```
376
-
377
- ## Platform Support
378
-
379
- ### Web (works in any JS environment)
380
-
381
- | Adapter | Backend | Use case |
382
- |---------|---------|----------|
383
- | `memory` | In-memory `Map` | Always-available fallback, tests |
384
- | `localStorage` | `window.localStorage` | Persistent key-value (~5 MB) |
385
- | `sessionStorage` | `window.sessionStorage` | Session-scoped data |
386
- | `indexedDB` | IndexedDB | Large structured data |
387
- | `cookies` | `document.cookie` | Small, server-accessible data |
388
- | `cache` | Cache API | Service-worker / HTTP cache |
389
- | `url` | `location` query/hash | Shareable UI state (see above) |
390
-
391
- ### iOS and Android (via Capacitor)
392
-
393
- Strata ships as a Capacitor plugin (native iOS + Android). In a Capacitor app, after `yarn add strata-storage` run **`npx cap sync`** so the native module is copied into your iOS/Android projects — the native adapters (`secure`, `sqlite`, `preferences`, `filesystem`) won't work on-device without it.
394
-
395
- Register the native adapters you need when running under Capacitor. All four are zero-runtime-dependency: SQLite is hand-rolled (no plugin dependency) and filesystem uses the platform's native `FileManager` / `java.io.File`.
396
-
397
- ```typescript
398
- import { defineStorage } from 'strata-storage';
399
- import {
400
- registerCapacitorAdapters,
401
- PreferencesAdapter,
402
- SecureAdapter,
403
- SqliteAdapter,
404
- FilesystemAdapter,
405
- } from 'strata-storage/capacitor';
406
-
407
- const storage = defineStorage();
408
-
409
- // Easiest: register all native adapters at once (also refreshes the active set).
410
- await registerCapacitorAdapters(storage);
411
-
412
- // …or register individually for fine-grained control / custom adapter config:
413
- // storage.registerAdapter(new PreferencesAdapter()); // UserDefaults / SharedPreferences
414
- // storage.registerAdapter(new SecureAdapter()); // Keychain / EncryptedSharedPreferences
415
- // storage.registerAdapter(new SqliteAdapter()); // native SQLite
416
- // storage.registerAdapter(new FilesystemAdapter()); // native files
357
+ type StorageType =
358
+ | 'memory' | 'localStorage' | 'sessionStorage' | 'indexedDB' | 'cookies' | 'cache' | 'url'
359
+ | 'preferences' | 'secure' | 'sqlite' | 'filesystem';
360
+
361
+ interface StorageOptions {
362
+ storage?: StorageType; // target a specific adapter
363
+ ttl?: number; // milliseconds
364
+ sliding?: boolean; // reset the TTL on each read
365
+ tags?: string[]; // for query()
366
+ encrypt?: boolean; // per-call override (async only)
367
+ compress?: boolean; // per-call override (async only)
368
+ verify?: boolean; // integrity check on read
369
+ durable?: boolean; // read-back-and-retry on write
370
+ }
417
371
 
418
- await storage.set('secret', token, { storage: 'secure' });
372
+ interface StrataConfig {
373
+ defaultStorages?: StorageType[];
374
+ adapters?: { /* per-adapter settings — see Configuration */ };
375
+ encryption?: EncryptionConfig;
376
+ compression?: CompressionConfig;
377
+ sync?: SyncConfig;
378
+ integrity?: boolean;
379
+ durableWrites?: boolean;
380
+ mirror?: StorageType[];
381
+ autoBackup?: { interval: number; storage: StorageType };
382
+ debug?: boolean;
383
+ }
419
384
  ```
420
385
 
421
- | Adapter | iOS backend | Android backend |
422
- |---------|-------------|-----------------|
423
- | `preferences` | UserDefaults | SharedPreferences |
424
- | `secure` | Keychain | EncryptedSharedPreferences |
425
- | `sqlite` | SQLite (multi-store) | SQLite (multi-store) |
426
- | `filesystem` | FileManager | java.io.File |
427
-
428
- **SQLite multi-store** (2.6.0+): each `SqliteAdapter` instance binds to a `(database, table)` pair, so distinct logical stores map to distinct physical SQLite files / tables and cannot collide.
429
-
430
- ```typescript
431
- import { SqliteAdapter } from 'strata-storage/capacitor';
432
-
433
- const analytics = defineStorage();
434
- analytics.registerAdapter(new SqliteAdapter({ database: 'analytics', table: 'events' }));
386
+ <a id="command-line"></a>
387
+ ## 💻 Command Line&nbsp;[#](#command-line)
435
388
 
436
- const audit = defineStorage();
437
- audit.registerAdapter(new SqliteAdapter({ database: 'audit', table: 'rows' }));
438
- // → separate physical .db files; writes to `analytics` can never bleed into `audit`.
389
+ ```bash
390
+ npx strata-storage <command>
439
391
  ```
440
392
 
441
- `await storage.size(true)` aggregates `{ total, count, byStorage, ... }`; native SQLite and filesystem additionally report a per-column byte breakdown (keys / values / metadata) when called on those adapters directly.
442
-
443
- > **Honest note:** the native iOS/Android adapters depend on your downstream Capacitor project setup and platform configuration, and native behavior cannot be exercised in a web/Node environment. Follow the [device-verification guide](https://stratastorage-docs.aoneahsan.com/guides/platforms/device-verification) to verify on a real iOS and Android device after integrating.
444
-
445
- ### Firebase (optional cloud sync)
446
-
447
- ```typescript
448
- import { defineStorage } from 'strata-storage';
449
- import { enableFirebaseSync } from 'strata-storage/firebase';
450
-
451
- const storage = defineStorage();
452
- await enableFirebaseSync(storage, {
453
- apiKey: '…', authDomain: '…', projectId: '…', appId: '…',
454
- firestore: true,
455
- });
456
- // 'firestore' / 'realtime' are runtime adapter names (not in the StorageType
457
- // union, so strict TS may need a cast on the options object).
458
- await storage.set('data', value, { storage: 'firestore' });
393
+ | Command | What it does |
394
+ |---|---|
395
+ | `configure` | Interactive wizard that writes a Strata configuration for your project. |
396
+ | `init` | Alias for `configure`. |
397
+ | `setup` | Alias for `configure`. |
398
+ | `--help` | Print usage. |
399
+
400
+ The CLI is optional everything it produces can be written by hand.
401
+
402
+ <a id="examples"></a>
403
+ ## 🧪 Examples&nbsp;[#](#examples)
404
+
405
+ | Goal | Example |
406
+ |---|---|
407
+ | See every core call in one file | [`docs/examples/basic-usage.ts`](https://github.com/aoneahsan/strata-storage/blob/main/docs/examples/basic-usage.ts) |
408
+ | Run a real app against a local build | [`example-apps/demo-app`](https://github.com/aoneahsan/strata-storage/tree/main/example-apps/demo-app) |
409
+ | Browse framework and feature recipes | [Examples on the docs site](https://stratastorage-docs.aoneahsan.com/examples) |
410
+
411
+ <a id="advanced-features"></a>
412
+ ## 🎛️ Advanced Features&nbsp;[#](#advanced-features)
413
+
414
+ - **Encryption** — AES-GCM through Web Crypto, per instance or per call.
415
+ [→](https://stratastorage-docs.aoneahsan.com/guides/features/encryption)
416
+ - **Compression** — applied above a byte threshold you set.
417
+ [→](https://stratastorage-docs.aoneahsan.com/guides/features/compression)
418
+ - **TTL and expiry** — absolute or sliding, with a cleanup sweep.
419
+ [→](https://stratastorage-docs.aoneahsan.com/api/features/ttl)
420
+ - **Queries** — MongoDB-style conditions over values and tags.
421
+ [→](https://stratastorage-docs.aoneahsan.com/guides/features/queries)
422
+ - **Cross-tab sync** — change notifications across tabs of one origin.
423
+ [→](https://stratastorage-docs.aoneahsan.com/guides/features/sync)
424
+ - **Integrity, durable writes, mirroring, snapshots** — the opt-in recovery set, all off by default.
425
+ [→](https://stratastorage-docs.aoneahsan.com/api/features/recovery)
426
+ - **Migrations** — an experimental adapter-level utility for reshaping stored data.
427
+ [→](https://stratastorage-docs.aoneahsan.com/guides/features/migrations)
428
+ - **Firebase sync** — mirror values to Firestore or the Realtime Database.
429
+ [→](https://stratastorage-docs.aoneahsan.com/guides/platforms/firebase)
430
+
431
+ <a id="recovery-troubleshooting"></a>
432
+ ## 🚑 Recovery & Troubleshooting&nbsp;[#](#recovery-troubleshooting)
433
+
434
+ | Symptom | Cause | Fix |
435
+ |---|---|---|
436
+ | Native adapters do nothing on device, but web works | The native module was never copied into the iOS/Android project | Run `npx cap sync`, then rebuild the app |
437
+ | `Cannot find module 'strata-storage/react'` or its types | TypeScript is on `moduleResolution: "node"`, which cannot read sub-path exports | Set `"moduleResolution": "bundler"` or `"nodenext"` in `tsconfig.json` |
438
+ | `StorageError` telling you to use the async API | A sync call targeted an async-only adapter (`indexedDB`, `cache`, `sqlite`, `filesystem`, `secure`, `preferences`) | Use `await storage.get/set(...)`, or pass `{ storage: 'localStorage' }` |
439
+ | `setSync` throws with `{ encrypt: true }` or `{ compress: true }` | Web Crypto and compression are asynchronous | Use `await storage.set(...)` for encrypted or compressed values |
440
+ | `getSync` throws on a value you stored earlier | The value was written encrypted or compressed | Read it with `await storage.get(...)` |
441
+ | `IntegrityError` on read | The stored value no longer matches its checksum | Configure `mirror` for read-repair, or pass `{ ignoreCorruption: true }` to get `null` instead |
442
+ | `No available storage adapters` | Every adapter in `defaultStorages` reported unavailable — common in Node and SSR | Include `'memory'` in `defaultStorages`, or guard the call behind a browser check |
443
+ | Console errors naming keys your app owns, not Strata's | Known open defect — see [Limitations](#limitations) | Set a prefix: `defineStorage({ adapters: { localStorage: { prefix: 'myapp:' } } })` |
444
+
445
+ More: [Troubleshooting](https://stratastorage-docs.aoneahsan.com/reference/troubleshooting) ·
446
+ [FAQ](https://stratastorage-docs.aoneahsan.com/reference/faq).
447
+
448
+ <a id="limitations"></a>
449
+ ## 🚧 Limitations&nbsp;[#](#limitations)
450
+
451
+ - **ESM only.** There is no CommonJS build. `engines.node` is `>=24.13.0`, where Node can `require()` an ESM
452
+ graph; on older Node a `require('strata-storage')` will fail.
453
+ - **No automated test suite.** This is a deliberate project decision — `yarn typecheck`, `yarn lint` and
454
+ `yarn build` are the gates, in local development and in CI. There is no unit or integration coverage to
455
+ point at.
456
+ - **Native behaviour cannot be verified from web or Node.** The iOS and Android adapters depend on your
457
+ Capacitor project's own configuration, so verify them on a real device using the
458
+ [device-verification guide](https://stratastorage-docs.aoneahsan.com/guides/platforms/device-verification).
459
+ - **Integrity checksums are not cryptographic.** They are FNV-1a: they cheaply catch accidental corruption
460
+ such as truncated writes, and they do **not** resist deliberate tampering. Use encryption for that.
461
+ - **The synchronous API is genuinely limited.** It works only on `memory`, `localStorage`,
462
+ `sessionStorage`, `cookies` and `url`, and it cannot encrypt or compress.
463
+ - **The URL adapter is not durable storage.** URLs have practical length limits around 2,000 characters,
464
+ and in `'query'` mode the data is sent to the server and appears in its logs. Use `'hash'` mode to keep it
465
+ client-side.
466
+ - **Node support is minimal.** Only the `memory` adapter is available outside a browser, so values do not
467
+ persist across processes.
468
+ - **Known open defect — web adapters default to an empty key prefix.** With no prefix, `keys()` on
469
+ `localStorage`/`sessionStorage` returns every key on the origin, including keys written by other code, and
470
+ the TTL sweep reads them. In the worst case a foreign key whose value happens to be JSON with an expired
471
+ `expires` field can be removed. Until this is fixed, set an explicit prefix:
472
+ `defineStorage({ adapters: { localStorage: { prefix: 'myapp:' } } })`. Tracked as `ISSUE-01` in
473
+ [docs/REPORTED-ISSUES.md](https://github.com/aoneahsan/strata-storage/blob/main/docs/REPORTED-ISSUES.md).
474
+ - **Firebase adapter names are not in the `StorageType` union.** `'firestore'` and `'realtime'` are runtime
475
+ names, so strict TypeScript may need a cast on the options object.
476
+
477
+ <a id="documentation"></a>
478
+ ## 📚 Documentation&nbsp;[#](#documentation)
479
+
480
+ | Document | Read it when |
481
+ |---|---|
482
+ | [Installation](https://stratastorage-docs.aoneahsan.com/installation) | setting the package up for the first time |
483
+ | [Quick start](https://stratastorage-docs.aoneahsan.com/quick-start) | you want a working call in two minutes |
484
+ | [Configuration](https://stratastorage-docs.aoneahsan.com/configuration) | you need the full option set |
485
+ | [API reference](https://stratastorage-docs.aoneahsan.com/api) | you need an exact signature |
486
+ | [Adapters](https://stratastorage-docs.aoneahsan.com/api/adapters) | choosing a backend, or writing your own |
487
+ | [Platform guides](https://stratastorage-docs.aoneahsan.com/guides/platforms/capacitor) | wiring web, iOS, Android, Capacitor or Firebase |
488
+ | [Recovery and integrity](https://stratastorage-docs.aoneahsan.com/api/features/recovery) | the data must survive corruption |
489
+ | [Migration guide](https://stratastorage-docs.aoneahsan.com/migration) | upgrading from an earlier major |
490
+ | [Troubleshooting](https://stratastorage-docs.aoneahsan.com/reference/troubleshooting) · [FAQ](https://stratastorage-docs.aoneahsan.com/reference/faq) | something is not behaving |
491
+ | [AI integration guide](https://github.com/aoneahsan/strata-storage/blob/main/AI-INTEGRATION-GUIDE.md) | a coding agent is implementing against this package |
492
+ | [llms.txt](https://stratastorage-docs.aoneahsan.com/llms.txt) · [llms-full.txt](https://stratastorage-docs.aoneahsan.com/llms-full.txt) | you need the docs as machine-readable text |
493
+
494
+ <a id="changelog"></a>
495
+ ## 🔄 Changelog&nbsp;[#](#changelog)
496
+
497
+ Latest release: **`2.8.5`** — documentation only: the at-a-glance table above reported the previous version, because it is a static duplicate of `package.json`. Full history in the changelog.
498
+
499
+ Full history: [CHANGELOG.md](https://github.com/aoneahsan/strata-storage/blob/main/CHANGELOG.md).
500
+
501
+ <a id="contributing"></a>
502
+ ## 🤝 Contributing&nbsp;[#](#contributing)
503
+
504
+ Fork and open a pull request — see
505
+ [CONTRIBUTING.md](https://github.com/aoneahsan/strata-storage/blob/main/CONTRIBUTING.md) for setup,
506
+ standards, and how to
507
+ [request collaborator access](https://github.com/aoneahsan/strata-storage/blob/main/CONTRIBUTING.md#becoming-a-contributor).
508
+ `main` is protected: every change lands through a reviewed pull request.
509
+
510
+ <a id="repository"></a>
511
+ ## 🗂️ Repository&nbsp;[#](#repository)
512
+
513
+ ```text
514
+ src/ TypeScript source — core, adapters, features, framework integrations
515
+ dist/ build output (published)
516
+ ios/ native iOS plugin sources (published, for Capacitor)
517
+ android/ native Android plugin sources (published, for Capacitor)
518
+ scripts/ build script and the npx CLI (published)
519
+ docs/ internal project records — NOT the docs site
520
+ example-apps/ runnable demo application
459
521
  ```
460
522
 
461
- ## Storage Types
462
-
463
- | Type | Platform | Synchronous | Encrypt/Compress | Notes |
464
- |------|----------|-------------|-------------------|-------|
465
- | `memory` | All | ✅ | async only | Always available |
466
- | `localStorage` | Web | ✅ | async only | ~5 MB, persistent |
467
- | `sessionStorage` | Web | ✅ | async only | Session-scoped |
468
- | `indexedDB` | Web | ❌ | async only | Large structured data |
469
- | `cookies` | Web | ✅ | async only | ~4 KB, server-readable |
470
- | `cache` | Web | ❌ | async only | Cache API |
471
- | `url` | Web | ✅ | async only | Shareable UI state, length-limited |
472
- | `preferences` | Mobile | ❌ | async only | UserDefaults / SharedPreferences |
473
- | `secure` | Mobile | ❌ | async only | Keychain / EncryptedSharedPreferences |
474
- | `sqlite` | Mobile | ❌ | async only | Native SQLite — multi-store via `(database, table)` (2.6.0+) |
475
- | `filesystem` | Mobile | ❌ | async only | Native files — file-per-key with atomic writes (2.6.0+) |
476
-
477
- "async only" means encryption and compression require the `await storage.set(...)` path — the synchronous API cannot encrypt or compress.
478
-
479
- ## Requirements
480
-
481
- - **Node.js:** `>= 24.13.0`
482
- - **TypeScript:** strict mode supported (optional, recommended)
483
- - **Capacitor:** `@capacitor/core >= 8.0.0` (for native platforms; optional peer dependency)
484
-
485
- Optional peer dependencies (install only the ones you use): `react >= 19.2.3`, `vue >= 3.5.26`, `@angular/core` & `@angular/forms >= 21.0.6`.
486
-
487
- ## Documentation
488
-
489
- 📚 **Docs:** [stratastorage-docs.aoneahsan.com](https://stratastorage-docs.aoneahsan.com) · site source in [aoneahsan/strata-storage-docs](https://github.com/aoneahsan/strata-storage-docs)
490
- 🤖 **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)
491
-
492
- ### Getting Started
493
- - [Introduction](https://stratastorage-docs.aoneahsan.com/) · [Installation](https://stratastorage-docs.aoneahsan.com/installation) · [Quick Start](https://stratastorage-docs.aoneahsan.com/quick-start) · [Configuration](https://stratastorage-docs.aoneahsan.com/configuration)
494
-
495
- ### API
496
- - [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)
497
- - [All adapters](https://stratastorage-docs.aoneahsan.com/api/adapters) — web (localStorage, IndexedDB, cookies, Cache, URL, …) + Capacitor (Preferences, Secure, SQLite, Filesystem) + remote (Firebase)
498
-
499
- ### Features
500
- - [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)
501
-
502
- ### Platforms
503
- - [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)
504
-
505
- ### Examples & Reference
506
- - [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)
507
-
508
- ## Contributing
509
-
510
- Contributions are welcome — please read the [Contributing Guide](./CONTRIBUTING.md). `main` is protected: changes land through an approved pull request (the maintainer is the only direct-push), and you can [request contributor access](./CONTRIBUTING.md#becoming-a-contributor) if you'd like to help regularly.
523
+ The documentation site lives in its own repository:
524
+ [aoneahsan/strata-storage-docs](https://github.com/aoneahsan/strata-storage-docs).
511
525
 
512
- ## License
526
+ <a id="support"></a>
527
+ ## 💬 Support&nbsp;[#](#support)
513
528
 
514
- 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.
529
+ Questions and bugs: [open an issue](https://github.com/aoneahsan/strata-storage/issues).
515
530
 
516
- ## Author
531
+ If this package saves you time, you can support its maintenance at
532
+ [aoneahsan.com/payment](https://aoneahsan.com/payment?project-id=strata-storage&project-identifier=strata-storage).
517
533
 
518
- **Ahsan Mahmood**
519
- - Email: aoneahsan@gmail.com
520
- - LinkedIn: [linkedin.com/in/aoneahsan](https://linkedin.com/in/aoneahsan)
521
- - Portfolio: [aoneahsan.com](https://aoneahsan.com)
522
- - GitHub: [@aoneahsan](https://github.com/aoneahsan)
523
- - NPM: [npmjs.com/~aoneahsan](https://www.npmjs.com/~aoneahsan)
524
- - Phone/WhatsApp: +923046619706
534
+ <a id="license"></a>
535
+ ## 📄 License&nbsp;[#](#license)
525
536
 
526
- ## Links
537
+ MIT © Ahsan Mahmood — see
538
+ [LICENSE](https://github.com/aoneahsan/strata-storage/blob/main/LICENSE).
527
539
 
528
- - **NPM Package:** https://www.npmjs.com/package/strata-storage
529
- - **GitHub Repo:** https://github.com/aoneahsan/strata-storage
530
- - **Documentation:** https://stratastorage-docs.aoneahsan.com
531
- - **Website:** https://stratastorage.aoneahsan.com
540
+ <a id="author"></a>
541
+ ## 👤 Author&nbsp;[#](#author)
532
542
 
533
- ## Support
543
+ **Ahsan Mahmood** — [aoneahsan.com](https://aoneahsan.com) · [GitHub](https://github.com/aoneahsan) ·
544
+ [LinkedIn](https://linkedin.com/in/aoneahsan) · [aoneahsan@gmail.com](mailto:aoneahsan@gmail.com)
534
545
 
535
- - 🐛 **Found a bug or have a feature request?** [Open a GitHub issue](https://github.com/aoneahsan/strata-storage/issues).
536
- - 📖 Read the [FAQ](https://stratastorage-docs.aoneahsan.com/reference/faq) and [Troubleshooting](https://stratastorage-docs.aoneahsan.com/reference/troubleshooting), or browse the full [documentation](https://stratastorage-docs.aoneahsan.com).
537
- - 💬 Anything else? [Contact us](https://stratastorage.aoneahsan.com/contact).
546
+ <a id="links"></a>
547
+ ## 🔗 Links&nbsp;[#](#links)
538
548
 
539
- ---
549
+ | | |
550
+ |---|---|
551
+ | Documentation | https://stratastorage-docs.aoneahsan.com |
552
+ | npm | https://www.npmjs.com/package/strata-storage |
553
+ | Repository | https://github.com/aoneahsan/strata-storage |
554
+ | Issues | https://github.com/aoneahsan/strata-storage/issues |
555
+ | Changelog | https://github.com/aoneahsan/strata-storage/blob/main/CHANGELOG.md |
556
+ | Docs site source | https://github.com/aoneahsan/strata-storage-docs |
557
+ | Project website | https://stratastorage.aoneahsan.com |
558
+ | Support the project | https://aoneahsan.com/payment |
540
559
 
541
- Developed with ❤️ by the **Strata Storage Team** — maintained by [Ahsan Mahmood](https://aoneahsan.com) · aoneahsan@gmail.com.
560
+ <a id="keywords"></a>
561
+ ## 🏷️ Keywords&nbsp;[#](#keywords)
542
562
 
543
- **One API. Every Storage. Everywhere.**
563
+ *storage · capacitor · localstorage · indexeddb · sqlite · keychain · cross-platform · zero-dependencies ·
564
+ react · vue · angular · typescript*