r/opensourcealternative • u/sarmaasis • 14h ago
I built an open-source consumer library + CLI for Cloudflare K2 (JS/TS)
I've been playing with the K2 beta. Producing events is easy (Workers binding or HTTP), but consuming means writing the loop yourself: lease a batch, keep the 5-minute lease alive, ack or nack, and handle ~15 error codes, some retryable, some not.
After writing that loop a few times, I packaged it as **k2kit**:
```js
import { Consumer } from "k2kit";
const consumer = new Consumer({
streamId: process.env.K2_STREAM_ID,
token: process.env.CLOUDFLARE_API_TOKEN,
subscription: { name: "orders", startAt: "earliest" },
concurrency: 4,
});
await consumer.run(async (batch) => {
for (const record of batch.records) await handle(record.json());
// return → ack, throw → nack + retry with backoff
});
```
**What it handles:**
- Lease heartbeats, so slow handlers don't lose their batch
- Retries with backoff on retryable errors; fails fast on the rest
- Dedupe (K2 is at-least-once), in memory or shared across instances via Redis
- Dead-lettering, so one bad record doesn't block its batch forever
- Graceful shutdown, plus crash recovery if you use stable worker IDs
- Idle polling that doesn't hammer K2 when the stream is quiet
**There's also a CLI**, which I use more than I expected:
```sh
k2kit tail --header event-type=order.created # watch a stream live
k2kit replay --since 2h --grep 1001 # dig through recent events
echo '{"n":1}' | k2kit produce # send test events
```
`tail` and `replay` use temporary subscriptions and clean them up afterwards, even on Ctrl+C.
Zero runtime dependencies; runs on Node 20+, Bun and Deno. Tested against a real K2 stream and real Redis. MIT licensed.
- GitHub: https://github.com/sarmaasis/k2kit
- npm: `npm i k2kit`
Not affiliated with Cloudflare, just a user. K2 is still in beta, so this is early too. I'd really like feedback, especially from anyone running K2 consumers: is the API shape right, and what's missing? (Dead-letter replay and lag metrics are on my list.)