npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@paykernel/store-durable-objects

v0.1.1

Published

Cloudflare SQLite-backed Durable Object stores for PayKernel lease-aware idempotency, webhook inbox, and reconciliation (per-partition strong coordination).

Downloads

294

Readme

@paykernel/store-durable-objects

Cloudflare SQLite-backed Durable Object stores for @paykernel/core lease-aware idempotency, webhook inbox, and reconciliation contracts (Phase 9).

Phase 17 production adapter. Multi-host via partitioned Durable Objects with deterministic sharding. Strong coordination is per partition (per DO instance) — not a global multi-primary store.

This is not packages/store-d1 (shared D1).
This is not packages/store-sqlite (local single-host file DB).
This is not packages/store-turso (Turso / libSQL clients).
There is no generic packages/adapter-cloudflare umbrella.

Install

bun add @paykernel/store-durable-objects
# optional DX types (not required at runtime):
bun add -d @cloudflare/workers-types

Quick start (Worker client + sharding)

import {
  createDoPaymentStores,
} from "@paykernel/store-durable-objects";

// Explicit sharding required — NEVER a silent global Durable Object.
const stores = createDoPaymentStores({
  namespace: env.PAYMENTS_DO,
  sharding: { kind: "hash", partitions: 32 }, // or { kind: "key" }
});

const r = await stores.idempotency.reserve({
  key: "pay_123",
  fingerprint: "fp",
  owner: "worker-1",
  leaseMs: 30_000,
});
// 1) claim  2) exit storage txn  3) external provider work  4) complete with leaseToken

Direct storage path (tests / in-object)

import {
  createDoPaymentStoresFromStorage,
  createDoExecutor,
  createDoStores,
  migrateDoAdapter,
  PaymentsStoreObject,
} from "@paykernel/store-durable-objects";

// Explicit migrate — NEVER automatic on import or default createDoPaymentStores.
await migrateDoAdapter(storage); // DoStorageLike or DoExecutor

const bundle = createDoPaymentStoresFromStorage({ storage });
// or
const object = new PaymentsStoreObject({ storage });
await object.ensureSchema();

Normal operation uses the Workers DO binding only — no Cloudflare REST API or account token is required for store construction.

Wrangler (SQLite-backed DO)

See examples/wrangler.toml:

[[durable_objects.bindings]]
name = "PAYMENTS_DO"
class_name = "PaymentsStoreDurableObject"

[[migrations]]
tag = "v1"
new_sqlite_classes = ["PaymentsStoreDurableObject"]

Use new_sqlite_classes (not legacy KV-only new_classes) so storage.sql / transactionSync are available.

Required DO RPC methods

Forward every name in REQUIRED_DO_RPC_METHODS from your PaymentsStoreDurableObject wrapper. Hash sharding requires bindHashPartitionLayout (DO-1). See docs/wrangler.md.

tableNamespace is sent on every store RPC and applied inside the DO.

Sharding

| Strategy | Behavior | | -------- | -------- | | key | One object per key — strongest per-key serialization | | hash | Bounded partitions (partitions >= 1, recommend ≥ 16). partitions = 1 is a single partition (all keys share one DO; not a silent global default). | | tenant | One object per tenant. Worker strategy: static tenantId string, or a function of key only (store contracts have no tenantId). |

  • Within a shard: requests serialize (single-threaded DO).
  • Across shards: no global total order.
  • Hot-key risk: many ops for the same key/tenant hit the same object → latency/cost concentration.
  • Forbidden: defaulting all payment work to one global Durable Object.

Details: docs/sharding.md.

Claims (summary)

Prefer engine-level single-statement (sync storage.sql.exec):

INSERT … ON CONFLICT DO UPDATE … WHERE … RETURNING …

Multi-statement only inside storage.transactionSync(() => { … })sync callback, no await.
Never BEGIN/COMMIT via sql.exec. Never unprotected get-then-set.

Pattern: claim → commit → external work → complete with lease token.

Details: docs/claims.md.

Guarantees (honest)

| Field | Value | | ----- | ----- | | coordinationScope | multi-host (partitioned DO) | | durability | durable | | consistency.claims | strong (within partition) | | consistency.readAfterWrite | strong (within single DO instance) | | staleReadsPossible | false (within partition) |

Cross-partition: no global order. Full notes: DO_STORAGE_ADAPTER_MANIFEST / docs/guarantees.md.

Optional alarms (default-off)

One alarm per DO + due queue table; handlers are at-least-once and must re-check lease/claim state. Bounded retries + backoff/jitter.

Alarms are not wired to failWebhook — webhook recovery is pull-only (listRetryable). See docs/alarms.md.

Docs

See monorepo docs/adapter-selection.md for the Phase 18 capability matrix and decision tree.

| Doc | Topic | | --- | ----- | | docs/overview.md | Architecture & when to use | | docs/sharding.md | Strategies, ordering, hot keys | | docs/guarantees.md | Manifest honesty | | docs/claims.md | Atomic claims | | docs/transactions.md | transactionSync sync-only; no external I/O in txn | | docs/crash-boundaries.md | Crash / lease reclaim / eviction | | docs/wrangler.md | Binding + new_sqlite_classes | | docs/migrations.md | Explicit ensure/migrate | | docs/testing.md | Mock DO SQL, FakeClock, partitions, alarms | | docs/alarms.md | Optional partition alarms (at-least-once) | | docs/limits.md | DO CPU/storage limits; hot partitions; vs D1 |

License

MIT