@contractspec/lib.bus 1.46.2 → 1.47.0

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.
@@ -1 +1 @@
1
- {"version":3,"file":"auditableBus.js","names":["record: AuditRecord","envelope: AuditableEventEnvelope<T>"],"sources":["../src/auditableBus.ts"],"sourcesContent":["import {\n type EventEnvelope,\n type EventKey,\n eventKey,\n type EventSpec,\n} from '@contractspec/lib.contracts';\nimport type { AnySchemaModel } from '@contractspec/lib.schema';\nimport type { EventBus } from './eventBus';\nimport { encodeEvent, decodeEvent } from './eventBus';\nimport type { EventMetadata } from './metadata';\n\n/**\n * Extended event envelope with metadata for auditing.\n */\nexport interface AuditableEventEnvelope<T = unknown> extends EventEnvelope<T> {\n metadata?: EventMetadata;\n}\n\n/**\n * Audit record for persisting event history.\n */\nexport interface AuditRecord {\n id: string;\n eventKey: string;\n eventVersion: string;\n payload: unknown;\n metadata?: EventMetadata;\n occurredAt: string;\n traceId?: string;\n recordedAt: Date;\n}\n\n/**\n * Audit storage adapter interface.\n */\nexport interface AuditStorage {\n /** Store an audit record */\n store(record: AuditRecord): Promise<void>;\n /** Query audit records */\n query?(options: AuditQueryOptions): Promise<AuditRecord[]>;\n}\n\n/**\n * Options for querying audit records.\n */\nexport interface AuditQueryOptions {\n eventKey?: string;\n actorId?: string;\n targetId?: string;\n orgId?: string;\n traceId?: string;\n from?: Date;\n to?: Date;\n limit?: number;\n offset?: number;\n}\n\n/**\n * Options for creating an auditable event bus.\n */\nexport interface AuditableEventBusOptions {\n /** Underlying event bus for publishing */\n bus: EventBus;\n /** Audit storage adapter */\n storage?: AuditStorage;\n /** Default metadata to include with all events */\n defaultMetadata?: EventMetadata;\n /** Filter function to decide which events to audit */\n shouldAudit?: (eventKey: string, envelope: AuditableEventEnvelope) => boolean;\n /** Transform function for audit records */\n transformAuditRecord?: (record: AuditRecord) => AuditRecord;\n}\n\n/**\n * AuditableEventBus wraps an EventBus to automatically record events for audit trail.\n */\nexport class AuditableEventBus implements EventBus {\n private readonly bus: EventBus;\n private readonly storage?: AuditStorage;\n private readonly defaultMetadata: EventMetadata;\n private readonly shouldAudit: (\n eventKey: string,\n envelope: AuditableEventEnvelope\n ) => boolean;\n private readonly transformAuditRecord?: (record: AuditRecord) => AuditRecord;\n\n constructor(options: AuditableEventBusOptions) {\n this.bus = options.bus;\n this.storage = options.storage;\n this.defaultMetadata = options.defaultMetadata ?? {};\n this.shouldAudit = options.shouldAudit ?? (() => true);\n this.transformAuditRecord = options.transformAuditRecord;\n }\n\n /**\n * Publish an event and optionally record it for audit.\n */\n async publish(topic: EventKey, bytes: Uint8Array): Promise<void> {\n // Publish to underlying bus first\n await this.bus.publish(topic, bytes);\n\n // Record for audit if storage is configured\n if (this.storage) {\n try {\n const envelope = decodeEvent<unknown>(bytes) as AuditableEventEnvelope;\n\n if (this.shouldAudit(envelope.key, envelope)) {\n let record: AuditRecord = {\n id: crypto.randomUUID(),\n eventKey: envelope.key,\n eventVersion: envelope.version,\n payload: envelope.payload,\n metadata: {\n ...this.defaultMetadata,\n ...envelope.metadata,\n },\n occurredAt: envelope.occurredAt,\n traceId: envelope.traceId,\n recordedAt: new Date(),\n };\n\n if (this.transformAuditRecord) {\n record = this.transformAuditRecord(record);\n }\n\n await this.storage.store(record);\n }\n } catch (error) {\n // Log but don't fail publishing if audit fails\n console.error('Failed to record audit:', error);\n }\n }\n }\n\n /**\n * Subscribe to events from the underlying bus.\n */\n async subscribe(\n topic: EventKey | string,\n handler: (bytes: Uint8Array) => Promise<void>\n ): Promise<() => Promise<void>> {\n return this.bus.subscribe(topic, handler);\n }\n\n /**\n * Query audit records (if storage supports it).\n */\n async queryAudit(options: AuditQueryOptions): Promise<AuditRecord[]> {\n if (!this.storage?.query) {\n throw new Error('Audit storage does not support querying');\n }\n return this.storage.query(options);\n }\n}\n\n/**\n * Create an auditable publisher that includes metadata.\n */\nexport function makeAuditablePublisher<T extends AnySchemaModel>(\n bus: AuditableEventBus | EventBus,\n spec: EventSpec<T>,\n defaultMetadata?: EventMetadata\n) {\n return async (\n payload: T,\n options?: { traceId?: string; metadata?: EventMetadata }\n ) => {\n const envelope: AuditableEventEnvelope<T> = {\n id: crypto.randomUUID(),\n occurredAt: new Date().toISOString(),\n key: spec.meta.key,\n version: spec.meta.version,\n payload,\n traceId: options?.traceId,\n metadata: {\n ...defaultMetadata,\n ...options?.metadata,\n },\n };\n await bus.publish(\n eventKey(spec.meta.key, spec.meta.version),\n encodeEvent(envelope)\n );\n };\n}\n\n/**\n * In-memory audit storage for development/testing.\n */\nexport class InMemoryAuditStorage implements AuditStorage {\n private records: AuditRecord[] = [];\n\n async store(record: AuditRecord): Promise<void> {\n this.records.push(record);\n }\n\n async query(options: AuditQueryOptions): Promise<AuditRecord[]> {\n let results = [...this.records];\n\n if (options.eventKey) {\n results = results.filter((r) => r.eventKey === options.eventKey);\n }\n\n if (options.actorId) {\n results = results.filter((r) => r.metadata?.actorId === options.actorId);\n }\n\n if (options.targetId) {\n results = results.filter(\n (r) => r.metadata?.targetId === options.targetId\n );\n }\n\n if (options.orgId) {\n results = results.filter((r) => r.metadata?.orgId === options.orgId);\n }\n\n if (options.traceId) {\n results = results.filter((r) => r.traceId === options.traceId);\n }\n\n if (options.from) {\n const from = options.from;\n results = results.filter((r) => new Date(r.occurredAt) >= from);\n }\n\n if (options.to) {\n const to = options.to;\n results = results.filter((r) => new Date(r.occurredAt) <= to);\n }\n\n // Sort by occurredAt descending\n results.sort(\n (a, b) =>\n new Date(b.occurredAt).getTime() - new Date(a.occurredAt).getTime()\n );\n\n // Apply pagination\n const offset = options.offset ?? 0;\n const limit = options.limit ?? 100;\n return results.slice(offset, offset + limit);\n }\n\n /**\n * Get all records (for testing).\n */\n getAll(): AuditRecord[] {\n return [...this.records];\n }\n\n /**\n * Clear all records (for testing).\n */\n clear(): void {\n this.records = [];\n }\n}\n\n/**\n * Create an auditable event bus with in-memory storage.\n */\nexport function createAuditableEventBus(\n bus: EventBus,\n options?: Omit<AuditableEventBusOptions, 'bus'>\n): AuditableEventBus {\n return new AuditableEventBus({\n bus,\n storage: options?.storage ?? new InMemoryAuditStorage(),\n ...options,\n });\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"auditableBus.js","names":[],"sources":["../src/auditableBus.ts"],"sourcesContent":["import {\n type EventEnvelope,\n type EventKey,\n eventKey,\n type EventSpec,\n} from '@contractspec/lib.contracts';\nimport type { AnySchemaModel } from '@contractspec/lib.schema';\nimport type { EventBus } from './eventBus';\nimport { encodeEvent, decodeEvent } from './eventBus';\nimport type { EventMetadata } from './metadata';\n\n/**\n * Extended event envelope with metadata for auditing.\n */\nexport interface AuditableEventEnvelope<T = unknown> extends EventEnvelope<T> {\n metadata?: EventMetadata;\n}\n\n/**\n * Audit record for persisting event history.\n */\nexport interface AuditRecord {\n id: string;\n eventKey: string;\n eventVersion: string;\n payload: unknown;\n metadata?: EventMetadata;\n occurredAt: string;\n traceId?: string;\n recordedAt: Date;\n}\n\n/**\n * Audit storage adapter interface.\n */\nexport interface AuditStorage {\n /** Store an audit record */\n store(record: AuditRecord): Promise<void>;\n /** Query audit records */\n query?(options: AuditQueryOptions): Promise<AuditRecord[]>;\n}\n\n/**\n * Options for querying audit records.\n */\nexport interface AuditQueryOptions {\n eventKey?: string;\n actorId?: string;\n targetId?: string;\n orgId?: string;\n traceId?: string;\n from?: Date;\n to?: Date;\n limit?: number;\n offset?: number;\n}\n\n/**\n * Options for creating an auditable event bus.\n */\nexport interface AuditableEventBusOptions {\n /** Underlying event bus for publishing */\n bus: EventBus;\n /** Audit storage adapter */\n storage?: AuditStorage;\n /** Default metadata to include with all events */\n defaultMetadata?: EventMetadata;\n /** Filter function to decide which events to audit */\n shouldAudit?: (eventKey: string, envelope: AuditableEventEnvelope) => boolean;\n /** Transform function for audit records */\n transformAuditRecord?: (record: AuditRecord) => AuditRecord;\n}\n\n/**\n * AuditableEventBus wraps an EventBus to automatically record events for audit trail.\n */\nexport class AuditableEventBus implements EventBus {\n private readonly bus: EventBus;\n private readonly storage?: AuditStorage;\n private readonly defaultMetadata: EventMetadata;\n private readonly shouldAudit: (\n eventKey: string,\n envelope: AuditableEventEnvelope\n ) => boolean;\n private readonly transformAuditRecord?: (record: AuditRecord) => AuditRecord;\n\n constructor(options: AuditableEventBusOptions) {\n this.bus = options.bus;\n this.storage = options.storage;\n this.defaultMetadata = options.defaultMetadata ?? {};\n this.shouldAudit = options.shouldAudit ?? (() => true);\n this.transformAuditRecord = options.transformAuditRecord;\n }\n\n /**\n * Publish an event and optionally record it for audit.\n */\n async publish(topic: EventKey, bytes: Uint8Array): Promise<void> {\n // Publish to underlying bus first\n await this.bus.publish(topic, bytes);\n\n // Record for audit if storage is configured\n if (this.storage) {\n try {\n const envelope = decodeEvent<unknown>(bytes) as AuditableEventEnvelope;\n\n if (this.shouldAudit(envelope.key, envelope)) {\n let record: AuditRecord = {\n id: crypto.randomUUID(),\n eventKey: envelope.key,\n eventVersion: envelope.version,\n payload: envelope.payload,\n metadata: {\n ...this.defaultMetadata,\n ...envelope.metadata,\n },\n occurredAt: envelope.occurredAt,\n traceId: envelope.traceId,\n recordedAt: new Date(),\n };\n\n if (this.transformAuditRecord) {\n record = this.transformAuditRecord(record);\n }\n\n await this.storage.store(record);\n }\n } catch (error) {\n // Log but don't fail publishing if audit fails\n console.error('Failed to record audit:', error);\n }\n }\n }\n\n /**\n * Subscribe to events from the underlying bus.\n */\n async subscribe(\n topic: EventKey | string,\n handler: (bytes: Uint8Array) => Promise<void>\n ): Promise<() => Promise<void>> {\n return this.bus.subscribe(topic, handler);\n }\n\n /**\n * Query audit records (if storage supports it).\n */\n async queryAudit(options: AuditQueryOptions): Promise<AuditRecord[]> {\n if (!this.storage?.query) {\n throw new Error('Audit storage does not support querying');\n }\n return this.storage.query(options);\n }\n}\n\n/**\n * Create an auditable publisher that includes metadata.\n */\nexport function makeAuditablePublisher<T extends AnySchemaModel>(\n bus: AuditableEventBus | EventBus,\n spec: EventSpec<T>,\n defaultMetadata?: EventMetadata\n) {\n return async (\n payload: T,\n options?: { traceId?: string; metadata?: EventMetadata }\n ) => {\n const envelope: AuditableEventEnvelope<T> = {\n id: crypto.randomUUID(),\n occurredAt: new Date().toISOString(),\n key: spec.meta.key,\n version: spec.meta.version,\n payload,\n traceId: options?.traceId,\n metadata: {\n ...defaultMetadata,\n ...options?.metadata,\n },\n };\n await bus.publish(\n eventKey(spec.meta.key, spec.meta.version),\n encodeEvent(envelope)\n );\n };\n}\n\n/**\n * In-memory audit storage for development/testing.\n */\nexport class InMemoryAuditStorage implements AuditStorage {\n private records: AuditRecord[] = [];\n\n async store(record: AuditRecord): Promise<void> {\n this.records.push(record);\n }\n\n async query(options: AuditQueryOptions): Promise<AuditRecord[]> {\n let results = [...this.records];\n\n if (options.eventKey) {\n results = results.filter((r) => r.eventKey === options.eventKey);\n }\n\n if (options.actorId) {\n results = results.filter((r) => r.metadata?.actorId === options.actorId);\n }\n\n if (options.targetId) {\n results = results.filter(\n (r) => r.metadata?.targetId === options.targetId\n );\n }\n\n if (options.orgId) {\n results = results.filter((r) => r.metadata?.orgId === options.orgId);\n }\n\n if (options.traceId) {\n results = results.filter((r) => r.traceId === options.traceId);\n }\n\n if (options.from) {\n const from = options.from;\n results = results.filter((r) => new Date(r.occurredAt) >= from);\n }\n\n if (options.to) {\n const to = options.to;\n results = results.filter((r) => new Date(r.occurredAt) <= to);\n }\n\n // Sort by occurredAt descending\n results.sort(\n (a, b) =>\n new Date(b.occurredAt).getTime() - new Date(a.occurredAt).getTime()\n );\n\n // Apply pagination\n const offset = options.offset ?? 0;\n const limit = options.limit ?? 100;\n return results.slice(offset, offset + limit);\n }\n\n /**\n * Get all records (for testing).\n */\n getAll(): AuditRecord[] {\n return [...this.records];\n }\n\n /**\n * Clear all records (for testing).\n */\n clear(): void {\n this.records = [];\n }\n}\n\n/**\n * Create an auditable event bus with in-memory storage.\n */\nexport function createAuditableEventBus(\n bus: EventBus,\n options?: Omit<AuditableEventBusOptions, 'bus'>\n): AuditableEventBus {\n return new AuditableEventBus({\n bus,\n storage: options?.storage ?? new InMemoryAuditStorage(),\n ...options,\n });\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"eventBus.js","names":["envelope: EventEnvelope<T>"],"sources":["../src/eventBus.ts"],"sourcesContent":["import {\n type EventEnvelope,\n type EventKey,\n eventKey,\n type EventSpec,\n} from '@contractspec/lib.contracts';\nimport type { AnySchemaModel } from '@contractspec/lib.schema';\n\nexport interface EventBus {\n publish: (topic: EventKey, bytes: Uint8Array) => Promise<void>;\n subscribe: (\n topic: EventKey | string, // allow wildcard if your broker supports it\n handler: (bytes: Uint8Array) => Promise<void>\n ) => Promise<() => Promise<void>>; // returns unsubscribe\n}\n\n/** Helper to encode a typed event envelope into JSON string */\nexport function encodeEvent<T>(envelope: EventEnvelope<T>): Uint8Array {\n return new TextEncoder().encode(JSON.stringify(envelope));\n}\n\n/** Helper to decode JSON string into a typed event envelope */\nexport function decodeEvent<T>(data: Uint8Array): EventEnvelope<T> {\n return JSON.parse(new TextDecoder().decode(data)) as EventEnvelope<T>;\n}\n\n/**\n * Create a typed publisher function for a given event spec.\n * It ensures payload conformance at compile time and builds the correct topic.\n */\nexport function makePublisher<T extends AnySchemaModel>(\n bus: EventBus,\n spec: EventSpec<T>\n) {\n return async (payload: T, traceId?: string) => {\n const envelope: EventEnvelope<T> = {\n id: crypto.randomUUID(),\n occurredAt: new Date().toISOString(),\n key: spec.meta.key,\n version: spec.meta.version,\n payload,\n traceId,\n };\n await bus.publish(\n eventKey(spec.meta.key, spec.meta.version),\n encodeEvent(envelope)\n );\n };\n}\n"],"mappings":";;;;AAiBA,SAAgB,YAAe,UAAwC;AACrE,QAAO,IAAI,aAAa,CAAC,OAAO,KAAK,UAAU,SAAS,CAAC;;;AAI3D,SAAgB,YAAe,MAAoC;AACjE,QAAO,KAAK,MAAM,IAAI,aAAa,CAAC,OAAO,KAAK,CAAC;;;;;;AAOnD,SAAgB,cACd,KACA,MACA;AACA,QAAO,OAAO,SAAY,YAAqB;EAC7C,MAAMA,WAA6B;GACjC,IAAI,OAAO,YAAY;GACvB,6BAAY,IAAI,MAAM,EAAC,aAAa;GACpC,KAAK,KAAK,KAAK;GACf,SAAS,KAAK,KAAK;GACnB;GACA;GACD;AACD,QAAM,IAAI,QACR,SAAS,KAAK,KAAK,KAAK,KAAK,KAAK,QAAQ,EAC1C,YAAY,SAAS,CACtB"}
1
+ {"version":3,"file":"eventBus.js","names":[],"sources":["../src/eventBus.ts"],"sourcesContent":["import {\n type EventEnvelope,\n type EventKey,\n eventKey,\n type EventSpec,\n} from '@contractspec/lib.contracts';\nimport type { AnySchemaModel } from '@contractspec/lib.schema';\n\nexport interface EventBus {\n publish: (topic: EventKey, bytes: Uint8Array) => Promise<void>;\n subscribe: (\n topic: EventKey | string, // allow wildcard if your broker supports it\n handler: (bytes: Uint8Array) => Promise<void>\n ) => Promise<() => Promise<void>>; // returns unsubscribe\n}\n\n/** Helper to encode a typed event envelope into JSON string */\nexport function encodeEvent<T>(envelope: EventEnvelope<T>): Uint8Array {\n return new TextEncoder().encode(JSON.stringify(envelope));\n}\n\n/** Helper to decode JSON string into a typed event envelope */\nexport function decodeEvent<T>(data: Uint8Array): EventEnvelope<T> {\n return JSON.parse(new TextDecoder().decode(data)) as EventEnvelope<T>;\n}\n\n/**\n * Create a typed publisher function for a given event spec.\n * It ensures payload conformance at compile time and builds the correct topic.\n */\nexport function makePublisher<T extends AnySchemaModel>(\n bus: EventBus,\n spec: EventSpec<T>\n) {\n return async (payload: T, traceId?: string) => {\n const envelope: EventEnvelope<T> = {\n id: crypto.randomUUID(),\n occurredAt: new Date().toISOString(),\n key: spec.meta.key,\n version: spec.meta.version,\n payload,\n traceId,\n };\n await bus.publish(\n eventKey(spec.meta.key, spec.meta.version),\n encodeEvent(envelope)\n );\n };\n}\n"],"mappings":";;;;AAiBA,SAAgB,YAAe,UAAwC;AACrE,QAAO,IAAI,aAAa,CAAC,OAAO,KAAK,UAAU,SAAS,CAAC;;;AAI3D,SAAgB,YAAe,MAAoC;AACjE,QAAO,KAAK,MAAM,IAAI,aAAa,CAAC,OAAO,KAAK,CAAC;;;;;;AAOnD,SAAgB,cACd,KACA,MACA;AACA,QAAO,OAAO,SAAY,YAAqB;EAC7C,MAAM,WAA6B;GACjC,IAAI,OAAO,YAAY;GACvB,6BAAY,IAAI,MAAM,EAAC,aAAa;GACpC,KAAK,KAAK,KAAK;GACf,SAAS,KAAK,KAAK;GACnB;GACA;GACD;AACD,QAAM,IAAI,QACR,SAAS,KAAK,KAAK,KAAK,KAAK,KAAK,QAAQ,EAC1C,YAAY,SAAS,CACtB"}
@@ -1 +1 @@
1
- {"version":3,"file":"filtering.js","names":["bus: EventBus","domain: string","envelope: AuditableEventEnvelope<T>","fullFilter: EventFilter"],"sources":["../src/filtering.ts"],"sourcesContent":["import type { EventKey, EventSpec } from '@contractspec/lib.contracts';\nimport type { AnySchemaModel } from '@contractspec/lib.schema';\nimport type { EventBus } from './eventBus';\nimport { decodeEvent } from './eventBus';\nimport type { AuditableEventEnvelope } from './auditableBus';\nimport { satisfies } from 'compare-versions';\n\n/**\n * Event filter configuration.\n */\nexport interface EventFilter {\n /** Filter by event name pattern (supports * wildcard) */\n eventName?: string;\n /** Filter by domain prefix */\n domain?: string;\n /** Filter by version */\n version?: string;\n /** Filter by actor ID */\n actorId?: string;\n /** Filter by organization ID */\n orgId?: string;\n /** Filter by custom tags */\n tags?: Record<string, string>;\n /** Custom predicate function */\n predicate?: (envelope: AuditableEventEnvelope) => boolean;\n}\n\n/**\n * Check if an event matches a filter.\n */\nexport function matchesFilter(\n envelope: AuditableEventEnvelope,\n filter: EventFilter\n): boolean {\n // Check event name pattern\n if (filter.eventName) {\n const pattern = filter.eventName.replace(/\\*/g, '.*');\n const regex = new RegExp(`^${pattern}$`);\n if (!regex.test(envelope.key)) {\n return false;\n }\n }\n\n // Check domain prefix\n if (filter.domain) {\n if (!envelope.key.startsWith(filter.domain + '.')) {\n return false;\n }\n }\n\n // Check version\n if (filter.version) {\n if (!envelope.version || !satisfies(envelope.version, filter.version)) {\n return false;\n }\n }\n\n // Check metadata fields\n if (filter.actorId && envelope.metadata?.actorId !== filter.actorId) {\n return false;\n }\n\n if (filter.orgId && envelope.metadata?.orgId !== filter.orgId) {\n return false;\n }\n\n // Check tags\n if (filter.tags) {\n const eventTags = envelope.metadata?.tags ?? {};\n for (const [key, value] of Object.entries(filter.tags)) {\n if (eventTags[key] !== value) {\n return false;\n }\n }\n }\n\n // Custom predicate\n if (filter.predicate && !filter.predicate(envelope)) {\n return false;\n }\n\n return true;\n}\n\n/**\n * Create a filtered subscriber that only receives matching events.\n */\nexport function createFilteredSubscriber(\n bus: EventBus,\n filter: EventFilter,\n handler: (envelope: AuditableEventEnvelope) => Promise<void>\n) {\n return async (topic: EventKey | string) => {\n return bus.subscribe(topic, async (bytes) => {\n const envelope = decodeEvent<unknown>(bytes) as AuditableEventEnvelope;\n\n if (matchesFilter(envelope, filter)) {\n await handler(envelope);\n }\n });\n };\n}\n\n/**\n * Domain-specific event bus that filters by domain prefix.\n */\nexport class DomainEventBus {\n constructor(\n private readonly bus: EventBus,\n private readonly domain: string\n ) {}\n\n /**\n * Publish a domain event.\n */\n async publish<T extends AnySchemaModel>(\n spec: EventSpec<T>,\n payload: T,\n metadata?: AuditableEventEnvelope['metadata']\n ): Promise<void> {\n // Ensure event name starts with domain\n const eventName = spec.meta.key.startsWith(this.domain + '.')\n ? spec.meta.key\n : `${this.domain}.${spec.meta.key}`;\n\n const envelope: AuditableEventEnvelope<T> = {\n id: crypto.randomUUID(),\n occurredAt: new Date().toISOString(),\n key: eventName,\n version: spec.meta.version,\n payload,\n metadata,\n };\n\n const bytes = new TextEncoder().encode(JSON.stringify(envelope));\n await this.bus.publish(`${eventName}.v${spec.meta.version}`, bytes);\n }\n\n /**\n * Subscribe to all domain events.\n */\n async subscribeAll(\n handler: (envelope: AuditableEventEnvelope) => Promise<void>\n ): Promise<() => Promise<void>> {\n // Subscribe to wildcard pattern if supported\n return this.bus.subscribe(`${this.domain}.*`, async (bytes) => {\n const envelope = decodeEvent<unknown>(bytes) as AuditableEventEnvelope;\n await handler(envelope);\n });\n }\n\n /**\n * Subscribe with filter.\n */\n async subscribeFiltered(\n filter: Omit<EventFilter, 'domain'>,\n handler: (envelope: AuditableEventEnvelope) => Promise<void>\n ): Promise<() => Promise<void>> {\n const fullFilter: EventFilter = {\n ...filter,\n domain: this.domain,\n };\n\n return this.bus.subscribe(`${this.domain}.*`, async (bytes) => {\n const envelope = decodeEvent<unknown>(bytes) as AuditableEventEnvelope;\n\n if (matchesFilter(envelope, fullFilter)) {\n await handler(envelope);\n }\n });\n }\n}\n\n/**\n * Create a domain-scoped event bus.\n */\nexport function createDomainBus(bus: EventBus, domain: string): DomainEventBus {\n return new DomainEventBus(bus, domain);\n}\n\n/**\n * Event router that routes events to different handlers based on filters.\n */\nexport class EventRouter {\n private routes: {\n filter: EventFilter;\n handler: (envelope: AuditableEventEnvelope) => Promise<void>;\n }[] = [];\n\n /**\n * Add a route.\n */\n route(\n filter: EventFilter,\n handler: (envelope: AuditableEventEnvelope) => Promise<void>\n ): this {\n this.routes.push({ filter, handler });\n return this;\n }\n\n /**\n * Route an event to matching handlers.\n */\n async dispatch(envelope: AuditableEventEnvelope): Promise<void> {\n const matchingRoutes = this.routes.filter((r) =>\n matchesFilter(envelope, r.filter)\n );\n\n await Promise.all(matchingRoutes.map((r) => r.handler(envelope)));\n }\n\n /**\n * Create a subscriber that routes events.\n */\n createSubscriber(\n bus: EventBus\n ): (topic: EventKey | string) => Promise<() => Promise<void>> {\n return async (topic: EventKey | string) => {\n return bus.subscribe(topic, async (bytes) => {\n const envelope = decodeEvent<unknown>(bytes) as AuditableEventEnvelope;\n await this.dispatch(envelope);\n });\n };\n }\n}\n\n/**\n * Create an event router.\n */\nexport function createEventRouter(): EventRouter {\n return new EventRouter();\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"filtering.js","names":[],"sources":["../src/filtering.ts"],"sourcesContent":["import type { EventKey, EventSpec } from '@contractspec/lib.contracts';\nimport type { AnySchemaModel } from '@contractspec/lib.schema';\nimport type { EventBus } from './eventBus';\nimport { decodeEvent } from './eventBus';\nimport type { AuditableEventEnvelope } from './auditableBus';\nimport { satisfies } from 'compare-versions';\n\n/**\n * Event filter configuration.\n */\nexport interface EventFilter {\n /** Filter by event name pattern (supports * wildcard) */\n eventName?: string;\n /** Filter by domain prefix */\n domain?: string;\n /** Filter by version */\n version?: string;\n /** Filter by actor ID */\n actorId?: string;\n /** Filter by organization ID */\n orgId?: string;\n /** Filter by custom tags */\n tags?: Record<string, string>;\n /** Custom predicate function */\n predicate?: (envelope: AuditableEventEnvelope) => boolean;\n}\n\n/**\n * Check if an event matches a filter.\n */\nexport function matchesFilter(\n envelope: AuditableEventEnvelope,\n filter: EventFilter\n): boolean {\n // Check event name pattern\n if (filter.eventName) {\n const pattern = filter.eventName.replace(/\\*/g, '.*');\n const regex = new RegExp(`^${pattern}$`);\n if (!regex.test(envelope.key)) {\n return false;\n }\n }\n\n // Check domain prefix\n if (filter.domain) {\n if (!envelope.key.startsWith(filter.domain + '.')) {\n return false;\n }\n }\n\n // Check version\n if (filter.version) {\n if (!envelope.version || !satisfies(envelope.version, filter.version)) {\n return false;\n }\n }\n\n // Check metadata fields\n if (filter.actorId && envelope.metadata?.actorId !== filter.actorId) {\n return false;\n }\n\n if (filter.orgId && envelope.metadata?.orgId !== filter.orgId) {\n return false;\n }\n\n // Check tags\n if (filter.tags) {\n const eventTags = envelope.metadata?.tags ?? {};\n for (const [key, value] of Object.entries(filter.tags)) {\n if (eventTags[key] !== value) {\n return false;\n }\n }\n }\n\n // Custom predicate\n if (filter.predicate && !filter.predicate(envelope)) {\n return false;\n }\n\n return true;\n}\n\n/**\n * Create a filtered subscriber that only receives matching events.\n */\nexport function createFilteredSubscriber(\n bus: EventBus,\n filter: EventFilter,\n handler: (envelope: AuditableEventEnvelope) => Promise<void>\n) {\n return async (topic: EventKey | string) => {\n return bus.subscribe(topic, async (bytes) => {\n const envelope = decodeEvent<unknown>(bytes) as AuditableEventEnvelope;\n\n if (matchesFilter(envelope, filter)) {\n await handler(envelope);\n }\n });\n };\n}\n\n/**\n * Domain-specific event bus that filters by domain prefix.\n */\nexport class DomainEventBus {\n constructor(\n private readonly bus: EventBus,\n private readonly domain: string\n ) {}\n\n /**\n * Publish a domain event.\n */\n async publish<T extends AnySchemaModel>(\n spec: EventSpec<T>,\n payload: T,\n metadata?: AuditableEventEnvelope['metadata']\n ): Promise<void> {\n // Ensure event name starts with domain\n const eventName = spec.meta.key.startsWith(this.domain + '.')\n ? spec.meta.key\n : `${this.domain}.${spec.meta.key}`;\n\n const envelope: AuditableEventEnvelope<T> = {\n id: crypto.randomUUID(),\n occurredAt: new Date().toISOString(),\n key: eventName,\n version: spec.meta.version,\n payload,\n metadata,\n };\n\n const bytes = new TextEncoder().encode(JSON.stringify(envelope));\n await this.bus.publish(`${eventName}.v${spec.meta.version}`, bytes);\n }\n\n /**\n * Subscribe to all domain events.\n */\n async subscribeAll(\n handler: (envelope: AuditableEventEnvelope) => Promise<void>\n ): Promise<() => Promise<void>> {\n // Subscribe to wildcard pattern if supported\n return this.bus.subscribe(`${this.domain}.*`, async (bytes) => {\n const envelope = decodeEvent<unknown>(bytes) as AuditableEventEnvelope;\n await handler(envelope);\n });\n }\n\n /**\n * Subscribe with filter.\n */\n async subscribeFiltered(\n filter: Omit<EventFilter, 'domain'>,\n handler: (envelope: AuditableEventEnvelope) => Promise<void>\n ): Promise<() => Promise<void>> {\n const fullFilter: EventFilter = {\n ...filter,\n domain: this.domain,\n };\n\n return this.bus.subscribe(`${this.domain}.*`, async (bytes) => {\n const envelope = decodeEvent<unknown>(bytes) as AuditableEventEnvelope;\n\n if (matchesFilter(envelope, fullFilter)) {\n await handler(envelope);\n }\n });\n }\n}\n\n/**\n * Create a domain-scoped event bus.\n */\nexport function createDomainBus(bus: EventBus, domain: string): DomainEventBus {\n return new DomainEventBus(bus, domain);\n}\n\n/**\n * Event router that routes events to different handlers based on filters.\n */\nexport class EventRouter {\n private routes: {\n filter: EventFilter;\n handler: (envelope: AuditableEventEnvelope) => Promise<void>;\n }[] = [];\n\n /**\n * Add a route.\n */\n route(\n filter: EventFilter,\n handler: (envelope: AuditableEventEnvelope) => Promise<void>\n ): this {\n this.routes.push({ filter, handler });\n return this;\n }\n\n /**\n * Route an event to matching handlers.\n */\n async dispatch(envelope: AuditableEventEnvelope): Promise<void> {\n const matchingRoutes = this.routes.filter((r) =>\n matchesFilter(envelope, r.filter)\n );\n\n await Promise.all(matchingRoutes.map((r) => r.handler(envelope)));\n }\n\n /**\n * Create a subscriber that routes events.\n */\n createSubscriber(\n bus: EventBus\n ): (topic: EventKey | string) => Promise<() => Promise<void>> {\n return async (topic: EventKey | string) => {\n return bus.subscribe(topic, async (bytes) => {\n const envelope = decodeEvent<unknown>(bytes) as AuditableEventEnvelope;\n await this.dispatch(envelope);\n });\n };\n }\n}\n\n/**\n * Create an event router.\n */\nexport function createEventRouter(): EventRouter {\n return new EventRouter();\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@contractspec/lib.bus",
3
- "version": "1.46.2",
3
+ "version": "1.47.0",
4
4
  "description": "Event bus and messaging primitives",
5
5
  "keywords": [
6
6
  "contractspec",
@@ -22,25 +22,23 @@
22
22
  "lint:check": "eslint src"
23
23
  },
24
24
  "devDependencies": {
25
- "@contractspec/tool.tsdown": "1.46.2",
26
- "@contractspec/tool.typescript": "1.46.2",
25
+ "@contractspec/tool.tsdown": "1.47.0",
26
+ "@contractspec/tool.typescript": "1.47.0",
27
27
  "@types/express": "^5.0.3",
28
- "tsdown": "^0.18.3",
28
+ "tsdown": "^0.19.0",
29
29
  "typescript": "^5.9.3"
30
30
  },
31
31
  "dependencies": {
32
- "@contractspec/lib.schema": "1.46.2",
33
- "@contractspec/lib.contracts": "1.46.2",
32
+ "@contractspec/lib.schema": "1.47.0",
33
+ "@contractspec/lib.contracts": "1.47.0",
34
34
  "compare-versions": "^6.1.1"
35
35
  },
36
36
  "peerDependencies": {
37
- "elysia": "^1.4.19",
37
+ "elysia": "^1.4.21",
38
38
  "express": "^5.2.1",
39
39
  "next": "16.1.1"
40
40
  },
41
41
  "type": "module",
42
- "main": "./dist/index.js",
43
- "module": "./dist/index.js",
44
42
  "types": "./dist/index.d.ts",
45
43
  "files": [
46
44
  "dist",