core api

#

The small set of primitives you use most

These cards keep one idea per surface so the mental model stays lightweight.

resource(url, config)

Register a GET endpoint as offline-capable and let Eidos pick the cache strategy.

cache
  • Use offline: true to enable fetch interception and cache persistence.
  • Override strategy only when you want to force a specific cache policy.
  • Add maxAge when the data should refresh after a short TTL.
resource.ts
const products = resource('/api/products', {
offline: true,
})
const data = await products.json<Product[]>()

action(fn, config)

Wrap async mutations so offline writes are persisted and replayed later.

queue
  • Use reliability: "neverLose" when dropping a write would be painful.
  • Give anonymous functions a name so replay can find them after refresh.
  • Tune maxRetries when you need a shorter or longer retry window.
  • onOptimistic updates the UI instantly; onRollback reverts if the action permanently fails.
action.ts
const createOrder = action(
async (payload: OrderPayload) => {
const res = await fetch('/api/orders', {
method: 'POST',
body: JSON.stringify(payload),
})
return res.json()
},
{
reliability: 'neverLose',
name: 'createOrder',
onOptimistic: (payload) => addOptimisticOrder(payload),
onRollback: (payload) => removeOptimisticOrder(payload),
},
)

EidosProvider

Register the SW and hydrate the runtime once near the root of the app.

root
  • Set swPath if the worker lives somewhere other than /eidos-sw.js.
  • Leave autoReplay on unless you want full manual control of queue replay.
  • Keep the provider near the root so status hooks stay available everywhere.
main.tsx
<EidosProvider swPath="/eidos-sw.js" autoReplay>
<App />
</EidosProvider>

replayQueue()

Trigger queue replay yourself when you want a manual recovery action.

replay
  • Usually runs automatically when connectivity returns.
  • Useful for a "Retry now" button or a manual sync control.
  • Returns a result summary so you can surface what happened.
recovery.ts
const result = await replayQueue()
// { attempted, succeeded, failed, retrying, skipped }

conflict (ConflictConfig)

Decide what happens when a queued write replays against state that has since changed.

replay
  • Only consulted when a replay receives a 4xx response.
  • serverWins drops the queued item; clientWins keeps retrying.
  • merge / custom call resolve(ctx) with the error, args, and attempt count.
  • Return { resolved: args } to rewrite the queued write and retry, or 'skip' to drop it.
conflict.ts
action(reserveStock, {
reliability: 'neverLose',
name: 'reserveStock',
conflict: {
strategy: 'custom',
resolve: ({ error, args }) => {
if (error instanceof StockConflictError) {
const [payload] = args
return { resolved: [{ ...payload, quantity: error.available }] }
}
return 'skip'
},
},
})