nostrbasedocs
Start building
Guide
.md

Sign and queue a write

Sign in while your signer is available. Queue a mutation with the normal query API:

await db.auth.signInWithExtension();

const result = await db
  .from("todos")
  .upsert({ id: "task-1", title: "Work offline", done: false })
  .queue()
  .select();

console.log(result.meta?.receipts); // Queued receipts, not relay acknowledgements.

// Later, with the same author signed in:
const replay = await db.offline.flush();

queue() checks the local cache and signs immediately. It cannot guarantee an insert is globally unique. The signed event enters the queue before it enters the optimistic cache. An IndexedDB-backed queue survives restart; the default queue is in memory unless a persistent adapter is supplied.

For protocol-specific events that you have already signed:

const queued = await db.offline.enqueueSigned(signedEvent);
const entries = await db.offline.list();
await db.offline.remove(signedEvent.id);

enqueueSigned() verifies the signature and requires the event’s author to match the signed-in user. Ephemeral events cannot be queued. Queue receipts include queued: true and persisted: true, which means the selected adapter accepted the entry. The memory adapter is not durable storage.

Replay sends exactly the saved event. It never requests a new signature, changes timestamps, publishes other authors’ cached events, or retries a different account’s queue entries. Rejected writes stay queued with attempt counts and the latest relay receipts. A write leaves the queue once the current client’s minWriteAcks requirement is met.

const controller = new AbortController();
const replay = db.offline.flush({ signal: controller.signal });
controller.abort();
await replay;

Cancellation stops further work. A relay can have accepted an event before cancellation or before an acknowledgement is lost. Replaying the same event ID handles that case. Removing an entry stops its future delivery. Its optimistic signed event remains in the cache, including a persistent cache. Removal does not roll back record state or send a Nostr deletion request. To inspect relay-confirmed state after removal, create a separate client with a fresh empty cache and pull from the relays. A same-cache restart retains the optimistic event.

Replay is manual by default. Set offline.autoReplay: true or call db.offline.startAutoReplay() to enable replay after sign-in, durable enqueue, browser online, and configured relay connection. See automatic replay for retry options, receipts, cancellation, and private group recovery. Multiple tabs can retry an identical event; the SDK does not provide a distributed queue lock. Signed writes can lose to newer record versions published by another device.

Search guides, API methods, and protocols.