BotConfig.durability. Every field is optional; {} enables durability with the in-memory backend.
Properties
backend?
MemoryDurability, FileDurability, or a store’s
backend (new PostgresDurability({ pool }) from @botmesh/postgres-store,
new RedisDurability({ client }) from @botmesh/redis-store, SQLiteStore#durability(),
or a KvDurability over any DurableKv). Default: a new
MemoryDurability (survives nothing but redeliveries within the process).
journal?
Deprecated
Use DurabilityConfig.backend (same value; the old name of the option). Setting both to different backends throws aConfigValidationError.
instanceId?
<hostname>/<botId>/<connectionId> on a single-process backend (memory, file);
on a shared backend (Postgres, Redis) that id plus a per-boot suffix, so two processes
on one host never share it — a restart then waits for the old leases to expire.
failOpen?
false (default): when the journal cannot record an inbound event, the event is NOT
dispatched (fail-closed) — an 'error' is emitted and the dedupe key is released so
a transport redelivery is processed. true: dispatch it without the journal.
inbox?
leaseMs?
60_000 ms.
maxAttempts?
5.
backoff?
{ baseMs: 1000, capMs: 60000, jitter: 0.2 }.
mediaRefs?
IProvider.serializeMediaRef)
so a replayed message (crash recovery, background retry) can still download it
(IProvider.rehydrateMediaRef). Only applies to providers with those hooks. The
reference grants access to the media, like the message body stored next to it.
false: journal media tokens as they are, as before (a replayed message may then be
unable to download its media). Default true.
outbox?
retries?
5.
backoff?
RateLimitedError waits at least its retryAfterMs). Default as inbox.backoff.
inlineMaxMs?
ctx.reply / bot.send keeps retrying inline before it rejects with
SendDeferredError and leaves the send to the background sweeper. Default '15s'.
onAmbiguous?
'skip' (default) marks it unknown — possible loss, never a
duplicate; 'resend' sends it again — never a loss, possible duplicate.
maxPayloadBytes?
leaseMs?
60_000 ms.
onDiverged?
<inboundId>:<n>) took another path (e.g. a non-persistent flow lost on a crash):
'send' (default) sends the new content under a new key — never a lost reply;
'skip' answers it with the recorded ref, as if it were the same send. Explicit
idempotencyKeys are never compared: the caller names the send.
pollMs?
1000 ms.
retention?
done/sent records this long before the sweeper purges them. It bounds how long
a late transport redelivery is still recognised as a duplicate. Default '7d'; 0 disables purging.