@burdenoff/be-sdk 2026.513.2 → 2026.513.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -284,8 +284,11 @@ async function createRedisStreamsEventTarget(options = {}) {
|
|
|
284
284
|
password: options.password ?? process.env["REDIS_PASSWORD"],
|
|
285
285
|
name: "graphql-pubsub"
|
|
286
286
|
});
|
|
287
|
-
|
|
288
|
-
|
|
287
|
+
void conn.connect().then(() => logger.info("[RedisStreamsEventTarget] redis connected")).catch((err) => {
|
|
288
|
+
logger.warn("[RedisStreamsEventTarget] redis connect failed; pubsub will retry on demand", {
|
|
289
|
+
error: err instanceof Error ? err.message : String(err)
|
|
290
|
+
});
|
|
291
|
+
});
|
|
289
292
|
const streamKey = /* @__PURE__ */ __name((type) => `boff:pubsub:${prefix}:${type.replace(/\./g, ":")}`, "streamKey");
|
|
290
293
|
const listeners = /* @__PURE__ */ new Map();
|
|
291
294
|
const readers = /* @__PURE__ */ new Map();
|
|
@@ -402,7 +405,7 @@ async function createRedisStreamsEventTarget(options = {}) {
|
|
|
402
405
|
void (async () => {
|
|
403
406
|
try {
|
|
404
407
|
const payload = await serializer.stringify(detail);
|
|
405
|
-
await
|
|
408
|
+
await conn.getClient().xadd(streamKey(event.type), "MAXLEN", "~", maxLen, "*", "payload", payload);
|
|
406
409
|
} catch (err) {
|
|
407
410
|
logger.error("[RedisStreamsEventTarget] dispatch failed", {
|
|
408
411
|
type: event.type,
|
|
@@ -431,5 +434,5 @@ async function createRedisStreamsEventTarget(options = {}) {
|
|
|
431
434
|
__name(createRedisStreamsEventTarget, "createRedisStreamsEventTarget");
|
|
432
435
|
|
|
433
436
|
export { createNatsEventTarget, createRedisStreamsEventTarget, graphql_exports };
|
|
434
|
-
//# sourceMappingURL=chunk-
|
|
435
|
-
//# sourceMappingURL=chunk-
|
|
437
|
+
//# sourceMappingURL=chunk-MI72VKNQ.js.map
|
|
438
|
+
//# sourceMappingURL=chunk-MI72VKNQ.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/graphql/index.ts","../src/graphql/nats-event-target.ts","../src/graphql/redis-streams-event-target.ts"],"names":["createNatsEventTarget","options","natsUrl","connectionOptions","serializer","stringify","data","JSON","parse","message","subjectPrefix","sc","StringCodec","defaultConnectionOptions","name","maxReconnectAttempts","reconnectTimeWait","pingInterval","maxPingOut","timeout","mergedConnectionOptions","effectiveUser","user","process","env","effectivePass","pass","password","connectionConfig","type","url","Array","isArray","token","creds","credsFile","connectionManager","connection","NatsConnectionManager","connect","getNatsConnection","logger","info","error","Error","callbacks","Map","subscriptions","getSubject","eventType","subscribeToNats","has","subject","subscription","subscribe","set","debug","msg","messageData","decode","payload","eventCallbacks","get","size","event","CustomEvent","detail","callback","from","callbackError","messageError","subscriptionError","unsubscribeFromNats","unsubscribe","delete","eventTarget","addEventListener","listener","Set","add","listenerCount","removeEventListener","remainingListeners","dispatchEvent","encode","publish","serializeError","close","entries","clear","disconnect","isHealthy","isClosed","createRedisStreamsEventTarget","redisUrl","prefix","maxLen","d","m","conn","RedisStreamsConnection","then","catch","err","warn","String","streamKey","replace","listeners","readers","closed","startReader","stopped","stream","loop","blockingClient","makeBlockingClient","lastId","raw","xreadgroup","call","Promise","r","setTimeout","id","rawFields","fields","i","length","cbs","ev","cb","cbErr","stop","stopReader","target","getClient","xadd","values","isConnected"],"mappings":"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","file":"chunk-MI72VKNQ.js","sourcesContent":["/**\n * GraphQL Utilities Module\n *\n * Provides GraphQL-related utilities for Burdenoff products.\n *\n * @module graphql\n */\n\nexport { createNatsEventTarget } from './nats-event-target.js';\nexport type { NatsEventTarget, NatsEventTargetOptions, MessageSerializer } from './nats-event-target.js';\n\nexport { createRedisStreamsEventTarget } from './redis-streams-event-target.js';\nexport type {\n RedisStreamsEventTarget,\n RedisStreamsEventTargetOptions,\n} from './redis-streams-event-target.js';\n\n// Injectable services for GraphQL Modules\nexport { Logger, createDatabaseService } from './services/index.js';\nexport type { DatabaseService, PrismaTransactionClient } from './services/index.js';\n","/**\n * NATS-based EventTarget Implementation for GraphQL Yoga Distributed PubSub\n *\n * Provides NATS pub/sub infrastructure for GraphQL subscriptions across multiple server instances.\n * This enables horizontal scaling of GraphQL servers while maintaining real-time subscription functionality.\n *\n * Uses event queue abstraction's NatsConnectionManager for connection management\n * while maintaining Core NATS pub/sub for low-latency GraphQL subscriptions\n *\n * Architecture:\n * - Uses NATS Core NATS (not JetStream) for low-latency pub/sub\n * - Implements DOM EventTarget interface required by graphql-yoga's createPubSub\n * - Handles message serialization/deserialization with JSON (customizable)\n * - Manages NATS subscriptions and publishing lifecycle\n * - Includes error handling and reconnection logic\n *\n * Features:\n * - Automatic subscription management per event type\n * - Multiple listener support per event type\n * - Custom serialization support (e.g., SuperJSON for complex types)\n * - Graceful connection handling and cleanup\n * - TypeScript type safety\n *\n * @example\n * ```typescript\n * import { createNatsEventTarget } from '@burdenoff/be-sdk';\n * import { createPubSub } from 'graphql-yoga';\n *\n * const eventTarget = await createNatsEventTarget({\n * natsUrl: 'nats://localhost:4222',\n * });\n *\n * const pubsub = createPubSub({ eventTarget });\n * ```\n *\n * Reference Implementation:\n * Based on @graphql-yoga/redis-event-target pattern\n * https://github.com/graphql-hive/graphql-yoga/tree/main/packages/event-target/redis-event-target\n */\n\nimport type { NatsConnection, Subscription } from 'nats';\nimport { StringCodec } from 'nats';\nimport { logger } from '../logger/index.js';\nimport { NatsConnectionManager } from '../event-queue/implementations/nats/NatsConnection.js';\nimport type { BaseQueueConfig } from '../event-queue/types/config.js';\n\n/**\n * Message Serializer Interface\n *\n * Allows custom serialization for event payloads.\n * Useful for handling non-JSON-serializable data (Dates, BigInts, etc.)\n *\n * @example\n * ```typescript\n * import superjson from 'superjson';\n *\n * const eventTarget = await createNatsEventTarget({\n * natsUrl: 'nats://localhost:4222',\n * serializer: {\n * stringify: (data) => superjson.stringify(data),\n * parse: (message) => superjson.parse(message),\n * }\n * });\n * ```\n */\nexport interface MessageSerializer {\n /**\n * Serialize data to string for transmission over NATS\n */\n stringify: (data: unknown) => string | Promise<string>;\n\n /**\n * Deserialize string message from NATS back to original type\n */\n parse: (message: string) => unknown | Promise<unknown>;\n}\n\n/**\n * NATS EventTarget Options\n */\nexport interface NatsEventTargetOptions {\n /**\n * NATS server URL(s)\n * Examples:\n * - Single server: 'nats://localhost:4222'\n * - Multiple servers: ['nats://server1:4222', 'nats://server2:4222']\n * - With credentials: 'nats://user:password@localhost:4222'\n */\n natsUrl: string | string[];\n\n /**\n * Optional NATS connection options\n * See: https://github.com/nats-io/nats.js#connection-options\n */\n connectionOptions?: {\n /**\n * Connection name for debugging\n * @default 'graphql-pubsub'\n */\n name?: string;\n\n /**\n * Maximum reconnection attempts (-1 for infinite)\n * @default -1\n */\n maxReconnectAttempts?: number;\n\n /**\n * Time to wait between reconnection attempts (ms)\n * @default 2000\n */\n reconnectTimeWait?: number;\n\n /**\n * Ping interval (ms)\n * @default 20000\n */\n pingInterval?: number;\n\n /**\n * Maximum outstanding pings\n * @default 2\n */\n maxPingOut?: number;\n\n /**\n * Connection timeout (ms)\n * @default 20000\n */\n timeout?: number;\n\n /**\n * NATS credentials file contents (JWT + NKEY seed)\n */\n creds?: string;\n\n /**\n * Path to a NATS credentials file\n */\n credsFile?: string;\n };\n\n /**\n * Custom message serializer\n * Defaults to JSON.stringify/parse\n */\n serializer?: MessageSerializer;\n\n /**\n * Subject prefix for all GraphQL subscription topics\n * Useful for namespacing in multi-tenant or multi-app environments\n *\n * @default 'graphql.pubsub'\n *\n * Example: With prefix 'myapp.gql', a subscription to 'MESSAGE_ADDED'\n * will use NATS subject 'myapp.gql.MESSAGE_ADDED'\n */\n subjectPrefix?: string;\n}\n\n/**\n * Event Listener Type\n * Compatible with DOM EventListener interface\n */\ntype EventListener = (event: Event) => void;\n\n/**\n * NATS EventTarget Implementation\n *\n * Implements the EventTarget interface required by graphql-yoga's createPubSub.\n * Uses NATS Core NATS for pub/sub messaging across distributed GraphQL servers.\n */\nexport interface NatsEventTarget {\n /**\n * Subscribe to events of a specific type\n *\n * @param type - Event type (GraphQL subscription trigger)\n * @param listener - Callback function to invoke when event is received\n */\n addEventListener(type: string, listener: EventListener): void;\n\n /**\n * Unsubscribe from events of a specific type\n *\n * @param type - Event type (GraphQL subscription trigger)\n * @param listener - Callback function to remove\n */\n removeEventListener(type: string, listener: EventListener): void;\n\n /**\n * Publish an event to all subscribers\n *\n * @param event - Event to dispatch (must have 'type' and 'detail' properties)\n * @returns Always returns true (EventTarget interface requirement)\n */\n dispatchEvent(event: Event): boolean;\n\n /**\n * Close the NATS connection and cleanup resources\n * Should be called on application shutdown\n */\n close(): Promise<void>;\n\n /**\n * Check if the NATS connection is healthy\n */\n isHealthy(): boolean;\n}\n\n/**\n * Create NATS-based EventTarget for GraphQL Yoga Distributed PubSub\n *\n * This function creates an EventTarget implementation that uses NATS for\n * distributed publish-subscribe across multiple GraphQL server instances.\n *\n * @param options - NATS connection and configuration options\n * @returns Promise resolving to NatsEventTarget instance\n *\n * @example\n * ```typescript\n * // Basic usage\n * const eventTarget = await createNatsEventTarget({\n * natsUrl: 'nats://localhost:4222',\n * });\n *\n * const pubsub = createPubSub({ eventTarget });\n * ```\n *\n * @example\n * ```typescript\n * // With custom configuration\n * const eventTarget = await createNatsEventTarget({\n * natsUrl: ['nats://server1:4222', 'nats://server2:4222'],\n * connectionOptions: {\n * name: 'my-graphql-server',\n * maxReconnectAttempts: 10,\n * reconnectTimeWait: 1000,\n * },\n * subjectPrefix: 'myapp.graphql',\n * serializer: {\n * stringify: (data) => JSON.stringify(data),\n * parse: (msg) => JSON.parse(msg),\n * },\n * });\n * ```\n *\n * @throws {Error} If connection to NATS server fails\n */\nexport async function createNatsEventTarget(options: NatsEventTargetOptions): Promise<NatsEventTarget> {\n const {\n natsUrl,\n connectionOptions = {},\n serializer = {\n stringify: async (data: unknown): Promise<string> => JSON.stringify(data),\n parse: async (message: string): Promise<unknown> => JSON.parse(message),\n },\n subjectPrefix = 'graphql.pubsub',\n } = options;\n\n // NATS StringCodec for encoding/decoding messages\n const sc = StringCodec();\n\n // Default connection options\n const defaultConnectionOptions = {\n name: 'graphql-pubsub',\n maxReconnectAttempts: -1, // Infinite reconnects\n reconnectTimeWait: 2000, // 2 seconds\n pingInterval: 20000, // 20 seconds\n maxPingOut: 2,\n timeout: 20000, // 20 seconds\n };\n\n const mergedConnectionOptions = {\n ...defaultConnectionOptions,\n ...connectionOptions,\n };\n\n // Create connection manager config. Auth is sourced from\n // connectionOptions.user/pass first, then falls back to NATS_USER /\n // NATS_PASSWORD env vars. Required because the bun-bundled `nats`\n // 2.29.x client mis-parses URL-embedded credentials, so the URL must\n // be credential-free and auth must arrive as separate ConnectionOptions.\n const effectiveUser = (mergedConnectionOptions as { user?: string }).user ?? process.env['NATS_USER'];\n const effectivePass =\n (mergedConnectionOptions as { pass?: string; password?: string }).pass ??\n (mergedConnectionOptions as { pass?: string; password?: string }).password ??\n process.env['NATS_PASSWORD'];\n const connectionConfig: BaseQueueConfig = {\n type: 'nats',\n url: Array.isArray(natsUrl) ? (natsUrl[0] ?? 'nats://localhost:4222') : natsUrl,\n name: mergedConnectionOptions.name,\n user: effectiveUser,\n password: effectivePass,\n token: (mergedConnectionOptions as { token?: string }).token ?? process.env['NATS_TOKEN'],\n creds: (mergedConnectionOptions as { creds?: string }).creds ?? process.env['NATS_CREDS'],\n credsFile: (mergedConnectionOptions as { credsFile?: string }).credsFile ?? process.env['NATS_CREDS_FILE'],\n maxReconnectAttempts: mergedConnectionOptions.maxReconnectAttempts,\n reconnectTimeWait: mergedConnectionOptions.reconnectTimeWait,\n };\n\n // Connect to NATS using connection manager\n let connectionManager: NatsConnectionManager;\n let connection: NatsConnection;\n try {\n connectionManager = new NatsConnectionManager(connectionConfig);\n await connectionManager.connect();\n connection = connectionManager.getNatsConnection();\n\n logger.info('[NatsEventTarget] Connected to NATS', {\n url: connectionConfig.url,\n name: connectionConfig.name,\n });\n } catch (error) {\n logger.error('[NatsEventTarget] Failed to connect to NATS', {\n error: error instanceof Error ? error.message : 'Unknown error',\n url: connectionConfig.url,\n });\n throw error;\n }\n\n // Track callbacks per event type\n // Map<eventType, Set<listener>>\n const callbacks = new Map<string, Set<EventListener>>();\n\n // Track NATS subscriptions per event type\n // Map<eventType, Subscription>\n const subscriptions = new Map<string, Subscription>();\n\n /**\n * Get NATS subject for an event type\n * Prefixes the event type with the configured subject prefix\n */\n const getSubject = (eventType: string): string => {\n return `${subjectPrefix}.${eventType}`;\n };\n\n /**\n * Subscribe to NATS subject for an event type\n * Creates a new NATS subscription if one doesn't exist\n */\n const subscribeToNats = (eventType: string): void => {\n // Check if already subscribed\n if (subscriptions.has(eventType)) {\n return;\n }\n\n const subject = getSubject(eventType);\n\n try {\n // Create NATS subscription\n const subscription = connection.subscribe(subject);\n\n // Store subscription\n subscriptions.set(eventType, subscription);\n\n logger.debug('[NatsEventTarget] Subscribed to NATS subject', {\n eventType,\n subject,\n });\n\n // Process messages asynchronously\n void (async (): Promise<void> => {\n try {\n for await (const msg of subscription) {\n try {\n // Decode and deserialize message\n const messageData = sc.decode(msg.data);\n const payload = await serializer.parse(messageData);\n\n // Get callbacks for this event type\n const eventCallbacks = callbacks.get(eventType);\n\n if (eventCallbacks && eventCallbacks.size > 0) {\n // Create CustomEvent with payload\n const event = new CustomEvent(eventType, {\n detail: payload,\n });\n\n // Dispatch to all registered callbacks\n for (const callback of Array.from(eventCallbacks)) {\n try {\n callback(event);\n } catch (callbackError) {\n logger.error('[NatsEventTarget] Error in event callback', {\n eventType,\n error: callbackError instanceof Error ? callbackError.message : 'Unknown error',\n });\n }\n }\n }\n } catch (messageError) {\n logger.error('[NatsEventTarget] Error processing NATS message', {\n eventType,\n subject,\n error: messageError instanceof Error ? messageError.message : 'Unknown error',\n });\n }\n }\n } catch (subscriptionError) {\n logger.error('[NatsEventTarget] Error in NATS subscription loop', {\n eventType,\n subject,\n error: subscriptionError instanceof Error ? subscriptionError.message : 'Unknown error',\n });\n }\n })();\n } catch (error) {\n logger.error('[NatsEventTarget] Failed to subscribe to NATS subject', {\n eventType,\n subject,\n error: error instanceof Error ? error.message : 'Unknown error',\n });\n throw error;\n }\n };\n\n /**\n * Unsubscribe from NATS subject for an event type\n * Only unsubscribes if no more callbacks are registered\n */\n const unsubscribeFromNats = (eventType: string): void => {\n const subscription = subscriptions.get(eventType);\n\n if (subscription) {\n try {\n subscription.unsubscribe();\n subscriptions.delete(eventType);\n\n logger.debug('[NatsEventTarget] Unsubscribed from NATS subject', {\n eventType,\n subject: getSubject(eventType),\n });\n } catch (error) {\n logger.error('[NatsEventTarget] Failed to unsubscribe from NATS subject', {\n eventType,\n error: error instanceof Error ? error.message : 'Unknown error',\n });\n }\n }\n };\n\n /**\n * EventTarget Implementation\n */\n const eventTarget: NatsEventTarget = {\n /**\n * Add event listener (subscribe)\n */\n addEventListener(type: string, listener: EventListener): void {\n try {\n // Get or create callback set for this event type\n let eventCallbacks = callbacks.get(type);\n\n if (!eventCallbacks) {\n eventCallbacks = new Set();\n callbacks.set(type, eventCallbacks);\n\n // First listener for this event type - subscribe to NATS\n subscribeToNats(type);\n }\n\n // Add listener to set\n eventCallbacks.add(listener);\n\n logger.debug('[NatsEventTarget] Event listener added', {\n eventType: type,\n listenerCount: eventCallbacks.size,\n });\n } catch (error) {\n logger.error('[NatsEventTarget] Failed to add event listener', {\n eventType: type,\n error: error instanceof Error ? error.message : 'Unknown error',\n });\n throw error;\n }\n },\n\n /**\n * Remove event listener (unsubscribe)\n */\n removeEventListener(type: string, listener: EventListener): void {\n try {\n const eventCallbacks = callbacks.get(type);\n\n if (eventCallbacks) {\n // Remove listener from set\n eventCallbacks.delete(listener);\n\n const remainingListeners = eventCallbacks.size;\n\n logger.debug('[NatsEventTarget] Event listener removed', {\n eventType: type,\n remainingListeners,\n });\n\n // If no more listeners, unsubscribe from NATS and cleanup\n if (remainingListeners === 0) {\n callbacks.delete(type);\n unsubscribeFromNats(type);\n }\n }\n } catch (error) {\n logger.error('[NatsEventTarget] Failed to remove event listener', {\n eventType: type,\n error: error instanceof Error ? error.message : 'Unknown error',\n });\n throw error;\n }\n },\n\n /**\n * Dispatch event (publish)\n */\n dispatchEvent(event: Event): boolean {\n try {\n const eventType = event.type;\n const subject = getSubject(eventType);\n\n // Extract payload from CustomEvent detail or use event itself\n const payload = 'detail' in event ? (event as CustomEvent).detail : event;\n\n // Serialize payload (fire and forget for async serializers)\n void (async (): Promise<void> => {\n try {\n const message = await serializer.stringify(payload);\n\n // Encode and publish to NATS\n const data = sc.encode(message);\n connection.publish(subject, data);\n\n logger.debug('[NatsEventTarget] Event dispatched to NATS', {\n eventType,\n subject,\n });\n } catch (serializeError) {\n logger.error('[NatsEventTarget] Failed to serialize event for dispatch', {\n eventType,\n error: serializeError instanceof Error ? serializeError.message : 'Unknown error',\n });\n }\n })();\n\n return true;\n } catch (error) {\n logger.error('[NatsEventTarget] Failed to dispatch event', {\n eventType: event.type,\n error: error instanceof Error ? error.message : 'Unknown error',\n });\n throw error;\n }\n },\n\n /**\n * Close NATS connection and cleanup\n */\n async close(): Promise<void> {\n try {\n logger.info('[NatsEventTarget] Closing NATS connection...');\n\n // Unsubscribe from all subjects\n for (const [eventType, subscription] of Array.from(subscriptions.entries())) {\n try {\n subscription.unsubscribe();\n logger.debug('[NatsEventTarget] Unsubscribed from subject', {\n eventType,\n });\n } catch (error) {\n logger.error('[NatsEventTarget] Error unsubscribing from subject', {\n eventType,\n error: error instanceof Error ? error.message : 'Unknown error',\n });\n }\n }\n\n // Clear all subscriptions and callbacks\n subscriptions.clear();\n callbacks.clear();\n\n // Disconnect using connection manager\n await connectionManager.disconnect();\n\n logger.info('[NatsEventTarget] NATS connection closed successfully');\n } catch (error) {\n logger.error('[NatsEventTarget] Failed to close NATS connection', {\n error: error instanceof Error ? error.message : 'Unknown error',\n });\n throw error;\n }\n },\n\n /**\n * Check if connection is healthy\n */\n isHealthy(): boolean {\n return !connection.isClosed();\n },\n };\n\n return eventTarget;\n}\n","/**\n * Redis Streams-based EventTarget for graphql-yoga distributed PubSub.\n *\n * Each server tails a per-event-type stream with `XREAD BLOCK ... $` (no\n * consumer group) so every instance receives every dispatch — the fan-out\n * semantics GraphQL subscriptions require.\n *\n * For durable inter-svc events use `event-queue/createPublisher` instead.\n */\nimport { logger } from '../logger/index.js';\nimport { RedisStreamsConnection } from '../event-queue/implementations/redis-streams/RedisStreamsConnection.js';\n\nexport interface RedisStreamsEventTarget {\n addEventListener(type: string, listener: (event: Event) => void): void;\n removeEventListener(type: string, listener: (event: Event) => void): void;\n dispatchEvent(event: Event): boolean;\n close(): Promise<void>;\n isHealthy(): boolean;\n}\n\nexport interface RedisStreamsEventTargetOptions {\n /** Redis connection URL. Defaults to `REDIS_URL` env. */\n redisUrl?: string;\n /** Optional password override. */\n password?: string;\n /** Subject prefix; keys become `<prefix>.<type>` mapped via `:` separator. */\n subjectPrefix?: string;\n /** Approximate MAXLEN trim for each pubsub stream. Default 1000. */\n maxLen?: number;\n /** Per-event serialiser. */\n serializer?: {\n stringify: (data: unknown) => string | Promise<string>;\n parse: (msg: string) => unknown | Promise<unknown>;\n };\n}\n\nexport async function createRedisStreamsEventTarget(\n options: RedisStreamsEventTargetOptions = {}\n): Promise<RedisStreamsEventTarget> {\n const url = options.redisUrl ?? process.env['REDIS_URL'];\n if (!url) throw new Error('[RedisStreamsEventTarget] redisUrl or REDIS_URL is required');\n const prefix = options.subjectPrefix ?? 'graphql.pubsub';\n const maxLen = options.maxLen ?? 1000;\n const serializer = options.serializer ?? {\n stringify: (d: unknown): string => JSON.stringify(d),\n parse: (m: string): unknown => JSON.parse(m),\n };\n\n const conn = new RedisStreamsConnection({\n type: 'redis-streams',\n url,\n password: options.password ?? process.env['REDIS_PASSWORD'],\n name: 'graphql-pubsub',\n });\n // Connect in the background — don't block svc startup on Redis reachability.\n void conn\n .connect()\n .then(() => logger.info('[RedisStreamsEventTarget] redis connected'))\n .catch((err) => {\n logger.warn('[RedisStreamsEventTarget] redis connect failed; pubsub will retry on demand', {\n error: err instanceof Error ? err.message : String(err),\n });\n });\n\n const streamKey = (type: string): string => `boff:pubsub:${prefix}:${type.replace(/\\./g, ':')}`;\n\n const listeners = new Map<string, Set<(event: Event) => void>>();\n const readers = new Map<string, { stop: () => void }>();\n let closed = false;\n\n function startReader(type: string): void {\n if (readers.has(type) || closed) return;\n let stopped = false;\n const stream = streamKey(type);\n\n const loop = async (): Promise<void> => {\n const blockingClient = await conn.makeBlockingClient();\n let lastId = '$';\n try {\n while (!stopped && !closed) {\n let raw: Array<[string, Array<[string, string[]]>]> | null = null;\n try {\n raw = (await blockingClient.xreadgroup(\n // pretend-arg pattern: we actually want XREAD, fall through\n 'COUNT',\n 50,\n 'BLOCK',\n 5000,\n 'STREAMS',\n stream,\n lastId\n )) as Array<[string, Array<[string, string[]]>]> | null;\n } catch {\n // Some ioredis typings make xreadgroup the only signature; fall back to xread via raw command.\n try {\n raw = (await (blockingClient as unknown as {\n call: (...args: unknown[]) => Promise<unknown>;\n }).call('XREAD', 'COUNT', 50, 'BLOCK', 5000, 'STREAMS', stream, lastId)) as Array<\n [string, Array<[string, string[]]>]\n > | null;\n } catch (err) {\n logger.debug('[RedisStreamsEventTarget] xread error', {\n stream,\n error: err instanceof Error ? err.message : String(err),\n });\n await new Promise((r) => setTimeout(r, 1000));\n continue;\n }\n }\n if (!raw) continue;\n for (const [, entries] of raw) {\n for (const [id, rawFields] of entries) {\n lastId = id;\n const fields: Record<string, string> = {};\n for (let i = 0; i + 1 < rawFields.length; i += 2) {\n fields[rawFields[i]!] = rawFields[i + 1]!;\n }\n const payload = await serializer.parse(fields['payload'] ?? 'null');\n const cbs = listeners.get(type);\n if (!cbs) continue;\n const ev = new CustomEvent(type, { detail: payload });\n for (const cb of Array.from(cbs)) {\n try {\n cb(ev);\n } catch (cbErr) {\n logger.error('[RedisStreamsEventTarget] listener error', {\n type,\n error: cbErr instanceof Error ? cbErr.message : String(cbErr),\n });\n }\n }\n }\n }\n }\n } finally {\n try {\n blockingClient.disconnect();\n } catch {\n /* ignore */\n }\n }\n };\n\n readers.set(type, {\n stop: (): void => {\n stopped = true;\n },\n });\n void loop().catch((err) => {\n logger.error('[RedisStreamsEventTarget] reader crashed', {\n type,\n error: err instanceof Error ? err.message : String(err),\n });\n });\n }\n\n function stopReader(type: string): void {\n const r = readers.get(type);\n if (r) {\n r.stop();\n readers.delete(type);\n }\n }\n\n const target: RedisStreamsEventTarget = {\n addEventListener(type, listener): void {\n let set = listeners.get(type);\n if (!set) {\n set = new Set();\n listeners.set(type, set);\n startReader(type);\n }\n set.add(listener);\n },\n removeEventListener(type, listener): void {\n const set = listeners.get(type);\n if (!set) return;\n set.delete(listener);\n if (set.size === 0) {\n listeners.delete(type);\n stopReader(type);\n }\n },\n dispatchEvent(event): boolean {\n const detail = 'detail' in event ? (event as CustomEvent).detail : event;\n void (async (): Promise<void> => {\n try {\n const payload = await serializer.stringify(detail);\n await conn.getClient().xadd(streamKey(event.type), 'MAXLEN', '~', maxLen, '*', 'payload', payload);\n } catch (err) {\n logger.error('[RedisStreamsEventTarget] dispatch failed', {\n type: event.type,\n error: err instanceof Error ? err.message : String(err),\n });\n }\n })();\n return true;\n },\n async close(): Promise<void> {\n closed = true;\n for (const r of readers.values()) r.stop();\n readers.clear();\n listeners.clear();\n await conn.disconnect();\n },\n isHealthy(): boolean {\n return conn.isConnected();\n },\n };\n\n logger.info('[RedisStreamsEventTarget] ready', { prefix });\n return target;\n}\n"]}
|
package/dist/graphql/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { createNatsEventTarget, createRedisStreamsEventTarget } from '../chunk-
|
|
1
|
+
export { createNatsEventTarget, createRedisStreamsEventTarget } from '../chunk-MI72VKNQ.js';
|
|
2
2
|
export { Logger, createDatabaseService } from '../chunk-QLVKMWFA.js';
|
|
3
3
|
import '../chunk-QKJR4L7B.js';
|
|
4
4
|
import '../chunk-CBZNP6RF.js';
|
package/dist/index.js
CHANGED
|
@@ -18,7 +18,7 @@ import './chunk-TKBD2ONF.js';
|
|
|
18
18
|
import { EventsModule } from './chunk-3JBKPVWY.js';
|
|
19
19
|
export { event_queue_exports as EventQueue, EventsModule } from './chunk-3JBKPVWY.js';
|
|
20
20
|
import './chunk-Q6HJARHV.js';
|
|
21
|
-
export { graphql_exports as GraphQL } from './chunk-
|
|
21
|
+
export { graphql_exports as GraphQL } from './chunk-MI72VKNQ.js';
|
|
22
22
|
import './chunk-QLVKMWFA.js';
|
|
23
23
|
export { i18n_exports as I18n, createTranslator, getLanguage, getLocale, hasI18n, t } from './chunk-IYE2NTRX.js';
|
|
24
24
|
export { init_exports as Init } from './chunk-OMKFTTAN.js';
|
|
@@ -32,8 +32,8 @@ import { AuthModule } from './chunk-WBWM7UY7.js';
|
|
|
32
32
|
export { AuthModule } from './chunk-WBWM7UY7.js';
|
|
33
33
|
export { utils_exports as Utils } from './chunk-MOCUBSTW.js';
|
|
34
34
|
export { cache_exports as Cache } from './chunk-4XGGWW36.js';
|
|
35
|
-
export { createInternalClient, createInternalClientForTenant, createInternalClientForWorkspaces } from './chunk-VI4VSNTI.js';
|
|
36
35
|
export { captcha_exports as Captcha, isCaptchaEnabled, verifyCaptcha, verifyCaptchaIfEnabled } from './chunk-YMZEUTD2.js';
|
|
36
|
+
export { createInternalClient, createInternalClientForTenant, createInternalClientForWorkspaces } from './chunk-VI4VSNTI.js';
|
|
37
37
|
export { crypto_exports as Crypto } from './chunk-SBS4S2PJ.js';
|
|
38
38
|
import { DatabaseModule } from './chunk-5CAA3JST.js';
|
|
39
39
|
export { DatabaseModule } from './chunk-5CAA3JST.js';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@burdenoff/be-sdk",
|
|
3
|
-
"version": "2026.513.
|
|
3
|
+
"version": "2026.513.3",
|
|
4
4
|
"description": "Backend SDK for Burdenoff products providing unified access to notifications, RBAC, activity tracking, usage monitoring, and more",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/graphql/index.ts","../src/graphql/nats-event-target.ts","../src/graphql/redis-streams-event-target.ts"],"names":["createNatsEventTarget","options","natsUrl","connectionOptions","serializer","stringify","data","JSON","parse","message","subjectPrefix","sc","StringCodec","defaultConnectionOptions","name","maxReconnectAttempts","reconnectTimeWait","pingInterval","maxPingOut","timeout","mergedConnectionOptions","effectiveUser","user","process","env","effectivePass","pass","password","connectionConfig","type","url","Array","isArray","token","creds","credsFile","connectionManager","connection","NatsConnectionManager","connect","getNatsConnection","logger","info","error","Error","callbacks","Map","subscriptions","getSubject","eventType","subscribeToNats","has","subject","subscription","subscribe","set","debug","msg","messageData","decode","payload","eventCallbacks","get","size","event","CustomEvent","detail","callback","from","callbackError","messageError","subscriptionError","unsubscribeFromNats","unsubscribe","delete","eventTarget","addEventListener","listener","Set","add","listenerCount","removeEventListener","remainingListeners","dispatchEvent","encode","publish","serializeError","close","entries","clear","disconnect","isHealthy","isClosed","createRedisStreamsEventTarget","redisUrl","prefix","maxLen","d","m","conn","RedisStreamsConnection","cmd","getClient","streamKey","replace","listeners","readers","closed","startReader","stopped","stream","loop","blockingClient","makeBlockingClient","lastId","raw","xreadgroup","call","err","String","Promise","r","setTimeout","id","rawFields","fields","i","length","cbs","ev","cb","cbErr","stop","catch","stopReader","target","xadd","values","isConnected"],"mappings":"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","file":"chunk-3HCMPYG6.js","sourcesContent":["/**\n * GraphQL Utilities Module\n *\n * Provides GraphQL-related utilities for Burdenoff products.\n *\n * @module graphql\n */\n\nexport { createNatsEventTarget } from './nats-event-target.js';\nexport type { NatsEventTarget, NatsEventTargetOptions, MessageSerializer } from './nats-event-target.js';\n\nexport { createRedisStreamsEventTarget } from './redis-streams-event-target.js';\nexport type {\n RedisStreamsEventTarget,\n RedisStreamsEventTargetOptions,\n} from './redis-streams-event-target.js';\n\n// Injectable services for GraphQL Modules\nexport { Logger, createDatabaseService } from './services/index.js';\nexport type { DatabaseService, PrismaTransactionClient } from './services/index.js';\n","/**\n * NATS-based EventTarget Implementation for GraphQL Yoga Distributed PubSub\n *\n * Provides NATS pub/sub infrastructure for GraphQL subscriptions across multiple server instances.\n * This enables horizontal scaling of GraphQL servers while maintaining real-time subscription functionality.\n *\n * Uses event queue abstraction's NatsConnectionManager for connection management\n * while maintaining Core NATS pub/sub for low-latency GraphQL subscriptions\n *\n * Architecture:\n * - Uses NATS Core NATS (not JetStream) for low-latency pub/sub\n * - Implements DOM EventTarget interface required by graphql-yoga's createPubSub\n * - Handles message serialization/deserialization with JSON (customizable)\n * - Manages NATS subscriptions and publishing lifecycle\n * - Includes error handling and reconnection logic\n *\n * Features:\n * - Automatic subscription management per event type\n * - Multiple listener support per event type\n * - Custom serialization support (e.g., SuperJSON for complex types)\n * - Graceful connection handling and cleanup\n * - TypeScript type safety\n *\n * @example\n * ```typescript\n * import { createNatsEventTarget } from '@burdenoff/be-sdk';\n * import { createPubSub } from 'graphql-yoga';\n *\n * const eventTarget = await createNatsEventTarget({\n * natsUrl: 'nats://localhost:4222',\n * });\n *\n * const pubsub = createPubSub({ eventTarget });\n * ```\n *\n * Reference Implementation:\n * Based on @graphql-yoga/redis-event-target pattern\n * https://github.com/graphql-hive/graphql-yoga/tree/main/packages/event-target/redis-event-target\n */\n\nimport type { NatsConnection, Subscription } from 'nats';\nimport { StringCodec } from 'nats';\nimport { logger } from '../logger/index.js';\nimport { NatsConnectionManager } from '../event-queue/implementations/nats/NatsConnection.js';\nimport type { BaseQueueConfig } from '../event-queue/types/config.js';\n\n/**\n * Message Serializer Interface\n *\n * Allows custom serialization for event payloads.\n * Useful for handling non-JSON-serializable data (Dates, BigInts, etc.)\n *\n * @example\n * ```typescript\n * import superjson from 'superjson';\n *\n * const eventTarget = await createNatsEventTarget({\n * natsUrl: 'nats://localhost:4222',\n * serializer: {\n * stringify: (data) => superjson.stringify(data),\n * parse: (message) => superjson.parse(message),\n * }\n * });\n * ```\n */\nexport interface MessageSerializer {\n /**\n * Serialize data to string for transmission over NATS\n */\n stringify: (data: unknown) => string | Promise<string>;\n\n /**\n * Deserialize string message from NATS back to original type\n */\n parse: (message: string) => unknown | Promise<unknown>;\n}\n\n/**\n * NATS EventTarget Options\n */\nexport interface NatsEventTargetOptions {\n /**\n * NATS server URL(s)\n * Examples:\n * - Single server: 'nats://localhost:4222'\n * - Multiple servers: ['nats://server1:4222', 'nats://server2:4222']\n * - With credentials: 'nats://user:password@localhost:4222'\n */\n natsUrl: string | string[];\n\n /**\n * Optional NATS connection options\n * See: https://github.com/nats-io/nats.js#connection-options\n */\n connectionOptions?: {\n /**\n * Connection name for debugging\n * @default 'graphql-pubsub'\n */\n name?: string;\n\n /**\n * Maximum reconnection attempts (-1 for infinite)\n * @default -1\n */\n maxReconnectAttempts?: number;\n\n /**\n * Time to wait between reconnection attempts (ms)\n * @default 2000\n */\n reconnectTimeWait?: number;\n\n /**\n * Ping interval (ms)\n * @default 20000\n */\n pingInterval?: number;\n\n /**\n * Maximum outstanding pings\n * @default 2\n */\n maxPingOut?: number;\n\n /**\n * Connection timeout (ms)\n * @default 20000\n */\n timeout?: number;\n\n /**\n * NATS credentials file contents (JWT + NKEY seed)\n */\n creds?: string;\n\n /**\n * Path to a NATS credentials file\n */\n credsFile?: string;\n };\n\n /**\n * Custom message serializer\n * Defaults to JSON.stringify/parse\n */\n serializer?: MessageSerializer;\n\n /**\n * Subject prefix for all GraphQL subscription topics\n * Useful for namespacing in multi-tenant or multi-app environments\n *\n * @default 'graphql.pubsub'\n *\n * Example: With prefix 'myapp.gql', a subscription to 'MESSAGE_ADDED'\n * will use NATS subject 'myapp.gql.MESSAGE_ADDED'\n */\n subjectPrefix?: string;\n}\n\n/**\n * Event Listener Type\n * Compatible with DOM EventListener interface\n */\ntype EventListener = (event: Event) => void;\n\n/**\n * NATS EventTarget Implementation\n *\n * Implements the EventTarget interface required by graphql-yoga's createPubSub.\n * Uses NATS Core NATS for pub/sub messaging across distributed GraphQL servers.\n */\nexport interface NatsEventTarget {\n /**\n * Subscribe to events of a specific type\n *\n * @param type - Event type (GraphQL subscription trigger)\n * @param listener - Callback function to invoke when event is received\n */\n addEventListener(type: string, listener: EventListener): void;\n\n /**\n * Unsubscribe from events of a specific type\n *\n * @param type - Event type (GraphQL subscription trigger)\n * @param listener - Callback function to remove\n */\n removeEventListener(type: string, listener: EventListener): void;\n\n /**\n * Publish an event to all subscribers\n *\n * @param event - Event to dispatch (must have 'type' and 'detail' properties)\n * @returns Always returns true (EventTarget interface requirement)\n */\n dispatchEvent(event: Event): boolean;\n\n /**\n * Close the NATS connection and cleanup resources\n * Should be called on application shutdown\n */\n close(): Promise<void>;\n\n /**\n * Check if the NATS connection is healthy\n */\n isHealthy(): boolean;\n}\n\n/**\n * Create NATS-based EventTarget for GraphQL Yoga Distributed PubSub\n *\n * This function creates an EventTarget implementation that uses NATS for\n * distributed publish-subscribe across multiple GraphQL server instances.\n *\n * @param options - NATS connection and configuration options\n * @returns Promise resolving to NatsEventTarget instance\n *\n * @example\n * ```typescript\n * // Basic usage\n * const eventTarget = await createNatsEventTarget({\n * natsUrl: 'nats://localhost:4222',\n * });\n *\n * const pubsub = createPubSub({ eventTarget });\n * ```\n *\n * @example\n * ```typescript\n * // With custom configuration\n * const eventTarget = await createNatsEventTarget({\n * natsUrl: ['nats://server1:4222', 'nats://server2:4222'],\n * connectionOptions: {\n * name: 'my-graphql-server',\n * maxReconnectAttempts: 10,\n * reconnectTimeWait: 1000,\n * },\n * subjectPrefix: 'myapp.graphql',\n * serializer: {\n * stringify: (data) => JSON.stringify(data),\n * parse: (msg) => JSON.parse(msg),\n * },\n * });\n * ```\n *\n * @throws {Error} If connection to NATS server fails\n */\nexport async function createNatsEventTarget(options: NatsEventTargetOptions): Promise<NatsEventTarget> {\n const {\n natsUrl,\n connectionOptions = {},\n serializer = {\n stringify: async (data: unknown): Promise<string> => JSON.stringify(data),\n parse: async (message: string): Promise<unknown> => JSON.parse(message),\n },\n subjectPrefix = 'graphql.pubsub',\n } = options;\n\n // NATS StringCodec for encoding/decoding messages\n const sc = StringCodec();\n\n // Default connection options\n const defaultConnectionOptions = {\n name: 'graphql-pubsub',\n maxReconnectAttempts: -1, // Infinite reconnects\n reconnectTimeWait: 2000, // 2 seconds\n pingInterval: 20000, // 20 seconds\n maxPingOut: 2,\n timeout: 20000, // 20 seconds\n };\n\n const mergedConnectionOptions = {\n ...defaultConnectionOptions,\n ...connectionOptions,\n };\n\n // Create connection manager config. Auth is sourced from\n // connectionOptions.user/pass first, then falls back to NATS_USER /\n // NATS_PASSWORD env vars. Required because the bun-bundled `nats`\n // 2.29.x client mis-parses URL-embedded credentials, so the URL must\n // be credential-free and auth must arrive as separate ConnectionOptions.\n const effectiveUser = (mergedConnectionOptions as { user?: string }).user ?? process.env['NATS_USER'];\n const effectivePass =\n (mergedConnectionOptions as { pass?: string; password?: string }).pass ??\n (mergedConnectionOptions as { pass?: string; password?: string }).password ??\n process.env['NATS_PASSWORD'];\n const connectionConfig: BaseQueueConfig = {\n type: 'nats',\n url: Array.isArray(natsUrl) ? (natsUrl[0] ?? 'nats://localhost:4222') : natsUrl,\n name: mergedConnectionOptions.name,\n user: effectiveUser,\n password: effectivePass,\n token: (mergedConnectionOptions as { token?: string }).token ?? process.env['NATS_TOKEN'],\n creds: (mergedConnectionOptions as { creds?: string }).creds ?? process.env['NATS_CREDS'],\n credsFile: (mergedConnectionOptions as { credsFile?: string }).credsFile ?? process.env['NATS_CREDS_FILE'],\n maxReconnectAttempts: mergedConnectionOptions.maxReconnectAttempts,\n reconnectTimeWait: mergedConnectionOptions.reconnectTimeWait,\n };\n\n // Connect to NATS using connection manager\n let connectionManager: NatsConnectionManager;\n let connection: NatsConnection;\n try {\n connectionManager = new NatsConnectionManager(connectionConfig);\n await connectionManager.connect();\n connection = connectionManager.getNatsConnection();\n\n logger.info('[NatsEventTarget] Connected to NATS', {\n url: connectionConfig.url,\n name: connectionConfig.name,\n });\n } catch (error) {\n logger.error('[NatsEventTarget] Failed to connect to NATS', {\n error: error instanceof Error ? error.message : 'Unknown error',\n url: connectionConfig.url,\n });\n throw error;\n }\n\n // Track callbacks per event type\n // Map<eventType, Set<listener>>\n const callbacks = new Map<string, Set<EventListener>>();\n\n // Track NATS subscriptions per event type\n // Map<eventType, Subscription>\n const subscriptions = new Map<string, Subscription>();\n\n /**\n * Get NATS subject for an event type\n * Prefixes the event type with the configured subject prefix\n */\n const getSubject = (eventType: string): string => {\n return `${subjectPrefix}.${eventType}`;\n };\n\n /**\n * Subscribe to NATS subject for an event type\n * Creates a new NATS subscription if one doesn't exist\n */\n const subscribeToNats = (eventType: string): void => {\n // Check if already subscribed\n if (subscriptions.has(eventType)) {\n return;\n }\n\n const subject = getSubject(eventType);\n\n try {\n // Create NATS subscription\n const subscription = connection.subscribe(subject);\n\n // Store subscription\n subscriptions.set(eventType, subscription);\n\n logger.debug('[NatsEventTarget] Subscribed to NATS subject', {\n eventType,\n subject,\n });\n\n // Process messages asynchronously\n void (async (): Promise<void> => {\n try {\n for await (const msg of subscription) {\n try {\n // Decode and deserialize message\n const messageData = sc.decode(msg.data);\n const payload = await serializer.parse(messageData);\n\n // Get callbacks for this event type\n const eventCallbacks = callbacks.get(eventType);\n\n if (eventCallbacks && eventCallbacks.size > 0) {\n // Create CustomEvent with payload\n const event = new CustomEvent(eventType, {\n detail: payload,\n });\n\n // Dispatch to all registered callbacks\n for (const callback of Array.from(eventCallbacks)) {\n try {\n callback(event);\n } catch (callbackError) {\n logger.error('[NatsEventTarget] Error in event callback', {\n eventType,\n error: callbackError instanceof Error ? callbackError.message : 'Unknown error',\n });\n }\n }\n }\n } catch (messageError) {\n logger.error('[NatsEventTarget] Error processing NATS message', {\n eventType,\n subject,\n error: messageError instanceof Error ? messageError.message : 'Unknown error',\n });\n }\n }\n } catch (subscriptionError) {\n logger.error('[NatsEventTarget] Error in NATS subscription loop', {\n eventType,\n subject,\n error: subscriptionError instanceof Error ? subscriptionError.message : 'Unknown error',\n });\n }\n })();\n } catch (error) {\n logger.error('[NatsEventTarget] Failed to subscribe to NATS subject', {\n eventType,\n subject,\n error: error instanceof Error ? error.message : 'Unknown error',\n });\n throw error;\n }\n };\n\n /**\n * Unsubscribe from NATS subject for an event type\n * Only unsubscribes if no more callbacks are registered\n */\n const unsubscribeFromNats = (eventType: string): void => {\n const subscription = subscriptions.get(eventType);\n\n if (subscription) {\n try {\n subscription.unsubscribe();\n subscriptions.delete(eventType);\n\n logger.debug('[NatsEventTarget] Unsubscribed from NATS subject', {\n eventType,\n subject: getSubject(eventType),\n });\n } catch (error) {\n logger.error('[NatsEventTarget] Failed to unsubscribe from NATS subject', {\n eventType,\n error: error instanceof Error ? error.message : 'Unknown error',\n });\n }\n }\n };\n\n /**\n * EventTarget Implementation\n */\n const eventTarget: NatsEventTarget = {\n /**\n * Add event listener (subscribe)\n */\n addEventListener(type: string, listener: EventListener): void {\n try {\n // Get or create callback set for this event type\n let eventCallbacks = callbacks.get(type);\n\n if (!eventCallbacks) {\n eventCallbacks = new Set();\n callbacks.set(type, eventCallbacks);\n\n // First listener for this event type - subscribe to NATS\n subscribeToNats(type);\n }\n\n // Add listener to set\n eventCallbacks.add(listener);\n\n logger.debug('[NatsEventTarget] Event listener added', {\n eventType: type,\n listenerCount: eventCallbacks.size,\n });\n } catch (error) {\n logger.error('[NatsEventTarget] Failed to add event listener', {\n eventType: type,\n error: error instanceof Error ? error.message : 'Unknown error',\n });\n throw error;\n }\n },\n\n /**\n * Remove event listener (unsubscribe)\n */\n removeEventListener(type: string, listener: EventListener): void {\n try {\n const eventCallbacks = callbacks.get(type);\n\n if (eventCallbacks) {\n // Remove listener from set\n eventCallbacks.delete(listener);\n\n const remainingListeners = eventCallbacks.size;\n\n logger.debug('[NatsEventTarget] Event listener removed', {\n eventType: type,\n remainingListeners,\n });\n\n // If no more listeners, unsubscribe from NATS and cleanup\n if (remainingListeners === 0) {\n callbacks.delete(type);\n unsubscribeFromNats(type);\n }\n }\n } catch (error) {\n logger.error('[NatsEventTarget] Failed to remove event listener', {\n eventType: type,\n error: error instanceof Error ? error.message : 'Unknown error',\n });\n throw error;\n }\n },\n\n /**\n * Dispatch event (publish)\n */\n dispatchEvent(event: Event): boolean {\n try {\n const eventType = event.type;\n const subject = getSubject(eventType);\n\n // Extract payload from CustomEvent detail or use event itself\n const payload = 'detail' in event ? (event as CustomEvent).detail : event;\n\n // Serialize payload (fire and forget for async serializers)\n void (async (): Promise<void> => {\n try {\n const message = await serializer.stringify(payload);\n\n // Encode and publish to NATS\n const data = sc.encode(message);\n connection.publish(subject, data);\n\n logger.debug('[NatsEventTarget] Event dispatched to NATS', {\n eventType,\n subject,\n });\n } catch (serializeError) {\n logger.error('[NatsEventTarget] Failed to serialize event for dispatch', {\n eventType,\n error: serializeError instanceof Error ? serializeError.message : 'Unknown error',\n });\n }\n })();\n\n return true;\n } catch (error) {\n logger.error('[NatsEventTarget] Failed to dispatch event', {\n eventType: event.type,\n error: error instanceof Error ? error.message : 'Unknown error',\n });\n throw error;\n }\n },\n\n /**\n * Close NATS connection and cleanup\n */\n async close(): Promise<void> {\n try {\n logger.info('[NatsEventTarget] Closing NATS connection...');\n\n // Unsubscribe from all subjects\n for (const [eventType, subscription] of Array.from(subscriptions.entries())) {\n try {\n subscription.unsubscribe();\n logger.debug('[NatsEventTarget] Unsubscribed from subject', {\n eventType,\n });\n } catch (error) {\n logger.error('[NatsEventTarget] Error unsubscribing from subject', {\n eventType,\n error: error instanceof Error ? error.message : 'Unknown error',\n });\n }\n }\n\n // Clear all subscriptions and callbacks\n subscriptions.clear();\n callbacks.clear();\n\n // Disconnect using connection manager\n await connectionManager.disconnect();\n\n logger.info('[NatsEventTarget] NATS connection closed successfully');\n } catch (error) {\n logger.error('[NatsEventTarget] Failed to close NATS connection', {\n error: error instanceof Error ? error.message : 'Unknown error',\n });\n throw error;\n }\n },\n\n /**\n * Check if connection is healthy\n */\n isHealthy(): boolean {\n return !connection.isClosed();\n },\n };\n\n return eventTarget;\n}\n","/**\n * Redis Streams-based EventTarget for graphql-yoga distributed PubSub.\n *\n * Each server tails a per-event-type stream with `XREAD BLOCK ... $` (no\n * consumer group) so every instance receives every dispatch — the fan-out\n * semantics GraphQL subscriptions require.\n *\n * For durable inter-svc events use `event-queue/createPublisher` instead.\n */\nimport { logger } from '../logger/index.js';\nimport { RedisStreamsConnection } from '../event-queue/implementations/redis-streams/RedisStreamsConnection.js';\n\nexport interface RedisStreamsEventTarget {\n addEventListener(type: string, listener: (event: Event) => void): void;\n removeEventListener(type: string, listener: (event: Event) => void): void;\n dispatchEvent(event: Event): boolean;\n close(): Promise<void>;\n isHealthy(): boolean;\n}\n\nexport interface RedisStreamsEventTargetOptions {\n /** Redis connection URL. Defaults to `REDIS_URL` env. */\n redisUrl?: string;\n /** Optional password override. */\n password?: string;\n /** Subject prefix; keys become `<prefix>.<type>` mapped via `:` separator. */\n subjectPrefix?: string;\n /** Approximate MAXLEN trim for each pubsub stream. Default 1000. */\n maxLen?: number;\n /** Per-event serialiser. */\n serializer?: {\n stringify: (data: unknown) => string | Promise<string>;\n parse: (msg: string) => unknown | Promise<unknown>;\n };\n}\n\nexport async function createRedisStreamsEventTarget(\n options: RedisStreamsEventTargetOptions = {}\n): Promise<RedisStreamsEventTarget> {\n const url = options.redisUrl ?? process.env['REDIS_URL'];\n if (!url) throw new Error('[RedisStreamsEventTarget] redisUrl or REDIS_URL is required');\n const prefix = options.subjectPrefix ?? 'graphql.pubsub';\n const maxLen = options.maxLen ?? 1000;\n const serializer = options.serializer ?? {\n stringify: (d: unknown): string => JSON.stringify(d),\n parse: (m: string): unknown => JSON.parse(m),\n };\n\n const conn = new RedisStreamsConnection({\n type: 'redis-streams',\n url,\n password: options.password ?? process.env['REDIS_PASSWORD'],\n name: 'graphql-pubsub',\n });\n await conn.connect();\n const cmd = conn.getClient();\n\n const streamKey = (type: string): string => `boff:pubsub:${prefix}:${type.replace(/\\./g, ':')}`;\n\n const listeners = new Map<string, Set<(event: Event) => void>>();\n const readers = new Map<string, { stop: () => void }>();\n let closed = false;\n\n function startReader(type: string): void {\n if (readers.has(type) || closed) return;\n let stopped = false;\n const stream = streamKey(type);\n\n const loop = async (): Promise<void> => {\n const blockingClient = await conn.makeBlockingClient();\n let lastId = '$';\n try {\n while (!stopped && !closed) {\n let raw: Array<[string, Array<[string, string[]]>]> | null = null;\n try {\n raw = (await blockingClient.xreadgroup(\n // pretend-arg pattern: we actually want XREAD, fall through\n 'COUNT',\n 50,\n 'BLOCK',\n 5000,\n 'STREAMS',\n stream,\n lastId\n )) as Array<[string, Array<[string, string[]]>]> | null;\n } catch {\n // Some ioredis typings make xreadgroup the only signature; fall back to xread via raw command.\n try {\n raw = (await (blockingClient as unknown as {\n call: (...args: unknown[]) => Promise<unknown>;\n }).call('XREAD', 'COUNT', 50, 'BLOCK', 5000, 'STREAMS', stream, lastId)) as Array<\n [string, Array<[string, string[]]>]\n > | null;\n } catch (err) {\n logger.debug('[RedisStreamsEventTarget] xread error', {\n stream,\n error: err instanceof Error ? err.message : String(err),\n });\n await new Promise((r) => setTimeout(r, 1000));\n continue;\n }\n }\n if (!raw) continue;\n for (const [, entries] of raw) {\n for (const [id, rawFields] of entries) {\n lastId = id;\n const fields: Record<string, string> = {};\n for (let i = 0; i + 1 < rawFields.length; i += 2) {\n fields[rawFields[i]!] = rawFields[i + 1]!;\n }\n const payload = await serializer.parse(fields['payload'] ?? 'null');\n const cbs = listeners.get(type);\n if (!cbs) continue;\n const ev = new CustomEvent(type, { detail: payload });\n for (const cb of Array.from(cbs)) {\n try {\n cb(ev);\n } catch (cbErr) {\n logger.error('[RedisStreamsEventTarget] listener error', {\n type,\n error: cbErr instanceof Error ? cbErr.message : String(cbErr),\n });\n }\n }\n }\n }\n }\n } finally {\n try {\n blockingClient.disconnect();\n } catch {\n /* ignore */\n }\n }\n };\n\n readers.set(type, {\n stop: (): void => {\n stopped = true;\n },\n });\n void loop().catch((err) => {\n logger.error('[RedisStreamsEventTarget] reader crashed', {\n type,\n error: err instanceof Error ? err.message : String(err),\n });\n });\n }\n\n function stopReader(type: string): void {\n const r = readers.get(type);\n if (r) {\n r.stop();\n readers.delete(type);\n }\n }\n\n const target: RedisStreamsEventTarget = {\n addEventListener(type, listener): void {\n let set = listeners.get(type);\n if (!set) {\n set = new Set();\n listeners.set(type, set);\n startReader(type);\n }\n set.add(listener);\n },\n removeEventListener(type, listener): void {\n const set = listeners.get(type);\n if (!set) return;\n set.delete(listener);\n if (set.size === 0) {\n listeners.delete(type);\n stopReader(type);\n }\n },\n dispatchEvent(event): boolean {\n const detail = 'detail' in event ? (event as CustomEvent).detail : event;\n void (async (): Promise<void> => {\n try {\n const payload = await serializer.stringify(detail);\n await cmd.xadd(streamKey(event.type), 'MAXLEN', '~', maxLen, '*', 'payload', payload);\n } catch (err) {\n logger.error('[RedisStreamsEventTarget] dispatch failed', {\n type: event.type,\n error: err instanceof Error ? err.message : String(err),\n });\n }\n })();\n return true;\n },\n async close(): Promise<void> {\n closed = true;\n for (const r of readers.values()) r.stop();\n readers.clear();\n listeners.clear();\n await conn.disconnect();\n },\n isHealthy(): boolean {\n return conn.isConnected();\n },\n };\n\n logger.info('[RedisStreamsEventTarget] ready', { prefix });\n return target;\n}\n"]}
|