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

@vendit-dev/event-store-client

v1.1.3

Published

Client encapsulating GRPC interface to communicate with vendit event store server.

Readme

@vendit-dev/event-store-client

Client encapsulating the gRPC interface to communicate with the vendit event store server.

Version lines

| Line | Branch | Transport | Status | | --- | --- | --- | --- | | 1.x | v1-sqs | AWS SQS | Active development | | 0.x | master | BullMQ (Redis) | Maintenance for legacy projects |

The 1.x line replaces BullMQ with AWS SQS as the event delivery transport. Both lines are maintained independently: fixes for legacy (BullMQ) consumers land on master and release as 0.x, while SQS-based development happens on v1-sqs and releases as 1.x.

What changed in 1.0.0

  • BullMQ removed. Events are now delivered through one SQS Standard queue per (aggregate, context, service) subscription.
  • Queues are owned by the event store server. The client never creates queues; on saga registration it calls the new Subscribe gRPC RPC and receives the queue URL to poll. The client only needs sqs:ReceiveMessage, sqs:DeleteMessage, sqs:ChangeMessageVisibility and sqs:GetQueueAttributes permissions.
  • Revision-ordered processing. SQS Standard queues deliver out of order, so the client gates saga invocation by stream revision: an event whose revision is ahead of currentRevision + 1 is returned to the queue (with a short visibility timeout) and redelivered until the gap fills. After outOfOrderMaxReceiveCount redeliveries the event is processed anyway so a permanently missing revision cannot wedge a stream. Events published with revision: -1 (side-effect events) bypass gating.
  • Redis stays for distributed locking only. The per-stream mutex that serializes saga processing across replicas still uses Redis. redisFeaturesEnabled: false disables both the Redis mutex and queue consumption, exactly as in 0.x (useful for tests).

Everything else — the public API (useSagas, store, publish, created, updated, deleted, rebuild, resyncAggregate, snapshots) — is unchanged from 0.x.

New constructor options (all optional)

const eventManager = new VenditEventManager({
  // ...existing options (host, port, serviceName, apiKey, context, redis, ...)

  sqsClient,                        // injected SQSClient instance (takes precedence)
  sqsConfig,                        // SQSClientConfig used to build a client when sqsClient is not given
                                    //   default: { region: AWS_REGION ?? AWS_DEFAULT_REGION ?? 'ap-northeast-2' }
  sqsWaitTimeSeconds: 20,           // long-polling wait per receive
  sqsBatchSize: 10,                 // messages per receive (1-10)
  outOfOrderRetryDelaySeconds: 5,   // visibility timeout applied to future-revision events
  outOfOrderMaxReceiveCount: 30,    // receives after which ordering is no longer enforced
});

AWS credentials resolve through the SDK default provider chain (env vars, shared config/SSO profile, IAM role). Pass your own sqsClient for custom credential handling.

Subscribe heartbeat & dead-queue ejection (1.1.2+)

The client re-calls the (idempotent) Subscribe RPC every subscribeHeartbeatIntervalMs (default 5 min, 0 disables). This keeps the server-side registration fresh and self-heals dead-queue ejection: the event store unsubscribes a service whose queue shows a large backlog with zero in-flight messages over several consecutive checks (i.e. nobody is consuming). The queue itself is left intact (14-day retention). If a service was ejected and later recovers, the heartbeat re-registers it automatically — but events published while it was unsubscribed were never queued for it, so it should run resyncAggregate to fill the gap.

Saga transactions (1.1.0+)

Sagas can opt into distributed transactions coordinated by the event store server. See apps/event-store-svc/docs/SAGA_TRANSACTIONS.md in vpms-cluster for the full protocol.

const sagas: EventSaga<Context> = {
  Reservation: {
    transaction: 1,            // integer >= 1; lower groups run first
    rollback: async (event, ctx, buildResult) => { /* compensate */ },
    // or rollback: 'REBUILD' (requires prebuild) - mechanical compensation by
    // replaying the stream from the latest snapshot.
    revision: async (event, ctx) => ...,
    build: async (event, ctx, processors) => ...,  // reversible work only
  },
};

// Publisher side: store + wait for the whole multi-service transaction.
const result = await eventManager.storeTransactional(
  { streamId, type: 'CREATED', data, aggregate: 'Reservation' },
  { timeoutMs: 30_000 },
);
// result.status: COMMITTED | ROLLED_BACK | ROLLED_BACK_PARTIAL | TIMED_OUT
// result.failedServices / result.rollbackFailures: per-participant detail

Semantics summary:

  • Sagas with the same transaction group across services commit or roll back together per event; lower-numbered groups complete before higher ones; plain sagas run last and only for committed events.
  • A build throw fails the transaction. Processors awaited by build propagate; fire-and-forget processors are pure side effects (and escape rollback - choose the bucket by choosing whether to await).
  • Failed events stay in the store marked ROLLED_BACK and are skipped (but counted) by replays; subsequent events on the stream wait for the transaction to resolve.
  • A terminally failed rollback parks only that (service, stream) pair; resolve via eventManager.resolveTransaction(eventId, service, resolution) with RETRY_ROLLBACK | MARK_ROLLED_BACK | MARK_COMMITTED.
  • eventManager.getTransactionTopology() shows which services participate in which groups per aggregate.
  • Test every transactional saga with testCompensationSymmetry (exported) so compensation logic cannot rot unnoticed.
  • Function rollbacks must be idempotent and guard against unapplied events: redelivery and race recovery can (rarely) deliver a rollback for an event this service never built. Start every function rollback with a guard like if (model.revision !== event.revision) return; — or use rollback: 'REBUILD', which is immune by construction (it derives state from the stream instead of inverting operations).

Migrating a service from 0.x

  1. Bump the dependency to ^1.0.0.
  2. Deploy against an event store server that supports the Subscribe RPC (publishes to SQS instead of BullMQ).
  3. Ensure the runtime has SQS consume permissions and AWS_REGION set (or pass sqsClient/sqsConfig).
  4. Drain or ignore the legacy VSCSUBKEY_* BullMQ queues in Redis; they are no longer consumed.

Development

yarn install
npm run protoc   # regenerate src/proto from src/eventStore.proto (requires protoc)
npm run build    # tsc -> lib/

build.sh post-processes the generated src/proto/eventStore.ts (protobufjs import extension, SubscriptionPushExceptAck narrowing) — do not hand-edit the generated file.