strata-storage 2.6.0 → 2.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (130) hide show
  1. package/AI-INTEGRATION-GUIDE.md +97 -10
  2. package/README.md +70 -70
  3. package/android/AGENTS.md +18 -3
  4. package/android/CLAUDE.md +36 -3
  5. package/android/build.gradle +5 -1
  6. package/android/src/main/java/com/strata/storage/EncryptedStorage.java +31 -18
  7. package/android/src/main/java/com/strata/storage/FilesystemStorage.java +62 -10
  8. package/android/src/main/java/com/strata/storage/SQLiteStorage.java +65 -13
  9. package/android/src/main/java/com/strata/storage/SharedPreferencesStorage.java +63 -51
  10. package/android/src/main/java/com/stratastorage/StrataStoragePlugin.java +80 -11
  11. package/dist/README.md +70 -70
  12. package/dist/adapters/capacitor/FilesystemAdapter.d.ts +2 -2
  13. package/dist/adapters/capacitor/FilesystemAdapter.d.ts.map +1 -1
  14. package/dist/adapters/capacitor/FilesystemAdapter.js +6 -2
  15. package/dist/adapters/capacitor/PreferencesAdapter.d.ts +2 -2
  16. package/dist/adapters/capacitor/PreferencesAdapter.d.ts.map +1 -1
  17. package/dist/adapters/capacitor/PreferencesAdapter.js +6 -2
  18. package/dist/adapters/capacitor/SecureAdapter.d.ts +3 -3
  19. package/dist/adapters/capacitor/SecureAdapter.d.ts.map +1 -1
  20. package/dist/adapters/capacitor/SecureAdapter.js +6 -2
  21. package/dist/adapters/capacitor/SqliteAdapter.d.ts +24 -3
  22. package/dist/adapters/capacitor/SqliteAdapter.d.ts.map +1 -1
  23. package/dist/adapters/capacitor/SqliteAdapter.js +105 -23
  24. package/dist/adapters/capacitor/index.d.ts +4 -4
  25. package/dist/adapters/web/CacheAdapter.d.ts +2 -2
  26. package/dist/adapters/web/CookieAdapter.d.ts +2 -2
  27. package/dist/adapters/web/IndexedDBAdapter.d.ts +10 -3
  28. package/dist/adapters/web/IndexedDBAdapter.d.ts.map +1 -1
  29. package/dist/adapters/web/IndexedDBAdapter.js +14 -3
  30. package/dist/adapters/web/LocalStorageAdapter.d.ts +2 -2
  31. package/dist/adapters/web/MemoryAdapter.d.ts +2 -2
  32. package/dist/adapters/web/SessionStorageAdapter.d.ts +10 -10
  33. package/dist/adapters/web/SessionStorageAdapter.d.ts.map +1 -1
  34. package/dist/adapters/web/SessionStorageAdapter.js +3 -2
  35. package/dist/adapters/web/URLAdapter.d.ts +2 -2
  36. package/dist/adapters/web/index.d.ts +7 -7
  37. package/dist/capacitor.d.ts +6 -6
  38. package/dist/capacitor.d.ts.map +1 -1
  39. package/dist/capacitor.js +5 -4
  40. package/dist/core/AdapterRegistry.d.ts +1 -1
  41. package/dist/core/BaseAdapter.d.ts +21 -5
  42. package/dist/core/BaseAdapter.d.ts.map +1 -1
  43. package/dist/core/BaseAdapter.js +29 -1
  44. package/dist/core/Strata.d.ts +41 -7
  45. package/dist/core/Strata.d.ts.map +1 -1
  46. package/dist/core/Strata.js +476 -118
  47. package/dist/features/compression/index.d.ts +1 -1
  48. package/dist/features/compression.d.ts +5 -1
  49. package/dist/features/compression.d.ts.map +1 -1
  50. package/dist/features/encryption/index.d.ts +1 -1
  51. package/dist/features/encryption.d.ts +55 -2
  52. package/dist/features/encryption.d.ts.map +1 -1
  53. package/dist/features/encryption.js +139 -26
  54. package/dist/features/migration.d.ts +1 -1
  55. package/dist/features/observer/index.d.ts +1 -1
  56. package/dist/features/observer.d.ts +1 -1
  57. package/dist/features/query/index.d.ts +1 -1
  58. package/dist/features/query.d.ts +1 -1
  59. package/dist/features/query.d.ts.map +1 -1
  60. package/dist/features/query.js +3 -1
  61. package/dist/features/sync/index.d.ts +1 -1
  62. package/dist/features/sync.d.ts +19 -3
  63. package/dist/features/sync.d.ts.map +1 -1
  64. package/dist/features/sync.js +57 -9
  65. package/dist/features/ttl/index.d.ts +1 -1
  66. package/dist/features/ttl.d.ts +2 -2
  67. package/dist/firebase.d.ts +1 -1
  68. package/dist/firebase.d.ts.map +1 -1
  69. package/dist/firebase.js +34 -9
  70. package/dist/index.d.ts +24 -22
  71. package/dist/index.d.ts.map +1 -1
  72. package/dist/index.js +6 -1
  73. package/dist/integrations/angular/index.d.ts +2 -2
  74. package/dist/integrations/angular/index.d.ts.map +1 -1
  75. package/dist/integrations/angular/index.js +7 -8
  76. package/dist/integrations/react/index.d.ts +3 -3
  77. package/dist/integrations/react/index.d.ts.map +1 -1
  78. package/dist/integrations/react/index.js +16 -4
  79. package/dist/integrations/vue/index.d.ts +2 -2
  80. package/dist/integrations/vue/index.d.ts.map +1 -1
  81. package/dist/integrations/vue/index.js +5 -2
  82. package/dist/package.json +11 -2
  83. package/dist/plugin/definitions.d.ts +29 -3
  84. package/dist/plugin/definitions.d.ts.map +1 -1
  85. package/dist/plugin/index.d.ts +2 -2
  86. package/dist/plugin/index.d.ts.map +1 -1
  87. package/dist/plugin/index.js +3 -0
  88. package/dist/plugin/web.d.ts +11 -2
  89. package/dist/plugin/web.d.ts.map +1 -1
  90. package/dist/plugin/web.js +23 -4
  91. package/dist/types/index.d.ts +50 -20
  92. package/dist/types/index.d.ts.map +1 -1
  93. package/dist/types/index.js +1 -10
  94. package/dist/utils/index.d.ts +5 -0
  95. package/dist/utils/index.d.ts.map +1 -1
  96. package/dist/utils/index.js +7 -0
  97. package/ios/AGENTS.md +14 -3
  98. package/ios/CLAUDE.md +25 -3
  99. package/ios/Plugin/FilesystemStorage.swift +19 -0
  100. package/ios/Plugin/SQLiteStorage.swift +59 -9
  101. package/ios/Plugin/StrataStoragePlugin.m +1 -0
  102. package/ios/Plugin/StrataStoragePlugin.swift +87 -34
  103. package/ios/Plugin/UserDefaultsStorage.swift +47 -46
  104. package/package.json +29 -26
  105. package/scripts/build.js +16 -14
  106. package/scripts/cli.js +1 -1
  107. package/scripts/configure.js +2 -2
  108. package/scripts/postinstall.js +3 -2
  109. package/dist/android/AGENTS.md +0 -51
  110. package/dist/android/CLAUDE.md +0 -89
  111. package/dist/android/build.gradle +0 -58
  112. package/dist/android/proguard-rules.pro +0 -11
  113. package/dist/android/settings.gradle +0 -2
  114. package/dist/android/src/main/AndroidManifest.xml +0 -2
  115. package/dist/android/src/main/java/com/strata/storage/EncryptedStorage.java +0 -218
  116. package/dist/android/src/main/java/com/strata/storage/FilesystemStorage.java +0 -287
  117. package/dist/android/src/main/java/com/strata/storage/SQLiteStorage.java +0 -371
  118. package/dist/android/src/main/java/com/strata/storage/SharedPreferencesStorage.java +0 -209
  119. package/dist/android/src/main/java/com/stratastorage/StrataStoragePlugin.java +0 -616
  120. package/dist/core/StorageStrategy.d.ts +0 -55
  121. package/dist/core/StorageStrategy.d.ts.map +0 -1
  122. package/dist/core/StorageStrategy.js +0 -200
  123. package/dist/ios/AGENTS.md +0 -48
  124. package/dist/ios/CLAUDE.md +0 -84
  125. package/dist/ios/Plugin/FilesystemStorage.swift +0 -218
  126. package/dist/ios/Plugin/KeychainStorage.swift +0 -233
  127. package/dist/ios/Plugin/SQLiteStorage.swift +0 -426
  128. package/dist/ios/Plugin/StrataStoragePlugin.m +0 -23
  129. package/dist/ios/Plugin/StrataStoragePlugin.swift +0 -411
  130. package/dist/ios/Plugin/UserDefaultsStorage.swift +0 -87
