{"_id":"@chance-get-yours/nestjs-nats-jetstream-microservice","_rev":"25-aef1fb7e0a6cffcacff51ce2e9200dae","name":"@chance-get-yours/nestjs-nats-jetstream-microservice","dist-tags":{"latest":"0.1.0"},"versions":{"0.1.0":{"name":"@chance-get-yours/nestjs-nats-jetstream-microservice","version":"0.1.0","keywords":["nestjs","microservice","transporter","nats","jetstream","eventsourcing","eventmodelling"],"author":{"name":"Vincent Vermersch [vermersch@gmail.com]"},"license":"MIT","_id":"@chance-get-yours/nestjs-nats-jetstream-microservice@0.1.0","maintainers":[{"name":"amaury-hanser","email":"amaury.hanser@chance.co"},{"name":"vinceve","email":"vermersch@gmail.com"},{"name":"macadock","email":"mathieu@barriere.me"},{"name":"hpatadia","email":"hp011235@gmail.com"},{"name":"chance-admin","email":"tech-services@chance.co"},{"name":"arnaudcoutin","email":"a.coutin06@gmail.com"},{"name":"aymen.mouelhi","email":"aymen.mouelhi@gmail.com"},{"name":"jeromedesmares","email":"desmaresjerome@gmail.com"}],"homepage":"https://github.com/chance-get-yours/nestjs-nats-jetstream-microservice#readme","bugs":{"url":"https://github.com/chance-get-yours/nestjs-nats-jetstream-microservice/issues"},"dist":{"shasum":"b263250b6283303f316e08053381d2b79f220e94","tarball":"https://registry.npmjs.org/@chance-get-yours/nestjs-nats-jetstream-microservice/-/nestjs-nats-jetstream-microservice-0.1.0.tgz","fileCount":52,"integrity":"sha512-Y6nXTcpGRGkjA/SwvCFpCy1rW6my2dda5JJ13U3Vz6npAGYejQNeZcP/PCVGCJifwtz5SqIf4rI7ciRU0vm2+w==","signatures":[{"sig":"MEUCIQCfyavmOd8T5dkS33sNuDyGhKNCWd3jdIiggfEccaB9PwIgCCvDjuxfm6AdhkgwARAMjyk8cUYPQ8FgFRUb1NarWN0=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":188152},"main":"dist/index.js","types":"dist/index.d.ts","gitHead":"e56a91baa4f37241e0e1f994a1467b4d7d857512","scripts":{"lint":"eslint \"{src,apps,libs,test}/**/*.ts\" --fix","test":"exit 0","build":"rimraf dist && tsc","watch":"tsc -w","format":"prettier --write \"src/**/*.ts\""},"_npmUser":{"name":"vinceve","email":"vermersch@gmail.com"},"repository":{"url":"git+https://github.com/chance-get-yours/nestjs-nats-jetstream-microservice.git","type":"git"},"_npmVersion":"9.6.2","description":"NATS JetStream Custom Transporter for NestJS","directories":{},"_nodeVersion":"18.9.0","dependencies":{"nats":"^2.10.0","rxjs":"^7.4.0","cloudevents":"^6.0.3","reflect-metadata":"^0.1.13"},"_hasShrinkwrap":false,"devDependencies":{"rimraf":"^3.0.2","prettier":"^2.7.1","typescript":"^4.4.4","@types/node":"^18.11.13","@nestjs/core":"^8.2.0","@nestjs/common":"^8.2.0","@nestjs/microservices":"^8.2.0","eslint-config-prettier":"^8.5.0","eslint-plugin-prettier":"^4.2.1","@typescript-eslint/eslint-plugin":"^5.33.1"},"_npmOperationalInternal":{"tmp":"tmp/nestjs-nats-jetstream-microservice_0.1.0_1685438806021_0.5804264601746907","host":"s3://npm-registry-packages"}}},"time":{"created":"2023-05-30T09:26:46.021Z","modified":"2026-06-29T13:04:10.335Z","0.1.0":"2023-05-30T09:26:46.233Z"},"bugs":{"url":"https://github.com/chance-get-yours/nestjs-nats-jetstream-microservice/issues"},"author":{"name":"Vincent Vermersch [vermersch@gmail.com]"},"license":"MIT","homepage":"https://github.com/chance-get-yours/nestjs-nats-jetstream-microservice#readme","keywords":["nestjs","microservice","transporter","nats","jetstream","eventsourcing","eventmodelling"],"repository":{"url":"git+https://github.com/chance-get-yours/nestjs-nats-jetstream-microservice.git","type":"git"},"description":"NATS JetStream Custom Transporter for NestJS","maintainers":[{"email":"cedric.champeix@chance.co","name":"champeicchance"},{"email":"tech-services@chance.co","name":"chance-admin"},{"email":"theophile.cathelin@gmail.com","name":"theoscat"},{"email":"d.laureaux@timoa.com","name":"timoa"},{"email":"thomas.lepore@chance.co","name":"thomaschance"},{"email":"vivien.desaintexupery@chance.co","name":"vdesain"},{"email":"muriloime@gmail.com","name":"muriloime"},{"email":"thiago.ps@gmail.com","name":"thiagosabetta"},{"email":"contact@raphaelgimenez.fr","name":"graphael"},{"email":"guillaume.gomez@chance.co","name":"guillaume-chance"}],"readme":"# NATS JetStream Custom Transporter for NestJS microservice\n## Goals of this library\n- Cover all NATS [JetStream features](https://docs.nats.io/nats-concepts/jetstream).\n- Enjoy NestJS [interceptors](https://docs.nestjs.com/microservices/interceptors), [exceptions filters](https://docs.nestjs.com/microservices/exception-filters), [pipes](https://docs.nestjs.com/microservices/pipes), [guards](https://docs.nestjs.com/microservices/guards) .\n- If NestJS transporter doesn't fit NATS JetStream needs, [NATS is preferred](https://github.com/nats-io/nats.deno/blob/fd397655e390b36cd52119ec80ce3446f54cb614/examples/jetstream/js_readme_publish_examples.ts).\n- Doesn't cover [NATS microservice](https://docs.nestjs.com/microservices/nats) features\n\n## Install\n### Library\n```bash\nnpm i @nestjs/microservices\nnpm i nats\nnpm i @chance/nestjs-nats-jetstream-microservice\n```\n### Server\nNATS server could run locally\n```bash\ndocker run -d --name nats -p 4222:4222 -p 6222:6222 -p 8222:8222 nats --jetstream -m 8222\n```\nor using [Synadia NGS](https://www.synadia.com/ngs) for quick setup.\n### Cli\n[NATS cli](https://docs.nats.io/running-a-nats-service/clients) covers all needs from the command line\n\n```bash\nbrew tap nats-io/nats-tools\nbrew install nats-io/nats-tools/nats\n```\nOr download [official release](https://github.com/nats-io/natscli/releases/).\n\n## Configuration\n### Streams\n> Streams are 'message stores', each stream defines how messages are stored and what the limits (duration, size, interest) of the retention are. Streams consume normal NATS subjects, any message published on those subjects will be captured in the defined storage system. You can do a normal publish to the subject for unacknowledged delivery, though it's better to use the JetStream publish calls instead as the JetStream server will reply with an acknowledgement that it was successfully stored.\n\nSubjects can be queried using [NATS syntax](https://docs.nats.io/nats-concepts/subjects)\n\n[Configurations options](https://docs.nats.io/nats-concepts/jetstream/streams) could be set using the library \n\n```typescript\nconst bootstrap = async () => {\n  const options: CustomStrategy = {\n    strategy: new NatsJetStreamServer({\n      connectionOptions: {\n        servers: \"127.0.0.1:4222\",\n        // Name the client for connection hostname to avoid overlap\n        name: `nats-connection.${os.hostname()}`,\n      },\n      // Stream will be created if not exist\n      // To work we need all this stream to be available\n      assertStreams: [\n        {\n          name: \"booking\",\n          description: \"Booking domain with all its events\",\n          subjects: [\"booking.>\"],\n        } as Partial<StreamConfig>\n      ],\n    }),\n  };\n\n  // hybrid microservice and web application\n  const app = await NestFactory.create<NestFastifyApplication>(HotelBookingModule);\n  const microService = app.connectMicroservice(options);\n  await microService.listen();\n  return app;\n};\nbootstrap();\n\n```\n\n### Consumer options\n\n> A consumer is a stateful view of a stream. It acts as interface for clients to consume a subset of messages stored in a stream and will keep track of which messages were delivered and acknowledged by clients.\n> Unlike with core NATS which provides an at most once delivery guarantee of a message, a consumer can provide an at least once delivery guarantee.\n\n[Configuration options](https://docs.nats.io/nats-concepts/jetstream/consumers) could be set using library and the decorator. Or be set using the cli and using the named consumer with the decorator\n\n```typescript\n@Controller()\nexport class BotNatsController {\n  constructor(private scheduleCleaning: ScheduleCleaningCommandHandler) {}\n\n  // Consumer will be created if not exists\n  // Updated if exists\n  @EventPattern(\"ConsumerName\", {\n    description: \"Trigger cleaning side effect when room is booked\",\n    filter_subject: \"booking.*.room-booked-event.>\",\n    deliver_to: \"cleanupInbox\",\n    durable: \"cleanupStack\",\n    manual_ack: true,\n  } as ConsumeOptions)\n  async cleanup(\n    @Payload() event: RoomBookedEvent,\n    @Ctx() context: NatsJetStreamContext\n  ) {\n    // DO the work\n    context.message.ack();\n  }\n}\n\n```\n\n### Publishing events\n```typescript\n@Module({\n  imports: [\n    NatsJetStreamTransport.register({\n      connectionOptions: {\n      servers: \"127.0.0.1:4222\",\n      name: \"hotel-booking-publisher\",\n    }})\n  ],\n  controllers: [BotNatsController,],\n  providers: [],\n})\nexport class HotelBookingModule {}\n```\n\n```typescript\n@Injectable()\nexport class BookRoomCommandHandler {\n  constructor(private client: NatsJetStreamClient) {}\n  async handle(command: BookRoomCommand) {\n    // CloudEvent like syntax here, but nothing's mandatory\n    const event = new RoomBookedEvent(\n      { ...command.data, date: isoDate.toISOString() },\n      source,\n      correlationId\n    );\n    const uniqueBookingSlug = `booked-${correlationId}`;\n    this.client\n      .publish(\n        'my.super.subject',\n        event,\n        // deduplication trick : booking slug is unique using message ID\n        // dupe-window should be configured on stream, default 2mn\n        { msgID: uniqueBookingSlug }\n      )\n      .then((res: PubAck) => {\n        if (!res.duplicate) {\n          return res;\n        }\n        throw new ConflictException('MsgID already exists error');\n      });\n  }\n}\n```","readmeFilename":"README.md"}