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/AI-INTEGRATION-GUIDE.md +1 -1
- package/CHANGELOG.md +465 -0
- package/README.md +434 -413
- package/dist/package.json +2 -107
- package/package.json +17 -17
- package/scripts/build.js +18 -56
- package/scripts/postinstall.js +14 -11
- package/dist/README.md +0 -543
package/README.md
CHANGED
|
@@ -1,60 +1,191 @@
|
|
|
1
|
-
|
|
1
|
+
<div align="center">
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
<img src="https://raw.githubusercontent.com/aoneahsan/strata-storage/main/assets/logo.svg" alt="Strata Storage logo" width="120" />
|
|
4
4
|
|
|
5
|
-
-
|
|
5
|
+
<h1>strata-storage</h1>
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
[](LICENSE)
|
|
9
|
-
[](https://www.typescriptlang.org/)
|
|
10
|
-
[](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
|
-
|
|
20
|
-
|
|
21
|
-
-
|
|
22
|
-
-
|
|
23
|
-
|
|
24
|
-
-
|
|
25
|
-
|
|
26
|
-
|
|
9
|
+
[](https://www.npmjs.com/package/strata-storage)
|
|
10
|
+
[](https://www.npmjs.com/package/strata-storage)
|
|
11
|
+
[](https://github.com/aoneahsan/strata-storage/blob/main/LICENSE)
|
|
12
|
+
[](https://www.npmjs.com/package/strata-storage)
|
|
13
|
+
[](https://bundlephobia.com/package/strata-storage)
|
|
14
|
+
[](https://github.com/aoneahsan/strata-storage/actions/workflows/ci.yml)
|
|
15
|
+
[](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 [#](#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 [#](#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 [#](#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 [#](#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 [#](#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 [#](#installation)
|
|
27
143
|
|
|
28
144
|
```bash
|
|
29
145
|
yarn add strata-storage
|
|
30
146
|
```
|
|
31
147
|
|
|
32
|
-
|
|
148
|
+
Nothing else is needed for web use. Install only the optional peer you actually import:
|
|
33
149
|
|
|
34
150
|
```bash
|
|
35
|
-
|
|
36
|
-
yarn add
|
|
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
|
-
|
|
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 [#](#quick-start)
|
|
43
169
|
|
|
44
|
-
The
|
|
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
|
-
|
|
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
|
-
|
|
182
|
+
<a id="usage"></a>
|
|
183
|
+
## 🛠️ Usage [#](#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', '
|
|
198
|
+
await storage.set('token', '…', { encrypt: true });
|
|
68
199
|
```
|
|
69
200
|
|
|
70
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
143
|
-
|
|
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
|
-
|
|
166
|
-
|
|
167
|
-
bootstrapApplication(AppComponent, {
|
|
168
|
-
providers: [provideStrata(storage)], // or provideStrata({ defaultStorages: ['indexedDB'] })
|
|
169
|
-
});
|
|
253
|
+
bootstrapApplication(AppComponent, { providers: [provideStrata(defineStorage())] });
|
|
170
254
|
```
|
|
171
255
|
|
|
172
|
-
|
|
173
|
-
|
|
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
|
-
|
|
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.
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
217
|
-
|
|
278
|
+
storage.setSync('lastTab', 'inbox');
|
|
279
|
+
const tab = storage.getSync<string>('lastTab');
|
|
280
|
+
storage.removeSync('lastTab');
|
|
218
281
|
```
|
|
219
282
|
|
|
220
|
-
|
|
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
|
-
|
|
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
|
-
|
|
301
|
-
|
|
302
|
-
|
|
301
|
+
<a id="configuration"></a>
|
|
302
|
+
## ⚙️ Configuration [#](#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 [#](#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 [#](#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
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 [#](#command-line)
|
|
435
388
|
|
|
436
|
-
|
|
437
|
-
|
|
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
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
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 [#](#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 [#](#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 [#](#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 [#](#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 [#](#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 [#](#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 [#](#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 [#](#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
|
-
|
|
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
|
-
|
|
526
|
+
<a id="support"></a>
|
|
527
|
+
## 💬 Support [#](#support)
|
|
513
528
|
|
|
514
|
-
|
|
529
|
+
Questions and bugs: [open an issue](https://github.com/aoneahsan/strata-storage/issues).
|
|
515
530
|
|
|
516
|
-
|
|
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
|
-
|
|
519
|
-
|
|
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 [#](#license)
|
|
525
536
|
|
|
526
|
-
|
|
537
|
+
MIT © Ahsan Mahmood — see
|
|
538
|
+
[LICENSE](https://github.com/aoneahsan/strata-storage/blob/main/LICENSE).
|
|
527
539
|
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
- **Documentation:** https://stratastorage-docs.aoneahsan.com
|
|
531
|
-
- **Website:** https://stratastorage.aoneahsan.com
|
|
540
|
+
<a id="author"></a>
|
|
541
|
+
## 👤 Author [#](#author)
|
|
532
542
|
|
|
533
|
-
|
|
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
|
-
|
|
536
|
-
|
|
537
|
-
- 💬 Anything else? [Contact us](https://stratastorage.aoneahsan.com/contact).
|
|
546
|
+
<a id="links"></a>
|
|
547
|
+
## 🔗 Links [#](#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
|
-
|
|
560
|
+
<a id="keywords"></a>
|
|
561
|
+
## 🏷️ Keywords [#](#keywords)
|
|
542
562
|
|
|
543
|
-
|
|
563
|
+
*storage · capacitor · localstorage · indexeddb · sqlite · keychain · cross-platform · zero-dependencies ·
|
|
564
|
+
react · vue · angular · typescript*
|