libp2r2p 0.10.22 → 0.10.23

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -820,6 +820,24 @@ The NIP-94 extension also carries optional `download` intent; see
820
820
 
821
821
  ## Reliable IndexedDB queue reservations
822
822
 
823
+ `queue.putBy(indexName, item, { existingOnly = false })` atomically inserts or
824
+ replaces an item through a declared unique, non-multiEntry index. Its key is
825
+ extracted from the item's index keyPath, including nested paths and compound
826
+ keys. Existing items retain their position; new keys append to the tail. It
827
+ returns `true` after commit, or `false` without inserting when `existingOnly`
828
+ is true and the key is absent. This allows late progress checkpoints to avoid
829
+ recreating a cancelled record. Values are cloned before asynchronous work.
830
+
831
+ Unknown, non-unique or multiEntry indexes throw `ValidationError` with
832
+ `QUEUE_PUT_INDEX_INVALID`; missing or invalid IndexedDB keys use
833
+ `QUEUE_PUT_KEY_INVALID`. Cloning, storage and other unique-index failures retain
834
+ their operational errors. Lookup, replacement and byte accounting share one
835
+ transaction and roll back together. Capacity policy matches `setAt` for a
836
+ replacement and `push` for an insertion. Replacing a reserved item invalidates
837
+ the old token: its `ack`, `nack` and `renew` return false. Successful writes wake
838
+ local waiting consumers. Like the other indexed methods, `putBy` is exclusive
839
+ to `idb-queue`; the Web Storage queue's common API is unchanged.
840
+
823
841
  `createQueue({ prefix, evictionPolicy: 'reject', maxBytes })` opts out of
824
842
  capacity eviction. Oversized items reject with `QUEUE_ITEM_TOO_LARGE`, full
825
843
  queues with `QUEUE_CAPACITY_EXCEEDED`; browser quota errors propagate without
@@ -725,6 +725,34 @@ export async function createQueue ({
725
725
  })
726
726
  }
727
727
 
728
+ async function putBy (indexName, item, { existingOnly = false } = {}) {
729
+ const definition = indexDefinitions.find(index => index.name === indexName)
730
+ if (!definition?.unique || definition.multiEntry) throw new ValidationError('QUEUE_PUT_INDEX_INVALID')
731
+ // Snapshot before awaiting IndexedDB so the lookup key and stored value
732
+ // cannot diverge if the caller changes its object during the transaction.
733
+ const value = structuredClone(item)
734
+ const readKey = path => path.split('.').reduce((part, key) => part?.[key], value)
735
+ const key = Array.isArray(definition.keyPath) ? definition.keyPath.map(readKey) : readKey(definition.keyPath)
736
+ try { indexedDB.cmp(key, key) } catch { throw new ValidationError('QUEUE_PUT_KEY_INVALID') }
737
+ const requiredBytes = itemForStorage(0, value).byteSize
738
+ const written = await mutate(async (tx, state) => {
739
+ const { result: previous } = await run('get', [key], ITEMS_STORE, indexName, { tx })
740
+ if (previous) {
741
+ const index = previous.position - state.head
742
+ await putItem(tx, state, previous.position, value, {
743
+ direction: evictionDirectionFor('setAt', { index, length: state.tail - state.head }),
744
+ protectedPositions: new Set([previous.position])
745
+ })
746
+ } else {
747
+ if (existingOnly) return false
748
+ await pushInTransaction(tx, state, value)
749
+ }
750
+ return true
751
+ }, { requiredBytes })
752
+ if (written) wake()
753
+ return written
754
+ }
755
+
728
756
  async function getBy (indexName, query) {
729
757
  // Explicit index operations avoid scanning queue values in JavaScript.
730
758
  return snapshot(async tx => {
@@ -899,6 +927,7 @@ export async function createQueue ({
899
927
  removeWhere,
900
928
  some,
901
929
  clear,
930
+ putBy,
902
931
  getBy,
903
932
  someBy,
904
933
  removeBy,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "libp2r2p",
3
- "version": "0.10.22",
3
+ "version": "0.10.23",
4
4
  "description": "Peer-to-relay-to-peer",
5
5
  "keywords": [
6
6
  "p2r2p",