{"_id":"@apso/domain-events","name":"@apso/domain-events","dist-tags":{"latest":"0.1.0"},"versions":{"0.1.0":{"name":"@apso/domain-events","version":"0.1.0","description":"Durable domain-event spine (transactional outbox + runtime-selected delivery) for NestJS + TypeORM.","license":"MIT","author":{"name":"Apso"},"main":"dist/index.js","types":"dist/index.d.ts","scripts":{"build":"tsc -p tsconfig.json","clean":"rm -rf dist *.tsbuildinfo","test":"jest","lint":"tsc -p tsconfig.json --noEmit"},"peerDependencies":{"@nestjs/common":">=9 <12","@nestjs/core":">=9 <12","@nestjs/typeorm":">=9 <12","rxjs":">=7","typeorm":">=0.3"},"optionalDependencies":{"@aws-sdk/client-eventbridge":"^3.0.0","@aws-sdk/client-sqs":"^3.0.0","@nestjs/microservices":"^10.0.0","kafkajs":"^2.0.0"},"devDependencies":{"@nestjs/common":"^10.0.0","@nestjs/core":"^10.0.0","@nestjs/typeorm":"^10.0.0","reflect-metadata":"^0.2.2","rxjs":"^7.8.1","typeorm":"^0.3.20"},"keywords":["apso","domain-events","outbox","nestjs","typeorm"],"_id":"@apso/domain-events@0.1.0","gitHead":"80c659b5d024f051a332bf3f6f346e7cad3e0326","_nodeVersion":"20.20.2","_npmVersion":"10.8.2","dist":{"integrity":"sha512-D0jUIMhqGdzEwZdtdzS/I/mQgQ+7i1tBrXK5QUixnlPEPdGuCvDcGGiUpLvCs0Sm9Ol3gKTjJ4N47iTGcAQ+Ow==","shasum":"2c97b5ab625e73c7b2ceed7b8e32909811678f98","tarball":"https://registry.npmjs.org/@apso/domain-events/-/domain-events-0.1.0.tgz","fileCount":50,"unpackedSize":76738,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQC1SruCPGDkx46+5tdzX7pF0/OOyc6/MXyxZOeZ24eFEQIgFBkFsmKyDncxHVkMldk+ngXTiG0o/DKDUjPKjvXNgsM="}]},"_npmUser":{"name":"cultron","email":"mcullerton@gmail.com"},"directories":{},"maintainers":[{"name":"cultron","email":"mcullerton@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/domain-events_0.1.0_1781466214465_0.8360430639126244"},"_hasShrinkwrap":false}},"time":{"created":"2026-06-14T19:43:34.298Z","0.1.0":"2026-06-14T19:43:34.600Z","modified":"2026-06-14T19:43:34.789Z"},"maintainers":[{"name":"cultron","email":"mcullerton@gmail.com"}],"description":"Durable domain-event spine (transactional outbox + runtime-selected delivery) for NestJS + TypeORM.","keywords":["apso","domain-events","outbox","nestjs","typeorm"],"author":{"name":"Apso"},"license":"MIT","readme":"# @apso/domain-events\n\nDurable **domain-event spine** for NestJS + TypeORM — the standard\n**transactional outbox** pattern, surfaced with generic domain-event naming.\n\nState changes to opted-in entities write a `DomainEvent` row **in the same\ntransaction**; a self-contained relay drains pending rows and fans them out to\nruntime-selected delivery destinations.\n\nSee the cross-language [`CONTRACT.md`](../../../CONTRACT.md) for the behavior all\nlanguage implementations honor (TypeScript is the reference).\n\n## Install\n\n```bash\nnpm install @apso/domain-events\n```\n\nPeer deps: `@nestjs/common`, `@nestjs/core`, `@nestjs/typeorm`, `typeorm`,\n`rxjs`. Broker SDKs (`@nestjs/microservices` + `kafkajs`, `@aws-sdk/client-sqs`,\n`@aws-sdk/client-eventbridge`) are **optional** and loaded lazily — a\nwebhook-only deployment needs none of them.\n\n## Wire it up\n\n```ts\nimport { DomainEventsModule } from '@apso/domain-events';\nimport { Product } from './product/product.entity';\n\n@Module({\n  imports: [\n    DomainEventsModule.forRoot({\n      entities: [Product], // the CLI-emitted manifest of opted-in entities\n      // mapper?: MyDomainEventMapper,  // optional override\n      // pollIntervalMs?: 5000,         // optional, default 5000\n    }),\n  ],\n})\nexport class AppModule {}\n```\n\n`forRoot` is `@Global()`. The relay starts its own `setInterval` drain on\napplication bootstrap and clears it on shutdown — **no external scheduler\ndependency**.\n\n## Delivery destinations\n\nActive destinations are chosen ENTIRELY at runtime from `EVENTS_DESTINATION`\n(comma-separated → fan-out). Unknown name → startup error.\n\n| name | env | dependency |\n|---|---|---|\n| `webhook` | `EVENTS_WEBHOOK_URL`, `EVENTS_WEBHOOK_SECRET` | none (native fetch + crypto) |\n| `kafka` | `EVENTS_KAFKA_BROKERS`, `EVENTS_KAFKA_TOPIC` | `@nestjs/microservices` + `kafkajs` (lazy) |\n| `sqs` | `AWS_REGION`, `EVENTS_SQS_QUEUE_URL` | `@aws-sdk/client-sqs` (lazy) |\n| `eventbridge` | `AWS_REGION`, `EVENTS_EVENTBRIDGE_BUS` | `@aws-sdk/client-eventbridge` (lazy) |\n\nThe webhook adapter signs with [Standard Webhooks](https://www.standardwebhooks.com/)\n(`webhook-id`, `webhook-timestamp`, `webhook-signature: v1,<sig>`).\n\n## Duplicates — consumer-side dedupe is MANDATORY with multiple destinations\n\nDelivery is at-least-once and tracked at the **event grain** (a single\n`events.status`), NOT per (event × destination). With more than one active\ndestination, a failure in any one destination retries the **whole** event, so\nhealthy destinations receive it **again** on every retry. Consumers MUST dedupe\non `event.id` whenever multiple destinations are active. (A single destination —\nthe common case — never duplicates beyond ordinary at-least-once.)\n","readmeFilename":"README.md","_rev":"1-8fa5dc5e39420bece37cf4eccc7338f1"}