Skip to content

3.0.1

Latest

Choose a tag to compare

@unadlib unadlib released this 29 Sep 10:46

LocalSpace 3.0.1

A patch release that fixes data-loss and hang bugs in 3.0.0, hardens the encryption plugin, and speeds up IndexedDB transactions. Stored data formats are unchanged: 3.0.1 reads everything 3.0.0 and 2.x wrote, and the pinned 2.1.1 rollback bridge still reads what 3.0.1 writes (unless you opt into the new bindStorageKey option).

Upgrade notes

Most apps can upgrade without changes. Review these items first:

  • Encrypted stores containing plaintext: reading a value that is not an encrypted payload through encryptionPlugin now rejects with DESERIALIZATION_FAILED (details.reason: 'unencrypted-value') instead of returning it. If a store still holds values written before encryption was enabled, read them through an instance created with allowPlaintext: true and rewrite them.
  • Encryption configuration: ivLength below 12 bytes and an AES-GCM tagLength outside 96, 104, 112, 120, or 128 bits now throw INVALID_CONFIG.
  • key(index): indexes that are not safe integers (NaN, Infinity, fractions) now reject with INVALID_ARGUMENT. Negative or out-of-range integers still return null.
  • TTLPluginOptions.cleanupBatchSize is deprecated and has no effect.

Security

  • Encrypted instances now reject stored values that are not encrypted payloads instead of returning them unchanged, so values injected by anyone with storage access are no longer accepted as authentic. Use allowPlaintext: true only on a migration instance.
  • encryptionPlugin now enforces an IV of at least 96 bits and an authentication tag of at least 96 bits.
  • Serialization failures no longer log the value to the console, which could expose plaintext that the encryption plugin was about to protect.

Added

  • bindStorageKey encryption option (opt-in). Each ciphertext is authenticated against its database name, store name, and key as AES-GCM additional data, so a payload copied to another key or store fails to decrypt. Values written before enabling it stay readable until rewritten. Bound values cannot be read by 3.0.0 or the 2.1.x rollback bridge, and the option cannot be combined with algorithm.additionalData.

Fixed

  • localStorage / React Native store isolation: a default store no longer reads, counts, clears, or drops the keys of named stores that share its database name. Previously clear() on { name: 'app' } also deleted the data of { name: 'app', storeName: 'users' }. Named stores now register under localspace:stores:<name> on their first write; existing key prefixes are unchanged.
  • localStorage removal: clear() and dropInstance() could leave entries behind in Chromium, which reorders native keys after a removal. Keys are now snapshotted before removal.
  • localStorage iteration: removing entries during iterate() (including TTL expiry) no longer skips live entries. With TTL, live entries that followed expired ones could be skipped entirely.
  • React Native iteration: keys removed during iterate() are now skipped instead of being passed to the iterator as null.
  • TTL concurrent writes: TTL removes an expired key only while it still holds the value that was read, so a fresh value written concurrently by the application, another tab, or the background sweep is no longer deleted. Drivers with native transactions perform the check and removal atomically; while a transaction is active on the same instance, removal is deferred to a later read or sweep.
  • IndexedDB key() hang: key(NaN), key(Infinity), and fractional indexes previously returned a promise that never settled. IndexedDB getItem, keys, key, and length now also reject when their transaction aborts.
  • dropInstance(options) now validates and normalizes options when no plugins are registered, matching instances with plugins.
  • TTL cleanup timer is unref'd so it no longer keeps a Node.js process alive.
  • Removed the stale console warning about using the lenient error policy with compression; compression failures already propagate under every policy.

Performance

  • IndexedDB transactions: keep-alive requests now count a single probe key instead of the whole object store, so their cost no longer grows with store size. In the release benchmark, transactions went from 4.17x to 2.65x of the 2.1.0 baseline.
  • TTL background sweep: performs one logical scan per interval instead of reading and decrypting every live entry twice.

Full Changelog: v3.0.0...v3.0.1