@burdenoff/be-sdk 2026.514.2 → 2026.516.2
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.
- package/dist/EventQueueFactory-6UJ3UIP4.js +6 -0
- package/dist/{EventQueueFactory-DGHBOV7I.js.map → EventQueueFactory-6UJ3UIP4.js.map} +1 -1
- package/dist/cache/index.d.ts +1 -1
- package/dist/cache/index.js +1 -1
- package/dist/{chunk-FT74HIIG.js → chunk-24VR7PF3.js} +2 -2
- package/dist/{chunk-FT74HIIG.js.map → chunk-24VR7PF3.js.map} +1 -1
- package/dist/chunk-75VTKG4Q.js +243 -0
- package/dist/chunk-75VTKG4Q.js.map +1 -0
- package/dist/{chunk-M3PYLAPT.js → chunk-7Y3RNUS3.js} +4 -4
- package/dist/{chunk-M3PYLAPT.js.map → chunk-7Y3RNUS3.js.map} +1 -1
- package/dist/{chunk-FSTWNBRX.js → chunk-MQ6OE5QR.js} +10 -33
- package/dist/chunk-MQ6OE5QR.js.map +1 -0
- package/dist/{chunk-N52W3RQA.js → chunk-MVHOP4IG.js} +3 -174
- package/dist/chunk-MVHOP4IG.js.map +1 -0
- package/dist/{chunk-S74C6CEN.js → chunk-Q6N74R6S.js} +61 -68
- package/dist/chunk-Q6N74R6S.js.map +1 -0
- package/dist/chunk-RRFNSBDZ.js +181 -0
- package/dist/chunk-RRFNSBDZ.js.map +1 -0
- package/dist/{chunk-D35GTG7Y.js → chunk-SNW4BLF2.js} +3 -3
- package/dist/{chunk-D35GTG7Y.js.map → chunk-SNW4BLF2.js.map} +1 -1
- package/dist/chunk-TM5RQ6P2.js +925 -0
- package/dist/chunk-TM5RQ6P2.js.map +1 -0
- package/dist/{chunk-IX5QCHWE.js → chunk-U455UF4O.js} +3 -3
- package/dist/{chunk-IX5QCHWE.js.map → chunk-U455UF4O.js.map} +1 -1
- package/dist/{chunk-CCV2AVAI.js → chunk-V4RLPTTT.js} +3 -3
- package/dist/{chunk-CCV2AVAI.js.map → chunk-V4RLPTTT.js.map} +1 -1
- package/dist/{chunk-KLYAIEAX.js → chunk-VKSB2K5E.js} +15 -30
- package/dist/chunk-VKSB2K5E.js.map +1 -0
- package/dist/event-queue/index.d.ts +2 -2
- package/dist/event-queue/index.js +4 -6
- package/dist/export/index.js +3 -3
- package/dist/gateway/index.js +2 -2
- package/dist/gateway/security/index.js +1 -1
- package/dist/graph/index.d.ts +2 -2
- package/dist/graph/index.js +5 -6
- package/dist/{graph-emitter-Bk0FqD53.d.ts → graph-emitter-Dp7UE1Yd.d.ts} +3 -2
- package/dist/graphql/index.d.ts +1 -1
- package/dist/graphql/index.js +2 -2
- package/dist/{index-C1ojTQq0.d.ts → index-B6IwtUb1.d.ts} +2 -0
- package/dist/{index-DZO2nvC9.d.ts → index-Bo58dlMU.d.ts} +2 -2
- package/dist/{index-syMAjErz.d.ts → index-D_Nc4UHi.d.ts} +6 -84
- package/dist/index-joONjwLt.d.ts +33 -0
- package/dist/{index-XY9x2I6b.d.ts → index-tJYziwMs.d.ts} +1 -0
- package/dist/index.d.ts +8 -8
- package/dist/index.js +14 -15
- package/dist/index.js.map +1 -1
- package/dist/init/index.d.ts +1 -1
- package/dist/init/index.js +3 -6
- package/dist/prisma/index.js +4 -6
- package/package.json +1 -6
- package/dist/EventQueueFactory-DGHBOV7I.js +0 -8
- package/dist/chunk-7V6GUNGP.js +0 -438
- package/dist/chunk-7V6GUNGP.js.map +0 -1
- package/dist/chunk-FSTWNBRX.js.map +0 -1
- package/dist/chunk-KLYAIEAX.js.map +0 -1
- package/dist/chunk-LRGXT37B.js +0 -1966
- package/dist/chunk-LRGXT37B.js.map +0 -1
- package/dist/chunk-N52W3RQA.js.map +0 -1
- package/dist/chunk-Q4HKXQVD.js +0 -478
- package/dist/chunk-Q4HKXQVD.js.map +0 -1
- package/dist/chunk-S74C6CEN.js.map +0 -1
- package/dist/chunk-UVYDP6P6.js +0 -13
- package/dist/chunk-UVYDP6P6.js.map +0 -1
- package/dist/config-QVYSAUMT.js +0 -4
- package/dist/config-QVYSAUMT.js.map +0 -1
- package/dist/index-CDFQRL-h.d.ts +0 -66
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import { resetGraphEventEmitter, getGraphEventEmitter, createMemoryPublisher, createGraphEventEmitter, createMemoryConsumer, createGraphEventEmitter2, NatsGraphEventEmitter, MemoryEventQueue, MemoryEventPublisher, MemoryEventConsumer, MemoryEventBus } from './chunk-
|
|
2
|
-
import { RedisStreamsEventPublisher, RedisStreamsEventConsumer,
|
|
3
|
-
import {
|
|
4
|
-
import { streamKey, dlqKey, RedisStreamsConnection } from './chunk-N52W3RQA.js';
|
|
1
|
+
import { resetGraphEventEmitter, getGraphEventEmitter, createMemoryPublisher, createGraphEventEmitter, createMemoryConsumer, createGraphEventEmitter2, NatsGraphEventEmitter, MemoryEventQueue, MemoryEventPublisher, MemoryEventConsumer, MemoryEventBus, GraphEventEmitterImpl } from './chunk-VKSB2K5E.js';
|
|
2
|
+
import { RedisStreamsEventPublisher, RedisStreamsEventConsumer, QueueType, EventQueueFactory } from './chunk-TM5RQ6P2.js';
|
|
3
|
+
import { streamKey, dlqKey, RedisStreamsConnection } from './chunk-MVHOP4IG.js';
|
|
5
4
|
import { logger } from './chunk-CBZNP6RF.js';
|
|
6
5
|
import { __export, __name } from './chunk-XE4OXN2W.js';
|
|
7
6
|
|
|
@@ -11,13 +10,12 @@ __export(event_queue_exports, {
|
|
|
11
10
|
EventPriority: () => EventPriority,
|
|
12
11
|
EventQueueFactory: () => EventQueueFactory,
|
|
13
12
|
EventsModule: () => EventsModule,
|
|
13
|
+
GraphEventEmitterImpl: () => GraphEventEmitterImpl,
|
|
14
14
|
MemoryEventBus: () => MemoryEventBus,
|
|
15
15
|
MemoryEventConsumer: () => MemoryEventConsumer,
|
|
16
16
|
MemoryEventPublisher: () => MemoryEventPublisher,
|
|
17
17
|
MemoryEventQueue: () => MemoryEventQueue,
|
|
18
18
|
ModuleEventsService: () => ModuleEventsService,
|
|
19
|
-
NatsEventConsumer: () => NatsEventConsumer,
|
|
20
|
-
NatsEventPublisher: () => NatsEventPublisher,
|
|
21
19
|
NatsGraphEventEmitter: () => NatsGraphEventEmitter,
|
|
22
20
|
QueueType: () => QueueType,
|
|
23
21
|
RedisStreamsConnection: () => RedisStreamsConnection,
|
|
@@ -451,42 +449,21 @@ var EventsModule = class {
|
|
|
451
449
|
};
|
|
452
450
|
|
|
453
451
|
// src/event-queue/index.ts
|
|
454
|
-
function isRedisStreamsSelected() {
|
|
455
|
-
const raw = (process.env["EVENT_QUEUE_TYPE"] ?? process.env["QUEUE_TYPE"] ?? "").toLowerCase();
|
|
456
|
-
if (raw === "redis-streams" || raw === "redis" || raw === "streams") return true;
|
|
457
|
-
if (raw === "nats") return false;
|
|
458
|
-
return !!process.env["REDIS_URL"] && !process.env["NATS_URL"] && !process.env["NATS_SERVERS"];
|
|
459
|
-
}
|
|
460
|
-
__name(isRedisStreamsSelected, "isRedisStreamsSelected");
|
|
461
452
|
function createPublisher() {
|
|
462
|
-
if (
|
|
453
|
+
if (process.env["REDIS_URL"]) {
|
|
463
454
|
return EventQueueFactory.createPublisherFromEnv();
|
|
464
455
|
}
|
|
465
|
-
|
|
466
|
-
if (!natsServers) {
|
|
467
|
-
return new MemoryEventPublisher();
|
|
468
|
-
}
|
|
469
|
-
if (!process.env["NATS_SERVERS"] && process.env["NATS_URL"]) {
|
|
470
|
-
process.env["NATS_SERVERS"] = process.env["NATS_URL"];
|
|
471
|
-
}
|
|
472
|
-
return EventQueueFactory.createPublisherFromEnv();
|
|
456
|
+
return new MemoryEventPublisher();
|
|
473
457
|
}
|
|
474
458
|
__name(createPublisher, "createPublisher");
|
|
475
459
|
function createConsumer(stream, consumer) {
|
|
476
|
-
if (
|
|
460
|
+
if (process.env["REDIS_URL"]) {
|
|
477
461
|
return EventQueueFactory.createConsumerFromEnv(stream, consumer);
|
|
478
462
|
}
|
|
479
|
-
|
|
480
|
-
if (!natsServers) {
|
|
481
|
-
return new MemoryEventConsumer(stream, consumer);
|
|
482
|
-
}
|
|
483
|
-
if (!process.env["NATS_SERVERS"] && process.env["NATS_URL"]) {
|
|
484
|
-
process.env["NATS_SERVERS"] = process.env["NATS_URL"];
|
|
485
|
-
}
|
|
486
|
-
return EventQueueFactory.createConsumerFromEnv(stream, consumer);
|
|
463
|
+
return new MemoryEventConsumer(stream, consumer);
|
|
487
464
|
}
|
|
488
465
|
__name(createConsumer, "createConsumer");
|
|
489
466
|
|
|
490
467
|
export { EventPriority, EventsModule, ModuleEventsService, createConsumer, createModuleEventsService, createPublisher, event_queue_exports };
|
|
491
|
-
//# sourceMappingURL=chunk-
|
|
492
|
-
//# sourceMappingURL=chunk-
|
|
468
|
+
//# sourceMappingURL=chunk-MQ6OE5QR.js.map
|
|
469
|
+
//# sourceMappingURL=chunk-MQ6OE5QR.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/event-queue/index.ts","../src/event-queue/module-events.ts","../src/event-queue/events.ts"],"names":["createGraphEventEmitter","ModuleEventsService","productSource","subjectPrefix","loggerLabel","publisher","connected","connecting","config","moduleName","charAt","toUpperCase","slice","natsServers","process","env","EventQueueFactory","createPublisherFromEnv","logger","info","MemoryEventPublisher","ensureConnected","connect","then","publish","subject","payload","data","buildPayload","type","action","id","userId","tenantId","workspaceId","correlationId","metadata","timestamp","Date","toISOString","buildSubject","entityType","normalizedType","replace","_match","p1","offset","toLowerCase","publishCreated","publishUpdated","publishDeleted","publishCustom","publishBulkCreated","_entityType","items","close","disconnect","healthCheck","result","isHealthy","status","healthy","message","error","createModuleEventsService","EventPriority","EventsModule","client","context","createStream","name","subjects","options","debug","mutation","variables","input","maxMessages","maxBytes","maxAge","storageType","replicas","response","query","getStreamInfo","deleteStream","purgeStream","sequence","purgedCount","createConsumer","streamName","consumerName","queueGroup","durableName","startPosition","ackMode","maxDeliver","ackWait","deleteConsumer","ackMessage","nakMessage","getConsumerInfo","createPublisher","stream","consumer","createConsumerFromEnv","MemoryEventConsumer"],"mappings":"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","file":"chunk-MQ6OE5QR.js","sourcesContent":["/**\n * Event Queue - Public API\n *\n * This module provides a complete abstraction over event queue systems (NATS, RabbitMQ, Kafka, SQS, etc.)\n * allowing the application to publish and consume events without direct dependency on any specific queue implementation.\n *\n * Usage:\n *\n * // Publishing events (workspaces-backend)\n * import { createPublisher } from './utils/event-queue';\n *\n * const publisher = createPublisher();\n * await publisher.connect();\n *\n * await publisher.publish({\n * subject: 'workspace.created',\n * data: { workspaceId: '123', name: 'My Workspace' },\n * metadata: { userId: 'user-123', source: 'api' }\n * });\n *\n * // Consuming events (workspaces-workers)\n * import { createConsumer } from './core/event-queue';\n *\n * const consumer = createConsumer('WORKSPACE_EVENTS', 'workspace-consumer');\n * await consumer.connect();\n *\n * await consumer.subscribe({\n * subject: 'workspace.*',\n * handler: async (event) => {\n * logger.log('Received event:', event.data);\n * await event.ack();\n * }\n * });\n */\n// Import factory for use in convenience functions\nimport { EventQueueFactory } from './factory/EventQueueFactory.js';\n// Import implementations for use in convenience functions\nimport { MemoryEventPublisher, MemoryEventConsumer } from './implementations/memory/MemoryEventQueue.js';\n// Import interfaces for type annotations\nimport type { IEventConsumer } from './interfaces/IEventConsumer.js';\nimport type { IEventPublisher } from './interfaces/IEventPublisher.js';\n\n// Export interfaces\nexport type { IEventQueue } from './interfaces/IEventQueue.js';\nexport type { IEventPublisher, PublishOptions } from './interfaces/IEventPublisher.js';\nexport type { IEventConsumer, ISubscription } from './interfaces/IEventConsumer.js';\n\n// Export types\nexport type {\n EventMessage,\n EventMetadata,\n AcknowledgeableEvent,\n EventHandler,\n StreamConfig,\n SubscriptionOptions,\n NATSConsumerOptions,\n} from './types/events.js';\n\nexport { QueueType } from './types/config.js';\n\nexport type {\n BaseQueueConfig,\n PublisherConfig,\n ConsumerConfig,\n EventQueueHealthCheckResult,\n QueueStatistics,\n} from './types/config.js';\n\n// Backwards compatibility alias\nexport type { EventQueueHealthCheckResult as HealthCheckResult } from './types/config.js';\n\n// Export factory\nexport { EventQueueFactory } from './factory/EventQueueFactory.js';\n\n// Export Redis Streams implementations\nexport {\n RedisStreamsEventPublisher,\n RedisStreamsEventConsumer,\n RedisStreamsConnection,\n streamKey as redisStreamKey,\n dlqKey as redisDlqKey,\n} from './implementations/redis-streams/index.js';\n\n// Export Memory implementations (for development/testing or fallback)\nexport {\n MemoryEventBus,\n MemoryEventQueue,\n MemoryEventPublisher,\n MemoryEventConsumer,\n createMemoryPublisher,\n createMemoryConsumer,\n createGraphEventEmitter as createMemoryGraphEventEmitter,\n} from './implementations/memory/MemoryEventQueue.js';\n\n// Export Graph Event Emitter (Redis Streams-backed). `NatsGraphEventEmitter`\n// is a deprecated alias retained for one release while consumers migrate.\nexport {\n GraphEventEmitterImpl,\n NatsGraphEventEmitter,\n getGraphEventEmitter,\n createGraphEventEmitter,\n resetGraphEventEmitter,\n} from './graph-emitter.js';\nexport type { GraphEventEmitter, EntityEventType, EntityEventRbacMetadata } from './graph-emitter.js';\n\n// Export Module Events Service\nexport { ModuleEventsService, createModuleEventsService } from './module-events.js';\nexport type { ModuleEventPayload, BulkEventPayload, ModuleEventsConfig } from './module-events.js';\n\n// Export high-level Events Module (GraphQL-based event publishing)\nexport { EventsModule } from './events.js';\nexport {\n EventPriority,\n type PublishEventOptions,\n type SubscribeOptions,\n type EventMessage as GraphQLEventMessage,\n type PublishResult,\n type StreamInfo,\n} from './events.js';\n\n/**\n * Create an event publisher from environment configuration.\n *\n * Backend resolution:\n * - `REDIS_URL` set → Redis Streams (the only supported backend since\n * the NATS retirement on 2026-05-16).\n * - `REDIS_URL` unset → in-memory (dev/test fallback).\n */\nexport function createPublisher(): IEventPublisher {\n if (process.env['REDIS_URL']) {\n return EventQueueFactory.createPublisherFromEnv();\n }\n return new MemoryEventPublisher();\n}\n\n/**\n * Create an event consumer from environment configuration.\n */\nexport function createConsumer(stream: string, consumer: string): IEventConsumer {\n if (process.env['REDIS_URL']) {\n return EventQueueFactory.createConsumerFromEnv(stream, consumer);\n }\n return new MemoryEventConsumer(stream, consumer);\n}\n","/**\n * Module Events Service\n *\n * Generic event publishing service that modules can configure to publish\n * domain-specific events to NATS JetStream.\n *\n * @module event-queue/module-events\n * @category Events\n *\n * @example\n * ```typescript\n * import { createModuleEventsService } from '@burdenoff/be-sdk/event-queue';\n *\n * // Create a configured event service for the tags module\n * const tagsEventsService = createModuleEventsService({\n * moduleName: 'tags',\n * entityTypes: ['Tag', 'Vocabulary', 'Assignment'],\n * });\n *\n * // Publish events\n * await tagsEventsService.publishCreated('Tag', tagId, tagData, userId);\n * await tagsEventsService.publishUpdated('Vocabulary', vocabId, vocabData, userId);\n * ```\n */\nimport { logger } from '../logger/index.js';\nimport type { IEventPublisher } from './interfaces/IEventPublisher.js';\nimport { MemoryEventPublisher } from './implementations/memory/MemoryEventQueue.js';\nimport { EventQueueFactory } from './factory/EventQueueFactory.js';\n\n/**\n * Event payload structure for module events\n */\nexport interface ModuleEventPayload {\n /** Entity ID */\n id: string;\n /** Entity type (e.g., 'UniversalTag', 'UniversalTagVocabulary') */\n type: string;\n /** Action performed */\n action: 'created' | 'updated' | 'deleted' | 'assigned' | 'removed' | string;\n /** Entity data */\n data: Record<string, unknown>;\n /** Event metadata */\n metadata: {\n tenantId?: string;\n workspaceId?: string;\n userId: string;\n timestamp: string;\n productSource: string;\n correlationId?: string;\n };\n}\n\n/**\n * Bulk event payload structure\n */\nexport interface BulkEventPayload {\n /** Items in the bulk operation */\n items: Array<{ id: string; data: Record<string, unknown> }>;\n /** Event metadata */\n metadata: {\n tenantId?: string;\n workspaceId?: string;\n userId: string;\n timestamp: string;\n productSource: string;\n };\n}\n\n/**\n * Configuration for module events service\n */\nexport interface ModuleEventsConfig {\n /** Module name (used as productSource and in subject prefixes) */\n moduleName: string;\n /** Subject prefix override (defaults to moduleName) */\n subjectPrefix?: string;\n /** Custom logger label */\n loggerLabel?: string;\n}\n\n/**\n * Generic Module Events Service\n *\n * Provides a consistent interface for publishing domain events across all modules.\n * Automatically falls back to in-memory publisher when NATS is not configured.\n */\nexport class ModuleEventsService {\n private readonly productSource: string;\n private readonly subjectPrefix: string;\n private readonly loggerLabel: string;\n private publisher: IEventPublisher;\n private connected = false;\n private connecting: Promise<void> | null = null;\n\n constructor(config: ModuleEventsConfig) {\n this.productSource = config.moduleName;\n this.subjectPrefix = config.subjectPrefix || config.moduleName;\n this.loggerLabel =\n config.loggerLabel || `${config.moduleName.charAt(0).toUpperCase()}${config.moduleName.slice(1)}EventsService`;\n\n // Initialize publisher based on environment\n const natsServers = process.env['NATS_SERVERS'] || process.env['NATS_URL'];\n if (natsServers) {\n // Ensure NATS_SERVERS is set for downstream factory\n if (!process.env['NATS_SERVERS'] && process.env['NATS_URL']) {\n process.env['NATS_SERVERS'] = process.env['NATS_URL'];\n }\n this.publisher = EventQueueFactory.createPublisherFromEnv();\n logger.info(`[${this.loggerLabel}] Using NATS publisher`);\n } else {\n this.publisher = new MemoryEventPublisher();\n logger.info(`[${this.loggerLabel}] Using in-memory publisher (NATS_SERVERS not configured)`);\n }\n }\n\n /**\n * Ensure publisher is connected before publishing\n */\n private async ensureConnected(): Promise<void> {\n if (this.connected) {\n return;\n }\n\n if (this.connecting) {\n await this.connecting;\n return;\n }\n\n this.connecting = this.publisher.connect().then(() => {\n this.connected = true;\n this.connecting = null;\n logger.info(`[${this.loggerLabel}] Publisher connected`);\n });\n\n await this.connecting;\n }\n\n /**\n * Publish an event to the queue\n */\n private async publish(subject: string, payload: unknown): Promise<void> {\n await this.ensureConnected();\n await this.publisher.publish({\n subject,\n data: payload as Record<string, unknown>,\n });\n }\n\n /**\n * Build event payload\n */\n private buildPayload(\n type: string,\n action: string,\n id: string,\n data: Record<string, unknown>,\n userId: string,\n tenantId?: string,\n workspaceId?: string,\n correlationId?: string\n ): ModuleEventPayload {\n return {\n id,\n type,\n action,\n data,\n metadata: {\n tenantId,\n workspaceId,\n userId,\n timestamp: new Date().toISOString(),\n productSource: this.productSource,\n ...(correlationId && { correlationId }),\n },\n };\n }\n\n /**\n * Build subject string\n */\n private buildSubject(entityType: string, action: string): string {\n // Convert entityType from PascalCase to lowercase (e.g., UniversalTag -> tag)\n const normalizedType = entityType\n .replace(/^Universal/, '')\n .replace(/([A-Z])/g, (_match, p1, offset) => (offset > 0 ? '_' : '') + (p1 as string).toLowerCase())\n .replace(/^_/, '');\n return `${this.subjectPrefix}.${normalizedType}.${action}`;\n }\n\n /**\n * Publish entity created event\n */\n async publishCreated(\n entityType: string,\n id: string,\n data: Record<string, unknown>,\n userId: string,\n tenantId?: string,\n workspaceId?: string\n ): Promise<void> {\n const payload = this.buildPayload(entityType, 'created', id, data, userId, tenantId, workspaceId);\n await this.publish(this.buildSubject(entityType, 'created'), payload);\n }\n\n /**\n * Publish entity updated event\n */\n async publishUpdated(\n entityType: string,\n id: string,\n data: Record<string, unknown>,\n userId: string,\n tenantId?: string,\n workspaceId?: string\n ): Promise<void> {\n const payload = this.buildPayload(entityType, 'updated', id, data, userId, tenantId, workspaceId);\n await this.publish(this.buildSubject(entityType, 'updated'), payload);\n }\n\n /**\n * Publish entity deleted event\n */\n async publishDeleted(\n entityType: string,\n id: string,\n userId: string,\n tenantId?: string,\n workspaceId?: string\n ): Promise<void> {\n const payload = this.buildPayload(entityType, 'deleted', id, {}, userId, tenantId, workspaceId);\n await this.publish(this.buildSubject(entityType, 'deleted'), payload);\n }\n\n /**\n * Publish custom action event\n */\n async publishCustom(\n entityType: string,\n action: string,\n id: string,\n data: Record<string, unknown>,\n userId: string,\n tenantId?: string,\n workspaceId?: string\n ): Promise<void> {\n const payload = this.buildPayload(entityType, action, id, data, userId, tenantId, workspaceId);\n await this.publish(this.buildSubject(entityType, action), payload);\n }\n\n /**\n * Publish bulk created event\n */\n async publishBulkCreated(\n _entityType: string,\n items: Array<{ id: string; data: Record<string, unknown> }>,\n userId: string,\n tenantId?: string,\n workspaceId?: string\n ): Promise<void> {\n const payload: BulkEventPayload = {\n items,\n metadata: {\n tenantId,\n workspaceId,\n userId,\n timestamp: new Date().toISOString(),\n productSource: this.productSource,\n },\n };\n await this.publish(`${this.subjectPrefix}.bulk.created`, payload);\n }\n\n /**\n * Close event queue connection\n */\n async close(): Promise<void> {\n if (this.connected) {\n await this.publisher.disconnect();\n this.connected = false;\n logger.info(`[${this.loggerLabel}] Publisher disconnected`);\n }\n }\n\n /**\n * Get health check status\n */\n async healthCheck(): Promise<{ healthy: boolean; message: string }> {\n const result = await this.publisher.healthCheck();\n const isHealthy = result.status === 'healthy';\n return {\n healthy: isHealthy,\n message: result.error || (isHealthy ? 'Healthy' : 'Unhealthy'),\n };\n }\n}\n\n/**\n * Create a module events service instance\n */\nexport function createModuleEventsService(config: ModuleEventsConfig): ModuleEventsService {\n return new ModuleEventsService(config);\n}\n","/**\n * Events Module\n * Helpers for sending events to NATS JetStream queue\n */\n\nimport type { BurdenoffGraphQLClient } from '../client/graphql.js';\nimport type { SDKContext } from '../types/index.js';\nimport { logger } from '../logger/index.js';\n\nexport enum EventPriority {\n LOW = 'low',\n NORMAL = 'normal',\n HIGH = 'high',\n CRITICAL = 'critical',\n}\n\nexport interface PublishEventOptions {\n /** Event subject/topic */\n subject: string;\n /** Event payload */\n data: Record<string, unknown>;\n /** Event priority */\n priority?: EventPriority;\n /** Event metadata */\n metadata?: Record<string, unknown>;\n /** Delay delivery by milliseconds */\n delay?: number;\n /** Message ID (for deduplication) */\n messageId?: string;\n /** Workspace context */\n workspaceId?: string;\n /** Organization context */\n organizationId?: string;\n}\n\nexport interface SubscribeOptions {\n /** Subject pattern to subscribe to */\n subject: string;\n /** Queue group name */\n queueGroup?: string;\n /** Durable consumer name */\n durableName?: string;\n /** Start from specific position */\n startPosition?: 'first' | 'last' | 'new';\n /** Acknowledge mode */\n ackMode?: 'explicit' | 'auto';\n /** Max messages to deliver */\n maxDeliver?: number;\n /** Acknowledgment timeout in milliseconds */\n ackWait?: number;\n}\n\nexport interface EventMessage {\n id: string;\n subject: string;\n data: Record<string, unknown>;\n priority: EventPriority;\n metadata?: Record<string, unknown>;\n workspaceId?: string;\n organizationId?: string;\n publishedAt: string;\n publishedBy?: string;\n}\n\nexport interface PublishResult {\n messageId: string;\n subject: string;\n sequence: number;\n timestamp: string;\n}\n\nexport interface StreamInfo {\n name: string;\n subjects: string[];\n messageCount: number;\n byteCount: number;\n firstSequence: number;\n lastSequence: number;\n consumerCount: number;\n}\n\n/**\n * Events Module\n */\nexport class EventsModule {\n constructor(\n private client: BurdenoffGraphQLClient,\n private context: SDKContext\n ) {}\n\n /**\n * Create stream\n */\n public async createStream(\n name: string,\n subjects: string[],\n options?: {\n maxMessages?: number;\n maxBytes?: number;\n maxAge?: number;\n storageType?: 'file' | 'memory';\n replicas?: number;\n }\n ): Promise<StreamInfo> {\n logger.debug('[Events] Creating stream', { name, subjects });\n\n const mutation = `\n mutation CreateStream($input: CreateStreamInput!) {\n createStream(input: $input) {\n name\n subjects\n messageCount\n byteCount\n firstSequence\n lastSequence\n consumerCount\n }\n }\n `;\n\n const variables = {\n input: {\n name,\n subjects,\n maxMessages: options?.maxMessages,\n maxBytes: options?.maxBytes,\n maxAge: options?.maxAge,\n storageType: options?.storageType || 'file',\n replicas: options?.replicas || 1,\n },\n };\n\n const response = await this.client.query<{ createStream: StreamInfo }>(mutation, variables, this.context);\n\n logger.info('[Events] Stream created', { name });\n\n return response.createStream;\n }\n\n /**\n * Get stream info\n */\n public async getStreamInfo(name: string): Promise<StreamInfo> {\n logger.debug('[Events] Getting stream info', { name });\n\n const query = `\n query GetStreamInfo($name: String!) {\n getStreamInfo(name: $name) {\n name\n subjects\n messageCount\n byteCount\n firstSequence\n lastSequence\n consumerCount\n }\n }\n `;\n\n const response = await this.client.query<{ getStreamInfo: StreamInfo }>(query, { name }, this.context);\n\n return response.getStreamInfo;\n }\n\n /**\n * Delete stream\n */\n public async deleteStream(name: string): Promise<boolean> {\n logger.debug('[Events] Deleting stream', { name });\n\n const mutation = `\n mutation DeleteStream($name: String!) {\n deleteStream(name: $name) {\n success\n }\n }\n `;\n\n await this.client.query(mutation, { name }, this.context);\n\n logger.info('[Events] Stream deleted', { name });\n\n return true;\n }\n\n /**\n * Purge stream messages\n */\n public async purgeStream(name: string, options?: { subject?: string; sequence?: number }): Promise<number> {\n logger.debug('[Events] Purging stream', { name, options });\n\n const mutation = `\n mutation PurgeStream($name: String!, $subject: String, $sequence: Int) {\n purgeStream(name: $name, subject: $subject, sequence: $sequence) {\n purgedCount\n }\n }\n `;\n\n const response = await this.client.query<{ purgeStream: { purgedCount: number } }>(\n mutation,\n { name, subject: options?.subject, sequence: options?.sequence },\n this.context\n );\n\n logger.info('[Events] Stream purged', { name, purgedCount: response.purgeStream.purgedCount });\n\n return response.purgeStream.purgedCount;\n }\n\n /**\n * Create consumer\n */\n public async createConsumer(\n streamName: string,\n consumerName: string,\n options: SubscribeOptions\n ): Promise<{ name: string; pending: number }> {\n logger.debug('[Events] Creating consumer', { streamName, consumerName });\n\n const mutation = `\n mutation CreateConsumer($input: CreateConsumerInput!) {\n createConsumer(input: $input) {\n name\n pending\n }\n }\n `;\n\n const variables = {\n input: {\n streamName,\n consumerName,\n subject: options.subject,\n queueGroup: options.queueGroup,\n durableName: options.durableName,\n startPosition: options.startPosition || 'last',\n ackMode: options.ackMode || 'explicit',\n maxDeliver: options.maxDeliver || 5,\n ackWait: options.ackWait || 30000,\n },\n };\n\n const response = await this.client.query<{ createConsumer: { name: string; pending: number } }>(\n mutation,\n variables,\n this.context\n );\n\n logger.info('[Events] Consumer created', { consumerName });\n\n return response.createConsumer;\n }\n\n /**\n * Delete consumer\n */\n public async deleteConsumer(streamName: string, consumerName: string): Promise<boolean> {\n logger.debug('[Events] Deleting consumer', { streamName, consumerName });\n\n const mutation = `\n mutation DeleteConsumer($streamName: String!, $consumerName: String!) {\n deleteConsumer(streamName: $streamName, consumerName: $consumerName) {\n success\n }\n }\n `;\n\n await this.client.query(mutation, { streamName, consumerName }, this.context);\n\n logger.info('[Events] Consumer deleted', { consumerName });\n\n return true;\n }\n\n /**\n * Acknowledge message\n */\n public async ackMessage(streamName: string, consumerName: string, sequence: number): Promise<boolean> {\n logger.debug('[Events] Acknowledging message', { streamName, consumerName, sequence });\n\n const mutation = `\n mutation AckMessage($streamName: String!, $consumerName: String!, $sequence: Int!) {\n ackMessage(streamName: $streamName, consumerName: $consumerName, sequence: $sequence) {\n success\n }\n }\n `;\n\n await this.client.query(mutation, { streamName, consumerName, sequence }, this.context);\n\n return true;\n }\n\n /**\n * Negative acknowledge message (requeue)\n */\n public async nakMessage(streamName: string, consumerName: string, sequence: number): Promise<boolean> {\n logger.debug('[Events] Negative acknowledging message', { streamName, consumerName, sequence });\n\n const mutation = `\n mutation NakMessage($streamName: String!, $consumerName: String!, $sequence: Int!) {\n nakMessage(streamName: $streamName, consumerName: $consumerName, sequence: $sequence) {\n success\n }\n }\n `;\n\n await this.client.query(mutation, { streamName, consumerName, sequence }, this.context);\n\n return true;\n }\n\n /**\n * Get consumer info\n */\n public async getConsumerInfo(\n streamName: string,\n consumerName: string\n ): Promise<{\n name: string;\n pending: number;\n redelivered: number;\n numAckPending: number;\n }> {\n logger.debug('[Events] Getting consumer info', { streamName, consumerName });\n\n const query = `\n query GetConsumerInfo($streamName: String!, $consumerName: String!) {\n getConsumerInfo(streamName: $streamName, consumerName: $consumerName) {\n name\n pending\n redelivered\n numAckPending\n }\n }\n `;\n\n const response = await this.client.query<{\n getConsumerInfo: {\n name: string;\n pending: number;\n redelivered: number;\n numAckPending: number;\n };\n }>(query, { streamName, consumerName }, this.context);\n\n return response.getConsumerInfo;\n }\n}\n"]}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { logger } from './chunk-CBZNP6RF.js';
|
|
2
2
|
import { __name } from './chunk-XE4OXN2W.js';
|
|
3
|
-
import { connect, credsAuthenticator } from 'nats';
|
|
4
3
|
|
|
5
4
|
// src/event-queue/implementations/redis-streams/keyspace.ts
|
|
6
5
|
var DEFAULT_PREFIX = "boff:events";
|
|
@@ -242,177 +241,7 @@ var RedisStreamsConnection = class {
|
|
|
242
241
|
return this.getClient().ping();
|
|
243
242
|
}
|
|
244
243
|
};
|
|
245
|
-
var NatsConnectionManager = class {
|
|
246
|
-
static {
|
|
247
|
-
__name(this, "NatsConnectionManager");
|
|
248
|
-
}
|
|
249
|
-
config;
|
|
250
|
-
nc = null;
|
|
251
|
-
js = null;
|
|
252
|
-
jsm = null;
|
|
253
|
-
connected = false;
|
|
254
|
-
connectionPromise = null;
|
|
255
|
-
constructor(config) {
|
|
256
|
-
this.config = config;
|
|
257
|
-
}
|
|
258
|
-
/**
|
|
259
|
-
* Connect to NATS server
|
|
260
|
-
*/
|
|
261
|
-
async connect() {
|
|
262
|
-
if (this.connectionPromise) {
|
|
263
|
-
return this.connectionPromise;
|
|
264
|
-
}
|
|
265
|
-
if (this.connected) {
|
|
266
|
-
logger.debug("[NatsConnection] Already connected");
|
|
267
|
-
return;
|
|
268
|
-
}
|
|
269
|
-
this.connectionPromise = this._doConnect();
|
|
270
|
-
try {
|
|
271
|
-
await this.connectionPromise;
|
|
272
|
-
} finally {
|
|
273
|
-
this.connectionPromise = null;
|
|
274
|
-
}
|
|
275
|
-
}
|
|
276
|
-
/**
|
|
277
|
-
* Internal connection logic
|
|
278
|
-
*/
|
|
279
|
-
async _doConnect() {
|
|
280
|
-
try {
|
|
281
|
-
const connectionOptions = await createNatsConnectionOptions(this.config);
|
|
282
|
-
this.nc = await connect(connectionOptions);
|
|
283
|
-
this.js = this.nc.jetstream();
|
|
284
|
-
this.jsm = await this.nc.jetstreamManager();
|
|
285
|
-
this.connected = true;
|
|
286
|
-
logger.info("[NatsConnection] Connected to NATS", {
|
|
287
|
-
url: this.config.url,
|
|
288
|
-
name: this.config.name
|
|
289
|
-
});
|
|
290
|
-
this.setupEventHandlers();
|
|
291
|
-
} catch (error) {
|
|
292
|
-
logger.error("[NatsConnection] Failed to connect to NATS", {
|
|
293
|
-
error: error instanceof Error ? error.message : "Unknown error",
|
|
294
|
-
url: this.config.url
|
|
295
|
-
});
|
|
296
|
-
throw error;
|
|
297
|
-
}
|
|
298
|
-
}
|
|
299
|
-
/**
|
|
300
|
-
* Setup connection event handlers
|
|
301
|
-
*/
|
|
302
|
-
setupEventHandlers() {
|
|
303
|
-
if (!this.nc) return;
|
|
304
|
-
(async () => {
|
|
305
|
-
if (!this.nc) return;
|
|
306
|
-
for await (const status of this.nc.status()) {
|
|
307
|
-
if (status.type === "disconnect") {
|
|
308
|
-
this.connected = false;
|
|
309
|
-
} else if (status.type === "reconnect") {
|
|
310
|
-
this.connected = true;
|
|
311
|
-
}
|
|
312
|
-
}
|
|
313
|
-
})().catch((error) => {
|
|
314
|
-
logger.error("[NatsConnection] Error handling connection events", {
|
|
315
|
-
error: error instanceof Error ? error.message : "Unknown error"
|
|
316
|
-
});
|
|
317
|
-
});
|
|
318
|
-
}
|
|
319
|
-
/**
|
|
320
|
-
* Disconnect from NATS
|
|
321
|
-
*/
|
|
322
|
-
async disconnect() {
|
|
323
|
-
if (!this.connected || !this.nc) {
|
|
324
|
-
return;
|
|
325
|
-
}
|
|
326
|
-
try {
|
|
327
|
-
await this.nc.drain();
|
|
328
|
-
await this.nc.close();
|
|
329
|
-
this.connected = false;
|
|
330
|
-
this.nc = null;
|
|
331
|
-
this.js = null;
|
|
332
|
-
this.jsm = null;
|
|
333
|
-
logger.info("[NatsConnection] Disconnected from NATS");
|
|
334
|
-
} catch (error) {
|
|
335
|
-
logger.error("[NatsConnection] Error disconnecting from NATS", {
|
|
336
|
-
error: error instanceof Error ? error.message : "Unknown error"
|
|
337
|
-
});
|
|
338
|
-
}
|
|
339
|
-
}
|
|
340
|
-
/**
|
|
341
|
-
* Check if connected
|
|
342
|
-
*/
|
|
343
|
-
isConnected() {
|
|
344
|
-
return this.connected && this.nc !== null && !this.nc.isClosed();
|
|
345
|
-
}
|
|
346
|
-
/**
|
|
347
|
-
* Get JetStream client
|
|
348
|
-
*/
|
|
349
|
-
getJetStream() {
|
|
350
|
-
if (!this.js) {
|
|
351
|
-
throw new Error("NATS not connected - call connect() first");
|
|
352
|
-
}
|
|
353
|
-
return this.js;
|
|
354
|
-
}
|
|
355
|
-
/**
|
|
356
|
-
* Get JetStream Manager
|
|
357
|
-
*/
|
|
358
|
-
getJetStreamManager() {
|
|
359
|
-
if (!this.jsm) {
|
|
360
|
-
throw new Error("NATS not connected - call connect() first");
|
|
361
|
-
}
|
|
362
|
-
return this.jsm;
|
|
363
|
-
}
|
|
364
|
-
/**
|
|
365
|
-
* Get NATS connection
|
|
366
|
-
*/
|
|
367
|
-
getNatsConnection() {
|
|
368
|
-
if (!this.nc) {
|
|
369
|
-
throw new Error("NATS not connected - call connect() first");
|
|
370
|
-
}
|
|
371
|
-
return this.nc;
|
|
372
|
-
}
|
|
373
|
-
};
|
|
374
|
-
async function createNatsConnectionOptions(config) {
|
|
375
|
-
const connectionOptions = {
|
|
376
|
-
servers: config.url,
|
|
377
|
-
name: config.name,
|
|
378
|
-
user: config.user,
|
|
379
|
-
pass: config.password,
|
|
380
|
-
token: config.token,
|
|
381
|
-
maxReconnectAttempts: config.maxReconnectAttempts ?? -1,
|
|
382
|
-
reconnectTimeWait: config.reconnectTimeWait ?? 2e3
|
|
383
|
-
};
|
|
384
|
-
const creds = await resolveNatsCreds(config);
|
|
385
|
-
if (creds) {
|
|
386
|
-
connectionOptions.authenticator = credsAuthenticator(new TextEncoder().encode(creds));
|
|
387
|
-
delete connectionOptions.user;
|
|
388
|
-
delete connectionOptions.pass;
|
|
389
|
-
delete connectionOptions.token;
|
|
390
|
-
}
|
|
391
|
-
return connectionOptions;
|
|
392
|
-
}
|
|
393
|
-
__name(createNatsConnectionOptions, "createNatsConnectionOptions");
|
|
394
|
-
async function resolveNatsCreds(config) {
|
|
395
|
-
if (config.creds) {
|
|
396
|
-
return normalizeNatsCreds(config.creds);
|
|
397
|
-
}
|
|
398
|
-
if (!config.credsFile) {
|
|
399
|
-
return void 0;
|
|
400
|
-
}
|
|
401
|
-
const fs = await import('fs/promises');
|
|
402
|
-
return normalizeNatsCreds(await fs.readFile(config.credsFile, "utf8"));
|
|
403
|
-
}
|
|
404
|
-
__name(resolveNatsCreds, "resolveNatsCreds");
|
|
405
|
-
function normalizeNatsCreds(creds) {
|
|
406
|
-
if (creds.startsWith("base64:")) {
|
|
407
|
-
return Buffer.from(creds.slice("base64:".length), "base64").toString("utf8");
|
|
408
|
-
}
|
|
409
|
-
if (creds.includes("\\n") && !creds.includes("\n")) {
|
|
410
|
-
return creds.replaceAll("\\n", "\n");
|
|
411
|
-
}
|
|
412
|
-
return creds;
|
|
413
|
-
}
|
|
414
|
-
__name(normalizeNatsCreds, "normalizeNatsCreds");
|
|
415
244
|
|
|
416
|
-
export {
|
|
417
|
-
//# sourceMappingURL=chunk-
|
|
418
|
-
//# sourceMappingURL=chunk-
|
|
245
|
+
export { RedisStreamsConnection, boundaryOf, dedupKey, delayLockKey, delayQueueKey, dlqKey, isWildcard, matchSubject, registryKey, replyKey, streamKey };
|
|
246
|
+
//# sourceMappingURL=chunk-MVHOP4IG.js.map
|
|
247
|
+
//# sourceMappingURL=chunk-MVHOP4IG.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/event-queue/implementations/redis-streams/keyspace.ts","../src/event-queue/implementations/redis-streams/RedisStreamsConnection.ts"],"names":["DEFAULT_PREFIX","REGISTRY_PREFIX","DELAYQ_PREFIX","DELAYQ_LOCK_PREFIX","DLQ_PREFIX","DEDUP_PREFIX","REPLY_PREFIX","currentScope","setKeyScope","scope","scoped","prefix","subjectToKey","subject","replace","streamKey","opts","registryKey","boundary","boundaryOf","first","split","delayQueueKey","stream","delayLockKey","dlqKey","dedupKey","msgId","replyKey","correlationId","matchSubject","pattern","pParts","sParts","last","length","i","isWildcard","includes","ioredisModulePromise","loadIoRedis","mod","default","Redis","err","logger","error","Error","message","String","ctor","normaliseUrl","rawUrl","url","tls","test","host","dbIndex","parsed","URL","hostname","pathDb","pathname","parseInt","toString","RedisStreamsConnection","client","connecting","normalisedUrl","config","process","env","isConnected","status","connect","doConnect","finally","lazyConnect","maxRetriesPerRequest","enableReadyCheck","connectTimeout","connectionTimeout","reconnectOnError","retryStrategy","times","Math","min","password","user","servername","on","args","warn","info","keyScope","disconnect","quit","getClient","makeBlockingClient","dup","duplicate","ping"],"mappings":"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","file":"chunk-MVHOP4IG.js","sourcesContent":["/**\n * Redis Streams key namespace helpers.\n *\n * All keys are prefixed with `boff:` because DB 0 of Azure Managed Redis is\n * shared with the be-sdk cache provider.\n */\n\nexport interface KeyspaceOptions {\n /** Top-level prefix for event streams. Defaults to `boff:events`. */\n prefix?: string;\n}\n\nconst DEFAULT_PREFIX = 'boff:events';\nconst REGISTRY_PREFIX = 'boff:registry:subjects';\nconst DELAYQ_PREFIX = 'boff:delayq';\nconst DELAYQ_LOCK_PREFIX = 'boff:lock:delayq';\nconst DLQ_PREFIX = 'boff:dlq';\nconst DEDUP_PREFIX = 'boff:dedup';\nconst REPLY_PREFIX = 'boff:replies';\n\n// ── Process-wide key scope (DB-as-prefix) ────────────────────────────────\n//\n// Azure Managed Redis Balanced/B0 only exposes DB 0. Services that used to\n// rely on a non-zero DB index in their REDIS_URL (e.g. `…/4`) for namespace\n// isolation now share DB 0 — RedisStreamsConnection strips the path, pins\n// the connection to DB 0, and calls `setKeyScope(\"db4:\")` so every key that\n// flows through this module is automatically prefixed with `db4:`. That\n// preserves the per-service isolation the DB number used to give us without\n// any of the callers having to change.\n//\n// Default scope is empty (back-compat for services on classic Redis or\n// already using DB 0). Set once at connection time; reads are O(1).\nlet currentScope = '';\n\nexport function setKeyScope(scope: string): void {\n currentScope = scope ?? '';\n}\n\nexport function getKeyScope(): string {\n return currentScope;\n}\n\nfunction scoped(prefix: string): string {\n return currentScope ? `${currentScope}${prefix}` : prefix;\n}\n\n/** Convert a NATS-style subject to a Redis key segment (`.` → `:`). */\nexport function subjectToKey(subject: string): string {\n return subject.replace(/\\./g, ':');\n}\n\n/** Build the stream key for a given subject. */\nexport function streamKey(subject: string, opts: KeyspaceOptions = {}): string {\n const prefix = opts.prefix ?? DEFAULT_PREFIX;\n return `${scoped(prefix)}:${subjectToKey(subject)}`;\n}\n\n/** Stream key from a NATS-style wildcard prefix (e.g. `wspace`). */\nexport function registryKey(boundary: string): string {\n return `${scoped(REGISTRY_PREFIX)}:${boundary}`;\n}\n\n/** Extract the leading boundary (`x` in `x.y.z`). */\nexport function boundaryOf(subject: string): string {\n const first = subject.split('.')[0];\n return first ?? subject;\n}\n\n/** Sorted-set key for delayed-NAK re-delivery, scoped per stream. */\nexport function delayQueueKey(stream: string): string {\n return `${scoped(DELAYQ_PREFIX)}:${stream}`;\n}\n\n/** Lock key the delay-queue worker uses to serialise across replicas. */\nexport function delayLockKey(stream: string): string {\n return `${scoped(DELAYQ_LOCK_PREFIX)}:${stream}`;\n}\n\n/** Per-stream dead-letter queue. */\nexport function dlqKey(stream: string): string {\n return `${scoped(DLQ_PREFIX)}:${stream}`;\n}\n\n/** Per-message dedup marker key. */\nexport function dedupKey(stream: string, msgId: string): string {\n return `${scoped(DEDUP_PREFIX)}:${stream}:${msgId}`;\n}\n\n/** Reply-stream key for request/response emulation. */\nexport function replyKey(correlationId: string): string {\n return `${scoped(REPLY_PREFIX)}:${correlationId}`;\n}\n\n/**\n * Resolve a NATS-style subject pattern to a concrete list of stream keys, using\n * a registry of known subjects.\n *\n * Patterns supported:\n * - `x.y.z` — exact subject, returns single stream\n * - `x.>` — all subjects starting with `x.`\n * - `x.*` — all subjects with exactly one more segment after `x.`\n * - `x.*.z` — single-segment wildcard at position\n */\nexport function matchSubject(pattern: string, subject: string): boolean {\n if (pattern === subject) return true;\n const pParts = pattern.split('.');\n const sParts = subject.split('.');\n const last = pParts[pParts.length - 1];\n if (last === '>') {\n if (sParts.length < pParts.length) return false;\n for (let i = 0; i < pParts.length - 1; i++) {\n if (pParts[i] !== sParts[i]) return false;\n }\n return true;\n }\n if (pParts.length !== sParts.length) return false;\n for (let i = 0; i < pParts.length; i++) {\n if (pParts[i] !== '*' && pParts[i] !== sParts[i]) return false;\n }\n return true;\n}\n\n/** True if subject pattern contains a wildcard token. */\nexport function isWildcard(pattern: string): boolean {\n return pattern.includes('*') || pattern.includes('>');\n}\n","/**\n * Manages a single ioredis client (or cluster) for the Redis Streams backend.\n *\n * Connection URL conventions:\n * - `redis://host:port` — plaintext\n * - `rediss://host:port` — TLS (Azure Managed Redis uses port 10000)\n * - `valkey://`/`valkeys://` — accepted as aliases, normalised internally\n *\n * Hostname → SNI is set automatically for TLS endpoints so Azure-managed certs\n * validate.\n */\nimport { logger } from '../../../logger/index.js';\nimport type { BaseQueueConfig } from '../../types/config.js';\nimport { setKeyScope } from './keyspace.js';\n\ntype IoRedis = {\n status: string;\n connect: () => Promise<void>;\n disconnect: () => void;\n quit: () => Promise<unknown>;\n ping: () => Promise<string>;\n on: (event: string, handler: (...args: unknown[]) => void) => void;\n duplicate: () => IoRedis;\n // Stream + key commands used by publisher/consumer/sweeper\n xadd: (...args: unknown[]) => Promise<string>;\n xack: (...args: unknown[]) => Promise<number>;\n xreadgroup: (...args: unknown[]) => Promise<unknown>;\n xgroup: (...args: unknown[]) => Promise<unknown>;\n xautoclaim: (...args: unknown[]) => Promise<unknown>;\n xpending: (...args: unknown[]) => Promise<unknown>;\n xlen: (key: string) => Promise<number>;\n xinfo: (...args: unknown[]) => Promise<unknown>;\n xrevrange: (...args: unknown[]) => Promise<unknown>;\n xrange: (...args: unknown[]) => Promise<unknown>;\n xdel: (key: string, ...ids: string[]) => Promise<number>;\n set: (...args: unknown[]) => Promise<string | null>;\n expire: (key: string, seconds: number) => Promise<number>;\n del: (...keys: string[]) => Promise<number>;\n sadd: (key: string, ...members: string[]) => Promise<number>;\n smembers: (key: string) => Promise<string[]>;\n zadd: (...args: unknown[]) => Promise<number>;\n zrangebyscore: (...args: unknown[]) => Promise<string[]>;\n zrem: (key: string, ...members: string[]) => Promise<number>;\n pipeline: () => { xadd: (...args: unknown[]) => unknown; exec: () => Promise<Array<[Error | null, unknown]>> };\n};\n\ntype IoRedisCtor = new (url: string, opts: Record<string, unknown>) => IoRedis;\n\nlet ioredisModulePromise: Promise<IoRedisCtor | null> | null = null;\n\nasync function loadIoRedis(): Promise<IoRedisCtor> {\n if (!ioredisModulePromise) {\n ioredisModulePromise = (async () => {\n try {\n const mod = (await import('ioredis')) as unknown as { default?: IoRedisCtor; Redis?: IoRedisCtor };\n return mod.default ?? mod.Redis ?? null;\n } catch (err) {\n logger.error('[RedisStreamsConnection] ioredis not installed', {\n error: err instanceof Error ? err.message : String(err),\n });\n return null;\n }\n })();\n }\n const ctor = await ioredisModulePromise;\n if (!ctor) {\n throw new Error(\n '[RedisStreamsConnection] ioredis is required for the redis-streams event-queue backend. ' +\n \"Install it with: bun add ioredis (or npm i ioredis)\"\n );\n }\n return ctor;\n}\n\nfunction normaliseUrl(rawUrl: string): { url: string; tls: boolean; host: string; dbIndex: number } {\n let url = rawUrl;\n let tls = false;\n if (/^valkeys:\\/\\//.test(url)) {\n tls = true;\n url = url.replace(/^valkeys:\\/\\//, 'rediss://');\n } else if (/^valkey:\\/\\//.test(url)) {\n url = url.replace(/^valkey:\\/\\//, 'redis://');\n } else if (/^rediss:\\/\\//.test(url)) {\n tls = true;\n }\n let host = 'localhost';\n let dbIndex = 0;\n try {\n const parsed = new URL(url);\n host = parsed.hostname || host;\n // Azure Managed Redis Balanced/B0 only exposes DB 0. If the URL pins a\n // non-zero DB in its path (e.g. `…/4`), ioredis would issue `SELECT 4`\n // on every reconnect and the server returns `ERR DB index is out of\n // range` in a tight loop that pegs the event loop. Strip the path here\n // so the connection lands on DB 0, then surface the original index to\n // the caller — we use it as a key-prefix scope so the per-service\n // isolation the DB number used to give us is preserved.\n const pathDb = parsed.pathname.replace(/^\\//, '');\n if (pathDb && /^\\d+$/.test(pathDb)) {\n dbIndex = parseInt(pathDb, 10);\n parsed.pathname = '';\n url = parsed.toString();\n }\n } catch {\n /* keep defaults */\n }\n return { url, tls, host, dbIndex };\n}\n\nexport class RedisStreamsConnection {\n private client: IoRedis | null = null;\n private connecting: Promise<void> | null = null;\n private readonly tls: boolean;\n private readonly host: string;\n private readonly normalisedUrl: string;\n private readonly dbIndex: number;\n\n constructor(private readonly config: BaseQueueConfig) {\n const { url, tls, host, dbIndex } = normaliseUrl(config.url);\n this.normalisedUrl = url;\n this.tls = tls || process.env['REDIS_TLS'] === 'true';\n this.host = host;\n this.dbIndex = dbIndex;\n // Install the DB-as-prefix scope before the first publish/consume runs.\n // Safe to call at construction: keyspace.setKeyScope is process-wide and\n // every key produced after this point will be prefixed with `db{N}:`.\n if (dbIndex > 0) {\n setKeyScope(`db${String(dbIndex)}:`);\n }\n }\n\n /** True once `connect()` has resolved and ioredis is in `ready` state. */\n isConnected(): boolean {\n return this.client !== null && this.client.status === 'ready';\n }\n\n /** Connect lazily; subsequent calls await the in-flight promise. */\n async connect(): Promise<void> {\n if (this.isConnected()) return;\n if (this.connecting) {\n await this.connecting;\n return;\n }\n this.connecting = this.doConnect().finally(() => {\n this.connecting = null;\n });\n await this.connecting;\n }\n\n private async doConnect(): Promise<void> {\n const Redis = await loadIoRedis();\n const opts: Record<string, unknown> = {\n lazyConnect: true,\n maxRetriesPerRequest: null,\n enableReadyCheck: true,\n connectTimeout: this.config.connectionTimeout ?? 15000,\n reconnectOnError: () => true,\n retryStrategy: (times: number): number => Math.min(times * 200, 2000),\n };\n if (this.config.password) opts['password'] = this.config.password;\n if (this.config.user) opts['username'] = this.config.user;\n if (this.tls) {\n opts['tls'] = { servername: this.host };\n }\n this.client = new Redis(this.normalisedUrl, opts);\n this.client.on('error', (...args: unknown[]) => {\n const err = args[0] as Error | undefined;\n logger.warn('[RedisStreamsConnection] redis error', {\n error: err?.message ?? 'unknown',\n });\n });\n this.client.on('reconnecting', () => {\n logger.info('[RedisStreamsConnection] reconnecting');\n });\n await this.client.connect();\n logger.info('[RedisStreamsConnection] connected', {\n url: this.normalisedUrl.replace(/:[^:@/]*@/, ':***@'),\n tls: this.tls,\n dbIndex: this.dbIndex,\n keyScope: this.dbIndex > 0 ? `db${String(this.dbIndex)}:` : '',\n });\n }\n\n async disconnect(): Promise<void> {\n if (!this.client) return;\n try {\n await this.client.quit();\n } catch {\n this.client.disconnect();\n }\n this.client = null;\n }\n\n /** The shared command client. Throws if not connected. */\n getClient(): IoRedis {\n if (!this.client) {\n throw new Error('[RedisStreamsConnection] not connected — call connect() first');\n }\n return this.client;\n }\n\n /** Make a dedicated client (e.g. for a blocking XREADGROUP loop). */\n async makeBlockingClient(): Promise<IoRedis> {\n await this.connect();\n const dup = this.getClient().duplicate();\n if ('connect' in dup && typeof dup.connect === 'function') {\n try {\n await dup.connect();\n } catch {\n /* ioredis auto-connects in some versions */\n }\n }\n return dup;\n }\n\n async ping(): Promise<string> {\n await this.connect();\n return this.getClient().ping();\n }\n}\n\nexport type { IoRedis };\n"]}
|