Local proof harness / npm

Send it twice.
Prove it happens once.

Rehearse duplicate, delayed, and out-of-order webhooks before they charge, email, or provision twice.

Run the rehearsal

Zero runtime dependencies · No real provider calls · No telemetry

DUPE_GATE/01ARMED
Pixel-art signal lab where two identical green event pulses enter a gate and one cyan effect pulse exits.
IN: 02 EVENTSOUT: 01 EFFECT

01Declare a sequence

02Swap safe adapters

03Assert one effect

Interactive trace

Watch the same event cross the boundary twice.

This browser demo mirrors the library’s report model. Choose a handler, then inspect every delivery and business effect.

Ready
INPUT / DELIVERIES0/2
  1. 01 order.createdkey: order_demo_042 queued
  2. 02 order.createdkey: order_demo_042 +250 ms
OUTPUT / EFFECTS0

No effects recorded yet.

Start the rehearsal to populate this trace.
    Awaiting proofTwo synthetic deliveries are ready.

    Five-minute setup

    A test artifact your CI can enforce.

    Use the in-process recorder for unit tests or point the CLI at a running local handler. Both produce the same secret-safe report.

    order.rehearsal.test.ts
    import { defineScenario, runScenario, assertIdempotent }
      from 'idempotency-rehearsal';
    
    const report = await runScenario({
      scenario: defineScenario({
        name: 'duplicate after retry',
        deliveries: [original, { ...duplicate, afterMs: 250 }],
        expect: [{ adapter: 'payment', action: 'capture', idempotencyKey: 'order_demo_042', count: 1 }],
      }),
      handler: handleWebhook,
    });
    
    assertIdempotent(report); // exits loudly on the second effect

    The safety contract

    Production-shaped. Production-safe.

    The harness exercises timing and ordering without turning your test into a payment or email cannon.

    Declare the bad timeline

    Duplicate IDs, delayed retries, and concurrent groups are readable data—not bespoke sleep-and-curl scripts.

    Real side effects stay off

    Payment and email adapters record intent only. HTTP collection is loopback-only and test IDs are validated.

    Keep a durable proof

    Exact expectations and stable JSON output make the scenario a regression test your CI can keep.

    CLI mode

    Aim it at localhost.

    The runner posts your declared sequence and opens a temporary loopback collector for test-only effect adapters.

    local80×24
    $ npx idempotency-rehearsal run duplicate.json \
        --target http://127.0.0.1:3000/webhooks/orders

    PASS  delayed duplicate
          2 deliveries · 1 effect · 264ms
       one logical effect per idempotency key

    Before the next retry

    Make the second delivery boring.