strata-storage 2.8.2 → 2.8.4

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/dist/README.md DELETED
@@ -1,543 +0,0 @@
1
- # Strata Storage
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.
4
-
5
- - **[AI Integration Guide](./AI-INTEGRATION-GUIDE.md)** — quick reference for AI development agents (Claude Code, Cursor, Copilot).
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.2`
13
- - **License:** MIT
14
- - **Node.js:** `>= 24.13.0`
15
- - **Module format:** ESM only
16
-
17
- ## Why Strata Storage
18
-
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
27
-
28
- ```bash
29
- yarn add strata-storage
30
- ```
31
-
32
- Framework adapters import from sub-paths; no extra install beyond the framework itself:
33
-
34
- ```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
38
- yarn add @angular/core @angular/forms # for strata-storage/angular
39
- yarn add @capacitor/core # for strata-storage/capacitor
40
- ```
41
-
42
- ## Quick Start
43
-
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.
45
-
46
- ```typescript
47
- import { storage } from 'strata-storage';
48
-
49
- // No setup, no Provider, no initialize() call — works immediately.
50
- await storage.set('user', { id: 123, name: 'John Doe' });
51
- const user = await storage.get<{ id: number; name: string }>('user');
52
-
53
- await storage.remove('user');
54
- await storage.clear();
55
- ```
56
-
57
- Need your own configured instance? Use `defineStorage()` — it is the same factory the default instance is built from.
58
-
59
- ```typescript
60
- import { defineStorage } from 'strata-storage';
61
-
62
- export const storage = defineStorage({
63
- defaultStorages: ['indexedDB', 'localStorage'],
64
- encryption: { enabled: true, password: process.env.STORAGE_KEY! },
65
- });
66
-
67
- await storage.set('token', '...', { encrypt: true });
68
- ```
69
-
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
- ```
86
-
87
- ### React
88
-
89
- Bind the hooks to an instance once at module scope with `createStrataHooks`, then use them in any component — no `<StrataProvider>` needed.
90
-
91
- ```tsx
92
- // storage.ts
93
- import { defineStorage } from 'strata-storage';
94
- import { createStrataHooks } from 'strata-storage/react';
95
-
96
- export const storage = defineStorage();
97
- export const { useStorage, useStorageQuery, useStorageTTL } = createStrataHooks(storage);
98
- ```
99
-
100
- ```tsx
101
- // Settings.tsx
102
- import { useStorage } from './storage';
103
-
104
- function Settings() {
105
- // [value, setValue, loading]
106
- const [theme, setTheme, loading] = useStorage<string>('theme', 'light');
107
-
108
- if (loading) return <p>Loading…</p>;
109
-
110
- return (
111
- <button onClick={() => setTheme(theme === 'light' ? 'dark' : 'light')}>
112
- Theme: {theme}
113
- </button>
114
- );
115
- }
116
- ```
117
-
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
- ```
128
-
129
- ### Vue
130
-
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
- ```typescript
134
- // storage.ts
135
- import { defineStorage } from 'strata-storage';
136
- import { createStrataComposables } from 'strata-storage/vue';
137
-
138
- export const storage = defineStorage();
139
- export const { useStorage, useStorageQuery, useStorageTTL } = createStrataComposables(storage);
140
- ```
141
-
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
- ```
153
-
154
- ### Angular
155
-
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
- ```typescript
159
- // main.ts
160
- import { bootstrapApplication } from '@angular/platform-browser';
161
- import { defineStorage } from 'strata-storage';
162
- import { provideStrata } from 'strata-storage/angular';
163
- import { AppComponent } from './app/app.component';
164
-
165
- const storage = defineStorage();
166
-
167
- bootstrapApplication(AppComponent, {
168
- providers: [provideStrata(storage)], // or provideStrata({ defaultStorages: ['indexedDB'] })
169
- });
170
- ```
171
-
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
189
-
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:
191
-
192
- ```typescript
193
- import { defineStorage } from 'strata-storage';
194
-
195
- const storage = defineStorage();
196
-
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();
203
- ```
204
-
205
- ### Limitations (read these)
206
-
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.
214
-
215
- ```typescript
216
- // Pick a sync-capable backend explicitly when needed:
217
- storage.setSync('filters', { status: 'open' }, { storage: 'localStorage', ttl: 60_000 });
218
- ```
219
-
220
- ## URL Adapter
221
-
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.
223
-
224
- ```typescript
225
- import { defineStorage, URLAdapter } from 'strata-storage';
226
-
227
- const storage = defineStorage();
228
- storage.registerAdapter(new URLAdapter());
229
-
230
- // Write to the URL (no await needed — URL access is synchronous)
231
- storage.setSync('tab', 'pending', { storage: 'url' });
232
- storage.setSync('page', 3, { storage: 'url' });
233
-
234
- // Read it back (e.g. on reload)
235
- 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
-
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.
303
-
304
- ```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
- 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`.
394
-
395
- ```typescript
396
- import { defineStorage } from 'strata-storage';
397
- import {
398
- PreferencesAdapter,
399
- SecureAdapter,
400
- SqliteAdapter,
401
- FilesystemAdapter,
402
- } from 'strata-storage/capacitor';
403
-
404
- const storage = defineStorage();
405
- storage.registerAdapter(new PreferencesAdapter()); // UserDefaults / SharedPreferences
406
- storage.registerAdapter(new SecureAdapter()); // Keychain / EncryptedSharedPreferences
407
- storage.registerAdapter(new SqliteAdapter()); // native SQLite
408
- storage.registerAdapter(new FilesystemAdapter()); // native files
409
-
410
- await storage.set('secret', token, { storage: 'secure' });
411
- ```
412
-
413
- | Adapter | iOS backend | Android backend |
414
- |---------|-------------|-----------------|
415
- | `preferences` | UserDefaults | SharedPreferences |
416
- | `secure` | Keychain | EncryptedSharedPreferences |
417
- | `sqlite` | SQLite (multi-store) | SQLite (multi-store) |
418
- | `filesystem` | FileManager | java.io.File |
419
-
420
- **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.
421
-
422
- ```typescript
423
- import { SqliteAdapter } from 'strata-storage/capacitor';
424
-
425
- const analytics = defineStorage();
426
- analytics.registerAdapter(new SqliteAdapter({ database: 'analytics', table: 'events' }));
427
-
428
- const audit = defineStorage();
429
- audit.registerAdapter(new SqliteAdapter({ database: 'audit', table: 'rows' }));
430
- // → separate physical .db files; writes to `analytics` can never bleed into `audit`.
431
- ```
432
-
433
- `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.
434
-
435
- > **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.
436
-
437
- ### Firebase (optional cloud sync)
438
-
439
- ```typescript
440
- import { defineStorage } from 'strata-storage';
441
- import { enableFirebaseSync } from 'strata-storage/firebase';
442
-
443
- const storage = defineStorage();
444
- await enableFirebaseSync(storage, {
445
- apiKey: '…', authDomain: '…', projectId: '…', appId: '…',
446
- firestore: true,
447
- });
448
- // 'firestore' / 'realtime' are runtime adapter names (not in the StorageType
449
- // union, so strict TS may need a cast on the options object).
450
- await storage.set('data', value, { storage: 'firestore' });
451
- ```
452
-
453
- ## Storage Types
454
-
455
- | Type | Platform | Synchronous | Encrypt/Compress | Notes |
456
- |------|----------|-------------|-------------------|-------|
457
- | `memory` | All | ✅ | async only | Always available |
458
- | `localStorage` | Web | ✅ | async only | ~5 MB, persistent |
459
- | `sessionStorage` | Web | ✅ | async only | Session-scoped |
460
- | `indexedDB` | Web | ❌ | async only | Large structured data |
461
- | `cookies` | Web | ✅ | async only | ~4 KB, server-readable |
462
- | `cache` | Web | ❌ | async only | Cache API |
463
- | `url` | Web | ✅ | async only | Shareable UI state, length-limited |
464
- | `preferences` | Mobile | ❌ | async only | UserDefaults / SharedPreferences |
465
- | `secure` | Mobile | ❌ | async only | Keychain / EncryptedSharedPreferences |
466
- | `sqlite` | Mobile | ❌ | async only | Native SQLite — multi-store via `(database, table)` (2.6.0+) |
467
- | `filesystem` | Mobile | ❌ | async only | Native files — file-per-key with atomic writes (2.6.0+) |
468
-
469
- "async only" means encryption and compression require the `await storage.set(...)` path — the synchronous API cannot encrypt or compress.
470
-
471
- ## Requirements
472
-
473
- - **Node.js:** `>= 24.13.0`
474
- - **TypeScript:** strict mode supported (optional, recommended)
475
- - **Capacitor:** `@capacitor/core >= 8.0.0` (for native platforms; optional peer dependency)
476
-
477
- Optional peer dependencies (install only the ones you use): `react >= 19.2.3`, `vue >= 3.5.26`, `@angular/core` & `@angular/forms >= 21.0.6`.
478
-
479
- ## Documentation
480
-
481
- 📚 **Full documentation: [stratastorage-docs.aoneahsan.com](https://stratastorage-docs.aoneahsan.com)**
482
- 🤖 **For AI agents: [stratastorage-docs.aoneahsan.com/ai](https://stratastorage-docs.aoneahsan.com/ai)** (plus [`/llms.txt`](https://stratastorage-docs.aoneahsan.com/llms.txt) and [`/llms-full.txt`](https://stratastorage-docs.aoneahsan.com/llms-full.txt))
483
-
484
- ### Getting Started
485
- - [Installation](https://stratastorage-docs.aoneahsan.com/installation) · [Quick Start](https://stratastorage-docs.aoneahsan.com/quick-start) · [Configuration](https://stratastorage-docs.aoneahsan.com/configuration)
486
-
487
- ### API
488
- - [API Reference](https://stratastorage-docs.aoneahsan.com/api) · [Core (`Strata`)](https://stratastorage-docs.aoneahsan.com/api/core/strata) · [Types](https://stratastorage-docs.aoneahsan.com/api/core/types) · [Errors](https://stratastorage-docs.aoneahsan.com/api/core/errors)
489
- - [All adapters](https://stratastorage-docs.aoneahsan.com/api/adapters) — web (localStorage, IndexedDB, cookies, Cache, URL, …) + Capacitor (Preferences, Secure, SQLite, Filesystem) + remote (Firebase)
490
-
491
- ### Features
492
- - [Encryption](https://stratastorage-docs.aoneahsan.com/guides/features/encryption) · [Compression](https://stratastorage-docs.aoneahsan.com/guides/features/compression) · [TTL](https://stratastorage-docs.aoneahsan.com/api/features/ttl) · [Sync](https://stratastorage-docs.aoneahsan.com/guides/features/sync) · [Queries](https://stratastorage-docs.aoneahsan.com/guides/features/queries) · [Migrations](https://stratastorage-docs.aoneahsan.com/guides/features/migrations) · [Recovery & Integrity](https://stratastorage-docs.aoneahsan.com/api/features/recovery)
493
-
494
- ### Platforms
495
- - [Web](https://stratastorage-docs.aoneahsan.com/guides/platforms/web) · [iOS](https://stratastorage-docs.aoneahsan.com/guides/platforms/ios) · [Android](https://stratastorage-docs.aoneahsan.com/guides/platforms/android) · [Capacitor](https://stratastorage-docs.aoneahsan.com/guides/platforms/capacitor) · [Firebase](https://stratastorage-docs.aoneahsan.com/guides/platforms/firebase)
496
-
497
- ### Examples & Reference
498
- - [Examples](https://stratastorage-docs.aoneahsan.com/examples) · [Changelog](https://stratastorage-docs.aoneahsan.com/reference/changelog) · [FAQ](https://stratastorage-docs.aoneahsan.com/reference/faq) · [Troubleshooting](https://stratastorage-docs.aoneahsan.com/reference/troubleshooting) · [Migration](https://stratastorage-docs.aoneahsan.com/migration)
499
-
500
- ## Contributing
501
-
502
- Contributions are welcome — please read the [Contributing Guide](./.github/CONTRIBUTING.md).
503
-
504
- ## License
505
-
506
- MIT License — see [LICENSE](LICENSE). Free for commercial and non-commercial use, modification, distribution, and sublicensing; the only condition is keeping the copyright and license notice; provided without warranty.
507
-
508
- ## Author
509
-
510
- **Ahsan Mahmood**
511
- - Email: aoneahsan@gmail.com
512
- - LinkedIn: [linkedin.com/in/aoneahsan](https://linkedin.com/in/aoneahsan)
513
- - Portfolio: [aoneahsan.com](https://aoneahsan.com)
514
- - GitHub: [@aoneahsan](https://github.com/aoneahsan)
515
- - NPM: [npmjs.com/~aoneahsan](https://www.npmjs.com/~aoneahsan)
516
- - Phone/WhatsApp: +923046619706
517
-
518
- ## Links
519
-
520
- - **NPM Package:** https://www.npmjs.com/package/strata-storage
521
- - **Documentation:** https://stratastorage-docs.aoneahsan.com
522
- - **Website:** https://stratastorage.aoneahsan.com
523
-
524
- ## Support
525
-
526
- 1. Check the [FAQ](https://stratastorage-docs.aoneahsan.com/reference/faq) and [Troubleshooting](https://stratastorage-docs.aoneahsan.com/reference/troubleshooting)
527
- 2. Browse the [documentation](https://stratastorage-docs.aoneahsan.com)
528
- 3. [Contact us / report an issue](https://stratastorage.aoneahsan.com/contact)
529
-
530
- ---
531
-
532
- Developed with ❤️ by the **Strata Storage Team** — maintained by [Ahsan Mahmood](https://aoneahsan.com) · aoneahsan@gmail.com.
533
-
534
- **One API. Every Storage. Everywhere.**
535
-
536
- <!-- project-links:start -->
537
- ## Links
538
-
539
- - Live: https://www.npmjs.com/package/strata-storage
540
- - NPM: https://www.npmjs.com/package/strata-storage
541
-
542
- _URL source of truth: `01-code/projects/project-live-urls.json` (auto-generated — do not hand-edit between these markers)._
543
- <!-- project-links:end -->