feat(data): Added nats jetstream dependency

This commit is contained in:
2026-02-20 19:15:35 +01:00
parent 3584b3facf
commit bbf6ea6c0f
9 changed files with 489 additions and 18 deletions

View File

@@ -10,6 +10,7 @@ export const config = {
testing: process.env.NODE_ENV === "test",
jwt_secret: process.env.JWT_SECRET || "secretjwtsecret",
station_token_secret: process.env.STATION_TOKEN_SECRET || "",
nats_url: process.env.NATS_URL || "nats://localhost:4222",
phone_validation_countrycode: getPhoneCodeLocale(),
postalcode_validation_countrycode: getPostalCodeLocale(),
version: process.env.VERSION || require('../package.json').version,

View File

@@ -1,4 +1,5 @@
import { Application } from "express";
import NatsClient from "../nats/NatsClient";
import databaseLoader from "./database";
import expressLoader from "./express";
import openapiLoader from "./openapi";
@@ -9,6 +10,7 @@ import openapiLoader from "./openapi";
*/
export default async (app: Application) => {
await databaseLoader();
await NatsClient.connect();
await openapiLoader(app);
await expressLoader(app);
return app;

60
src/nats/NatsClient.ts Normal file
View File

@@ -0,0 +1,60 @@
import consola from 'consola';
import { connect, JetStreamClient, KV, KvOptions, NatsConnection } from 'nats';
import { config } from '../config';
/**
* Singleton NATS client.
* Call connect() once during app startup (after the DB loader).
* All other modules obtain the connection via getKV().
*/
class NatsClient {
private connection: NatsConnection | null = null;
private js: JetStreamClient | null = null;
private kvBuckets: Map<string, KV> = new Map();
/**
* Establishes the NATS connection and JetStream context.
* Must be called once before any KV operations.
*/
public async connect(): Promise<void> {
this.connection = await connect({ servers: config.nats_url });
this.js = this.connection.jetstream();
consola.success(`NATS connected to ${config.nats_url}`);
}
/**
* Returns a KV bucket by name, creating it if it doesn't exist yet.
* Results are cached — repeated calls with the same name return the same instance.
*/
public async getKV(bucketName: string, options?: Partial<KvOptions>): Promise<KV> {
if (this.kvBuckets.has(bucketName)) {
return this.kvBuckets.get(bucketName);
}
if (!this.js) {
throw new Error('NATS not connected. Call NatsClient.connect() first.');
}
const kv = await this.js.views.kv(bucketName, options);
this.kvBuckets.set(bucketName, kv);
return kv;
}
/**
* Gracefully closes the NATS connection.
* Call during app shutdown if needed.
*/
public async disconnect(): Promise<void> {
if (this.connection) {
await this.connection.drain();
this.connection = null;
this.js = null;
this.kvBuckets.clear();
consola.info('NATS disconnected.');
}
}
public isConnected(): boolean {
return this.connection !== null;
}
}
export default new NatsClient();