@pattern-stack/codegen 0.8.1 → 0.9.1
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/CHANGELOG.md +29 -0
- package/dist/{job-orchestrator.protocol-BwsBd37o.d.ts → job-orchestrator.protocol-CHOEqBDk.d.ts} +36 -1
- package/dist/runtime/subsystems/bridge/bridge-delivery-handler.d.ts +2 -2
- package/dist/runtime/subsystems/bridge/bridge-delivery-handler.js.map +1 -1
- package/dist/runtime/subsystems/bridge/bridge-outbox-drain-hook.js.map +1 -1
- package/dist/runtime/subsystems/bridge/bridge.module.d.ts +5 -1
- package/dist/runtime/subsystems/bridge/bridge.module.js +930 -275
- package/dist/runtime/subsystems/bridge/bridge.module.js.map +1 -1
- package/dist/runtime/subsystems/bridge/event-flow.service.d.ts +1 -1
- package/dist/runtime/subsystems/bridge/event-flow.service.js.map +1 -1
- package/dist/runtime/subsystems/bridge/index.d.ts +4 -1
- package/dist/runtime/subsystems/bridge/index.js +837 -182
- package/dist/runtime/subsystems/bridge/index.js.map +1 -1
- package/dist/runtime/subsystems/events/event-bus.drizzle-backend.d.ts +3 -1
- package/dist/runtime/subsystems/events/event-bus.drizzle-backend.js +92 -1
- package/dist/runtime/subsystems/events/event-bus.drizzle-backend.js.map +1 -1
- package/dist/runtime/subsystems/events/event-bus.memory-backend.d.ts +3 -1
- package/dist/runtime/subsystems/events/event-bus.memory-backend.js +99 -0
- package/dist/runtime/subsystems/events/event-bus.memory-backend.js.map +1 -1
- package/dist/runtime/subsystems/events/event-bus.redis-backend.js.map +1 -1
- package/dist/runtime/subsystems/events/event-keyset-cursor.d.ts +32 -0
- package/dist/runtime/subsystems/events/event-keyset-cursor.js +38 -0
- package/dist/runtime/subsystems/events/event-keyset-cursor.js.map +1 -0
- package/dist/runtime/subsystems/events/event-read.protocol.d.ts +94 -0
- package/dist/runtime/subsystems/events/event-read.protocol.js +9 -0
- package/dist/runtime/subsystems/events/event-read.protocol.js.map +1 -0
- package/dist/runtime/subsystems/events/events.module.js +177 -3
- package/dist/runtime/subsystems/events/events.module.js.map +1 -1
- package/dist/runtime/subsystems/events/events.tokens.d.ts +16 -1
- package/dist/runtime/subsystems/events/events.tokens.js +2 -0
- package/dist/runtime/subsystems/events/events.tokens.js.map +1 -1
- package/dist/runtime/subsystems/events/generated/bus.js.map +1 -1
- package/dist/runtime/subsystems/events/generated/index.js.map +1 -1
- package/dist/runtime/subsystems/events/index.d.ts +2 -1
- package/dist/runtime/subsystems/events/index.js +178 -3
- package/dist/runtime/subsystems/events/index.js.map +1 -1
- package/dist/runtime/subsystems/index.d.ts +3 -2
- package/dist/runtime/subsystems/index.js +1194 -264
- package/dist/runtime/subsystems/index.js.map +1 -1
- package/dist/runtime/subsystems/jobs/bullmq.config.d.ts +98 -0
- package/dist/runtime/subsystems/jobs/bullmq.config.js +143 -0
- package/dist/runtime/subsystems/jobs/bullmq.config.js.map +1 -0
- package/dist/runtime/subsystems/jobs/index.d.ts +8 -3
- package/dist/runtime/subsystems/jobs/index.js +861 -201
- package/dist/runtime/subsystems/jobs/index.js.map +1 -1
- package/dist/runtime/subsystems/jobs/job-handler.base.d.ts +2 -1
- package/dist/runtime/subsystems/jobs/job-handler.base.js.map +1 -1
- package/dist/runtime/subsystems/jobs/job-orchestrator.bullmq-backend.d.ts +108 -0
- package/dist/runtime/subsystems/jobs/job-orchestrator.bullmq-backend.js +922 -0
- package/dist/runtime/subsystems/jobs/job-orchestrator.bullmq-backend.js.map +1 -0
- package/dist/runtime/subsystems/jobs/job-orchestrator.drizzle-backend.d.ts +2 -1
- package/dist/runtime/subsystems/jobs/job-orchestrator.memory-backend.d.ts +2 -1
- package/dist/runtime/subsystems/jobs/job-orchestrator.memory-backend.js.map +1 -1
- package/dist/runtime/subsystems/jobs/job-orchestrator.protocol.d.ts +2 -1
- package/dist/runtime/subsystems/jobs/job-run-keyset-cursor.d.ts +53 -0
- package/dist/runtime/subsystems/jobs/job-run-keyset-cursor.js +57 -0
- package/dist/runtime/subsystems/jobs/job-run-keyset-cursor.js.map +1 -0
- package/dist/runtime/subsystems/jobs/job-run-service.drizzle-backend.d.ts +4 -2
- package/dist/runtime/subsystems/jobs/job-run-service.drizzle-backend.js +81 -1
- package/dist/runtime/subsystems/jobs/job-run-service.drizzle-backend.js.map +1 -1
- package/dist/runtime/subsystems/jobs/job-run-service.memory-backend.d.ts +4 -2
- package/dist/runtime/subsystems/jobs/job-run-service.memory-backend.js +81 -0
- package/dist/runtime/subsystems/jobs/job-run-service.memory-backend.js.map +1 -1
- package/dist/runtime/subsystems/jobs/job-run-service.protocol.d.ts +76 -2
- package/dist/runtime/subsystems/jobs/job-worker.bullmq-backend.d.ts +49 -0
- package/dist/runtime/subsystems/jobs/job-worker.bullmq-backend.js +374 -0
- package/dist/runtime/subsystems/jobs/job-worker.bullmq-backend.js.map +1 -0
- package/dist/runtime/subsystems/jobs/job-worker.d.ts +2 -1
- package/dist/runtime/subsystems/jobs/job-worker.js.map +1 -1
- package/dist/runtime/subsystems/jobs/job-worker.module.d.ts +44 -5
- package/dist/runtime/subsystems/jobs/job-worker.module.js +832 -178
- package/dist/runtime/subsystems/jobs/job-worker.module.js.map +1 -1
- package/dist/runtime/subsystems/jobs/jobs-domain.module.d.ts +10 -1
- package/dist/runtime/subsystems/jobs/jobs-domain.module.js +519 -20
- package/dist/runtime/subsystems/jobs/jobs-domain.module.js.map +1 -1
- package/dist/runtime/subsystems/jobs/jobs-errors.d.ts +2 -1
- package/dist/runtime/subsystems/jobs/pool-config.loader.d.ts +9 -1
- package/dist/runtime/subsystems/jobs/pool-config.loader.js +4 -0
- package/dist/runtime/subsystems/jobs/pool-config.loader.js.map +1 -1
- package/dist/runtime/subsystems/observability/index.d.ts +4 -3
- package/dist/runtime/subsystems/observability/index.js +109 -2
- package/dist/runtime/subsystems/observability/index.js.map +1 -1
- package/dist/runtime/subsystems/observability/observability.module.js +109 -2
- package/dist/runtime/subsystems/observability/observability.module.js.map +1 -1
- package/dist/runtime/subsystems/observability/observability.protocol.d.ts +64 -3
- package/dist/runtime/subsystems/observability/observability.service.d.ts +22 -4
- package/dist/runtime/subsystems/observability/observability.service.js +109 -2
- package/dist/runtime/subsystems/observability/observability.service.js.map +1 -1
- package/dist/runtime/subsystems/observability/reporters/bridge-metrics.reporter.d.ts +3 -2
- package/dist/runtime/subsystems/observability/reporters/index.d.ts +3 -2
- package/dist/src/cli/index.js +30 -6
- package/dist/src/cli/index.js.map +1 -1
- package/package.json +5 -1
- package/runtime/subsystems/bridge/bridge.module.ts +5 -0
- package/runtime/subsystems/events/event-bus.drizzle-backend.ts +109 -3
- package/runtime/subsystems/events/event-bus.memory-backend.ts +103 -1
- package/runtime/subsystems/events/event-keyset-cursor.ts +59 -0
- package/runtime/subsystems/events/event-read.protocol.ts +97 -0
- package/runtime/subsystems/events/events.module.ts +18 -2
- package/runtime/subsystems/events/events.tokens.ts +16 -0
- package/runtime/subsystems/events/index.ts +7 -0
- package/runtime/subsystems/jobs/bullmq.config.ts +125 -0
- package/runtime/subsystems/jobs/index.ts +22 -0
- package/runtime/subsystems/jobs/job-handler.base.ts +36 -0
- package/runtime/subsystems/jobs/job-orchestrator.bullmq-backend.ts +381 -0
- package/runtime/subsystems/jobs/job-run-keyset-cursor.ts +88 -0
- package/runtime/subsystems/jobs/job-run-service.drizzle-backend.ts +59 -1
- package/runtime/subsystems/jobs/job-run-service.memory-backend.ts +53 -0
- package/runtime/subsystems/jobs/job-run-service.protocol.ts +77 -0
- package/runtime/subsystems/jobs/job-worker.bullmq-backend.ts +311 -0
- package/runtime/subsystems/jobs/job-worker.module.ts +124 -10
- package/runtime/subsystems/jobs/jobs-domain.module.ts +40 -21
- package/runtime/subsystems/jobs/pool-config.loader.ts +11 -0
- package/runtime/subsystems/observability/index.ts +8 -0
- package/runtime/subsystems/observability/observability.protocol.ts +76 -0
- package/runtime/subsystems/observability/observability.service.ts +148 -1
- package/templates/entity/new/clean-lite-ps/prompt-extension.js +14 -12
- package/templates/relationship/new/prompt.js +8 -5
- package/templates/subsystem/jobs/worker.ejs.t +30 -7
- package/templates/subsystem/sync/sync-audit.schema.ejs.t +12 -16
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../runtime/subsystems/events/generated/bus.ts","../../../../../runtime/subsystems/events/events.tokens.ts","../../../../../runtime/subsystems/events/events-errors.ts","../../../../../runtime/subsystems/events/generated/schemas.ts","../../../../../runtime/subsystems/events/generated/registry.ts"],"sourcesContent":["// AUTO-GENERATED by @pattern-stack/codegen. Do not edit.\n// Run `codegen entity new --all` to refresh.\n\nimport { Injectable, Inject } from '@nestjs/common';\nimport { randomUUID } from 'crypto';\nimport { EVENT_BUS, EVENTS_MULTI_TENANT } from '../events.tokens';\nimport { MissingTenantIdError } from '../events-errors';\nimport type { IEventBus, DrizzleTransaction } from '../event-bus.protocol';\nimport { eventPayloadSchemas } from './schemas';\nimport { getEventMetadata } from './registry';\nimport type { EventTypeName, EventOfType, PayloadOfType } from './types';\n\n/**\n * Typed facade over IEventBus.\n *\n * Stamps `pool`, `direction`, `tier`, and `version` into `event.metadata`\n * from the generated `eventRegistry` before delegating to\n * `IEventBus.publish()`. Downstream backends (DrizzleEventBus) read those\n * values to populate the explicit `domain_events` columns.\n *\n * Tier stamping (AUDIT-3): every event carries `metadata.tier`, sourced\n * from the registry. For `tier: 'audit'` events, the bus FORCES\n * `metadata.pool = null` and `metadata.direction = null` regardless of\n * any caller-supplied values in `opts.metadata` — audit routing is\n * bus-stamped, not caller-controlled. Caller overrides are silently\n * dropped with a debug-level log (callers should not be specifying these\n * for audit events; see ai-docs/specs/issue-242/plan.md §AUDIT-3).\n *\n * Validation gating (EVT-Q5): `CODEGEN_EVENT_VALIDATE` env flag, default on.\n * Uses `safeParse` + `console.warn` — never throws, so a bad publish does\n * not crash a hot path.\n *\n * Multi-tenancy (EVT-6): when the EventsModule is configured with\n * `multiTenant: true`, every publish must supply `opts.metadata.tenantId`\n * — otherwise `publish()` throws `MissingTenantIdError`. When `multiTenant`\n * is `false` (default), no tenantId is required. If a tenantId IS supplied,\n * it is preserved on `event.metadata` and the Drizzle backend writes it to\n * `domain_events.tenant_id` (EVT-4).\n */\n@Injectable()\nexport class TypedEventBus {\n\tconstructor(\n\t\t@Inject(EVENT_BUS) private readonly bus: IEventBus,\n\t\t@Inject(EVENTS_MULTI_TENANT) private readonly multiTenant: boolean,\n\t) {}\n\n\tasync publish<T extends EventTypeName>(\n\t\ttype: T,\n\t\taggregateId: string,\n\t\tpayload: PayloadOfType<T>,\n\t\topts?: { tx?: DrizzleTransaction; metadata?: Record<string, unknown> },\n\t): Promise<void> {\n\t\tconst meta = getEventMetadata(type);\n\n\t\tconst flag = process.env['CODEGEN_EVENT_VALIDATE'];\n\t\tconst shouldValidate =\n\t\t\tflag === undefined ? true : flag !== 'false' && flag !== '0';\n\t\tif (shouldValidate) {\n\t\t\t// `eventPayloadSchemas` is typed as `Record<EventTypeName, z.ZodType>`,\n\t\t\t// so under `noUncheckedIndexedAccess` the indexed lookup widens\n\t\t\t// to `z.ZodType | undefined`. When no events are registered at\n\t\t\t// codegen time `EventTypeName` degrades to `string` and the\n\t\t\t// schemas object is literally `{}` — the guard below is the\n\t\t\t// honest handling of that empty-registry case (skip validation;\n\t\t\t// it's a warn-only best-effort check per the class docblock).\n\t\t\tconst schema = eventPayloadSchemas[type];\n\t\t\tif (schema) {\n\t\t\t\tconst check = schema.safeParse(payload);\n\t\t\t\tif (!check.success) {\n\t\t\t\t\tconsole.warn(\n\t\t\t\t\t\t`[TypedEventBus] payload validation failed for ${String(type)}:`,\n\t\t\t\t\t\tcheck.error.issues,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tconst tenantId = opts?.metadata?.['tenantId'];\n\t\tif (this.multiTenant && (tenantId === undefined || tenantId === null)) {\n\t\t\tthrow new MissingTenantIdError(type as string);\n\t\t}\n\n\t\tconst aggregateType =\n\t\t\tmeta.aggregate ?? meta.source ?? meta.destination ?? (type as string);\n\n\t\t// AUDIT-3: build metadata with tier-aware routing stamping. For\n\t\t// `tier: 'audit'` events the bus FORCES pool/direction to null,\n\t\t// even if the caller supplied them in opts.metadata. Audit routing\n\t\t// is bus-stamped, not caller-controlled (see plan §AUDIT-3).\n\t\tconst baseMetadata: Record<string, unknown> = { ...(opts?.metadata ?? {}) };\n\t\tif (meta.tier === 'audit') {\n\t\t\tif (\n\t\t\t\tbaseMetadata['pool'] !== undefined ||\n\t\t\t\tbaseMetadata['direction'] !== undefined\n\t\t\t) {\n\t\t\t\tconsole.debug(\n\t\t\t\t\t`[TypedEventBus] tier:audit event '${String(type)}' had pool/direction in opts.metadata; overriding to null.`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tbaseMetadata['pool'] = null;\n\t\t\tbaseMetadata['direction'] = null;\n\t\t\tbaseMetadata['tier'] = 'audit';\n\t\t} else {\n\t\t\tbaseMetadata['pool'] = meta.pool;\n\t\t\tbaseMetadata['direction'] = meta.direction;\n\t\t\tbaseMetadata['tier'] = 'domain';\n\t\t}\n\t\tbaseMetadata['version'] = meta.version;\n\n\t\tawait this.bus.publish(\n\t\t\t{\n\t\t\t\tid: randomUUID(),\n\t\t\t\ttype,\n\t\t\t\taggregateId,\n\t\t\t\taggregateType,\n\t\t\t\tpayload: payload as Record<string, unknown>,\n\t\t\t\toccurredAt: new Date(),\n\t\t\t\tmetadata: baseMetadata,\n\t\t\t},\n\t\t\topts?.tx,\n\t\t);\n\t}\n\n\tsubscribe<T extends EventTypeName>(\n\t\ttype: T,\n\t\thandler: (event: EventOfType<T>) => Promise<void>,\n\t): () => void {\n\t\treturn this.bus.subscribe<EventOfType<T>>(type, handler as never);\n\t}\n}\n","/**\n * Injection token for the event bus.\n *\n * String constant (not Symbol) so it matches by value across import boundaries.\n * Matches the token in runtime/constants/tokens.ts — both are 'EVENT_BUS'.\n *\n * Usage in use cases:\n * ```typescript\n * constructor(@Inject(EVENT_BUS) private readonly eventBus: IEventBus) {}\n * ```\n */\nexport const EVENT_BUS = 'EVENT_BUS' as const;\n\n/**\n * Injection token for the generated `TypedEventBus` facade.\n *\n * `TypedEventBus` lives in `runtime/subsystems/events/generated/bus.ts` and\n * wraps `IEventBus` with project-specific `AppDomainEvent`-typed `publish<T>()`\n * and `subscribe<T>()`. Use cases inject this token in preference to\n * `EVENT_BUS` when they want compile-time type safety on event shapes.\n *\n * String constant (not Symbol) so it matches by value across import\n * boundaries — same convention as `EVENT_BUS`.\n *\n * Provider registration lands in EVT-6 (EventsModule wiring); the token is\n * declared here so generated code can import it without depending on the\n * still-being-formalised module.\n */\nexport const TYPED_EVENT_BUS = 'TYPED_EVENT_BUS' as const;\n\n/**\n * Injection token for the resolved multi-tenancy flag.\n *\n * Provided by `EventsModule.forRoot(...)` as `options.multiTenant ?? false`.\n * Consumed by `TypedEventBus` to enforce the tenantId-is-required rule at\n * publish time.\n *\n * String constant (not Symbol) so it matches by value across import\n * boundaries — same convention as the other events tokens. (The jobs\n * subsystem uses Symbols for the analogous token; events chose strings\n * from the start and we keep the file internally consistent.)\n */\nexport const EVENTS_MULTI_TENANT = 'EVENTS_MULTI_TENANT' as const;\n\n/**\n * Injection token for the Redis connection URL used by RedisEventBus.\n * Provided automatically by EventsModule.forRoot({ backend: 'redis' }).\n */\nexport const REDIS_URL = Symbol('REDIS_URL');\n\n/**\n * Injection token for the resolved `EventsModuleOptions` object.\n *\n * Provided automatically by `EventsModule.forRoot(...)` /\n * `EventsModule.forRootAsync(...)`. Backends that need to observe module\n * configuration (e.g. `DrizzleEventBus` reading `opts.pools` for\n * pool-filtered drain) inject via this token.\n *\n * String-valued (not `Symbol`) so it matches by value across import\n * boundaries — same convention as `EVENT_BUS`.\n */\nexport const EVENTS_MODULE_OPTIONS = 'EVENTS_MODULE_OPTIONS' as const;\n","/**\n * Typed errors for the events subsystem (ADR-024, EVT-6).\n *\n * All thrown from the publish path of `TypedEventBus`. They exist as\n * classes so consumers can `instanceof` them in catch blocks and\n * exception filters can map them to HTTP codes.\n */\n\n/**\n * Thrown by `TypedEventBus.publish()` when the EventsModule is configured\n * with `multiTenant: true` and the caller did not supply\n * `opts.metadata.tenantId`. Multi-tenant mode requires every outbox row to\n * be attributable to a tenant — the `domain_events.tenant_id` column is\n * populated from this value and the drain loop uses it for future\n * tenant-scoped filtering (deferred — see ADR-024 §Multi-tenancy).\n *\n * Disable multi-tenancy at the module level (`multiTenant: false`, the\n * default) to opt out of the requirement entirely.\n */\nexport class MissingTenantIdError extends Error {\n override readonly name = 'MissingTenantIdError';\n constructor(public readonly eventType: string) {\n super(\n `Missing tenantId for event '${eventType}'. EventsModule is configured ` +\n `with multiTenant: true — every publish must include ` +\n `opts.metadata.tenantId. Either pass the tenantId or disable ` +\n `multi-tenancy on the module.`,\n );\n }\n}\n","// AUTO-GENERATED by @pattern-stack/codegen. Do not edit.\n// Run `codegen entity new --all` to refresh.\n\n\nimport { z } from 'zod';\nimport type { EventTypeName } from './types';\n\nexport const contactCreatedPayloadSchema = z.object({\n\taccountId: z.string().uuid().nullable(),\n\tcontactId: z.string().uuid(),\n\tcreatedBy: z.string().uuid(),\n}).strict();\n\nexport const contactMarkedChampionPayloadSchema = z.object({\n\tcontactId: z.string().uuid(),\n\topportunityId: z.string().uuid(),\n}).strict();\n\nexport const contactMergedPayloadSchema = z.object({\n\tmergedBy: z.string().uuid(),\n\tsourceId: z.string().uuid(),\n\ttargetId: z.string().uuid(),\n}).strict();\n\nexport const crmSyncStartedPayloadSchema = z.object({\n\trunId: z.string().uuid(),\n\tsource: z.string(),\n}).strict();\n\nexport const dealCreatedPayloadSchema = z.object({\n\taccountId: z.string().uuid(),\n\tdealId: z.string().uuid(),\n\townerId: z.string().uuid(),\n}).strict();\n\nexport const dealStageChangedPayloadSchema = z.object({\n\tdealId: z.string().uuid(),\n\tnewStage: z.string(),\n\toldStage: z.string(),\n}).strict();\n\nexport const stripePaymentReceivedPayloadSchema = z.object({\n\tamountCents: z.number(),\n\tcurrency: z.string(),\n\tcustomerId: z.string(),\n\teventId: z.string(),\n\treceivedAt: z.coerce.date(),\n}).strict();\n\nexport const webhookOutboundContactSyncPayloadSchema = z.object({\n\tcontactId: z.string().uuid(),\n\toccurredAt: z.coerce.date(),\n\toperation: z.string(),\n}).strict();\n\nexport const eventPayloadSchemas = {\n\t'contact_created': contactCreatedPayloadSchema,\n\t'contact_marked_champion': contactMarkedChampionPayloadSchema,\n\t'contact_merged': contactMergedPayloadSchema,\n\t'crm_sync_started': crmSyncStartedPayloadSchema,\n\t'deal_created': dealCreatedPayloadSchema,\n\t'deal_stage_changed': dealStageChangedPayloadSchema,\n\t'stripe_payment_received': stripePaymentReceivedPayloadSchema,\n\t'webhook_outbound_contact_sync': webhookOutboundContactSyncPayloadSchema,\n} as const satisfies Record<EventTypeName, z.ZodType>;\n","// AUTO-GENERATED by @pattern-stack/codegen. Do not edit.\n// Run `codegen entity new --all` to refresh.\n\n\nimport type { EventTypeName } from './types';\n\nexport interface EventMetadata {\n\ttype: EventTypeName;\n\ttier: 'domain' | 'audit';\n\tdirection: 'inbound' | 'change' | 'outbound' | null;\n\tpool: 'events_inbound' | 'events_change' | 'events_outbound' | null;\n\taggregate?: string;\n\tsource?: string;\n\tdestination?: string;\n\tversion: number;\n\tretry: { attempts: number; backoff: 'linear' | 'exponential' };\n}\n\nexport const eventRegistry = {\n\t'contact_created': {\n\t\ttype: 'contact_created',\n\t\ttier: 'domain',\n\t\tdirection: 'change',\n\t\tpool: 'events_change',\n\t\taggregate: 'contact',\n\t\tversion: 1,\n\t\tretry: { attempts: 3, backoff: 'exponential' },\n\t},\n\t'contact_marked_champion': {\n\t\ttype: 'contact_marked_champion',\n\t\ttier: 'domain',\n\t\tdirection: 'change',\n\t\tpool: 'events_change',\n\t\taggregate: 'contact',\n\t\tversion: 1,\n\t\tretry: { attempts: 3, backoff: 'exponential' },\n\t},\n\t'contact_merged': {\n\t\ttype: 'contact_merged',\n\t\ttier: 'domain',\n\t\tdirection: 'change',\n\t\tpool: 'events_change',\n\t\taggregate: 'contact',\n\t\tversion: 1,\n\t\tretry: { attempts: 3, backoff: 'exponential' },\n\t},\n\t'crm_sync_started': {\n\t\ttype: 'crm_sync_started',\n\t\ttier: 'audit',\n\t\tdirection: null,\n\t\tpool: null,\n\t\tversion: 1,\n\t\tretry: { attempts: 3, backoff: 'exponential' },\n\t},\n\t'deal_created': {\n\t\ttype: 'deal_created',\n\t\ttier: 'domain',\n\t\tdirection: 'change',\n\t\tpool: 'events_change',\n\t\taggregate: 'deal',\n\t\tversion: 1,\n\t\tretry: { attempts: 3, backoff: 'exponential' },\n\t},\n\t'deal_stage_changed': {\n\t\ttype: 'deal_stage_changed',\n\t\ttier: 'domain',\n\t\tdirection: 'change',\n\t\tpool: 'events_change',\n\t\taggregate: 'deal',\n\t\tversion: 1,\n\t\tretry: { attempts: 3, backoff: 'exponential' },\n\t},\n\t'stripe_payment_received': {\n\t\ttype: 'stripe_payment_received',\n\t\ttier: 'domain',\n\t\tdirection: 'inbound',\n\t\tpool: 'events_inbound',\n\t\tsource: 'stripe',\n\t\tversion: 1,\n\t\tretry: { attempts: 5, backoff: 'exponential' },\n\t},\n\t'webhook_outbound_contact_sync': {\n\t\ttype: 'webhook_outbound_contact_sync',\n\t\ttier: 'domain',\n\t\tdirection: 'outbound',\n\t\tpool: 'events_outbound',\n\t\taggregate: 'contact',\n\t\tdestination: 'crm',\n\t\tversion: 1,\n\t\tretry: { attempts: 3, backoff: 'exponential' },\n\t},\n} as const satisfies Record<EventTypeName, EventMetadata>;\n\nexport function getEventMetadata<T extends EventTypeName>(type: T): EventMetadata {\n\tconst meta = eventRegistry[type];\n\tif (!meta) {\n\t\tthrow new Error(`No registry entry for event type '${String(type)}' — declare events under events/*.yaml and re-run \\`codegen entity new --all\\`.`);\n\t}\n\treturn meta;\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../../../runtime/subsystems/events/generated/bus.ts","../../../../../runtime/subsystems/events/events.tokens.ts","../../../../../runtime/subsystems/events/events-errors.ts","../../../../../runtime/subsystems/events/generated/schemas.ts","../../../../../runtime/subsystems/events/generated/registry.ts"],"sourcesContent":["// AUTO-GENERATED by @pattern-stack/codegen. Do not edit.\n// Run `codegen entity new --all` to refresh.\n\nimport { Injectable, Inject } from '@nestjs/common';\nimport { randomUUID } from 'crypto';\nimport { EVENT_BUS, EVENTS_MULTI_TENANT } from '../events.tokens';\nimport { MissingTenantIdError } from '../events-errors';\nimport type { IEventBus, DrizzleTransaction } from '../event-bus.protocol';\nimport { eventPayloadSchemas } from './schemas';\nimport { getEventMetadata } from './registry';\nimport type { EventTypeName, EventOfType, PayloadOfType } from './types';\n\n/**\n * Typed facade over IEventBus.\n *\n * Stamps `pool`, `direction`, `tier`, and `version` into `event.metadata`\n * from the generated `eventRegistry` before delegating to\n * `IEventBus.publish()`. Downstream backends (DrizzleEventBus) read those\n * values to populate the explicit `domain_events` columns.\n *\n * Tier stamping (AUDIT-3): every event carries `metadata.tier`, sourced\n * from the registry. For `tier: 'audit'` events, the bus FORCES\n * `metadata.pool = null` and `metadata.direction = null` regardless of\n * any caller-supplied values in `opts.metadata` — audit routing is\n * bus-stamped, not caller-controlled. Caller overrides are silently\n * dropped with a debug-level log (callers should not be specifying these\n * for audit events; see ai-docs/specs/issue-242/plan.md §AUDIT-3).\n *\n * Validation gating (EVT-Q5): `CODEGEN_EVENT_VALIDATE` env flag, default on.\n * Uses `safeParse` + `console.warn` — never throws, so a bad publish does\n * not crash a hot path.\n *\n * Multi-tenancy (EVT-6): when the EventsModule is configured with\n * `multiTenant: true`, every publish must supply `opts.metadata.tenantId`\n * — otherwise `publish()` throws `MissingTenantIdError`. When `multiTenant`\n * is `false` (default), no tenantId is required. If a tenantId IS supplied,\n * it is preserved on `event.metadata` and the Drizzle backend writes it to\n * `domain_events.tenant_id` (EVT-4).\n */\n@Injectable()\nexport class TypedEventBus {\n\tconstructor(\n\t\t@Inject(EVENT_BUS) private readonly bus: IEventBus,\n\t\t@Inject(EVENTS_MULTI_TENANT) private readonly multiTenant: boolean,\n\t) {}\n\n\tasync publish<T extends EventTypeName>(\n\t\ttype: T,\n\t\taggregateId: string,\n\t\tpayload: PayloadOfType<T>,\n\t\topts?: { tx?: DrizzleTransaction; metadata?: Record<string, unknown> },\n\t): Promise<void> {\n\t\tconst meta = getEventMetadata(type);\n\n\t\tconst flag = process.env['CODEGEN_EVENT_VALIDATE'];\n\t\tconst shouldValidate =\n\t\t\tflag === undefined ? true : flag !== 'false' && flag !== '0';\n\t\tif (shouldValidate) {\n\t\t\t// `eventPayloadSchemas` is typed as `Record<EventTypeName, z.ZodType>`,\n\t\t\t// so under `noUncheckedIndexedAccess` the indexed lookup widens\n\t\t\t// to `z.ZodType | undefined`. When no events are registered at\n\t\t\t// codegen time `EventTypeName` degrades to `string` and the\n\t\t\t// schemas object is literally `{}` — the guard below is the\n\t\t\t// honest handling of that empty-registry case (skip validation;\n\t\t\t// it's a warn-only best-effort check per the class docblock).\n\t\t\tconst schema = eventPayloadSchemas[type];\n\t\t\tif (schema) {\n\t\t\t\tconst check = schema.safeParse(payload);\n\t\t\t\tif (!check.success) {\n\t\t\t\t\tconsole.warn(\n\t\t\t\t\t\t`[TypedEventBus] payload validation failed for ${String(type)}:`,\n\t\t\t\t\t\tcheck.error.issues,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tconst tenantId = opts?.metadata?.['tenantId'];\n\t\tif (this.multiTenant && (tenantId === undefined || tenantId === null)) {\n\t\t\tthrow new MissingTenantIdError(type as string);\n\t\t}\n\n\t\tconst aggregateType =\n\t\t\tmeta.aggregate ?? meta.source ?? meta.destination ?? (type as string);\n\n\t\t// AUDIT-3: build metadata with tier-aware routing stamping. For\n\t\t// `tier: 'audit'` events the bus FORCES pool/direction to null,\n\t\t// even if the caller supplied them in opts.metadata. Audit routing\n\t\t// is bus-stamped, not caller-controlled (see plan §AUDIT-3).\n\t\tconst baseMetadata: Record<string, unknown> = { ...(opts?.metadata ?? {}) };\n\t\tif (meta.tier === 'audit') {\n\t\t\tif (\n\t\t\t\tbaseMetadata['pool'] !== undefined ||\n\t\t\t\tbaseMetadata['direction'] !== undefined\n\t\t\t) {\n\t\t\t\tconsole.debug(\n\t\t\t\t\t`[TypedEventBus] tier:audit event '${String(type)}' had pool/direction in opts.metadata; overriding to null.`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tbaseMetadata['pool'] = null;\n\t\t\tbaseMetadata['direction'] = null;\n\t\t\tbaseMetadata['tier'] = 'audit';\n\t\t} else {\n\t\t\tbaseMetadata['pool'] = meta.pool;\n\t\t\tbaseMetadata['direction'] = meta.direction;\n\t\t\tbaseMetadata['tier'] = 'domain';\n\t\t}\n\t\tbaseMetadata['version'] = meta.version;\n\n\t\tawait this.bus.publish(\n\t\t\t{\n\t\t\t\tid: randomUUID(),\n\t\t\t\ttype,\n\t\t\t\taggregateId,\n\t\t\t\taggregateType,\n\t\t\t\tpayload: payload as Record<string, unknown>,\n\t\t\t\toccurredAt: new Date(),\n\t\t\t\tmetadata: baseMetadata,\n\t\t\t},\n\t\t\topts?.tx,\n\t\t);\n\t}\n\n\tsubscribe<T extends EventTypeName>(\n\t\ttype: T,\n\t\thandler: (event: EventOfType<T>) => Promise<void>,\n\t): () => void {\n\t\treturn this.bus.subscribe<EventOfType<T>>(type, handler as never);\n\t}\n}\n","/**\n * Injection token for the event bus.\n *\n * String constant (not Symbol) so it matches by value across import boundaries.\n * Matches the token in runtime/constants/tokens.ts — both are 'EVENT_BUS'.\n *\n * Usage in use cases:\n * ```typescript\n * constructor(@Inject(EVENT_BUS) private readonly eventBus: IEventBus) {}\n * ```\n */\nexport const EVENT_BUS = 'EVENT_BUS' as const;\n\n/**\n * Injection token for the read-side `IEventReadPort` over `domain_events`\n * (OBS-LIST-1).\n *\n * Bound by `EventsModule.forRoot` to the same backend instance as\n * `EVENT_BUS` for the `drizzle` and `memory` backends (both implement\n * `IEventReadPort`). The `redis` backend retains no history and therefore\n * does NOT provide this token — consumers composing it (e.g. the\n * observability combiner) inject it `@Optional()` and degrade to empty\n * results.\n *\n * String constant (not Symbol) so it matches by value across import\n * boundaries — same convention as `EVENT_BUS`.\n */\nexport const EVENT_READ_PORT = 'EVENT_READ_PORT' as const;\n\n/**\n * Injection token for the generated `TypedEventBus` facade.\n *\n * `TypedEventBus` lives in `runtime/subsystems/events/generated/bus.ts` and\n * wraps `IEventBus` with project-specific `AppDomainEvent`-typed `publish<T>()`\n * and `subscribe<T>()`. Use cases inject this token in preference to\n * `EVENT_BUS` when they want compile-time type safety on event shapes.\n *\n * String constant (not Symbol) so it matches by value across import\n * boundaries — same convention as `EVENT_BUS`.\n *\n * Provider registration lands in EVT-6 (EventsModule wiring); the token is\n * declared here so generated code can import it without depending on the\n * still-being-formalised module.\n */\nexport const TYPED_EVENT_BUS = 'TYPED_EVENT_BUS' as const;\n\n/**\n * Injection token for the resolved multi-tenancy flag.\n *\n * Provided by `EventsModule.forRoot(...)` as `options.multiTenant ?? false`.\n * Consumed by `TypedEventBus` to enforce the tenantId-is-required rule at\n * publish time.\n *\n * String constant (not Symbol) so it matches by value across import\n * boundaries — same convention as the other events tokens. (The jobs\n * subsystem uses Symbols for the analogous token; events chose strings\n * from the start and we keep the file internally consistent.)\n */\nexport const EVENTS_MULTI_TENANT = 'EVENTS_MULTI_TENANT' as const;\n\n/**\n * Injection token for the Redis connection URL used by RedisEventBus.\n * Provided automatically by EventsModule.forRoot({ backend: 'redis' }).\n */\nexport const REDIS_URL = Symbol('REDIS_URL');\n\n/**\n * Injection token for the resolved `EventsModuleOptions` object.\n *\n * Provided automatically by `EventsModule.forRoot(...)` /\n * `EventsModule.forRootAsync(...)`. Backends that need to observe module\n * configuration (e.g. `DrizzleEventBus` reading `opts.pools` for\n * pool-filtered drain) inject via this token.\n *\n * String-valued (not `Symbol`) so it matches by value across import\n * boundaries — same convention as `EVENT_BUS`.\n */\nexport const EVENTS_MODULE_OPTIONS = 'EVENTS_MODULE_OPTIONS' as const;\n","/**\n * Typed errors for the events subsystem (ADR-024, EVT-6).\n *\n * All thrown from the publish path of `TypedEventBus`. They exist as\n * classes so consumers can `instanceof` them in catch blocks and\n * exception filters can map them to HTTP codes.\n */\n\n/**\n * Thrown by `TypedEventBus.publish()` when the EventsModule is configured\n * with `multiTenant: true` and the caller did not supply\n * `opts.metadata.tenantId`. Multi-tenant mode requires every outbox row to\n * be attributable to a tenant — the `domain_events.tenant_id` column is\n * populated from this value and the drain loop uses it for future\n * tenant-scoped filtering (deferred — see ADR-024 §Multi-tenancy).\n *\n * Disable multi-tenancy at the module level (`multiTenant: false`, the\n * default) to opt out of the requirement entirely.\n */\nexport class MissingTenantIdError extends Error {\n override readonly name = 'MissingTenantIdError';\n constructor(public readonly eventType: string) {\n super(\n `Missing tenantId for event '${eventType}'. EventsModule is configured ` +\n `with multiTenant: true — every publish must include ` +\n `opts.metadata.tenantId. Either pass the tenantId or disable ` +\n `multi-tenancy on the module.`,\n );\n }\n}\n","// AUTO-GENERATED by @pattern-stack/codegen. Do not edit.\n// Run `codegen entity new --all` to refresh.\n\n\nimport { z } from 'zod';\nimport type { EventTypeName } from './types';\n\nexport const contactCreatedPayloadSchema = z.object({\n\taccountId: z.string().uuid().nullable(),\n\tcontactId: z.string().uuid(),\n\tcreatedBy: z.string().uuid(),\n}).strict();\n\nexport const contactMarkedChampionPayloadSchema = z.object({\n\tcontactId: z.string().uuid(),\n\topportunityId: z.string().uuid(),\n}).strict();\n\nexport const contactMergedPayloadSchema = z.object({\n\tmergedBy: z.string().uuid(),\n\tsourceId: z.string().uuid(),\n\ttargetId: z.string().uuid(),\n}).strict();\n\nexport const crmSyncStartedPayloadSchema = z.object({\n\trunId: z.string().uuid(),\n\tsource: z.string(),\n}).strict();\n\nexport const dealCreatedPayloadSchema = z.object({\n\taccountId: z.string().uuid(),\n\tdealId: z.string().uuid(),\n\townerId: z.string().uuid(),\n}).strict();\n\nexport const dealStageChangedPayloadSchema = z.object({\n\tdealId: z.string().uuid(),\n\tnewStage: z.string(),\n\toldStage: z.string(),\n}).strict();\n\nexport const stripePaymentReceivedPayloadSchema = z.object({\n\tamountCents: z.number(),\n\tcurrency: z.string(),\n\tcustomerId: z.string(),\n\teventId: z.string(),\n\treceivedAt: z.coerce.date(),\n}).strict();\n\nexport const webhookOutboundContactSyncPayloadSchema = z.object({\n\tcontactId: z.string().uuid(),\n\toccurredAt: z.coerce.date(),\n\toperation: z.string(),\n}).strict();\n\nexport const eventPayloadSchemas = {\n\t'contact_created': contactCreatedPayloadSchema,\n\t'contact_marked_champion': contactMarkedChampionPayloadSchema,\n\t'contact_merged': contactMergedPayloadSchema,\n\t'crm_sync_started': crmSyncStartedPayloadSchema,\n\t'deal_created': dealCreatedPayloadSchema,\n\t'deal_stage_changed': dealStageChangedPayloadSchema,\n\t'stripe_payment_received': stripePaymentReceivedPayloadSchema,\n\t'webhook_outbound_contact_sync': webhookOutboundContactSyncPayloadSchema,\n} as const satisfies Record<EventTypeName, z.ZodType>;\n","// AUTO-GENERATED by @pattern-stack/codegen. Do not edit.\n// Run `codegen entity new --all` to refresh.\n\n\nimport type { EventTypeName } from './types';\n\nexport interface EventMetadata {\n\ttype: EventTypeName;\n\ttier: 'domain' | 'audit';\n\tdirection: 'inbound' | 'change' | 'outbound' | null;\n\tpool: 'events_inbound' | 'events_change' | 'events_outbound' | null;\n\taggregate?: string;\n\tsource?: string;\n\tdestination?: string;\n\tversion: number;\n\tretry: { attempts: number; backoff: 'linear' | 'exponential' };\n}\n\nexport const eventRegistry = {\n\t'contact_created': {\n\t\ttype: 'contact_created',\n\t\ttier: 'domain',\n\t\tdirection: 'change',\n\t\tpool: 'events_change',\n\t\taggregate: 'contact',\n\t\tversion: 1,\n\t\tretry: { attempts: 3, backoff: 'exponential' },\n\t},\n\t'contact_marked_champion': {\n\t\ttype: 'contact_marked_champion',\n\t\ttier: 'domain',\n\t\tdirection: 'change',\n\t\tpool: 'events_change',\n\t\taggregate: 'contact',\n\t\tversion: 1,\n\t\tretry: { attempts: 3, backoff: 'exponential' },\n\t},\n\t'contact_merged': {\n\t\ttype: 'contact_merged',\n\t\ttier: 'domain',\n\t\tdirection: 'change',\n\t\tpool: 'events_change',\n\t\taggregate: 'contact',\n\t\tversion: 1,\n\t\tretry: { attempts: 3, backoff: 'exponential' },\n\t},\n\t'crm_sync_started': {\n\t\ttype: 'crm_sync_started',\n\t\ttier: 'audit',\n\t\tdirection: null,\n\t\tpool: null,\n\t\tversion: 1,\n\t\tretry: { attempts: 3, backoff: 'exponential' },\n\t},\n\t'deal_created': {\n\t\ttype: 'deal_created',\n\t\ttier: 'domain',\n\t\tdirection: 'change',\n\t\tpool: 'events_change',\n\t\taggregate: 'deal',\n\t\tversion: 1,\n\t\tretry: { attempts: 3, backoff: 'exponential' },\n\t},\n\t'deal_stage_changed': {\n\t\ttype: 'deal_stage_changed',\n\t\ttier: 'domain',\n\t\tdirection: 'change',\n\t\tpool: 'events_change',\n\t\taggregate: 'deal',\n\t\tversion: 1,\n\t\tretry: { attempts: 3, backoff: 'exponential' },\n\t},\n\t'stripe_payment_received': {\n\t\ttype: 'stripe_payment_received',\n\t\ttier: 'domain',\n\t\tdirection: 'inbound',\n\t\tpool: 'events_inbound',\n\t\tsource: 'stripe',\n\t\tversion: 1,\n\t\tretry: { attempts: 5, backoff: 'exponential' },\n\t},\n\t'webhook_outbound_contact_sync': {\n\t\ttype: 'webhook_outbound_contact_sync',\n\t\ttier: 'domain',\n\t\tdirection: 'outbound',\n\t\tpool: 'events_outbound',\n\t\taggregate: 'contact',\n\t\tdestination: 'crm',\n\t\tversion: 1,\n\t\tretry: { attempts: 3, backoff: 'exponential' },\n\t},\n} as const satisfies Record<EventTypeName, EventMetadata>;\n\nexport function getEventMetadata<T extends EventTypeName>(type: T): EventMetadata {\n\tconst meta = eventRegistry[type];\n\tif (!meta) {\n\t\tthrow new Error(`No registry entry for event type '${String(type)}' — declare events under events/*.yaml and re-run \\`codegen entity new --all\\`.`);\n\t}\n\treturn meta;\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../runtime/subsystems/events/generated/schemas.ts","../../../../../runtime/subsystems/events/generated/registry.ts","../../../../../runtime/subsystems/events/generated/bus.ts","../../../../../runtime/subsystems/events/events.tokens.ts","../../../../../runtime/subsystems/events/events-errors.ts"],"sourcesContent":["// AUTO-GENERATED by @pattern-stack/codegen. Do not edit.\n// Run `codegen entity new --all` to refresh.\n\n\nimport { z } from 'zod';\nimport type { EventTypeName } from './types';\n\nexport const contactCreatedPayloadSchema = z.object({\n\taccountId: z.string().uuid().nullable(),\n\tcontactId: z.string().uuid(),\n\tcreatedBy: z.string().uuid(),\n}).strict();\n\nexport const contactMarkedChampionPayloadSchema = z.object({\n\tcontactId: z.string().uuid(),\n\topportunityId: z.string().uuid(),\n}).strict();\n\nexport const contactMergedPayloadSchema = z.object({\n\tmergedBy: z.string().uuid(),\n\tsourceId: z.string().uuid(),\n\ttargetId: z.string().uuid(),\n}).strict();\n\nexport const crmSyncStartedPayloadSchema = z.object({\n\trunId: z.string().uuid(),\n\tsource: z.string(),\n}).strict();\n\nexport const dealCreatedPayloadSchema = z.object({\n\taccountId: z.string().uuid(),\n\tdealId: z.string().uuid(),\n\townerId: z.string().uuid(),\n}).strict();\n\nexport const dealStageChangedPayloadSchema = z.object({\n\tdealId: z.string().uuid(),\n\tnewStage: z.string(),\n\toldStage: z.string(),\n}).strict();\n\nexport const stripePaymentReceivedPayloadSchema = z.object({\n\tamountCents: z.number(),\n\tcurrency: z.string(),\n\tcustomerId: z.string(),\n\teventId: z.string(),\n\treceivedAt: z.coerce.date(),\n}).strict();\n\nexport const webhookOutboundContactSyncPayloadSchema = z.object({\n\tcontactId: z.string().uuid(),\n\toccurredAt: z.coerce.date(),\n\toperation: z.string(),\n}).strict();\n\nexport const eventPayloadSchemas = {\n\t'contact_created': contactCreatedPayloadSchema,\n\t'contact_marked_champion': contactMarkedChampionPayloadSchema,\n\t'contact_merged': contactMergedPayloadSchema,\n\t'crm_sync_started': crmSyncStartedPayloadSchema,\n\t'deal_created': dealCreatedPayloadSchema,\n\t'deal_stage_changed': dealStageChangedPayloadSchema,\n\t'stripe_payment_received': stripePaymentReceivedPayloadSchema,\n\t'webhook_outbound_contact_sync': webhookOutboundContactSyncPayloadSchema,\n} as const satisfies Record<EventTypeName, z.ZodType>;\n","// AUTO-GENERATED by @pattern-stack/codegen. Do not edit.\n// Run `codegen entity new --all` to refresh.\n\n\nimport type { EventTypeName } from './types';\n\nexport interface EventMetadata {\n\ttype: EventTypeName;\n\ttier: 'domain' | 'audit';\n\tdirection: 'inbound' | 'change' | 'outbound' | null;\n\tpool: 'events_inbound' | 'events_change' | 'events_outbound' | null;\n\taggregate?: string;\n\tsource?: string;\n\tdestination?: string;\n\tversion: number;\n\tretry: { attempts: number; backoff: 'linear' | 'exponential' };\n}\n\nexport const eventRegistry = {\n\t'contact_created': {\n\t\ttype: 'contact_created',\n\t\ttier: 'domain',\n\t\tdirection: 'change',\n\t\tpool: 'events_change',\n\t\taggregate: 'contact',\n\t\tversion: 1,\n\t\tretry: { attempts: 3, backoff: 'exponential' },\n\t},\n\t'contact_marked_champion': {\n\t\ttype: 'contact_marked_champion',\n\t\ttier: 'domain',\n\t\tdirection: 'change',\n\t\tpool: 'events_change',\n\t\taggregate: 'contact',\n\t\tversion: 1,\n\t\tretry: { attempts: 3, backoff: 'exponential' },\n\t},\n\t'contact_merged': {\n\t\ttype: 'contact_merged',\n\t\ttier: 'domain',\n\t\tdirection: 'change',\n\t\tpool: 'events_change',\n\t\taggregate: 'contact',\n\t\tversion: 1,\n\t\tretry: { attempts: 3, backoff: 'exponential' },\n\t},\n\t'crm_sync_started': {\n\t\ttype: 'crm_sync_started',\n\t\ttier: 'audit',\n\t\tdirection: null,\n\t\tpool: null,\n\t\tversion: 1,\n\t\tretry: { attempts: 3, backoff: 'exponential' },\n\t},\n\t'deal_created': {\n\t\ttype: 'deal_created',\n\t\ttier: 'domain',\n\t\tdirection: 'change',\n\t\tpool: 'events_change',\n\t\taggregate: 'deal',\n\t\tversion: 1,\n\t\tretry: { attempts: 3, backoff: 'exponential' },\n\t},\n\t'deal_stage_changed': {\n\t\ttype: 'deal_stage_changed',\n\t\ttier: 'domain',\n\t\tdirection: 'change',\n\t\tpool: 'events_change',\n\t\taggregate: 'deal',\n\t\tversion: 1,\n\t\tretry: { attempts: 3, backoff: 'exponential' },\n\t},\n\t'stripe_payment_received': {\n\t\ttype: 'stripe_payment_received',\n\t\ttier: 'domain',\n\t\tdirection: 'inbound',\n\t\tpool: 'events_inbound',\n\t\tsource: 'stripe',\n\t\tversion: 1,\n\t\tretry: { attempts: 5, backoff: 'exponential' },\n\t},\n\t'webhook_outbound_contact_sync': {\n\t\ttype: 'webhook_outbound_contact_sync',\n\t\ttier: 'domain',\n\t\tdirection: 'outbound',\n\t\tpool: 'events_outbound',\n\t\taggregate: 'contact',\n\t\tdestination: 'crm',\n\t\tversion: 1,\n\t\tretry: { attempts: 3, backoff: 'exponential' },\n\t},\n} as const satisfies Record<EventTypeName, EventMetadata>;\n\nexport function getEventMetadata<T extends EventTypeName>(type: T): EventMetadata {\n\tconst meta = eventRegistry[type];\n\tif (!meta) {\n\t\tthrow new Error(`No registry entry for event type '${String(type)}' — declare events under events/*.yaml and re-run \\`codegen entity new --all\\`.`);\n\t}\n\treturn meta;\n}\n","// AUTO-GENERATED by @pattern-stack/codegen. Do not edit.\n// Run `codegen entity new --all` to refresh.\n\nimport { Injectable, Inject } from '@nestjs/common';\nimport { randomUUID } from 'crypto';\nimport { EVENT_BUS, EVENTS_MULTI_TENANT } from '../events.tokens';\nimport { MissingTenantIdError } from '../events-errors';\nimport type { IEventBus, DrizzleTransaction } from '../event-bus.protocol';\nimport { eventPayloadSchemas } from './schemas';\nimport { getEventMetadata } from './registry';\nimport type { EventTypeName, EventOfType, PayloadOfType } from './types';\n\n/**\n * Typed facade over IEventBus.\n *\n * Stamps `pool`, `direction`, `tier`, and `version` into `event.metadata`\n * from the generated `eventRegistry` before delegating to\n * `IEventBus.publish()`. Downstream backends (DrizzleEventBus) read those\n * values to populate the explicit `domain_events` columns.\n *\n * Tier stamping (AUDIT-3): every event carries `metadata.tier`, sourced\n * from the registry. For `tier: 'audit'` events, the bus FORCES\n * `metadata.pool = null` and `metadata.direction = null` regardless of\n * any caller-supplied values in `opts.metadata` — audit routing is\n * bus-stamped, not caller-controlled. Caller overrides are silently\n * dropped with a debug-level log (callers should not be specifying these\n * for audit events; see ai-docs/specs/issue-242/plan.md §AUDIT-3).\n *\n * Validation gating (EVT-Q5): `CODEGEN_EVENT_VALIDATE` env flag, default on.\n * Uses `safeParse` + `console.warn` — never throws, so a bad publish does\n * not crash a hot path.\n *\n * Multi-tenancy (EVT-6): when the EventsModule is configured with\n * `multiTenant: true`, every publish must supply `opts.metadata.tenantId`\n * — otherwise `publish()` throws `MissingTenantIdError`. When `multiTenant`\n * is `false` (default), no tenantId is required. If a tenantId IS supplied,\n * it is preserved on `event.metadata` and the Drizzle backend writes it to\n * `domain_events.tenant_id` (EVT-4).\n */\n@Injectable()\nexport class TypedEventBus {\n\tconstructor(\n\t\t@Inject(EVENT_BUS) private readonly bus: IEventBus,\n\t\t@Inject(EVENTS_MULTI_TENANT) private readonly multiTenant: boolean,\n\t) {}\n\n\tasync publish<T extends EventTypeName>(\n\t\ttype: T,\n\t\taggregateId: string,\n\t\tpayload: PayloadOfType<T>,\n\t\topts?: { tx?: DrizzleTransaction; metadata?: Record<string, unknown> },\n\t): Promise<void> {\n\t\tconst meta = getEventMetadata(type);\n\n\t\tconst flag = process.env['CODEGEN_EVENT_VALIDATE'];\n\t\tconst shouldValidate =\n\t\t\tflag === undefined ? true : flag !== 'false' && flag !== '0';\n\t\tif (shouldValidate) {\n\t\t\t// `eventPayloadSchemas` is typed as `Record<EventTypeName, z.ZodType>`,\n\t\t\t// so under `noUncheckedIndexedAccess` the indexed lookup widens\n\t\t\t// to `z.ZodType | undefined`. When no events are registered at\n\t\t\t// codegen time `EventTypeName` degrades to `string` and the\n\t\t\t// schemas object is literally `{}` — the guard below is the\n\t\t\t// honest handling of that empty-registry case (skip validation;\n\t\t\t// it's a warn-only best-effort check per the class docblock).\n\t\t\tconst schema = eventPayloadSchemas[type];\n\t\t\tif (schema) {\n\t\t\t\tconst check = schema.safeParse(payload);\n\t\t\t\tif (!check.success) {\n\t\t\t\t\tconsole.warn(\n\t\t\t\t\t\t`[TypedEventBus] payload validation failed for ${String(type)}:`,\n\t\t\t\t\t\tcheck.error.issues,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tconst tenantId = opts?.metadata?.['tenantId'];\n\t\tif (this.multiTenant && (tenantId === undefined || tenantId === null)) {\n\t\t\tthrow new MissingTenantIdError(type as string);\n\t\t}\n\n\t\tconst aggregateType =\n\t\t\tmeta.aggregate ?? meta.source ?? meta.destination ?? (type as string);\n\n\t\t// AUDIT-3: build metadata with tier-aware routing stamping. For\n\t\t// `tier: 'audit'` events the bus FORCES pool/direction to null,\n\t\t// even if the caller supplied them in opts.metadata. Audit routing\n\t\t// is bus-stamped, not caller-controlled (see plan §AUDIT-3).\n\t\tconst baseMetadata: Record<string, unknown> = { ...(opts?.metadata ?? {}) };\n\t\tif (meta.tier === 'audit') {\n\t\t\tif (\n\t\t\t\tbaseMetadata['pool'] !== undefined ||\n\t\t\t\tbaseMetadata['direction'] !== undefined\n\t\t\t) {\n\t\t\t\tconsole.debug(\n\t\t\t\t\t`[TypedEventBus] tier:audit event '${String(type)}' had pool/direction in opts.metadata; overriding to null.`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tbaseMetadata['pool'] = null;\n\t\t\tbaseMetadata['direction'] = null;\n\t\t\tbaseMetadata['tier'] = 'audit';\n\t\t} else {\n\t\t\tbaseMetadata['pool'] = meta.pool;\n\t\t\tbaseMetadata['direction'] = meta.direction;\n\t\t\tbaseMetadata['tier'] = 'domain';\n\t\t}\n\t\tbaseMetadata['version'] = meta.version;\n\n\t\tawait this.bus.publish(\n\t\t\t{\n\t\t\t\tid: randomUUID(),\n\t\t\t\ttype,\n\t\t\t\taggregateId,\n\t\t\t\taggregateType,\n\t\t\t\tpayload: payload as Record<string, unknown>,\n\t\t\t\toccurredAt: new Date(),\n\t\t\t\tmetadata: baseMetadata,\n\t\t\t},\n\t\t\topts?.tx,\n\t\t);\n\t}\n\n\tsubscribe<T extends EventTypeName>(\n\t\ttype: T,\n\t\thandler: (event: EventOfType<T>) => Promise<void>,\n\t): () => void {\n\t\treturn this.bus.subscribe<EventOfType<T>>(type, handler as never);\n\t}\n}\n","/**\n * Injection token for the event bus.\n *\n * String constant (not Symbol) so it matches by value across import boundaries.\n * Matches the token in runtime/constants/tokens.ts — both are 'EVENT_BUS'.\n *\n * Usage in use cases:\n * ```typescript\n * constructor(@Inject(EVENT_BUS) private readonly eventBus: IEventBus) {}\n * ```\n */\nexport const EVENT_BUS = 'EVENT_BUS' as const;\n\n/**\n * Injection token for the generated `TypedEventBus` facade.\n *\n * `TypedEventBus` lives in `runtime/subsystems/events/generated/bus.ts` and\n * wraps `IEventBus` with project-specific `AppDomainEvent`-typed `publish<T>()`\n * and `subscribe<T>()`. Use cases inject this token in preference to\n * `EVENT_BUS` when they want compile-time type safety on event shapes.\n *\n * String constant (not Symbol) so it matches by value across import\n * boundaries — same convention as `EVENT_BUS`.\n *\n * Provider registration lands in EVT-6 (EventsModule wiring); the token is\n * declared here so generated code can import it without depending on the\n * still-being-formalised module.\n */\nexport const TYPED_EVENT_BUS = 'TYPED_EVENT_BUS' as const;\n\n/**\n * Injection token for the resolved multi-tenancy flag.\n *\n * Provided by `EventsModule.forRoot(...)` as `options.multiTenant ?? false`.\n * Consumed by `TypedEventBus` to enforce the tenantId-is-required rule at\n * publish time.\n *\n * String constant (not Symbol) so it matches by value across import\n * boundaries — same convention as the other events tokens. (The jobs\n * subsystem uses Symbols for the analogous token; events chose strings\n * from the start and we keep the file internally consistent.)\n */\nexport const EVENTS_MULTI_TENANT = 'EVENTS_MULTI_TENANT' as const;\n\n/**\n * Injection token for the Redis connection URL used by RedisEventBus.\n * Provided automatically by EventsModule.forRoot({ backend: 'redis' }).\n */\nexport const REDIS_URL = Symbol('REDIS_URL');\n\n/**\n * Injection token for the resolved `EventsModuleOptions` object.\n *\n * Provided automatically by `EventsModule.forRoot(...)` /\n * `EventsModule.forRootAsync(...)`. Backends that need to observe module\n * configuration (e.g. `DrizzleEventBus` reading `opts.pools` for\n * pool-filtered drain) inject via this token.\n *\n * String-valued (not `Symbol`) so it matches by value across import\n * boundaries — same convention as `EVENT_BUS`.\n */\nexport const EVENTS_MODULE_OPTIONS = 'EVENTS_MODULE_OPTIONS' as const;\n","/**\n * Typed errors for the events subsystem (ADR-024, EVT-6).\n *\n * All thrown from the publish path of `TypedEventBus`. They exist as\n * classes so consumers can `instanceof` them in catch blocks and\n * exception filters can map them to HTTP codes.\n */\n\n/**\n * Thrown by `TypedEventBus.publish()` when the EventsModule is configured\n * with `multiTenant: true` and the caller did not supply\n * `opts.metadata.tenantId`. Multi-tenant mode requires every outbox row to\n * be attributable to a tenant — the `domain_events.tenant_id` column is\n * populated from this value and the drain loop uses it for future\n * tenant-scoped filtering (deferred — see ADR-024 §Multi-tenancy).\n *\n * Disable multi-tenancy at the module level (`multiTenant: false`, the\n * default) to opt out of the requirement entirely.\n */\nexport class MissingTenantIdError extends Error {\n override readonly name = 'MissingTenantIdError';\n constructor(public readonly eventType: string) {\n super(\n `Missing tenantId for event '${eventType}'. EventsModule is configured ` +\n `with multiTenant: true — every publish must include ` +\n `opts.metadata.tenantId. Either pass the tenantId or disable ` +\n `multi-tenancy on the module.`,\n );\n }\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../../../runtime/subsystems/events/generated/schemas.ts","../../../../../runtime/subsystems/events/generated/registry.ts","../../../../../runtime/subsystems/events/generated/bus.ts","../../../../../runtime/subsystems/events/events.tokens.ts","../../../../../runtime/subsystems/events/events-errors.ts"],"sourcesContent":["// AUTO-GENERATED by @pattern-stack/codegen. Do not edit.\n// Run `codegen entity new --all` to refresh.\n\n\nimport { z } from 'zod';\nimport type { EventTypeName } from './types';\n\nexport const contactCreatedPayloadSchema = z.object({\n\taccountId: z.string().uuid().nullable(),\n\tcontactId: z.string().uuid(),\n\tcreatedBy: z.string().uuid(),\n}).strict();\n\nexport const contactMarkedChampionPayloadSchema = z.object({\n\tcontactId: z.string().uuid(),\n\topportunityId: z.string().uuid(),\n}).strict();\n\nexport const contactMergedPayloadSchema = z.object({\n\tmergedBy: z.string().uuid(),\n\tsourceId: z.string().uuid(),\n\ttargetId: z.string().uuid(),\n}).strict();\n\nexport const crmSyncStartedPayloadSchema = z.object({\n\trunId: z.string().uuid(),\n\tsource: z.string(),\n}).strict();\n\nexport const dealCreatedPayloadSchema = z.object({\n\taccountId: z.string().uuid(),\n\tdealId: z.string().uuid(),\n\townerId: z.string().uuid(),\n}).strict();\n\nexport const dealStageChangedPayloadSchema = z.object({\n\tdealId: z.string().uuid(),\n\tnewStage: z.string(),\n\toldStage: z.string(),\n}).strict();\n\nexport const stripePaymentReceivedPayloadSchema = z.object({\n\tamountCents: z.number(),\n\tcurrency: z.string(),\n\tcustomerId: z.string(),\n\teventId: z.string(),\n\treceivedAt: z.coerce.date(),\n}).strict();\n\nexport const webhookOutboundContactSyncPayloadSchema = z.object({\n\tcontactId: z.string().uuid(),\n\toccurredAt: z.coerce.date(),\n\toperation: z.string(),\n}).strict();\n\nexport const eventPayloadSchemas = {\n\t'contact_created': contactCreatedPayloadSchema,\n\t'contact_marked_champion': contactMarkedChampionPayloadSchema,\n\t'contact_merged': contactMergedPayloadSchema,\n\t'crm_sync_started': crmSyncStartedPayloadSchema,\n\t'deal_created': dealCreatedPayloadSchema,\n\t'deal_stage_changed': dealStageChangedPayloadSchema,\n\t'stripe_payment_received': stripePaymentReceivedPayloadSchema,\n\t'webhook_outbound_contact_sync': webhookOutboundContactSyncPayloadSchema,\n} as const satisfies Record<EventTypeName, z.ZodType>;\n","// AUTO-GENERATED by @pattern-stack/codegen. Do not edit.\n// Run `codegen entity new --all` to refresh.\n\n\nimport type { EventTypeName } from './types';\n\nexport interface EventMetadata {\n\ttype: EventTypeName;\n\ttier: 'domain' | 'audit';\n\tdirection: 'inbound' | 'change' | 'outbound' | null;\n\tpool: 'events_inbound' | 'events_change' | 'events_outbound' | null;\n\taggregate?: string;\n\tsource?: string;\n\tdestination?: string;\n\tversion: number;\n\tretry: { attempts: number; backoff: 'linear' | 'exponential' };\n}\n\nexport const eventRegistry = {\n\t'contact_created': {\n\t\ttype: 'contact_created',\n\t\ttier: 'domain',\n\t\tdirection: 'change',\n\t\tpool: 'events_change',\n\t\taggregate: 'contact',\n\t\tversion: 1,\n\t\tretry: { attempts: 3, backoff: 'exponential' },\n\t},\n\t'contact_marked_champion': {\n\t\ttype: 'contact_marked_champion',\n\t\ttier: 'domain',\n\t\tdirection: 'change',\n\t\tpool: 'events_change',\n\t\taggregate: 'contact',\n\t\tversion: 1,\n\t\tretry: { attempts: 3, backoff: 'exponential' },\n\t},\n\t'contact_merged': {\n\t\ttype: 'contact_merged',\n\t\ttier: 'domain',\n\t\tdirection: 'change',\n\t\tpool: 'events_change',\n\t\taggregate: 'contact',\n\t\tversion: 1,\n\t\tretry: { attempts: 3, backoff: 'exponential' },\n\t},\n\t'crm_sync_started': {\n\t\ttype: 'crm_sync_started',\n\t\ttier: 'audit',\n\t\tdirection: null,\n\t\tpool: null,\n\t\tversion: 1,\n\t\tretry: { attempts: 3, backoff: 'exponential' },\n\t},\n\t'deal_created': {\n\t\ttype: 'deal_created',\n\t\ttier: 'domain',\n\t\tdirection: 'change',\n\t\tpool: 'events_change',\n\t\taggregate: 'deal',\n\t\tversion: 1,\n\t\tretry: { attempts: 3, backoff: 'exponential' },\n\t},\n\t'deal_stage_changed': {\n\t\ttype: 'deal_stage_changed',\n\t\ttier: 'domain',\n\t\tdirection: 'change',\n\t\tpool: 'events_change',\n\t\taggregate: 'deal',\n\t\tversion: 1,\n\t\tretry: { attempts: 3, backoff: 'exponential' },\n\t},\n\t'stripe_payment_received': {\n\t\ttype: 'stripe_payment_received',\n\t\ttier: 'domain',\n\t\tdirection: 'inbound',\n\t\tpool: 'events_inbound',\n\t\tsource: 'stripe',\n\t\tversion: 1,\n\t\tretry: { attempts: 5, backoff: 'exponential' },\n\t},\n\t'webhook_outbound_contact_sync': {\n\t\ttype: 'webhook_outbound_contact_sync',\n\t\ttier: 'domain',\n\t\tdirection: 'outbound',\n\t\tpool: 'events_outbound',\n\t\taggregate: 'contact',\n\t\tdestination: 'crm',\n\t\tversion: 1,\n\t\tretry: { attempts: 3, backoff: 'exponential' },\n\t},\n} as const satisfies Record<EventTypeName, EventMetadata>;\n\nexport function getEventMetadata<T extends EventTypeName>(type: T): EventMetadata {\n\tconst meta = eventRegistry[type];\n\tif (!meta) {\n\t\tthrow new Error(`No registry entry for event type '${String(type)}' — declare events under events/*.yaml and re-run \\`codegen entity new --all\\`.`);\n\t}\n\treturn meta;\n}\n","// AUTO-GENERATED by @pattern-stack/codegen. Do not edit.\n// Run `codegen entity new --all` to refresh.\n\nimport { Injectable, Inject } from '@nestjs/common';\nimport { randomUUID } from 'crypto';\nimport { EVENT_BUS, EVENTS_MULTI_TENANT } from '../events.tokens';\nimport { MissingTenantIdError } from '../events-errors';\nimport type { IEventBus, DrizzleTransaction } from '../event-bus.protocol';\nimport { eventPayloadSchemas } from './schemas';\nimport { getEventMetadata } from './registry';\nimport type { EventTypeName, EventOfType, PayloadOfType } from './types';\n\n/**\n * Typed facade over IEventBus.\n *\n * Stamps `pool`, `direction`, `tier`, and `version` into `event.metadata`\n * from the generated `eventRegistry` before delegating to\n * `IEventBus.publish()`. Downstream backends (DrizzleEventBus) read those\n * values to populate the explicit `domain_events` columns.\n *\n * Tier stamping (AUDIT-3): every event carries `metadata.tier`, sourced\n * from the registry. For `tier: 'audit'` events, the bus FORCES\n * `metadata.pool = null` and `metadata.direction = null` regardless of\n * any caller-supplied values in `opts.metadata` — audit routing is\n * bus-stamped, not caller-controlled. Caller overrides are silently\n * dropped with a debug-level log (callers should not be specifying these\n * for audit events; see ai-docs/specs/issue-242/plan.md §AUDIT-3).\n *\n * Validation gating (EVT-Q5): `CODEGEN_EVENT_VALIDATE` env flag, default on.\n * Uses `safeParse` + `console.warn` — never throws, so a bad publish does\n * not crash a hot path.\n *\n * Multi-tenancy (EVT-6): when the EventsModule is configured with\n * `multiTenant: true`, every publish must supply `opts.metadata.tenantId`\n * — otherwise `publish()` throws `MissingTenantIdError`. When `multiTenant`\n * is `false` (default), no tenantId is required. If a tenantId IS supplied,\n * it is preserved on `event.metadata` and the Drizzle backend writes it to\n * `domain_events.tenant_id` (EVT-4).\n */\n@Injectable()\nexport class TypedEventBus {\n\tconstructor(\n\t\t@Inject(EVENT_BUS) private readonly bus: IEventBus,\n\t\t@Inject(EVENTS_MULTI_TENANT) private readonly multiTenant: boolean,\n\t) {}\n\n\tasync publish<T extends EventTypeName>(\n\t\ttype: T,\n\t\taggregateId: string,\n\t\tpayload: PayloadOfType<T>,\n\t\topts?: { tx?: DrizzleTransaction; metadata?: Record<string, unknown> },\n\t): Promise<void> {\n\t\tconst meta = getEventMetadata(type);\n\n\t\tconst flag = process.env['CODEGEN_EVENT_VALIDATE'];\n\t\tconst shouldValidate =\n\t\t\tflag === undefined ? true : flag !== 'false' && flag !== '0';\n\t\tif (shouldValidate) {\n\t\t\t// `eventPayloadSchemas` is typed as `Record<EventTypeName, z.ZodType>`,\n\t\t\t// so under `noUncheckedIndexedAccess` the indexed lookup widens\n\t\t\t// to `z.ZodType | undefined`. When no events are registered at\n\t\t\t// codegen time `EventTypeName` degrades to `string` and the\n\t\t\t// schemas object is literally `{}` — the guard below is the\n\t\t\t// honest handling of that empty-registry case (skip validation;\n\t\t\t// it's a warn-only best-effort check per the class docblock).\n\t\t\tconst schema = eventPayloadSchemas[type];\n\t\t\tif (schema) {\n\t\t\t\tconst check = schema.safeParse(payload);\n\t\t\t\tif (!check.success) {\n\t\t\t\t\tconsole.warn(\n\t\t\t\t\t\t`[TypedEventBus] payload validation failed for ${String(type)}:`,\n\t\t\t\t\t\tcheck.error.issues,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tconst tenantId = opts?.metadata?.['tenantId'];\n\t\tif (this.multiTenant && (tenantId === undefined || tenantId === null)) {\n\t\t\tthrow new MissingTenantIdError(type as string);\n\t\t}\n\n\t\tconst aggregateType =\n\t\t\tmeta.aggregate ?? meta.source ?? meta.destination ?? (type as string);\n\n\t\t// AUDIT-3: build metadata with tier-aware routing stamping. For\n\t\t// `tier: 'audit'` events the bus FORCES pool/direction to null,\n\t\t// even if the caller supplied them in opts.metadata. Audit routing\n\t\t// is bus-stamped, not caller-controlled (see plan §AUDIT-3).\n\t\tconst baseMetadata: Record<string, unknown> = { ...(opts?.metadata ?? {}) };\n\t\tif (meta.tier === 'audit') {\n\t\t\tif (\n\t\t\t\tbaseMetadata['pool'] !== undefined ||\n\t\t\t\tbaseMetadata['direction'] !== undefined\n\t\t\t) {\n\t\t\t\tconsole.debug(\n\t\t\t\t\t`[TypedEventBus] tier:audit event '${String(type)}' had pool/direction in opts.metadata; overriding to null.`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tbaseMetadata['pool'] = null;\n\t\t\tbaseMetadata['direction'] = null;\n\t\t\tbaseMetadata['tier'] = 'audit';\n\t\t} else {\n\t\t\tbaseMetadata['pool'] = meta.pool;\n\t\t\tbaseMetadata['direction'] = meta.direction;\n\t\t\tbaseMetadata['tier'] = 'domain';\n\t\t}\n\t\tbaseMetadata['version'] = meta.version;\n\n\t\tawait this.bus.publish(\n\t\t\t{\n\t\t\t\tid: randomUUID(),\n\t\t\t\ttype,\n\t\t\t\taggregateId,\n\t\t\t\taggregateType,\n\t\t\t\tpayload: payload as Record<string, unknown>,\n\t\t\t\toccurredAt: new Date(),\n\t\t\t\tmetadata: baseMetadata,\n\t\t\t},\n\t\t\topts?.tx,\n\t\t);\n\t}\n\n\tsubscribe<T extends EventTypeName>(\n\t\ttype: T,\n\t\thandler: (event: EventOfType<T>) => Promise<void>,\n\t): () => void {\n\t\treturn this.bus.subscribe<EventOfType<T>>(type, handler as never);\n\t}\n}\n","/**\n * Injection token for the event bus.\n *\n * String constant (not Symbol) so it matches by value across import boundaries.\n * Matches the token in runtime/constants/tokens.ts — both are 'EVENT_BUS'.\n *\n * Usage in use cases:\n * ```typescript\n * constructor(@Inject(EVENT_BUS) private readonly eventBus: IEventBus) {}\n * ```\n */\nexport const EVENT_BUS = 'EVENT_BUS' as const;\n\n/**\n * Injection token for the read-side `IEventReadPort` over `domain_events`\n * (OBS-LIST-1).\n *\n * Bound by `EventsModule.forRoot` to the same backend instance as\n * `EVENT_BUS` for the `drizzle` and `memory` backends (both implement\n * `IEventReadPort`). The `redis` backend retains no history and therefore\n * does NOT provide this token — consumers composing it (e.g. the\n * observability combiner) inject it `@Optional()` and degrade to empty\n * results.\n *\n * String constant (not Symbol) so it matches by value across import\n * boundaries — same convention as `EVENT_BUS`.\n */\nexport const EVENT_READ_PORT = 'EVENT_READ_PORT' as const;\n\n/**\n * Injection token for the generated `TypedEventBus` facade.\n *\n * `TypedEventBus` lives in `runtime/subsystems/events/generated/bus.ts` and\n * wraps `IEventBus` with project-specific `AppDomainEvent`-typed `publish<T>()`\n * and `subscribe<T>()`. Use cases inject this token in preference to\n * `EVENT_BUS` when they want compile-time type safety on event shapes.\n *\n * String constant (not Symbol) so it matches by value across import\n * boundaries — same convention as `EVENT_BUS`.\n *\n * Provider registration lands in EVT-6 (EventsModule wiring); the token is\n * declared here so generated code can import it without depending on the\n * still-being-formalised module.\n */\nexport const TYPED_EVENT_BUS = 'TYPED_EVENT_BUS' as const;\n\n/**\n * Injection token for the resolved multi-tenancy flag.\n *\n * Provided by `EventsModule.forRoot(...)` as `options.multiTenant ?? false`.\n * Consumed by `TypedEventBus` to enforce the tenantId-is-required rule at\n * publish time.\n *\n * String constant (not Symbol) so it matches by value across import\n * boundaries — same convention as the other events tokens. (The jobs\n * subsystem uses Symbols for the analogous token; events chose strings\n * from the start and we keep the file internally consistent.)\n */\nexport const EVENTS_MULTI_TENANT = 'EVENTS_MULTI_TENANT' as const;\n\n/**\n * Injection token for the Redis connection URL used by RedisEventBus.\n * Provided automatically by EventsModule.forRoot({ backend: 'redis' }).\n */\nexport const REDIS_URL = Symbol('REDIS_URL');\n\n/**\n * Injection token for the resolved `EventsModuleOptions` object.\n *\n * Provided automatically by `EventsModule.forRoot(...)` /\n * `EventsModule.forRootAsync(...)`. Backends that need to observe module\n * configuration (e.g. `DrizzleEventBus` reading `opts.pools` for\n * pool-filtered drain) inject via this token.\n *\n * String-valued (not `Symbol`) so it matches by value across import\n * boundaries — same convention as `EVENT_BUS`.\n */\nexport const EVENTS_MODULE_OPTIONS = 'EVENTS_MODULE_OPTIONS' as const;\n","/**\n * Typed errors for the events subsystem (ADR-024, EVT-6).\n *\n * All thrown from the publish path of `TypedEventBus`. They exist as\n * classes so consumers can `instanceof` them in catch blocks and\n * exception filters can map them to HTTP codes.\n */\n\n/**\n * Thrown by `TypedEventBus.publish()` when the EventsModule is configured\n * with `multiTenant: true` and the caller did not supply\n * `opts.metadata.tenantId`. Multi-tenant mode requires every outbox row to\n * be attributable to a tenant — the `domain_events.tenant_id` column is\n * populated from this value and the drain loop uses it for future\n * tenant-scoped filtering (deferred — see ADR-024 §Multi-tenancy).\n *\n * Disable multi-tenancy at the module level (`multiTenant: false`, the\n * default) to opt out of the requirement entirely.\n */\nexport class MissingTenantIdError extends Error {\n override readonly name = 'MissingTenantIdError';\n constructor(public readonly eventType: string) {\n super(\n `Missing tenantId for event '${eventType}'. EventsModule is configured ` +\n `with multiTenant: true — every publish must include ` +\n `opts.metadata.tenantId. Either pass the tenantId or disable ` +\n `multi-tenancy on the module.`,\n );\n }\n}\n"],"mappings":";;;;;;;;;;;;;AAIA,SAAS,SAAS;AAGX,IAAM,8BAA8B,EAAE,OAAO;AAAA,EACnD,WAAW,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS;AAAA,EACtC,WAAW,EAAE,OAAO,EAAE,KAAK;AAAA,EAC3B,WAAW,EAAE,OAAO,EAAE,KAAK;AAC5B,CAAC,EAAE,OAAO;AAEH,IAAM,qCAAqC,EAAE,OAAO;AAAA,EAC1D,WAAW,EAAE,OAAO,EAAE,KAAK;AAAA,EAC3B,eAAe,EAAE,OAAO,EAAE,KAAK;AAChC,CAAC,EAAE,OAAO;AAEH,IAAM,6BAA6B,EAAE,OAAO;AAAA,EAClD,UAAU,EAAE,OAAO,EAAE,KAAK;AAAA,EAC1B,UAAU,EAAE,OAAO,EAAE,KAAK;AAAA,EAC1B,UAAU,EAAE,OAAO,EAAE,KAAK;AAC3B,CAAC,EAAE,OAAO;AAEH,IAAM,8BAA8B,EAAE,OAAO;AAAA,EACnD,OAAO,EAAE,OAAO,EAAE,KAAK;AAAA,EACvB,QAAQ,EAAE,OAAO;AAClB,CAAC,EAAE,OAAO;AAEH,IAAM,2BAA2B,EAAE,OAAO;AAAA,EAChD,WAAW,EAAE,OAAO,EAAE,KAAK;AAAA,EAC3B,QAAQ,EAAE,OAAO,EAAE,KAAK;AAAA,EACxB,SAAS,EAAE,OAAO,EAAE,KAAK;AAC1B,CAAC,EAAE,OAAO;AAEH,IAAM,gCAAgC,EAAE,OAAO;AAAA,EACrD,QAAQ,EAAE,OAAO,EAAE,KAAK;AAAA,EACxB,UAAU,EAAE,OAAO;AAAA,EACnB,UAAU,EAAE,OAAO;AACpB,CAAC,EAAE,OAAO;AAEH,IAAM,qCAAqC,EAAE,OAAO;AAAA,EAC1D,aAAa,EAAE,OAAO;AAAA,EACtB,UAAU,EAAE,OAAO;AAAA,EACnB,YAAY,EAAE,OAAO;AAAA,EACrB,SAAS,EAAE,OAAO;AAAA,EAClB,YAAY,EAAE,OAAO,KAAK;AAC3B,CAAC,EAAE,OAAO;AAEH,IAAM,0CAA0C,EAAE,OAAO;AAAA,EAC/D,WAAW,EAAE,OAAO,EAAE,KAAK;AAAA,EAC3B,YAAY,EAAE,OAAO,KAAK;AAAA,EAC1B,WAAW,EAAE,OAAO;AACrB,CAAC,EAAE,OAAO;AAEH,IAAM,sBAAsB;AAAA,EAClC,mBAAmB;AAAA,EACnB,2BAA2B;AAAA,EAC3B,kBAAkB;AAAA,EAClB,oBAAoB;AAAA,EACpB,gBAAgB;AAAA,EAChB,sBAAsB;AAAA,EACtB,2BAA2B;AAAA,EAC3B,iCAAiC;AAClC;;;AC9CO,IAAM,gBAAgB;AAAA,EAC5B,mBAAmB;AAAA,IAClB,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,MAAM;AAAA,IACN,WAAW;AAAA,IACX,SAAS;AAAA,IACT,OAAO,EAAE,UAAU,GAAG,SAAS,cAAc;AAAA,EAC9C;AAAA,EACA,2BAA2B;AAAA,IAC1B,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,MAAM;AAAA,IACN,WAAW;AAAA,IACX,SAAS;AAAA,IACT,OAAO,EAAE,UAAU,GAAG,SAAS,cAAc;AAAA,EAC9C;AAAA,EACA,kBAAkB;AAAA,IACjB,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,MAAM;AAAA,IACN,WAAW;AAAA,IACX,SAAS;AAAA,IACT,OAAO,EAAE,UAAU,GAAG,SAAS,cAAc;AAAA,EAC9C;AAAA,EACA,oBAAoB;AAAA,IACnB,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,MAAM;AAAA,IACN,SAAS;AAAA,IACT,OAAO,EAAE,UAAU,GAAG,SAAS,cAAc;AAAA,EAC9C;AAAA,EACA,gBAAgB;AAAA,IACf,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,MAAM;AAAA,IACN,WAAW;AAAA,IACX,SAAS;AAAA,IACT,OAAO,EAAE,UAAU,GAAG,SAAS,cAAc;AAAA,EAC9C;AAAA,EACA,sBAAsB;AAAA,IACrB,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,MAAM;AAAA,IACN,WAAW;AAAA,IACX,SAAS;AAAA,IACT,OAAO,EAAE,UAAU,GAAG,SAAS,cAAc;AAAA,EAC9C;AAAA,EACA,2BAA2B;AAAA,IAC1B,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,OAAO,EAAE,UAAU,GAAG,SAAS,cAAc;AAAA,EAC9C;AAAA,EACA,iCAAiC;AAAA,IAChC,MAAM;AAAA,IACN,MAAM;AAAA,IACN,WAAW;AAAA,IACX,MAAM;AAAA,IACN,WAAW;AAAA,IACX,aAAa;AAAA,IACb,SAAS;AAAA,IACT,OAAO,EAAE,UAAU,GAAG,SAAS,cAAc;AAAA,EAC9C;AACD;AAEO,SAAS,iBAA0C,MAAwB;AACjF,QAAM,OAAO,cAAc,IAAI;AAC/B,MAAI,CAAC,MAAM;AACV,UAAM,IAAI,MAAM,qCAAqC,OAAO,IAAI,CAAC,sFAAiF;AAAA,EACnJ;AACA,SAAO;AACR;;;AChGA,SAAS,YAAY,cAAc;AACnC,SAAS,kBAAkB;;;ACOpB,IAAM,YAAY;AA+ClB,IAAM,sBAAsB;;;ACvC5B,IAAM,uBAAN,cAAmC,MAAM;AAAA,EAE9C,YAA4B,WAAmB;AAC7C;AAAA,MACE,+BAA+B,SAAS;AAAA,IAI1C;AAN0B;AAAA,EAO5B;AAAA,EAP4B;AAAA,EADV,OAAO;AAS3B;;;AFWO,IAAM,gBAAN,MAAoB;AAAA,EAC1B,YACqC,KACU,aAC7C;AAFmC;AACU;AAAA,EAC5C;AAAA,EAFkC;AAAA,EACU;AAAA,EAG/C,MAAM,QACL,MACA,aACA,SACA,MACgB;AAChB,UAAM,OAAO,iBAAiB,IAAI;AAElC,UAAM,OAAO,QAAQ,IAAI,wBAAwB;AACjD,UAAM,iBACL,SAAS,SAAY,OAAO,SAAS,WAAW,SAAS;AAC1D,QAAI,gBAAgB;AAQnB,YAAM,SAAS,oBAAoB,IAAI;AACvC,UAAI,QAAQ;AACX,cAAM,QAAQ,OAAO,UAAU,OAAO;AACtC,YAAI,CAAC,MAAM,SAAS;AACnB,kBAAQ;AAAA,YACP,iDAAiD,OAAO,IAAI,CAAC;AAAA,YAC7D,MAAM,MAAM;AAAA,UACb;AAAA,QACD;AAAA,MACD;AAAA,IACD;AAEA,UAAM,WAAW,MAAM,WAAW,UAAU;AAC5C,QAAI,KAAK,gBAAgB,aAAa,UAAa,aAAa,OAAO;AACtE,YAAM,IAAI,qBAAqB,IAAc;AAAA,IAC9C;AAEA,UAAM,gBACL,KAAK,aAAa,KAAK,UAAU,KAAK,eAAgB;AAMvD,UAAM,eAAwC,EAAE,GAAI,MAAM,YAAY,CAAC,EAAG;AAC1E,QAAI,KAAK,SAAS,SAAS;AAC1B,UACC,aAAa,MAAM,MAAM,UACzB,aAAa,WAAW,MAAM,QAC7B;AACD,gBAAQ;AAAA,UACP,qCAAqC,OAAO,IAAI,CAAC;AAAA,QAClD;AAAA,MACD;AACA,mBAAa,MAAM,IAAI;AACvB,mBAAa,WAAW,IAAI;AAC5B,mBAAa,MAAM,IAAI;AAAA,IACxB,OAAO;AACN,mBAAa,MAAM,IAAI,KAAK;AAC5B,mBAAa,WAAW,IAAI,KAAK;AACjC,mBAAa,MAAM,IAAI;AAAA,IACxB;AACA,iBAAa,SAAS,IAAI,KAAK;AAE/B,UAAM,KAAK,IAAI;AAAA,MACd;AAAA,QACC,IAAI,WAAW;AAAA,QACf;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA,YAAY,oBAAI,KAAK;AAAA,QACrB,UAAU;AAAA,MACX;AAAA,MACA,MAAM;AAAA,IACP;AAAA,EACD;AAAA,EAEA,UACC,MACA,SACa;AACb,WAAO,KAAK,IAAI,UAA0B,MAAM,OAAgB;AAAA,EACjE;AACD;AAzFa,gBAAN;AAAA,EADN,WAAW;AAAA,EAGT,0BAAO,SAAS;AAAA,EAChB,0BAAO,mBAAmB;AAAA,GAHhB;","names":[]}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export { DomainEvent, DrizzleTransaction, IEventBus } from './event-bus.protocol.js';
|
|
2
|
-
export {
|
|
2
|
+
export { EventPage, EventSummary, IEventReadPort, ListEventsQuery } from './event-read.protocol.js';
|
|
3
|
+
export { EVENTS_MODULE_OPTIONS, EVENTS_MULTI_TENANT, EVENT_BUS, EVENT_READ_PORT, TYPED_EVENT_BUS } from './events.tokens.js';
|
|
3
4
|
export { TypedEventBus } from './generated/bus.js';
|
|
4
5
|
export { MissingTenantIdError } from './events-errors.js';
|
|
5
6
|
export { EventsModule, EventsModuleOptions } from './events.module.js';
|
|
@@ -12,6 +12,7 @@ var __decorateParam = (index2, decorator) => (target, key) => decorator(target,
|
|
|
12
12
|
|
|
13
13
|
// runtime/subsystems/events/events.tokens.ts
|
|
14
14
|
var EVENT_BUS = "EVENT_BUS";
|
|
15
|
+
var EVENT_READ_PORT = "EVENT_READ_PORT";
|
|
15
16
|
var TYPED_EVENT_BUS = "TYPED_EVENT_BUS";
|
|
16
17
|
var EVENTS_MULTI_TENANT = "EVENTS_MULTI_TENANT";
|
|
17
18
|
var REDIS_URL = /* @__PURE__ */ Symbol("REDIS_URL");
|
|
@@ -245,7 +246,38 @@ var DRIZZLE = "DRIZZLE";
|
|
|
245
246
|
|
|
246
247
|
// runtime/subsystems/events/event-bus.drizzle-backend.ts
|
|
247
248
|
import { Injectable as Injectable2, Inject as Inject2, Logger, Optional } from "@nestjs/common";
|
|
248
|
-
import { eq, and, inArray, asc } from "drizzle-orm";
|
|
249
|
+
import { eq, and, inArray, asc, desc, gte, lt, or, sql as sql2 } from "drizzle-orm";
|
|
250
|
+
|
|
251
|
+
// runtime/subsystems/events/event-keyset-cursor.ts
|
|
252
|
+
var DEFAULT_EVENT_LIST_LIMIT = 50;
|
|
253
|
+
var MAX_EVENT_LIST_LIMIT = 200;
|
|
254
|
+
function clampEventLimit(limit) {
|
|
255
|
+
if (typeof limit !== "number" || !Number.isFinite(limit)) {
|
|
256
|
+
return DEFAULT_EVENT_LIST_LIMIT;
|
|
257
|
+
}
|
|
258
|
+
const floored = Math.floor(limit);
|
|
259
|
+
if (floored < 1) return 1;
|
|
260
|
+
if (floored > MAX_EVENT_LIST_LIMIT) return MAX_EVENT_LIST_LIMIT;
|
|
261
|
+
return floored;
|
|
262
|
+
}
|
|
263
|
+
function encodeEventCursor(keyset) {
|
|
264
|
+
const tuple = [keyset.occurredAt.toISOString(), keyset.id];
|
|
265
|
+
return Buffer.from(JSON.stringify(tuple), "utf8").toString("base64url");
|
|
266
|
+
}
|
|
267
|
+
function decodeEventCursor(cursor) {
|
|
268
|
+
try {
|
|
269
|
+
const json = Buffer.from(cursor, "base64url").toString("utf8");
|
|
270
|
+
const parsed = JSON.parse(json);
|
|
271
|
+
if (!Array.isArray(parsed) || parsed.length !== 2) return null;
|
|
272
|
+
const [iso, id] = parsed;
|
|
273
|
+
if (typeof iso !== "string" || typeof id !== "string") return null;
|
|
274
|
+
const occurredAt = new Date(iso);
|
|
275
|
+
if (Number.isNaN(occurredAt.getTime())) return null;
|
|
276
|
+
return { occurredAt, id };
|
|
277
|
+
} catch {
|
|
278
|
+
return null;
|
|
279
|
+
}
|
|
280
|
+
}
|
|
249
281
|
|
|
250
282
|
// runtime/subsystems/events/domain-events.schema.ts
|
|
251
283
|
import {
|
|
@@ -349,6 +381,24 @@ function toInsertValues(event) {
|
|
|
349
381
|
tenantId
|
|
350
382
|
};
|
|
351
383
|
}
|
|
384
|
+
function toEventSummary(r) {
|
|
385
|
+
const metadata = r.metadata ?? void 0;
|
|
386
|
+
const rootRunId = metadata?.["rootRunId"];
|
|
387
|
+
return {
|
|
388
|
+
id: r.id,
|
|
389
|
+
type: r.type,
|
|
390
|
+
aggregateId: r.aggregateId,
|
|
391
|
+
aggregateType: r.aggregateType,
|
|
392
|
+
status: r.status,
|
|
393
|
+
pool: r.pool,
|
|
394
|
+
direction: r.direction,
|
|
395
|
+
tier: r.tier,
|
|
396
|
+
rootRunId: typeof rootRunId === "string" ? rootRunId : null,
|
|
397
|
+
tenantId: r.tenantId,
|
|
398
|
+
occurredAt: r.occurredAt instanceof Date ? r.occurredAt : new Date(r.occurredAt),
|
|
399
|
+
processedAt: r.processedAt == null ? null : r.processedAt instanceof Date ? r.processedAt : new Date(r.processedAt)
|
|
400
|
+
};
|
|
401
|
+
}
|
|
352
402
|
var DrizzleEventBus = class {
|
|
353
403
|
constructor(db, opts, bridgeHook = null) {
|
|
354
404
|
this.db = db;
|
|
@@ -414,6 +464,48 @@ var DrizzleEventBus = class {
|
|
|
414
464
|
};
|
|
415
465
|
}
|
|
416
466
|
// ============================================================================
|
|
467
|
+
// IEventReadPort (OBS-LIST-1)
|
|
468
|
+
// ============================================================================
|
|
469
|
+
async listEvents(query = {}) {
|
|
470
|
+
const limit = clampEventLimit(query.limit);
|
|
471
|
+
const conditions = [];
|
|
472
|
+
if (query.poolId) conditions.push(eq(domainEvents.pool, query.poolId));
|
|
473
|
+
if (query.direction)
|
|
474
|
+
conditions.push(eq(domainEvents.direction, query.direction));
|
|
475
|
+
if (query.since) conditions.push(gte(domainEvents.occurredAt, query.since));
|
|
476
|
+
if (query.rootRunId) {
|
|
477
|
+
conditions.push(
|
|
478
|
+
sql2`${domainEvents.metadata}->>'rootRunId' = ${query.rootRunId}`
|
|
479
|
+
);
|
|
480
|
+
}
|
|
481
|
+
if (query.tenantId !== void 0) {
|
|
482
|
+
conditions.push(
|
|
483
|
+
query.tenantId === null ? sql2`${domainEvents.tenantId} is null` : eq(domainEvents.tenantId, query.tenantId)
|
|
484
|
+
);
|
|
485
|
+
}
|
|
486
|
+
if (query.cursor) {
|
|
487
|
+
const keyset = decodeEventCursor(query.cursor);
|
|
488
|
+
if (keyset) {
|
|
489
|
+
conditions.push(
|
|
490
|
+
or(
|
|
491
|
+
lt(domainEvents.occurredAt, keyset.occurredAt),
|
|
492
|
+
and(
|
|
493
|
+
eq(domainEvents.occurredAt, keyset.occurredAt),
|
|
494
|
+
lt(domainEvents.id, keyset.id)
|
|
495
|
+
)
|
|
496
|
+
)
|
|
497
|
+
);
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
const rows = await this.db.select().from(domainEvents).where(conditions.length > 0 ? and(...conditions) : void 0).orderBy(desc(domainEvents.occurredAt), desc(domainEvents.id)).limit(limit + 1);
|
|
501
|
+
const hasMore = rows.length > limit;
|
|
502
|
+
const page = hasMore ? rows.slice(0, limit) : rows;
|
|
503
|
+
const items = page.map(toEventSummary);
|
|
504
|
+
const last = page[page.length - 1];
|
|
505
|
+
const nextCursor = hasMore && last ? encodeEventCursor({ occurredAt: last.occurredAt, id: last.id }) : null;
|
|
506
|
+
return { items, nextCursor };
|
|
507
|
+
}
|
|
508
|
+
// ============================================================================
|
|
417
509
|
// Polling
|
|
418
510
|
// ============================================================================
|
|
419
511
|
/**
|
|
@@ -538,6 +630,27 @@ DrizzleEventBus = __decorateClass([
|
|
|
538
630
|
|
|
539
631
|
// runtime/subsystems/events/event-bus.memory-backend.ts
|
|
540
632
|
import { Inject as Inject3, Injectable as Injectable3, Logger as Logger2, Optional as Optional2 } from "@nestjs/common";
|
|
633
|
+
function toEventSummary2(event) {
|
|
634
|
+
const metadata = event.metadata;
|
|
635
|
+
const str = (key) => {
|
|
636
|
+
const v = metadata?.[key];
|
|
637
|
+
return typeof v === "string" ? v : null;
|
|
638
|
+
};
|
|
639
|
+
return {
|
|
640
|
+
id: event.id,
|
|
641
|
+
type: event.type,
|
|
642
|
+
aggregateId: event.aggregateId,
|
|
643
|
+
aggregateType: event.aggregateType,
|
|
644
|
+
status: "processed",
|
|
645
|
+
pool: str("pool"),
|
|
646
|
+
direction: str("direction"),
|
|
647
|
+
tier: str("tier") ?? "domain",
|
|
648
|
+
rootRunId: str("rootRunId"),
|
|
649
|
+
tenantId: str("tenantId"),
|
|
650
|
+
occurredAt: event.occurredAt,
|
|
651
|
+
processedAt: event.occurredAt
|
|
652
|
+
};
|
|
653
|
+
}
|
|
541
654
|
var MemoryEventBus = class {
|
|
542
655
|
logger = new Logger2(MemoryEventBus.name);
|
|
543
656
|
/** All events published since construction (or last clear). */
|
|
@@ -573,6 +686,53 @@ var MemoryEventBus = class {
|
|
|
573
686
|
set.delete(h);
|
|
574
687
|
};
|
|
575
688
|
}
|
|
689
|
+
// ============================================================================
|
|
690
|
+
// IEventReadPort (OBS-LIST-1)
|
|
691
|
+
// ============================================================================
|
|
692
|
+
async listEvents(query = {}) {
|
|
693
|
+
const limit = clampEventLimit(query.limit);
|
|
694
|
+
const keyset = query.cursor ? decodeEventCursor(query.cursor) : null;
|
|
695
|
+
const str = (e, key) => {
|
|
696
|
+
const v = e.metadata?.[key];
|
|
697
|
+
return typeof v === "string" ? v : null;
|
|
698
|
+
};
|
|
699
|
+
const matched = this.publishedEvents.filter((e) => {
|
|
700
|
+
if (query.poolId && str(e, "pool") !== query.poolId) return false;
|
|
701
|
+
if (query.direction && str(e, "direction") !== query.direction)
|
|
702
|
+
return false;
|
|
703
|
+
if (query.rootRunId && str(e, "rootRunId") !== query.rootRunId)
|
|
704
|
+
return false;
|
|
705
|
+
if (query.since && e.occurredAt.getTime() < query.since.getTime())
|
|
706
|
+
return false;
|
|
707
|
+
if (query.tenantId !== void 0) {
|
|
708
|
+
const t = str(e, "tenantId");
|
|
709
|
+
if (query.tenantId === null) {
|
|
710
|
+
if (t !== null) return false;
|
|
711
|
+
} else if (t !== query.tenantId) {
|
|
712
|
+
return false;
|
|
713
|
+
}
|
|
714
|
+
}
|
|
715
|
+
return true;
|
|
716
|
+
});
|
|
717
|
+
matched.sort((a, b) => {
|
|
718
|
+
const dt = b.occurredAt.getTime() - a.occurredAt.getTime();
|
|
719
|
+
if (dt !== 0) return dt;
|
|
720
|
+
return a.id < b.id ? 1 : a.id > b.id ? -1 : 0;
|
|
721
|
+
});
|
|
722
|
+
const seeked = keyset ? matched.filter((e) => {
|
|
723
|
+
const ct = e.occurredAt.getTime();
|
|
724
|
+
const kt = keyset.occurredAt.getTime();
|
|
725
|
+
if (ct < kt) return true;
|
|
726
|
+
if (ct > kt) return false;
|
|
727
|
+
return e.id < keyset.id;
|
|
728
|
+
}) : matched;
|
|
729
|
+
const hasMore = seeked.length > limit;
|
|
730
|
+
const page = hasMore ? seeked.slice(0, limit) : seeked;
|
|
731
|
+
const items = page.map(toEventSummary2);
|
|
732
|
+
const last = page[page.length - 1];
|
|
733
|
+
const nextCursor = hasMore && last ? encodeEventCursor({ occurredAt: last.occurredAt, id: last.id }) : null;
|
|
734
|
+
return { items, nextCursor };
|
|
735
|
+
}
|
|
576
736
|
/** Remove all published events and subscriptions. Useful in beforeEach. */
|
|
577
737
|
clear() {
|
|
578
738
|
this.publishedEvents.length = 0;
|
|
@@ -930,10 +1090,20 @@ var EventsModule = class {
|
|
|
930
1090
|
REDIS_URL
|
|
931
1091
|
]
|
|
932
1092
|
},
|
|
1093
|
+
{
|
|
1094
|
+
// Read port (OBS-LIST-1). Drizzle + memory backends implement
|
|
1095
|
+
// IEventReadPort on the EVENT_BUS instance; the redis backend
|
|
1096
|
+
// retains no history, so EVENT_READ_PORT resolves to `null` and
|
|
1097
|
+
// optional consumers (the observability combiner) degrade to
|
|
1098
|
+
// empty results.
|
|
1099
|
+
provide: EVENT_READ_PORT,
|
|
1100
|
+
useFactory: (options, bus) => options.backend === "redis" ? null : bus,
|
|
1101
|
+
inject: [EVENTS_MODULE_OPTIONS, EVENT_BUS]
|
|
1102
|
+
},
|
|
933
1103
|
TypedEventBus,
|
|
934
1104
|
{ provide: TYPED_EVENT_BUS, useExisting: TypedEventBus }
|
|
935
1105
|
],
|
|
936
|
-
exports: [EVENT_BUS, TYPED_EVENT_BUS, EVENTS_MULTI_TENANT]
|
|
1106
|
+
exports: [EVENT_BUS, EVENT_READ_PORT, TYPED_EVENT_BUS, EVENTS_MULTI_TENANT]
|
|
937
1107
|
};
|
|
938
1108
|
}
|
|
939
1109
|
static forRoot(options = { backend: "drizzle" }) {
|
|
@@ -961,9 +1131,13 @@ var EventsModule = class {
|
|
|
961
1131
|
providers: [
|
|
962
1132
|
{ provide: EVENTS_MODULE_OPTIONS, useValue: options },
|
|
963
1133
|
provider,
|
|
1134
|
+
// Read port (OBS-LIST-1): drizzle + memory backends implement
|
|
1135
|
+
// IEventReadPort on the same instance as EVENT_BUS. The redis
|
|
1136
|
+
// backend retains no history and does not provide this token.
|
|
1137
|
+
{ provide: EVENT_READ_PORT, useExisting: EVENT_BUS },
|
|
964
1138
|
...buildTypedBusProviders(multiTenant)
|
|
965
1139
|
],
|
|
966
|
-
exports: [EVENT_BUS, TYPED_EVENT_BUS, EVENTS_MULTI_TENANT]
|
|
1140
|
+
exports: [EVENT_BUS, EVENT_READ_PORT, TYPED_EVENT_BUS, EVENTS_MULTI_TENANT]
|
|
967
1141
|
};
|
|
968
1142
|
}
|
|
969
1143
|
};
|
|
@@ -975,6 +1149,7 @@ export {
|
|
|
975
1149
|
EVENTS_MODULE_OPTIONS,
|
|
976
1150
|
EVENTS_MULTI_TENANT,
|
|
977
1151
|
EVENT_BUS,
|
|
1152
|
+
EVENT_READ_PORT,
|
|
978
1153
|
EventsModule,
|
|
979
1154
|
MemoryEventBus,
|
|
980
1155
|
MissingTenantIdError,
|