# `memory.ts` — default in-memory `DeadLetterSink` ## Purpose Provides the default `DeadLetterSink` implementation shipped with the plugin: an unbounded `Array` backed sink suitable for tests and development environments. The list is most-recent-first via `unshift`, so a caller invoking `list({ limit: 10 })` always sees the ten most-recent exhausted deliveries. Production deployments typically configure a sibling sink (S3, Postgres, Mailpit) so dead letters survive process restart; this implementation exists so the plugin can boot with zero configuration and so tests can assert exhaustion behavior without standing up storage. ## Features - `record` is a single `unshift` — O(1) on every write. - `list` walks the array applying the optional `endpointId` filter and `limit` cap; returns a frozen-by-array slice. - No bounded capacity — operators relying on the in-memory sink in long-running services should rotate the plugin or wire a durable sibling. ## Usage: Basic ```ts import { MemoryDeadLetterSink } from "@suaveplan/api-plugin-webhook/dead-letter/memory"; const sink = new MemoryDeadLetterSink(); const failed = await sink.list(); ``` ## Usage: Advanced ```ts import { MemoryDeadLetterSink } from "@suaveplan/api-plugin-webhook/dead-letter/memory"; const sink = new MemoryDeadLetterSink(); await sink.record({ id: "dl-1", endpointId: "ep-1", tenantId: null, event: "order.created", payload: { id: "w-1", event: "order.created", data: {}, timestamp: "..." }, attempts: [], firstAttemptAt: "2026-05-18T00:00:00.000Z", finalAttemptAt: "2026-05-18T00:00:00.000Z", reason: "5x HTTP 500", }); const onlyForEp1 = await sink.list({ endpointId: "ep-1", limit: 5 }); console.log(onlyForEp1.length); // 1 ``` ## API Reference - `new MemoryDeadLetterSink()` — no constructor arguments. - `record(entry)` — pushes the entry to the front of the internal array. - `list(filter?)` — applies the optional `endpointId` and `limit` filter and returns a snapshot. Most-recent first. ## Implementation Notes Because the sink is an unbounded array in process memory, it must NOT be used as the durable record in production systems. The plugin docs flag this — operators wire a durable sibling sink or a composite sink that records to both memory (for fast inspection) and durable storage. The implementation chose `unshift` over `push` so consumers do not need to compute `reverse()` for the "most-recent first" view that operators want; the small cost (O(n) per insert) is acceptable for the in-memory implementation's intended use case.