package/dist/README.md CHANGED
@@ -7,9 +7,9 @@
7
7
  [![npm version](https://img.shields.io/npm/v/strata-storage.svg)](https://www.npmjs.com/package/strata-storage)
8
8
  [![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](LICENSE)
9
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://github.com/aoneahsan/strata-storage)
10
+ [![Platform](https://img.shields.io/badge/platform-Web%20%7C%20iOS%20%7C%20Android-lightgrey.svg)](https://stratastorage.aoneahsan.com)
11
11
 
12
- - **Version:** `2.5.0`
12
+ - **Version:** `2.7.0`
13
13
  - **License:** Apache-2.0
14
14
  - **Node.js:** `>= 24.13.0`
15
15
  - **Module format:** ESM only
@@ -71,7 +71,7 @@ await storage.set('token', '...', { encrypt: true });
71
71
 
72
72
  ## Provider-Free Usage
73
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 [docs/examples/frameworks](./docs/examples/frameworks).
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
75
 
76
76
  ### Vanilla JavaScript / TypeScript
77
77
 
@@ -390,15 +390,22 @@ const active = await storage.query({
390
390
 
391
391
  ### iOS and Android (via Capacitor)
392
392
 
393
- Register native adapters yourself when running under Capacitor:
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
394
 
395
395
  ```typescript
396
396
  import { defineStorage } from 'strata-storage';
397
- import { PreferencesAdapter, SecureStorageAdapter } from 'strata-storage/capacitor';
397
+ import {
398
+ PreferencesAdapter,
399
+ SecureAdapter,
400
+ SqliteAdapter,
401
+ FilesystemAdapter,
402
+ } from 'strata-storage/capacitor';
398
403
 
399
404
  const storage = defineStorage();
400
- storage.registerAdapter(new PreferencesAdapter()); // UserDefaults / SharedPreferences
401
- storage.registerAdapter(new SecureStorageAdapter()); // Keychain / EncryptedSharedPreferences
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
402
409
 
403
410
  await storage.set('secret', token, { storage: 'secure' });
404
411
  ```
@@ -407,10 +414,25 @@ await storage.set('secret', token, { storage: 'secure' });
407
414
  |---------|-------------|-----------------|
408
415
  | `preferences` | UserDefaults | SharedPreferences |
409
416
  | `secure` | Keychain | EncryptedSharedPreferences |
410
- | `sqlite` | SQLite | SQLite |
411
- | `filesystem` | FileManager | Filesystem |
417
+ | `sqlite` | SQLite (multi-store) | SQLite (multi-store) |
418
+ | `filesystem` | FileManager | java.io.File |
412
419
 
413
- > **Honest note:** the native iOS/Android adapters depend on your downstream Capacitor project setup and platform configuration. Behavior on a real device should be verified on-device — native storage cannot be exercised by the web/Node test suite.
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.
414
436
 
415
437
  ### Firebase (optional cloud sync)
416
438
 
@@ -419,7 +441,12 @@ import { defineStorage } from 'strata-storage';
419
441
  import { enableFirebaseSync } from 'strata-storage/firebase';
420
442
 
421
443
  const storage = defineStorage();
422
- await enableFirebaseSync(storage, { apiKey: '…', projectId: '…', firestore: true });
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).
423
450
  await storage.set('data', value, { storage: 'firestore' });
424
451
  ```
425
452
 
@@ -436,8 +463,8 @@ await storage.set('data', value, { storage: 'firestore' });
436
463
  | `url` | Web | ✅ | async only | Shareable UI state, length-limited |
437
464
  | `preferences` | Mobile | ❌ | async only | UserDefaults / SharedPreferences |
438
465
  | `secure` | Mobile | ❌ | async only | Keychain / EncryptedSharedPreferences |
439
- | `sqlite` | Mobile | ❌ | async only | Native SQLite |
440
- | `filesystem` | Mobile | ❌ | async only | Native files |
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+) |
441
468
 
442
469
  "async only" means encryption and compression require the `await storage.set(...)` path — the synchronous API cannot encrypt or compress.
443
470
 
@@ -451,59 +478,24 @@ Optional peer dependencies (install only the ones you use): `react >= 19.2.3`, `
451
478
 
452
479
  ## Documentation
453
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
+
454
484
  ### Getting Started
455
- - [Installation](./docs/getting-started/installation.md) install and set up
456
- - [Quick Start](./docs/getting-started/quick-start.md) — running in minutes
457
- - [Configuration](./docs/getting-started/configuration.md) — configuration options
458
-
459
- ### Core
460
- - [API Reference](./docs/api/README.md) — complete API
461
- - [Core API (`Strata`)](./docs/api/core/strata.md) — the main class
462
- - [Type Definitions](./docs/api/core/types.md) — TypeScript types
463
- - [Error Handling](./docs/api/core/errors.md) — error classes
464
-
465
- ### Storage Adapters
466
- - [Web Adapters](./docs/api/adapters/README.md#web-adapters)
467
- - [localStorage](./docs/api/adapters/web/localstorage.md)
468
- - [sessionStorage](./docs/api/adapters/web/sessionstorage.md)
469
- - [IndexedDB](./docs/api/adapters/web/indexeddb.md)
470
- - [Cookies](./docs/api/adapters/web/cookies.md)
471
- - [Cache API](./docs/api/adapters/web/cache.md)
472
- - [Memory](./docs/api/adapters/web/memory.md)
473
- - [URL](./docs/api/adapters/web/url.md)
474
- - [Capacitor Adapters](./docs/api/adapters/README.md#capacitor-adapters)
475
- - [Preferences](./docs/api/adapters/capacitor/preferences.md)
476
- - [Secure Storage](./docs/api/adapters/capacitor/secure.md)
477
- - [SQLite](./docs/api/adapters/capacitor/sqlite.md)
478
- - [Filesystem](./docs/api/adapters/capacitor/filesystem.md)
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)
479
490
 
480
491
  ### Features
481
- - [Encryption](./docs/guides/features/encryption.md)
482
- - [Compression](./docs/guides/features/compression.md)
483
- - [TTL Management](./docs/api/features/ttl.md)
484
- - [Cross-Tab Sync](./docs/guides/features/sync.md)
485
- - [Query Engine](./docs/guides/features/queries.md)
486
- - [Migrations](./docs/guides/features/migrations.md)
487
- - [Recovery & Integrity](./docs/api/features/recovery.md)
488
-
489
- ### Platform Guides
490
- - [Web](./docs/guides/platforms/web.md)
491
- - [iOS](./docs/guides/platforms/ios.md)
492
- - [Android](./docs/guides/platforms/android.md)
493
- - [Capacitor](./docs/guides/platforms/capacitor.md)
494
-
495
- ### Examples
496
- - [Basic Usage](./docs/examples/basic-usage.md)
497
- - [React Integration](./docs/examples/frameworks/react.md)
498
- - [Vue Integration](./docs/examples/frameworks/vue.md)
499
- - [Angular Integration](./docs/examples/frameworks/angular.md)
500
- - [All Examples](./docs/examples/README.md)
501
-
502
- ### Reference
503
- - [Changelog](./docs/reference/changelog.md)
504
- - [FAQ](./docs/reference/faq.md)
505
- - [Troubleshooting](./docs/reference/troubleshooting.md)
506
- - [Migration Guide](./docs/MIGRATION.md)
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)
507
499
 
508
500
  ## Contributing
509
501
 
@@ -525,17 +517,25 @@ Apache License 2.0 — see [LICENSE](LICENSE). Free for commercial use, modifica
525
517
 
526
518
  ## Links
527
519
 
528
- - **NPM Package:** [npmjs.com/package/strata-storage](https://www.npmjs.com/package/strata-storage)
529
- - **GitHub Repository:** [github.com/aoneahsan/strata-storage](https://github.com/aoneahsan/strata-storage)
530
- - **Issue Tracker:** [github.com/aoneahsan/strata-storage/issues](https://github.com/aoneahsan/strata-storage/issues)
531
- - **Documentation:** [github.com/aoneahsan/strata-storage/tree/main/docs](https://github.com/aoneahsan/strata-storage/tree/main/docs)
520
+ - **NPM Package:** https://www.npmjs.com/package/strata-storage
521
+ - **Documentation:** https://stratastorage-docs.aoneahsan.com
522
+ - **Website:** https://stratastorage.aoneahsan.com
532
523
 
533
524
  ## Support
534
525
 
535
- 1. Check the [FAQ](./docs/reference/faq.md)
536
- 2. Search [existing issues](https://github.com/aoneahsan/strata-storage/issues)
537
- 3. Open a [new issue](https://github.com/aoneahsan/strata-storage/issues/new)
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)
538
529
 
539
530
  ---
540
531
 
541
532
  Made by [Ahsan Mahmood](https://aoneahsan.com). **One API. Every Storage. Everywhere.**
533
+
534
+ <!-- project-links:start -->
535
+ ## Links
536
+
537
+ - Live: https://www.npmjs.com/package/strata-storage
538
+ - NPM: https://www.npmjs.com/package/strata-storage
539
+
540
+ _URL source of truth: `01-code/projects/project-live-urls.json` (auto-generated — do not hand-edit between these markers)._
541
+ <!-- project-links:end -->
@@ -2,8 +2,8 @@
2
2
  * Filesystem Adapter - Native file system storage
3
3
  * Direct file access on iOS and Android
4
4
  */
5
- import { BaseAdapter } from '@/core/BaseAdapter';
6
- import type { StorageType, StorageCapabilities, StorageValue, ClearOptions, SizeInfo } from '@/types';
5
+ import { BaseAdapter } from "../../core/BaseAdapter.js";
6
+ import type { StorageType, StorageCapabilities, StorageValue, ClearOptions, SizeInfo } from "../../types/index.js";
7
7
  /**
8
8
  * Native filesystem adapter using Capacitor plugin
9
9
  */
@@ -1 +1 @@
1
- {"version":3,"file":"FilesystemAdapter.d.ts","sourceRoot":"","sources":["../../../src/adapters/capacitor/FilesystemAdapter.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,KAAK,EACV,WAAW,EACX,mBAAmB,EACnB,YAAY,EACZ,YAAY,EACZ,QAAQ,EACT,MAAM,SAAS,CAAC;AAMjB;;GAEG;AACH,qBAAa,iBAAkB,SAAQ,WAAW;IAChD,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAgB;IAC1C,QAAQ,CAAC,YAAY,EAAE,mBAAmB,CAUxC;IAEF;;OAEG;IACG,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC;IAWrC;;OAEG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAIjC;;OAEG;IACG,GAAG,CAAC,CAAC,GAAG,OAAO,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;IAwBpE;;OAEG;IACG,GAAG,CAAC,CAAC,GAAG,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,YAAY,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAgB1E;;OAEG;IACG,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAiBxC;;OAEG;IACG,KAAK,CAAC,OAAO,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAiBlD;;OAEG;IACG,IAAI,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAwBxD;;OAEG;IACG,IAAI,CAAC,QAAQ,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC;CAYlD"}
1
+ {"version":3,"file":"FilesystemAdapter.d.ts","sourceRoot":"","sources":["../../../src/adapters/capacitor/FilesystemAdapter.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,KAAK,EACV,WAAW,EACX,mBAAmB,EACnB,YAAY,EACZ,YAAY,EACZ,QAAQ,EACT,MAAM,SAAS,CAAC;AAMjB;;GAEG;AACH,qBAAa,iBAAkB,SAAQ,WAAW;IAChD,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAgB;IAC1C,QAAQ,CAAC,YAAY,EAAE,mBAAmB,CAUxC;IAEF;;OAEG;IACG,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC;IAWrC;;OAEG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAIjC;;OAEG;IACG,GAAG,CAAC,CAAC,GAAG,OAAO,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;IAwBpE;;OAEG;IACG,GAAG,CAAC,CAAC,GAAG,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,YAAY,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAkB1E;;OAEG;IACG,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAmBxC;;OAEG;IACG,KAAK,CAAC,OAAO,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAiBlD;;OAEG;IACG,IAAI,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAwBxD;;OAEG;IACG,IAAI,CAAC,QAAQ,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC;CAYlD"}
@@ -71,7 +71,9 @@ export class FilesystemAdapter extends BaseAdapter {
71
71
  * Set a value in filesystem
72
72
  */
73
73
  async set(key, value) {
74
- const oldValue = await this.get(key);
74
+ // Only pay for a read-before-write (a native bridge round-trip) when a
75
+ // subscriber actually needs the previous value for the change event.
76
+ const oldValue = this.hasChangeListeners() ? await this.get(key) : null;
75
77
  try {
76
78
  await StrataStorage.set({
77
79
  key,
@@ -88,7 +90,9 @@ export class FilesystemAdapter extends BaseAdapter {
88
90
  * Remove a value from filesystem
89
91
  */
90
92
  async remove(key) {
91
- const oldValue = await this.get(key);
93
+ // Only pay for a read-before-write (a native bridge round-trip) when a
94
+ // subscriber actually needs the previous value for the change event.
95
+ const oldValue = this.hasChangeListeners() ? await this.get(key) : null;
92
96
  try {
93
97
  await StrataStorage.remove({
94
98
  key,
@@ -2,8 +2,8 @@
2
2
  * Preferences Adapter - Native preferences storage
3
3
  * iOS: UserDefaults, Android: SharedPreferences
4
4
  */
5
- import { BaseAdapter } from '@/core/BaseAdapter';
6
- import type { StorageType, StorageCapabilities, StorageValue, ClearOptions, SizeInfo } from '@/types';
5
+ import { BaseAdapter } from "../../core/BaseAdapter.js";
6
+ import type { StorageType, StorageCapabilities, StorageValue, ClearOptions, SizeInfo } from "../../types/index.js";
7
7
  /**
8
8
  * Native preferences adapter using Capacitor plugin
9
9
  */
@@ -1 +1 @@
1
- {"version":3,"file":"PreferencesAdapter.d.ts","sourceRoot":"","sources":["../../../src/adapters/capacitor/PreferencesAdapter.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,KAAK,EACV,WAAW,EACX,mBAAmB,EACnB,YAAY,EACZ,YAAY,EACZ,QAAQ,EACT,MAAM,SAAS,CAAC;AAMjB;;GAEG;AACH,qBAAa,kBAAmB,SAAQ,WAAW;IACjD,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAiB;IAC3C,QAAQ,CAAC,YAAY,EAAE,mBAAmB,CAUxC;IAEF;;OAEG;IACG,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC;IAWrC;;OAEG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAIjC;;OAEG;IACG,GAAG,CAAC,CAAC,GAAG,OAAO,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;IAwBpE;;OAEG;IACG,GAAG,CAAC,CAAC,GAAG,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,YAAY,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAgB1E;;OAEG;IACG,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAiBxC;;OAEG;IACG,KAAK,CAAC,OAAO,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAiBlD;;OAEG;IACG,IAAI,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAwBxD;;OAEG;IACG,IAAI,CAAC,QAAQ,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC;CAYlD"}
1
+ {"version":3,"file":"PreferencesAdapter.d.ts","sourceRoot":"","sources":["../../../src/adapters/capacitor/PreferencesAdapter.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,KAAK,EACV,WAAW,EACX,mBAAmB,EACnB,YAAY,EACZ,YAAY,EACZ,QAAQ,EACT,MAAM,SAAS,CAAC;AAMjB;;GAEG;AACH,qBAAa,kBAAmB,SAAQ,WAAW;IACjD,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAiB;IAC3C,QAAQ,CAAC,YAAY,EAAE,mBAAmB,CAUxC;IAEF;;OAEG;IACG,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC;IAWrC;;OAEG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAIjC;;OAEG;IACG,GAAG,CAAC,CAAC,GAAG,OAAO,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;IAwBpE;;OAEG;IACG,GAAG,CAAC,CAAC,GAAG,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,YAAY,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAkB1E;;OAEG;IACG,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAmBxC;;OAEG;IACG,KAAK,CAAC,OAAO,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAiBlD;;OAEG;IACG,IAAI,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAwBxD;;OAEG;IACG,IAAI,CAAC,QAAQ,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC;CAYlD"}
@@ -71,7 +71,9 @@ export class PreferencesAdapter extends BaseAdapter {
71
71
  * Set a value in preferences
72
72
  */
73
73
  async set(key, value) {
74
- const oldValue = await this.get(key);
74
+ // Only pay for a read-before-write (a native bridge round-trip) when a
75
+ // subscriber actually needs the previous value for the change event.
76
+ const oldValue = this.hasChangeListeners() ? await this.get(key) : null;
75
77
  try {
76
78
  await StrataStorage.set({
77
79
  key,
@@ -88,7 +90,9 @@ export class PreferencesAdapter extends BaseAdapter {
88
90
  * Remove a value from preferences
89
91
  */
90
92
  async remove(key) {
91
- const oldValue = await this.get(key);
93
+ // Only pay for a read-before-write (a native bridge round-trip) when a
94
+ // subscriber actually needs the previous value for the change event.
95
+ const oldValue = this.hasChangeListeners() ? await this.get(key) : null;
92
96
  try {
93
97
  await StrataStorage.remove({
94
98
  key,
@@ -2,8 +2,8 @@
2
2
  * Secure Adapter - Native secure storage
3
3
  * iOS: Keychain, Android: EncryptedSharedPreferences
4
4
  */
5
- import { BaseAdapter } from '@/core/BaseAdapter';
6
- import type { StorageType, StorageCapabilities, StorageValue, ClearOptions, SizeInfo } from '@/types';
5
+ import { BaseAdapter } from "../../core/BaseAdapter.js";
6
+ import type { StorageType, StorageCapabilities, StorageValue, ClearOptions, SizeInfo } from "../../types/index.js";
7
7
  /**
8
8
  * Native secure storage adapter using Capacitor plugin
9
9
  */
@@ -48,7 +48,7 @@ export declare class SecureAdapter extends BaseAdapter {
48
48
  setKeychainItem(key: string, value: string, options?: {
49
49
  service?: string;
50
50
  accessGroup?: string;
51
- accessible?: import('@/plugin/definitions').KeychainAccessible;
51
+ accessible?: import("../../plugin/definitions.js").KeychainAccessible;
52
52
  }): Promise<void>;
53
53
  /**
54
54
  * iOS-specific: Get from Keychain
@@ -1 +1 @@
1
- {"version":3,"file":"SecureAdapter.d.ts","sourceRoot":"","sources":["../../../src/adapters/capacitor/SecureAdapter.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,KAAK,EACV,WAAW,EACX,mBAAmB,EACnB,YAAY,EACZ,YAAY,EACZ,QAAQ,EACT,MAAM,SAAS,CAAC;AAMjB;;GAEG;AACH,qBAAa,aAAc,SAAQ,WAAW;IAC5C,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAY;IACtC,QAAQ,CAAC,YAAY,EAAE,mBAAmB,CAUxC;IAEF;;OAEG;IACG,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC;IAWrC;;OAEG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAIjC;;OAEG;IACG,GAAG,CAAC,CAAC,GAAG,OAAO,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;IAwBpE;;OAEG;IACG,GAAG,CAAC,CAAC,GAAG,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,YAAY,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAgB1E;;OAEG;IACG,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAiBxC;;OAEG;IACG,KAAK,CAAC,OAAO,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAiBlD;;OAEG;IACG,IAAI,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAwBxD;;OAEG;IACG,IAAI,CAAC,QAAQ,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC;IAajD;;OAEG;IACG,eAAe,CACnB,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,MAAM,EACb,OAAO,CAAC,EAAE;QACR,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,UAAU,CAAC,EAAE,OAAO,sBAAsB,EAAE,kBAAkB,CAAC;KAChE,GACA,OAAO,CAAC,IAAI,CAAC;IAYhB;;OAEG;IACG,eAAe,CACnB,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE;QACR,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,WAAW,CAAC,EAAE,MAAM,CAAC;KACtB,GACA,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAazB;;OAEG;IACG,sBAAsB,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAY3F;;OAEG;IACG,sBAAsB,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;CAY/E"}
1
+ {"version":3,"file":"SecureAdapter.d.ts","sourceRoot":"","sources":["../../../src/adapters/capacitor/SecureAdapter.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,KAAK,EACV,WAAW,EACX,mBAAmB,EACnB,YAAY,EACZ,YAAY,EACZ,QAAQ,EACT,MAAM,SAAS,CAAC;AAMjB;;GAEG;AACH,qBAAa,aAAc,SAAQ,WAAW;IAC5C,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAY;IACtC,QAAQ,CAAC,YAAY,EAAE,mBAAmB,CAUxC;IAEF;;OAEG;IACG,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC;IAWrC;;OAEG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAIjC;;OAEG;IACG,GAAG,CAAC,CAAC,GAAG,OAAO,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;IAwBpE;;OAEG;IACG,GAAG,CAAC,CAAC,GAAG,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,YAAY,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAkB1E;;OAEG;IACG,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAmBxC;;OAEG;IACG,KAAK,CAAC,OAAO,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAiBlD;;OAEG;IACG,IAAI,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAwBxD;;OAEG;IACG,IAAI,CAAC,QAAQ,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC;IAajD;;OAEG;IACG,eAAe,CACnB,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,MAAM,EACb,OAAO,CAAC,EAAE;QACR,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,UAAU,CAAC,EAAE,OAAO,sBAAsB,EAAE,kBAAkB,CAAC;KAChE,GACA,OAAO,CAAC,IAAI,CAAC;IAYhB;;OAEG;IACG,eAAe,CACnB,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE;QACR,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,WAAW,CAAC,EAAE,MAAM,CAAC;KACtB,GACA,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAazB;;OAEG;IACG,sBAAsB,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAY3F;;OAEG;IACG,sBAAsB,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;CAY/E"}
@@ -71,7 +71,9 @@ export class SecureAdapter extends BaseAdapter {
71
71
  * Set a value in secure storage
72
72
  */
73
73
  async set(key, value) {
74
- const oldValue = await this.get(key);
74
+ // Only pay for a read-before-write (a native bridge round-trip) when a
75
+ // subscriber actually needs the previous value for the change event.
76
+ const oldValue = this.hasChangeListeners() ? await this.get(key) : null;
75
77
  try {
76
78
  await StrataStorage.set({
77
79
  key,
@@ -88,7 +90,9 @@ export class SecureAdapter extends BaseAdapter {
88
90
  * Remove a value from secure storage
89
91
  */
90
92
  async remove(key) {
91
- const oldValue = await this.get(key);
93
+ // Only pay for a read-before-write (a native bridge round-trip) when a
94
+ // subscriber actually needs the previous value for the change event.
95
+ const oldValue = this.hasChangeListeners() ? await this.get(key) : null;
92
96
  try {
93
97
  await StrataStorage.remove({
94
98
  key,
@@ -2,8 +2,8 @@
2
2
  * SQLite Adapter - Native SQLite database storage
3
3
  * Available on iOS and Android
4
4
  */
5
- import { BaseAdapter } from '@/core/BaseAdapter';
6
- import type { StorageType, StorageCapabilities, StorageValue, ClearOptions, SizeInfo, QueryCondition, Transaction } from '@/types';
5
+ import { BaseAdapter } from "../../core/BaseAdapter.js";
6
+ import type { StorageType, StorageCapabilities, StorageValue, ClearOptions, SizeInfo, QueryCondition, Transaction } from "../../types/index.js";
7
7
  /**
8
8
  * Configuration options for SQLite adapter
9
9
  */
@@ -61,7 +61,28 @@ export declare class SqliteAdapter extends BaseAdapter {
61
61
  */
62
62
  size(detailed?: boolean): Promise<SizeInfo>;
63
63
  /**
64
- * Begin a transaction
64
+ * Reclaim expired rows in a single native round-trip and return the count.
65
+ *
66
+ * Because `keys()` and `query()` now exclude expired rows in SQL (there is no
67
+ * lazy per-key deletion on read anymore), this is what physically deletes
68
+ * them — driven by both the automatic TTL tick and `Strata.cleanupExpired()`.
69
+ *
70
+ * If the native bulk delete is present but fails at runtime, we log and return
71
+ * 0 (reads stay correct — expired rows are filtered — and the next tick
72
+ * retries); we deliberately do NOT fall back to the base per-key sweep, which
73
+ * cannot see expired rows on a build whose `keys()` already filters them. The
74
+ * base sweep is used only when no native bulk delete exists at all (an older
75
+ * native build whose `keys()` still surfaces expired rows).
76
+ */
77
+ cleanupExpired(): Promise<number>;
78
+ /**
79
+ * Begin a transaction.
80
+ *
81
+ * NOTE: this is a best-effort batch, not an atomic native SQLite transaction.
82
+ * Operations are queued and executed sequentially on commit(); there is no
83
+ * native BEGIN/COMMIT/ROLLBACK across the connection, so a failure midway
84
+ * cannot roll back already-applied writes. `capabilities.transactional` is
85
+ * therefore reported as `false`.
65
86
  */
66
87
  transaction(): Promise<Transaction>;
67
88
  }
@@ -1 +1 @@
1
- {"version":3,"file":"SqliteAdapter.d.ts","sourceRoot":"","sources":["../../../src/adapters/capacitor/SqliteAdapter.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,KAAK,EACV,WAAW,EACX,mBAAmB,EACnB,YAAY,EACZ,YAAY,EACZ,QAAQ,EACR,cAAc,EACd,WAAW,EACZ,MAAM,SAAS,CAAC;AAMjB;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,qBAAa,aAAc,SAAQ,WAAW;IAC5C,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAY;IACtC,QAAQ,CAAC,YAAY,EAAE,mBAAmB,CAUxC;IAEF,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,KAAK,CAAS;gBAEV,MAAM,GAAE,YAAiB;IAMrC;;OAEG;IACG,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC;IAWrC;;OAEG;IACG,UAAU,CAAC,MAAM,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAOtD;;OAEG;IACG,GAAG,CAAC,CAAC,GAAG,OAAO,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;IA0BpE;;OAEG;IACG,GAAG,CAAC,CAAC,GAAG,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,YAAY,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAkB1E;;OAEG;IACG,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAmBxC;;OAEG;IACG,KAAK,CAAC,OAAO,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAmBlD;;OAEG;IACG,IAAI,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IA0BxD;;OAEG;IACG,KAAK,CAAC,CAAC,GAAG,OAAO,EAAE,SAAS,EAAE,cAAc,GAAG,OAAO,CAAC,KAAK,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,CAAC,CAAA;KAAE,CAAC,CAAC;IA4B9F;;OAEG;IACG,IAAI,CAAC,QAAQ,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC;IAejD;;OAEG;IACG,WAAW,IAAI,OAAO,CAAC,WAAW,CAAC;CAK1C"}
1
+ {"version":3,"file":"SqliteAdapter.d.ts","sourceRoot":"","sources":["../../../src/adapters/capacitor/SqliteAdapter.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,KAAK,EACV,WAAW,EACX,mBAAmB,EACnB,YAAY,EACZ,YAAY,EACZ,QAAQ,EACR,cAAc,EACd,WAAW,EACZ,MAAM,SAAS,CAAC;AAMjB;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAyBD;;GAEG;AACH,qBAAa,aAAc,SAAQ,WAAW;IAC5C,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAY;IACtC,QAAQ,CAAC,YAAY,EAAE,mBAAmB,CAcxC;IAEF,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,KAAK,CAAS;gBAEV,MAAM,GAAE,YAAiB;IAQrC;;OAEG;IACG,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC;IAWrC;;OAEG;IACG,UAAU,CAAC,MAAM,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAatD;;OAEG;IACG,GAAG,CAAC,CAAC,GAAG,OAAO,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;IA0BpE;;OAEG;IACG,GAAG,CAAC,CAAC,GAAG,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,YAAY,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAoB1E;;OAEG;IACG,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAqBxC;;OAEG;IACG,KAAK,CAAC,OAAO,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAmBlD;;OAEG;IACG,IAAI,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAmBxD;;OAEG;IACG,KAAK,CAAC,CAAC,GAAG,OAAO,EAAE,SAAS,EAAE,cAAc,GAAG,OAAO,CAAC,KAAK,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,CAAC,CAAA;KAAE,CAAC,CAAC;IA0C9F;;OAEG;IACG,IAAI,CAAC,QAAQ,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC;IAejD;;;;;;;;;;;;;OAaG;IACG,cAAc,IAAI,OAAO,CAAC,MAAM,CAAC;IAiBvC;;;;;;;;OAQG;IACG,WAAW,IAAI,OAAO,CAAC,WAAW,CAAC;CAG1C"}
@@ -7,6 +7,25 @@ import { StrataStorage } from "../../plugin/index.js";
7
7
  import { StorageError, TransactionError } from "../../utils/errors.js";
8
8
  import { isCapacitor } from "../../utils/index.js";
9
9
  import { logger } from "../../utils/logger.js";
10
+ /**
11
+ * Strict SQL-identifier allow-list for the `database` (file stem) and `table`
12
+ * names. These two cannot be bound as parameters, so they are the only place a
13
+ * SQL injection could occur; everything else (keys, values) is bound.
14
+ */
15
+ const SQLITE_IDENTIFIER = /^[A-Za-z_][A-Za-z0-9_]*$/;
16
+ /**
17
+ * Reject — loudly — any `database`/`table` that is not a strict SQL identifier,
18
+ * instead of silently stripping illegal characters (which could let two
19
+ * distinct logical stores collapse into one physical table). This is the
20
+ * authoritative guard: hostile identifiers never reach the native layer, which
21
+ * also applies the same allow-list as defense-in-depth.
22
+ */
23
+ function assertValidIdentifier(kind, value) {
24
+ if (!SQLITE_IDENTIFIER.test(value)) {
25
+ throw new StorageError(`Invalid SQLite ${kind} name "${value}": must match ${SQLITE_IDENTIFIER.source} ` +
26
+ '(letters, digits and underscore only, not starting with a digit).');
27
+ }
28
+ }
10
29
  /**
11
30
  * Native SQLite adapter using Capacitor plugin
12
31
  */
@@ -16,7 +35,11 @@ export class SqliteAdapter extends BaseAdapter {
16
35
  persistent: true,
17
36
  synchronous: false,
18
37
  observable: false,
19
- transactional: true,
38
+ // `transaction()` queues operations and runs them sequentially on commit();
39
+ // it is NOT a single atomic native SQLite transaction (no BEGIN/COMMIT/
40
+ // ROLLBACK across the connection), so we report this honestly. See the
41
+ // SqliteTransaction note below.
42
+ transactional: false,
20
43
  queryable: true,
21
44
  maxSize: -1, // Limited by device storage
22
45
  binary: true,
@@ -29,6 +52,8 @@ export class SqliteAdapter extends BaseAdapter {
29
52
  super();
30
53
  this.database = config.database || 'strata_storage';
31
54
  this.table = config.table || 'storage';
55
+ assertValidIdentifier('database', this.database);
56
+ assertValidIdentifier('table', this.table);
32
57
  }
33
58
  /**
34
59
  * Check if SQLite is available
@@ -48,10 +73,14 @@ export class SqliteAdapter extends BaseAdapter {
48
73
  * Initialize the adapter
49
74
  */
50
75
  async initialize(config) {
51
- if (config?.database)
76
+ if (config?.database) {
77
+ assertValidIdentifier('database', config.database);
52
78
  this.database = config.database;
53
- if (config?.table)
79
+ }
80
+ if (config?.table) {
81
+ assertValidIdentifier('table', config.table);
54
82
  this.table = config.table;
83
+ }
55
84
  this.startTTLCleanup();
56
85
  }
57
86
  /**
@@ -84,7 +113,9 @@ export class SqliteAdapter extends BaseAdapter {
84
113
  * Set a value in SQLite
85
114
  */
86
115
  async set(key, value) {
87
- const oldValue = await this.get(key);
116
+ // Only pay for a read-before-write (a native bridge round-trip) when a
117
+ // subscriber actually needs the previous value for the change event.
118
+ const oldValue = this.hasChangeListeners() ? await this.get(key) : null;
88
119
  try {
89
120
  await StrataStorage.set({
90
121
  key,
@@ -103,7 +134,9 @@ export class SqliteAdapter extends BaseAdapter {
103
134
  * Remove a value from SQLite
104
135
  */
105
136
  async remove(key) {
106
- const oldValue = await this.get(key);
137
+ // Only pay for a read-before-write (a native bridge round-trip) when a
138
+ // subscriber actually needs the previous value for the change event.
139
+ const oldValue = this.hasChangeListeners() ? await this.get(key) : null;
107
140
  try {
108
141
  await StrataStorage.remove({
109
142
  key,
@@ -151,16 +184,11 @@ export class SqliteAdapter extends BaseAdapter {
151
184
  table: this.table,
152
185
  pattern: pattern instanceof RegExp ? pattern.source : pattern,
153
186
  });
154
- const keys = result.keys;
155
- // Check for expired keys
156
- const validKeys = [];
157
- for (const key of keys) {
158
- const value = await this.get(key);
159
- if (value) {
160
- validKeys.push(key);
161
- }
162
- }
163
- return this.filterKeys(validKeys, pattern);
187
+ // The native layer excludes expired rows in SQL (a single round-trip),
188
+ // so there is no per-key `get()` loop here. We still run `filterKeys`
189
+ // for the adapter's exact prefix/glob/RegExp semantics — native `LIKE`
190
+ // is only a coarse pre-filter.
191
+ return this.filterKeys(result.keys, pattern);
164
192
  }
165
193
  catch (error) {
166
194
  throw new StorageError(`Failed to get keys from SQLite: ${error}`);
@@ -180,12 +208,27 @@ export class SqliteAdapter extends BaseAdapter {
180
208
  table: this.table,
181
209
  condition,
182
210
  });
183
- // Filter expired entries
211
+ // The native layer returns the full non-expired wrapper for every
212
+ // candidate row in ONE round-trip, so the real query filter runs here in
213
+ // JS (mirroring BaseAdapter.query) without an N+1 `get()` per key.
214
+ const isStorageQuery = this.isStorageMetadataQuery(condition);
215
+ const normalizedCondition = isStorageQuery
216
+ ? condition
217
+ : this.normalizeValueQueryCondition(condition);
184
218
  const validResults = [];
185
219
  for (const item of result.results) {
186
- const value = await this.get(item.key);
187
- if (value) {
188
- validResults.push({ key: item.key, value: value.value });
220
+ // Use the batched wrapper; fall back to a per-key `get()` only for
221
+ // older native builds that surface keys alone (item.value undefined).
222
+ const stored = item.value ?? (await this.get(item.key));
223
+ if (!stored)
224
+ continue; // missing
225
+ if (this.isExpired(stored))
226
+ continue; // defensive: native already filters
227
+ const matches = isStorageQuery
228
+ ? this.queryEngine.matches(stored, normalizedCondition)
229
+ : this.queryEngine.matches(stored.value, normalizedCondition);
230
+ if (matches) {
231
+ validResults.push({ key: item.key, value: stored.value });
189
232
  }
190
233
  }
191
234
  return validResults;
@@ -212,16 +255,55 @@ export class SqliteAdapter extends BaseAdapter {
212
255
  }
213
256
  }
214
257
  /**
215
- * Begin a transaction
258
+ * Reclaim expired rows in a single native round-trip and return the count.
259
+ *
260
+ * Because `keys()` and `query()` now exclude expired rows in SQL (there is no
261
+ * lazy per-key deletion on read anymore), this is what physically deletes
262
+ * them — driven by both the automatic TTL tick and `Strata.cleanupExpired()`.
263
+ *
264
+ * If the native bulk delete is present but fails at runtime, we log and return
265
+ * 0 (reads stay correct — expired rows are filtered — and the next tick
266
+ * retries); we deliberately do NOT fall back to the base per-key sweep, which
267
+ * cannot see expired rows on a build whose `keys()` already filters them. The
268
+ * base sweep is used only when no native bulk delete exists at all (an older
269
+ * native build whose `keys()` still surfaces expired rows).
270
+ */
271
+ async cleanupExpired() {
272
+ if (StrataStorage.cleanupExpired) {
273
+ try {
274
+ const result = await StrataStorage.cleanupExpired({
275
+ storage: 'sqlite',
276
+ database: this.database,
277
+ table: this.table,
278
+ });
279
+ return result.removed;
280
+ }
281
+ catch (error) {
282
+ logger.error('Native SQLite cleanupExpired failed; will retry next tick:', error);
283
+ return 0;
284
+ }
285
+ }
286
+ return super.cleanupExpired();
287
+ }
288
+ /**
289
+ * Begin a transaction.
290
+ *
291
+ * NOTE: this is a best-effort batch, not an atomic native SQLite transaction.
292
+ * Operations are queued and executed sequentially on commit(); there is no
293
+ * native BEGIN/COMMIT/ROLLBACK across the connection, so a failure midway
294
+ * cannot roll back already-applied writes. `capabilities.transactional` is
295
+ * therefore reported as `false`.
216
296
  */
217
297
  async transaction() {
218
- // Transactions are handled natively
219
- // For now, return a simple implementation
220
298
  return new SqliteTransaction(this);
221
299
  }
222
300
  }
223
301
  /**
224
- * SQLite transaction implementation
302
+ * SQLite transaction implementation.
303
+ *
304
+ * Best-effort sequential batch (see SqliteAdapter.transaction): rollback() only
305
+ * discards queued-but-not-yet-committed operations; it cannot undo writes that
306
+ * commit() has already applied. Do not rely on this for atomic multi-key writes.
225
307
  */
226
308
  class SqliteTransaction {
227
309
  adapter;
@@ -2,8 +2,8 @@
2
2
  * Capacitor Native Storage Adapters
3
3
  * Export all native platform storage implementations
4
4
  */
5
- export { PreferencesAdapter } from './PreferencesAdapter';
6
- export { SqliteAdapter } from './SqliteAdapter';
7
- export { SecureAdapter } from './SecureAdapter';
8
- export { FilesystemAdapter } from './FilesystemAdapter';
5
+ export { PreferencesAdapter } from "./PreferencesAdapter.js";
6
+ export { SqliteAdapter } from "./SqliteAdapter.js";
7
+ export { SecureAdapter } from "./SecureAdapter.js";
8
+ export { FilesystemAdapter } from "./FilesystemAdapter.js";
9
9
  //# sourceMappingURL=index.d.ts.map
@@ -2,8 +2,8 @@
2
2
  * Cache Adapter - Service Worker Cache API implementation
3
3
  * Provides network-aware storage for offline support
4
4
  */
5
- import { BaseAdapter } from '@/core/BaseAdapter';
6
- import type { StorageType, StorageCapabilities, StorageValue, ClearOptions, SizeInfo, QueryCondition } from '@/types';
5
+ import { BaseAdapter } from "../../core/BaseAdapter.js";
6
+ import type { StorageType, StorageCapabilities, StorageValue, ClearOptions, SizeInfo, QueryCondition } from "../../types/index.js";
7
7
  /**
8
8
  * Cache API adapter for Service Worker environments
9
9
  */