Docs

Never lose a save

This is the reason Eidos exists. Reads are nice. Surviving a flaky Save is the product.

Next: Read offline →

The one option that matters

createOrder.ts
import { action } from '@sweidos/eidos'
import type { ActionContext } from '@sweidos/eidos'
export const createOrder = action(
async (payload, ctx: ActionContext) => {
const res = await fetch('/api/orders', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Idempotency-Key': ctx.idempotencyKey, // ← same ticket on every retry
},
body: JSON.stringify(payload),
})
return res.json()
},
{
reliability: 'neverLose', // ← keep the click
name: 'createOrder', // ← registration id after reload (not the ticket)
},
)
  • Set reliability to neverLose — persist to IndexedDB before / around the network call.
  • Give every action a stable name so replay works after a full page reload.
  • Forward ctx.idempotencyKey as Idempotency-Key (or in the body) so retries do not double-charge.
  • Optional later: priority, maxRetries, conflict, optimistic callbacks.

What you see in the UI

result shapes
const result = await createOrder(payload)
// Online + success → your function's return value
// Offline / flaky → { queued: true, id, message, idempotencyKey }

Show a calm “Saved — syncing when online” toast when 'queued' in result. Do not pretend the server already confirmed the order.

Your server’s one job

Eidos delivers at least once. A retry after a dropped response may hit your API twice. Deduplicate with the stable idempotencyKey from ActionContext (also on QueuedResult when offline).

server sketch
// Prefer a dedicated Idempotency-Key header, or accept it in the body.
// Store key → response. Same key = same business result.
Full safety checklist →

Watch the queue live

Playground → Actions shows pending / failed items. Header → sim offline forces the pocket path without killing Wi‑Fi.

Open action queue