Skip to content

feat: add atomic store updates#295

Open
brendanjryan wants to merge 14 commits intomainfrom
brendan/update-store-api
Open

feat: add atomic store updates#295
brendanjryan wants to merge 14 commits intomainfrom
brendan/update-store-api

Conversation

@brendanjryan
Copy link
Copy Markdown
Collaborator

@brendanjryan brendanjryan commented Apr 6, 2026

Summary

Add an atomic Store.update() primitive and a new AtomicStore type, then use them to eliminate race conditions in Tempo replay protection and channel state updates.

Why

The previous check-then-mark flow for replay protection and channel state mutation could race under concurrent requests or multi-instance deployments. This was an intentional choice at the time, but we now see a larger need for multi-instance deployments so want to add this primitive. AtomicStore gives store backends a typed atomic primitive and moves all sensitive Tempo paths onto it.

Notes

  • Store.update() is optional at the Store interface level but required for Tempo charge/session via AtomicStore.
  • Store.memory() always returns AtomicStore.
  • Callbacks passed to update must be synchronous, pure, and retry-safe.

@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new bot commented Apr 6, 2026

Open in StackBlitz

npm i https://pkg.pr.new/mppx@295

commit: 59bc4e1

@tempoxyz-bot
Copy link
Copy Markdown

tempoxyz-bot commented Apr 6, 2026

👁️ Cyclops Security Review

3dad711

🧭 Auditing · mode=normal · workers 0/3 done (3 left) · verify pending 0

Worker Engine Progress Status
pr-295-w1 gemini-3.1-pro-preview ✅ thread-1 ✅ thread-2 🔍 thread-3 Running
pr-295-w2 amp/deep 🔍 thread-1 · · Running
pr-295-w3 gpt-5.4 🔍 thread-1 · · Running
⚙️ Controls
  • 🚀 Keep only 1 remaining iteration per worker after the current work finishes.
  • 👀 Keep only 2 remaining iterations per worker after the current work finishes.
  • ❤️ Let only worker 1 continue; other workers skip queued iterations.
  • 😄 Let only worker 2 continue; other workers skip queued iterations.
  • 🎉 End faster by skipping queued iterations and moving toward consolidation.
  • 😕 Stop active workers/verifiers now and start consolidation immediately.

📜 7 events

🔍 pr-295-w1 iter 1/3 [audit-ripple.md]
🔍 pr-295-w2 iter 1/3 [audit-focused.md]
🔍 pr-295-w3 iter 1/3 [audit-deep-focus.md]
pr-295-w1 iter 1 — clear | Thread
🔍 pr-295-w1 iter 2/3 [audit-historical.md]
pr-295-w1 iter 2 — clear | Thread
🔍 pr-295-w1 iter 3/3 [audit-focused.md]

@brendanjryan brendanjryan force-pushed the brendan/update-store-api branch from ab1aca9 to 347da37 Compare April 6, 2026 19:47
@tempoxyz-bot
Copy link
Copy Markdown

👁️ Cyclops Security Review

6e7757a

🧭 Auditing · mode=normal · workers 0/3 done (3 left) · verify pending 0

Worker Engine Progress Status
pr-295-w1 gemini-3.1-pro-preview · · · Running
pr-295-w2 amp/deep · · · Running
pr-295-w3 gpt-5.4 · · · Running
⚙️ Controls
  • 🚀 Keep only 1 remaining iteration per worker after the current work finishes.
  • 👀 Keep only 2 remaining iterations per worker after the current work finishes.
  • ❤️ Let only worker 1 continue; other workers skip queued iterations.
  • 😄 Let only worker 2 continue; other workers skip queued iterations.
  • 🎉 End faster by skipping queued iterations and moving toward consolidation.
  • 😕 Stop active workers/verifiers now and start consolidation immediately.

@brendanjryan brendanjryan requested review from jxom and tmm April 6, 2026 21:27
@brendanjryan
Copy link
Copy Markdown
Collaborator Author

brendanjryan commented Apr 6, 2026

Refactored Store/AtomicStore to use Viem-style generic slot pattern per @tmm suggestion.

Before (structural patching):

type Store<itemMap> = { get; put; delete; update?: Update }
type AtomicStore<itemMap> = Omit<Store, "update"> & { update: Update }

After (compositional via 2nd generic slot):

type StoreActions<itemMap> = { get; put; delete }
type AtomicActions<itemMap> = { update: Update }

type Store<itemMap, extended> = StoreActions<itemMap> & extended
type AtomicStore<itemMap> = Store<itemMap, AtomicActions<itemMap>>

- Replace ChannelStore symbol hack with optional method on the type
- Extract wrapJsonUpdate helper to DRY cloudflare/redis update adapters
- Remove dead assertHashUnused (markHashUsed handles atomically)
- Simplify releaseHashUse to plain store.delete
…ypes

Instead of AtomicStore = Omit<Store, 'update'> & { update }, use a 2nd
generic slot on Store inspired by Viem's Client<..., extended> pattern:

- Store<itemMap, extended> — base type with compositional extended slot
- AtomicStore<itemMap> = Store<itemMap, AtomicActions<itemMap>>
- StoreActions — base get/put/delete interface
- AtomicActions — update capability, provided via the extended slot

This makes Store extensible for future capabilities (batch, watch, etc.)
without structural patching via Omit.
@brendanjryan brendanjryan force-pushed the brendan/update-store-api branch from 223db13 to 59bc4e1 Compare April 7, 2026 01:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants