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

@eco-foundation/eco-message-contracts

v2.2.1

Published

Message envelope, contract definitions, and payload schemas for Eco AMQP messaging

Readme

@eco-foundation/eco-message-contracts

The message envelope, defineContract(), and the live cross-service payload schemas for Eco's AMQP bus. Zero AMQP dependency — install this alone if you only need to define, publish-shape, or parse contracts. The transport lives in @eco-foundation/eco-messaging, which declares this package as a peer.

pnpm add @eco-foundation/eco-message-contracts

Requires zod (^3.25 || ^4) as a peer. Note the 3.25 floor: a service declaring an older range must raise the declared range even if its lockfile already resolves something newer.

What a contract is

A contract binds a payload schema to its routing, its deterministic identity, and its publication policy in one place, so those four facts cannot drift apart across the services that share the event.

import * as z from 'zod/v4';
import { defineContract } from '@eco-foundation/eco-message-contracts';

export const InventorySnapshot = defineContract({
  eventType: 'inventory.snapshot',
  routingKey: 'inventory.snapshot',
  bindingPattern: 'inventory.snapshot',
  schema: z.object({
    aggregateId: z.string().min(1),
    snapshotVersion: z.number().int().nonnegative(),
    actualBalance: z.string(), // decimal amount in base units, as a string wire type
  }),
  schemaVersion: 1,
  // Deterministic identity: the SAME logical event always resolves to the same messageId,
  // which is what makes an outbox retry safe rather than a duplicate.
  identity: (p) => `${p.aggregateId}:${p.snapshotVersion}`,
  // Optional: enforce apply-in-order-within-scope. A stale or out-of-order redelivery is
  // rejected before the handler runs, rather than being left to regress state.
  ordering: {
    field: 'snapshotVersion',
    version: (p) => p.snapshotVersion,
    scope: (p) => p.aggregateId,
  },
  delivery: 'required',
});

delivery may be static or payload-dependent, and resolvePublicationPolicy(validatedPayload) is the single admission decision derived from it. A required contract must also declare durability: 'caller-ledger' to be publishable directly — otherwise it is refused before it reaches the broker, because a persist-before-publish rule any call site can bypass silently is not a rule.

Declared field names are validated against the schema at definition time, so a typo in digestExcludes or an ordering.field that does not exist is a module-load failure rather than a silently-ineffective declaration.

Every static routing key is also exposed as routingKeyTemplate. For a payload-derived key, add an explicit template such as <chainId>.inventory.snapshot; the built-in catalog requires one for every contract and publishes it in the generated schema index for compatibility checks.

The envelope

buildEnvelope, readEnvelope, envelopeToHeaders, and the ENVELOPE_HEADERS constants are the canonical envelope surface. Every message carries a message ID, causation and correlation IDs, event type, schema version, source service, attempt count, and W3C trace context.

readEnvelope returns a discriminated result rather than throwing, so a malformed envelope is a value your consumer can park deliberately instead of an exception in a hot path.

Live contracts

Eight contracts ship with the package, exported as ALL_CONTRACTS and described by BALANCE_EVENTS_CATALOG (which records the producer and consumers of each, so the catalog answers "who breaks if I change this" without a code search):

| Event type | Binding pattern | | ------------------------------ | ------------------------------- | | withdrawal.created | *.withdrawal.created | | withdrawal.resolved | *.withdrawal.resolved | | withdrawal.refunded | *.withdrawal.refunded | | gateway-deposit.created | *.gateway-deposit.created | | gateway-burn.mint-confirmed | *.gateway-burn.mint-confirmed | | gateway-burn.burn-observed | *.gateway-burn.burn-observed | | rebalance.snapshot | rebalance.snapshot | | solver.actual-balance.update | solver.actual-balance.update |

Breaking payload versions

Breaking versions use real parsers, not a header allowlist. Define each historical schema with defineVersionAdapter(schema, upcast) under legacyVersions; consumers call parseVersion(envelope.schemaVersion, body) and handlers receive only the canonical current shape.

payloadDigest

payloadDigest(contract, payload) answers "does this publish carry anything a consumer can actually observe?" — for a producer whose version bump is unconditional and which would otherwise re-emit a terminal snapshot under a fresh version. Exclusions are declared per-contract via digestExcludes, apply at the root only, and arrays are never sorted (order is part of identity). Values JSON cannot faithfully represent are refused with the offending path named rather than silently mangled.

For non-TypeScript consumers

The tarball ships versioned, language-neutral JSON Schema artifacts, so a service in another language pins the published package (or vendors the files) instead of reimplementing the schemas:

  • @eco-foundation/eco-message-contracts/schemaschema/generated/index.json, the contract and envelope index with per-version schema paths.
  • @eco-foundation/eco-message-contracts/conformance → machine-readable conformance clauses, the AMQP wire mapping, and replay-verified delivery vectors.

The schemas deliberately do not reject unknown fields: a consumer must tolerate a field added by a newer producer, so validation is not a compatibility trap.

Documentation

These packages are the reference implementation of the standard, not its definition. The definition is two language-agnostic documents that a non-TypeScript service can implement against — read them before changing envelope headers, queue topology, settlement semantics, or the durable-publish rule:

Changes are tracked in CHANGELOG.md.