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

@damatjs/durability

v1.0.6

Published

Shared PostgreSQL durability contracts and infrastructure

Readme

@damatjs/durability

Shared PostgreSQL contracts for durable Damat infrastructure.

The package provides a structural query interface, a transaction client, versioned system-migration descriptors, the shared durability migration catalog, worker presence, operational controls, and shared inspection primitives. Jobs, durable events, and framework runtime behavior build on this package without making it own their domain APIs.

Client

import {
  createDurabilityClient,
  setDurabilityClient,
} from "@damatjs/durability";

const durability = createDurabilityClient({ pool });
setDurabilityClient(durability);

await durability.transaction(async (executor) => {
  await executor.query("INSERT INTO app_records (id) VALUES ($1)", ["rec_1"]);
});

DurabilityExecutor is the structural query contract accepted by durability APIs. A PostgreSQL pool, pool client, or compatible ORM executor can implement it. The default client uses Symbol.for("damatjs.durability.client"); standalone consumers may pass a client directly instead.

Transactional idempotency

import { withIdempotency } from "@damatjs/durability";

const result = await withIdempotency(
  { scope: "payment.capture", key: requestId },
  async (executor) => {
    await executor.query(
      "INSERT INTO payment_attempts (id, status) VALUES ($1, $2)",
      [requestId, "captured"],
    );
    return { captured: true };
  },
);

The first caller claims the scope/key pair and stores its JSON-safe result in the same PostgreSQL transaction as the operation. Concurrent duplicates wait for that transaction and replay the completed value. Failures roll back the claim with the database work, while an expired key may be claimed again.

The key also stores a SHA-256 fingerprint of canonical intent: object keys are sorted, array order is preserved, valid dates become ISO strings, and non-JSON values are rejected. The same key and fingerprint replay; changed or legacy unverifiable intent throws public IdempotencyConflictError, whose scope and key fields contain no payload data. Jobs, durable events, and pipelines apply the same conflict contract to their complete resolved intent.

Pass executor when the caller already owns a transaction. A supplied executor must be the active callback executor from createDurabilityClient().transaction or another Damat transaction owner such as ModuleService.transaction. Unmarked pools and inactive executors are rejected before the claim query. Without an executor, withIdempotency uses the configured default client.

cleanupExpiredIdempotency({ limit, before, executor }) removes expired keys in an ordered batch capped at 500 rows. Unexpired keys are preserved.

Transaction-adapter authors can use createTransactionalExecutor to create a fresh query-delegating wrapper for each callback, then call invalidateTransactionalExecutor in finally. The wrapper is active only for that callback and stays invalid after both commit and rollback, even when the adapter reuses its underlying client. Queries through an invalidated wrapper fail before reaching that client. Application code should not create transaction wrappers itself.

Durable acceleration outbox writes register one coalesced after-commit flush on these wrappers. createDurabilityClient().transaction and ModuleService.transaction run it only after PostgreSQL commits; rollback runs no publisher or relay request. Custom transaction adapters must call runAfterCommitCallbacks after their commit if they want the same prompt relay behavior.

The guarantee covers database effects performed through the supplied executor. Remote providers must receive the same idempotency key; a local transaction cannot make an external side effect exactly once.

Worker presence and controls

registerWorker, heartbeatWorker, markWorkerStopping, stopWorker, and listWorkers maintain an observational process registry. Mark a process as stopping before drain begins, then call stopWorker after drain completes. Repeated shutdown calls preserve the first stopping and stopped timestamps. listWorkers calculates active, stale, stopping, and stopped states from heartbeat and shutdown timestamps. This data supports capacity views; it never authorizes work claims, which require fenced leases owned by jobs or events.

pauseWork and resumeWork upsert the unique work-kind/scope control and append immutable actor-attributed activity in one transaction. Activity identity records the serialized control-write order. Without an executor, the configured durability client opens that transaction. A supplied executor must be an active Damat transaction executor. Pausing prevents future claims but does not terminate work already running.

Headless administration clients call validateWorkActor before storage so an operator ID and one of user, service, or system is always present.

Inspection primitives

The package exports versioned opaque cursors containing a canonical ISO timestamp and UUID, progress sampling, visibility policies, aligned time buckets, UUID lease tokens, immutable key/path redaction, and chronological bounded log retention that keeps one contiguous newest suffix.

encodeCursor(position, signingKey) and decodeCursor(cursor, signingKey) require the application to provide the same explicit, nonempty HMAC key. Modified cursors and cursors signed by another key are rejected across processes. Cursor signing protects pagination state; it does not replace endpoint authentication. Log limits require finite nonnegative integer count and byte values and report dropped counts and bytes so truncation remains visible without failing a handler.

validateWorkSummaryFilter validates the shared half-open summary range, safe-integer interval, optional clock/stale threshold, and a maximum of 1,000 intersecting buckets. Jobs and events attach their fixed domain dimensions to the returned buckets. BoundedRetentionRequest carries the common terminal cutoff and batch-size request shape.

Acceleration and retention control

PostgreSQL is the canonical record for durable work. recordAccelerationSignal writes a coordination/invalidation row through the same transaction executor as the state change. A framework relay publishes committed rows to Redis; rollback removes both the state change and its signal. Relay claims are leased and idempotent, so a crash after publication can produce a duplicate wake-up but cannot duplicate a fenced PostgreSQL claim.

getAccelerationHealth() reports the mode, pending outbox count, publication checkpoint, last successful publication and rebuild, and fallback interval. rebuildAccelerationProjection(actor) rebuilds Redis coordination indexes from PostgreSQL and audits the actor and reason. subscribeDurableInvalidations provides an in-process hook for a future HTTP/SSE adapter. Invalidations contain only resource identity, scope, and revision; consumers refetch canonical data. Jobs, durable events, and pipelines share this outbox. pipeline is a first-class resource/work kind, so its ready changes, controls, retention overrides, and visual invalidations use the same contracts without storing graph data in Redis.

setRetentionOverride and getRetentionOverride use number | "forever". Overrides are actor/reason audited and apply to remaining data. Operational presets are seven days, 90 days, and "forever"; the default is 90 days. "forever" is represented by nullable retention/expiry storage; the shared catalog migration extends existing retention overrides to the pipeline kind.

System migrations

durabilitySystemMigrations declares shared idempotency, worker, control, maintenance, acceleration outbox/state, and retention-override tables. Compose catalogs with collectSystemMigrations, then pass the result to the ORM migration runner.

damatRelation(name) returns a quoted "damat"."_damat_*" identifier for runtime SQL. relocateDamatRelations(names) returns idempotent SQL for moving legacy public relations while rejecting source/target conflicts. Its preflight also rejects a damat schema the migration role does not control or that already contains non-Damat relations.

Shared Damat relations live in the dedicated PostgreSQL damat schema. Use damatRelation(name) when building runtime SQL and relocateDamatRelations(names) when adding an ordered forward-only relocation migration for another durable capability. The migration runner keeps a transaction-local public, damat search path only for legacy migration SQL; runtime queries remain fully qualified.

Framework startup never creates these tables. Use assertSystemMigrationsApplied for a read-only readiness check; missing migrations instruct the operator to run damat-orm migrate:up.

See the internals guide for the package map and contracts.