@drarzter/kafka-client 0.9.3 → 0.10.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.
Files changed (170) hide show
  1. package/README.md +625 -8
  2. package/dist/chunk-CMO7SMVK.mjs +4814 -0
  3. package/dist/chunk-CMO7SMVK.mjs.map +1 -0
  4. package/dist/cli/dlq.d.ts +119 -0
  5. package/dist/cli/dlq.d.ts.map +1 -0
  6. package/dist/cli/index.d.ts +3 -0
  7. package/dist/cli/index.d.ts.map +1 -0
  8. package/dist/{chunk-TPIP5VV7.mjs → cli/index.js} +965 -265
  9. package/dist/cli/index.js.map +1 -0
  10. package/dist/cli/index.mjs +355 -0
  11. package/dist/cli/index.mjs.map +1 -0
  12. package/dist/client/config/from-env.d.ts +188 -0
  13. package/dist/client/config/from-env.d.ts.map +1 -0
  14. package/dist/client/config/index.d.ts +2 -0
  15. package/dist/client/config/index.d.ts.map +1 -0
  16. package/dist/client/errors.d.ts +67 -0
  17. package/dist/client/errors.d.ts.map +1 -0
  18. package/dist/client/kafka.client/admin/ops.d.ts +114 -0
  19. package/dist/client/kafka.client/admin/ops.d.ts.map +1 -0
  20. package/dist/client/kafka.client/consumer/features/delayed.d.ts +24 -0
  21. package/dist/client/kafka.client/consumer/features/delayed.d.ts.map +1 -0
  22. package/dist/client/kafka.client/consumer/features/dlq-replay.d.ts +52 -0
  23. package/dist/client/kafka.client/consumer/features/dlq-replay.d.ts.map +1 -0
  24. package/dist/client/kafka.client/consumer/features/routed.d.ts +4 -0
  25. package/dist/client/kafka.client/consumer/features/routed.d.ts.map +1 -0
  26. package/dist/client/kafka.client/consumer/features/snapshot.d.ts +10 -0
  27. package/dist/client/kafka.client/consumer/features/snapshot.d.ts.map +1 -0
  28. package/dist/client/kafka.client/consumer/features/window.d.ts +5 -0
  29. package/dist/client/kafka.client/consumer/features/window.d.ts.map +1 -0
  30. package/dist/client/kafka.client/consumer/handler.d.ts +149 -0
  31. package/dist/client/kafka.client/consumer/handler.d.ts.map +1 -0
  32. package/dist/client/kafka.client/consumer/ops.d.ts +51 -0
  33. package/dist/client/kafka.client/consumer/ops.d.ts.map +1 -0
  34. package/dist/client/kafka.client/consumer/pipeline.d.ts +167 -0
  35. package/dist/client/kafka.client/consumer/pipeline.d.ts.map +1 -0
  36. package/dist/client/kafka.client/consumer/queue.d.ts +37 -0
  37. package/dist/client/kafka.client/consumer/queue.d.ts.map +1 -0
  38. package/dist/client/kafka.client/consumer/retry-topic.d.ts +65 -0
  39. package/dist/client/kafka.client/consumer/retry-topic.d.ts.map +1 -0
  40. package/dist/client/kafka.client/consumer/setup.d.ts +63 -0
  41. package/dist/client/kafka.client/consumer/setup.d.ts.map +1 -0
  42. package/dist/client/kafka.client/consumer/start.d.ts +7 -0
  43. package/dist/client/kafka.client/consumer/start.d.ts.map +1 -0
  44. package/dist/client/kafka.client/consumer/stop.d.ts +19 -0
  45. package/dist/client/kafka.client/consumer/stop.d.ts.map +1 -0
  46. package/dist/client/kafka.client/consumer/subscribe-retry.d.ts +4 -0
  47. package/dist/client/kafka.client/consumer/subscribe-retry.d.ts.map +1 -0
  48. package/dist/client/kafka.client/context.d.ts +72 -0
  49. package/dist/client/kafka.client/context.d.ts.map +1 -0
  50. package/dist/client/kafka.client/index.d.ts +155 -0
  51. package/dist/client/kafka.client/index.d.ts.map +1 -0
  52. package/dist/client/kafka.client/infra/circuit-breaker.manager.d.ts +61 -0
  53. package/dist/client/kafka.client/infra/circuit-breaker.manager.d.ts.map +1 -0
  54. package/dist/client/kafka.client/infra/dedup.store.d.ts +28 -0
  55. package/dist/client/kafka.client/infra/dedup.store.d.ts.map +1 -0
  56. package/dist/client/kafka.client/infra/inflight.tracker.d.ts +22 -0
  57. package/dist/client/kafka.client/infra/inflight.tracker.d.ts.map +1 -0
  58. package/dist/client/kafka.client/infra/metrics.manager.d.ts +67 -0
  59. package/dist/client/kafka.client/infra/metrics.manager.d.ts.map +1 -0
  60. package/dist/client/kafka.client/producer/lifecycle.d.ts +41 -0
  61. package/dist/client/kafka.client/producer/lifecycle.d.ts.map +1 -0
  62. package/dist/client/kafka.client/producer/ops.d.ts +70 -0
  63. package/dist/client/kafka.client/producer/ops.d.ts.map +1 -0
  64. package/dist/client/kafka.client/producer/send.d.ts +21 -0
  65. package/dist/client/kafka.client/producer/send.d.ts.map +1 -0
  66. package/dist/client/kafka.client/validate-options.d.ts +11 -0
  67. package/dist/client/kafka.client/validate-options.d.ts.map +1 -0
  68. package/dist/client/message/envelope.d.ts +105 -0
  69. package/dist/client/message/envelope.d.ts.map +1 -0
  70. package/dist/client/message/schema-registry.d.ts +105 -0
  71. package/dist/client/message/schema-registry.d.ts.map +1 -0
  72. package/dist/client/message/topic.d.ts +138 -0
  73. package/dist/client/message/topic.d.ts.map +1 -0
  74. package/dist/client/message/versioned-schema.d.ts +53 -0
  75. package/dist/client/message/versioned-schema.d.ts.map +1 -0
  76. package/dist/client/outbox/index.d.ts +4 -0
  77. package/dist/client/outbox/index.d.ts.map +1 -0
  78. package/dist/client/outbox/outbox.relay.d.ts +90 -0
  79. package/dist/client/outbox/outbox.relay.d.ts.map +1 -0
  80. package/dist/client/outbox/outbox.store.d.ts +42 -0
  81. package/dist/client/outbox/outbox.store.d.ts.map +1 -0
  82. package/dist/client/outbox/outbox.types.d.ts +144 -0
  83. package/dist/client/outbox/outbox.types.d.ts.map +1 -0
  84. package/dist/client/security/acl.d.ts +108 -0
  85. package/dist/client/security/acl.d.ts.map +1 -0
  86. package/dist/client/security/index.d.ts +5 -0
  87. package/dist/client/security/index.d.ts.map +1 -0
  88. package/dist/client/security/providers.d.ts +88 -0
  89. package/dist/client/security/providers.d.ts.map +1 -0
  90. package/dist/client/security/resolve-security.d.ts +19 -0
  91. package/dist/client/security/resolve-security.d.ts.map +1 -0
  92. package/dist/client/security/security.types.d.ts +76 -0
  93. package/dist/client/security/security.types.d.ts.map +1 -0
  94. package/dist/client/transport/confluent.transport.d.ts +32 -0
  95. package/dist/client/transport/confluent.transport.d.ts.map +1 -0
  96. package/dist/client/transport/transport.interface.d.ts +216 -0
  97. package/dist/client/transport/transport.interface.d.ts.map +1 -0
  98. package/dist/client/types/admin.interface.d.ts +174 -0
  99. package/dist/client/types/admin.interface.d.ts.map +1 -0
  100. package/dist/client/types/admin.types.d.ts +140 -0
  101. package/dist/client/types/admin.types.d.ts.map +1 -0
  102. package/dist/client/types/client.d.ts +21 -0
  103. package/dist/client/types/client.d.ts.map +1 -0
  104. package/dist/client/types/common.d.ts +84 -0
  105. package/dist/client/types/common.d.ts.map +1 -0
  106. package/dist/client/types/config.types.d.ts +150 -0
  107. package/dist/client/types/config.types.d.ts.map +1 -0
  108. package/dist/client/types/consumer.interface.d.ts +115 -0
  109. package/dist/client/types/consumer.interface.d.ts.map +1 -0
  110. package/dist/{consumer.types-fFCag3VJ.d.mts → client/types/consumer.types.d.ts} +62 -383
  111. package/dist/client/types/consumer.types.d.ts.map +1 -0
  112. package/dist/client/types/dedup.types.d.ts +50 -0
  113. package/dist/client/types/dedup.types.d.ts.map +1 -0
  114. package/dist/client/types/lifecycle.interface.d.ts +72 -0
  115. package/dist/client/types/lifecycle.interface.d.ts.map +1 -0
  116. package/dist/client/types/producer.interface.d.ts +52 -0
  117. package/dist/client/types/producer.interface.d.ts.map +1 -0
  118. package/dist/client/types/producer.types.d.ts +90 -0
  119. package/dist/client/types/producer.types.d.ts.map +1 -0
  120. package/dist/client/types.d.ts +8 -0
  121. package/dist/client/types.d.ts.map +1 -0
  122. package/dist/core.d.ts +10 -314
  123. package/dist/core.d.ts.map +1 -0
  124. package/dist/core.js +1326 -74
  125. package/dist/core.js.map +1 -1
  126. package/dist/core.mjs +39 -3
  127. package/dist/index.d.ts +7 -128
  128. package/dist/index.d.ts.map +1 -0
  129. package/dist/index.js +1343 -74
  130. package/dist/index.js.map +1 -1
  131. package/dist/index.mjs +56 -3
  132. package/dist/index.mjs.map +1 -1
  133. package/dist/nest/kafka.constants.d.ts +5 -0
  134. package/dist/nest/kafka.constants.d.ts.map +1 -0
  135. package/dist/nest/kafka.decorator.d.ts +49 -0
  136. package/dist/nest/kafka.decorator.d.ts.map +1 -0
  137. package/dist/nest/kafka.explorer.d.ts +17 -0
  138. package/dist/nest/kafka.explorer.d.ts.map +1 -0
  139. package/dist/nest/kafka.health.d.ts +7 -0
  140. package/dist/nest/kafka.health.d.ts.map +1 -0
  141. package/dist/nest/kafka.module.d.ts +61 -0
  142. package/dist/nest/kafka.module.d.ts.map +1 -0
  143. package/dist/otel.d.ts +83 -5
  144. package/dist/otel.d.ts.map +1 -0
  145. package/dist/otel.js +100 -6
  146. package/dist/otel.js.map +1 -1
  147. package/dist/otel.mjs +98 -5
  148. package/dist/otel.mjs.map +1 -1
  149. package/dist/testing/client.mock.d.ts +47 -0
  150. package/dist/testing/client.mock.d.ts.map +1 -0
  151. package/dist/testing/index.d.ts +4 -0
  152. package/dist/testing/index.d.ts.map +1 -0
  153. package/dist/testing/test.container.d.ts +63 -0
  154. package/dist/testing/test.container.d.ts.map +1 -0
  155. package/dist/{testing.d.mts → testing/transport.fake.d.ts} +7 -111
  156. package/dist/testing/transport.fake.d.ts.map +1 -0
  157. package/dist/testing.d.ts +2 -318
  158. package/dist/testing.d.ts.map +1 -0
  159. package/dist/testing.js +28 -2
  160. package/dist/testing.js.map +1 -1
  161. package/dist/testing.mjs +28 -2
  162. package/dist/testing.mjs.map +1 -1
  163. package/package.json +22 -9
  164. package/dist/chunk-TPIP5VV7.mjs.map +0 -1
  165. package/dist/client-CBBUDDtu.d.ts +0 -751
  166. package/dist/client-D-SxYV2b.d.mts +0 -751
  167. package/dist/consumer.types-fFCag3VJ.d.ts +0 -958
  168. package/dist/core.d.mts +0 -314
  169. package/dist/index.d.mts +0 -128
  170. package/dist/otel.d.mts +0 -27
@@ -0,0 +1,105 @@
1
+ import type { MessageHeaders } from "../types";
2
+ export declare const HEADER_EVENT_ID = "x-event-id";
3
+ export declare const HEADER_CORRELATION_ID = "x-correlation-id";
4
+ export declare const HEADER_TIMESTAMP = "x-timestamp";
5
+ export declare const HEADER_SCHEMA_VERSION = "x-schema-version";
6
+ export declare const HEADER_TRACEPARENT = "traceparent";
7
+ /** Monotonically increasing logical clock stamped by the producer for deduplication. */
8
+ export declare const HEADER_LAMPORT_CLOCK = "x-lamport-clock";
9
+ /** Absolute epoch-ms deadline before which a delayed message must not be delivered. */
10
+ export declare const HEADER_DELAYED_UNTIL = "x-delayed-until";
11
+ /** Target topic a delayed message is forwarded to once its deadline passes. */
12
+ export declare const HEADER_DELAYED_TARGET = "x-delayed-target";
13
+ /**
14
+ * Typed wrapper combining a parsed message payload with Kafka metadata
15
+ * and envelope headers.
16
+ *
17
+ * On **send**, the library auto-generates envelope headers
18
+ * (`x-event-id`, `x-correlation-id`, `x-timestamp`, `x-schema-version`).
19
+ *
20
+ * On **consume**, the library extracts those headers and assembles
21
+ * an `EventEnvelope` that is passed to the handler.
22
+ *
23
+ * @example
24
+ * ```ts
25
+ * await kafka.startConsumer(['orders'], async (envelope: EventEnvelope<Order>) => {
26
+ * console.log(envelope.payload.orderId); // typed payload
27
+ * console.log(envelope.correlationId); // auto-propagated
28
+ * console.log(envelope.eventId); // unique message ID
29
+ * });
30
+ * ```
31
+ */
32
+ export interface EventEnvelope<T> {
33
+ /** Deserialized + validated message body. */
34
+ payload: T;
35
+ /** Topic the message was produced to / consumed from. */
36
+ topic: string;
37
+ /** Kafka partition (consume-side only, `-1` on send). */
38
+ partition: number;
39
+ /** Kafka offset (consume-side only, empty string on send). */
40
+ offset: string;
41
+ /** ISO-8601 timestamp set by the producer. */
42
+ timestamp: string;
43
+ /** Unique ID for this event (UUID v4). */
44
+ eventId: string;
45
+ /** Correlation ID — auto-propagated via AsyncLocalStorage. */
46
+ correlationId: string;
47
+ /** Schema version of the payload. */
48
+ schemaVersion: number;
49
+ /** W3C Trace Context `traceparent` header (set by OTel instrumentation). */
50
+ traceparent?: string;
51
+ /** All decoded Kafka headers for extensibility. */
52
+ headers: MessageHeaders;
53
+ }
54
+ interface EnvelopeCtx {
55
+ correlationId: string;
56
+ traceparent?: string;
57
+ }
58
+ /**
59
+ * Read the current envelope context (correlationId / traceparent) from ALS.
60
+ * Returns `undefined` outside of a Kafka consumer handler.
61
+ * @example
62
+ * ```ts
63
+ * const ctx = getEnvelopeContext();
64
+ * if (ctx) console.log('correlationId:', ctx.correlationId);
65
+ * ```
66
+ */
67
+ export declare function getEnvelopeContext(): EnvelopeCtx | undefined;
68
+ /**
69
+ * Execute `fn` inside an envelope context so nested sends inherit correlationId.
70
+ * Automatically called by the consumer pipeline — use this in tests or manual flows.
71
+ * @example
72
+ * ```ts
73
+ * await runWithEnvelopeContext({ correlationId: 'abc-123' }, async () => {
74
+ * await kafka.sendMessage('orders.created', payload); // inherits correlationId
75
+ * });
76
+ * ```
77
+ */
78
+ export declare function runWithEnvelopeContext<R>(ctx: EnvelopeCtx, fn: () => R): R;
79
+ /** Options accepted by `buildEnvelopeHeaders`. */
80
+ export interface EnvelopeHeaderOptions {
81
+ correlationId?: string;
82
+ schemaVersion?: number;
83
+ eventId?: string;
84
+ headers?: MessageHeaders;
85
+ }
86
+ /**
87
+ * Generate envelope headers for the send path.
88
+ *
89
+ * Priority for `correlationId`:
90
+ * explicit option → ALS context → new UUID.
91
+ */
92
+ export declare function buildEnvelopeHeaders(options?: EnvelopeHeaderOptions): MessageHeaders;
93
+ /**
94
+ * Decode kafkajs headers (`Record<string, Buffer | string | undefined>`)
95
+ * into plain `Record<string, string>`.
96
+ */
97
+ export declare function decodeHeaders(raw: Record<string, Buffer | string | (Buffer | string)[] | undefined> | undefined): MessageHeaders;
98
+ /**
99
+ * Build an `EventEnvelope` from a consumed kafkajs message.
100
+ * Tolerates missing envelope headers — generates defaults so messages
101
+ * from non-envelope producers still work.
102
+ */
103
+ export declare function extractEnvelope<T>(payload: T, headers: MessageHeaders, topic: string, partition: number, offset: string): EventEnvelope<T>;
104
+ export {};
105
+ //# sourceMappingURL=envelope.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"envelope.d.ts","sourceRoot":"","sources":["../../../src/client/message/envelope.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAI/C,eAAO,MAAM,eAAe,eAAe,CAAC;AAC5C,eAAO,MAAM,qBAAqB,qBAAqB,CAAC;AACxD,eAAO,MAAM,gBAAgB,gBAAgB,CAAC;AAC9C,eAAO,MAAM,qBAAqB,qBAAqB,CAAC;AACxD,eAAO,MAAM,kBAAkB,gBAAgB,CAAC;AAChD,wFAAwF;AACxF,eAAO,MAAM,oBAAoB,oBAAoB,CAAC;AACtD,uFAAuF;AACvF,eAAO,MAAM,oBAAoB,oBAAoB,CAAC;AACtD,+EAA+E;AAC/E,eAAO,MAAM,qBAAqB,qBAAqB,CAAC;AAIxD;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,WAAW,aAAa,CAAC,CAAC;IAC9B,6CAA6C;IAC7C,OAAO,EAAE,CAAC,CAAC;IACX,yDAAyD;IACzD,KAAK,EAAE,MAAM,CAAC;IACd,yDAAyD;IACzD,SAAS,EAAE,MAAM,CAAC;IAClB,8DAA8D;IAC9D,MAAM,EAAE,MAAM,CAAC;IACf,8CAA8C;IAC9C,SAAS,EAAE,MAAM,CAAC;IAClB,0CAA0C;IAC1C,OAAO,EAAE,MAAM,CAAC;IAChB,8DAA8D;IAC9D,aAAa,EAAE,MAAM,CAAC;IACtB,qCAAqC;IACrC,aAAa,EAAE,MAAM,CAAC;IACtB,4EAA4E;IAC5E,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,mDAAmD;IACnD,OAAO,EAAE,cAAc,CAAC;CACzB;AAID,UAAU,WAAW;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAID;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,IAAI,WAAW,GAAG,SAAS,CAE5D;AAED;;;;;;;;;GASG;AACH,wBAAgB,sBAAsB,CAAC,CAAC,EAAE,GAAG,EAAE,WAAW,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,CAE1E;AAID,kDAAkD;AAClD,MAAM,WAAW,qBAAqB;IACpC,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,cAAc,CAAC;CAC1B;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAClC,OAAO,GAAE,qBAA0B,GAClC,cAAc,CAuBhB;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAC3B,GAAG,EACC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,GAAG,SAAS,CAAC,GACjE,SAAS,GACZ,cAAc,CAehB;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,CAAC,EAC/B,OAAO,EAAE,CAAC,EACV,OAAO,EAAE,cAAc,EACvB,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,GACb,aAAa,CAAC,CAAC,CAAC,CAalB"}
@@ -0,0 +1,105 @@
1
+ import type { SchemaLike } from "./topic";
2
+ /** A schema registered in a Confluent-compatible Schema Registry. */
3
+ export interface RegisteredSchema {
4
+ /** Globally unique schema id assigned by the registry. */
5
+ id: number;
6
+ /** Version of the schema within its subject. */
7
+ version: number;
8
+ /** The schema definition string (JSON Schema / Avro / Protobuf source). */
9
+ schema: string;
10
+ }
11
+ /** Options for `SchemaRegistryClient`. */
12
+ export interface SchemaRegistryClientOptions {
13
+ /** Registry base URL, e.g. `http://localhost:8081` or a Confluent Cloud SR endpoint. */
14
+ baseUrl: string;
15
+ /** HTTP Basic credentials (Confluent Cloud SR API key/secret). */
16
+ auth?: {
17
+ username: string;
18
+ password: string;
19
+ };
20
+ /** Cache TTL for subject lookups in ms. Default: `300_000` (5 min). */
21
+ cacheTtlMs?: number;
22
+ /** Injectable fetch implementation (tests). Default: global `fetch`. */
23
+ fetchFn?: typeof fetch;
24
+ }
25
+ /** Schema type accepted by Confluent-compatible registries. */
26
+ export type RegistrySchemaType = "JSON" | "AVRO" | "PROTOBUF";
27
+ /**
28
+ * Minimal, dependency-free client for the Confluent Schema Registry REST API
29
+ * (works with Confluent Platform/Cloud, Redpanda, Karapace, AWS Glue SR proxy).
30
+ *
31
+ * Scope: subject/version management and compatibility checks — the pieces
32
+ * needed to keep locally-defined schemas in lockstep with a central registry.
33
+ * Payload (de)serialisation stays JSON as everywhere in this library; wire-format
34
+ * framing with magic bytes (Avro/Protobuf binary) is intentionally out of scope.
35
+ *
36
+ * @example
37
+ * ```ts
38
+ * const registry = new SchemaRegistryClient({ baseUrl: 'http://localhost:8081' });
39
+ * const { id } = await registry.registerSchema(
40
+ * 'order.created-value',
41
+ * JSON.stringify(orderJsonSchema),
42
+ * 'JSON',
43
+ * );
44
+ * ```
45
+ */
46
+ export declare class SchemaRegistryClient {
47
+ private readonly options;
48
+ private readonly fetchFn;
49
+ private readonly cacheTtlMs;
50
+ private readonly latestCache;
51
+ constructor(options: SchemaRegistryClientOptions);
52
+ private headers;
53
+ private request;
54
+ /** Fetch the latest schema registered under `subject`. Cached for `cacheTtlMs`. */
55
+ getLatestSchema(subject: string): Promise<RegisteredSchema>;
56
+ /** Fetch a specific schema version of a subject. */
57
+ getSchemaVersion(subject: string, version: number): Promise<RegisteredSchema>;
58
+ /**
59
+ * Register a schema under `subject` (idempotent — re-registering the same
60
+ * schema returns the existing id). Returns the registry-assigned schema id.
61
+ */
62
+ registerSchema(subject: string, schema: string, schemaType?: RegistrySchemaType): Promise<{
63
+ id: number;
64
+ }>;
65
+ /**
66
+ * Test `schema` against the subject's compatibility policy without registering.
67
+ * Returns `true` when the registry reports the schema as compatible.
68
+ */
69
+ checkCompatibility(subject: string, schema: string, schemaType?: RegistrySchemaType): Promise<boolean>;
70
+ }
71
+ /** Options for `registrySchema()`. */
72
+ export interface RegistrySchemaOptions<T> {
73
+ /**
74
+ * Local structural validator (Zod/Valibot/…) applied to every message.
75
+ * The registry governs schema *evolution*; this governs runtime *shape*.
76
+ */
77
+ validator?: SchemaLike<T>;
78
+ /**
79
+ * When `true` (default), the message's `x-schema-version` must not be newer
80
+ * than the latest version registered for the subject — a producer publishing
81
+ * an unregistered version fails loudly instead of drifting silently.
82
+ */
83
+ enforceVersion?: boolean;
84
+ }
85
+ /**
86
+ * Bridge a Schema Registry subject to this library's `SchemaLike` seam.
87
+ *
88
+ * On each `parse` the adapter resolves the subject's latest registered version
89
+ * (cached), optionally verifies the message's schema version does not exceed
90
+ * it, and delegates structural validation to the provided local validator.
91
+ * Attach the result to a `TopicDescriptor` like any other schema:
92
+ *
93
+ * @example
94
+ * ```ts
95
+ * const registry = new SchemaRegistryClient({ baseUrl: 'http://localhost:8081' });
96
+ *
97
+ * const OrderCreated = topic('order.created').schema(
98
+ * registrySchema(registry, 'order.created-value', {
99
+ * validator: z.object({ orderId: z.string() }),
100
+ * }),
101
+ * );
102
+ * ```
103
+ */
104
+ export declare function registrySchema<T = any>(client: SchemaRegistryClient, subject: string, options?: RegistrySchemaOptions<T>): SchemaLike<T>;
105
+ //# sourceMappingURL=schema-registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema-registry.d.ts","sourceRoot":"","sources":["../../../src/client/message/schema-registry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAsB,MAAM,SAAS,CAAC;AAE9D,qEAAqE;AACrE,MAAM,WAAW,gBAAgB;IAC/B,0DAA0D;IAC1D,EAAE,EAAE,MAAM,CAAC;IACX,gDAAgD;IAChD,OAAO,EAAE,MAAM,CAAC;IAChB,2EAA2E;IAC3E,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,0CAA0C;AAC1C,MAAM,WAAW,2BAA2B;IAC1C,wFAAwF;IACxF,OAAO,EAAE,MAAM,CAAC;IAChB,kEAAkE;IAClE,IAAI,CAAC,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC;IAC9C,uEAAuE;IACvE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,wEAAwE;IACxE,OAAO,CAAC,EAAE,OAAO,KAAK,CAAC;CACxB;AAED,+DAA+D;AAC/D,MAAM,MAAM,kBAAkB,GAAG,MAAM,GAAG,MAAM,GAAG,UAAU,CAAC;AAE9D;;;;;;;;;;;;;;;;;;GAkBG;AACH,qBAAa,oBAAoB;IAQnB,OAAO,CAAC,QAAQ,CAAC,OAAO;IAPpC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAe;IACvC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAGxB;gBAEyB,OAAO,EAAE,2BAA2B;IAQjE,OAAO,CAAC,OAAO;YAYD,OAAO;IAoBrB,mFAAmF;IAC7E,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAoBjE,oDAAoD;IAC9C,gBAAgB,CACpB,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,gBAAgB,CAAC;IAY5B;;;OAGG;IACG,cAAc,CAClB,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,EACd,UAAU,GAAE,kBAA2B,GACtC,OAAO,CAAC;QAAE,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC;IAS1B;;;OAGG;IACG,kBAAkB,CACtB,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,EACd,UAAU,GAAE,kBAA2B,GACtC,OAAO,CAAC,OAAO,CAAC;CAQpB;AAED,sCAAsC;AACtC,MAAM,WAAW,qBAAqB,CAAC,CAAC;IACtC;;;OAGG;IACH,SAAS,CAAC,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC;IAC1B;;;;OAIG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,cAAc,CAAC,CAAC,GAAG,GAAG,EACpC,MAAM,EAAE,oBAAoB,EAC5B,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,qBAAqB,CAAC,CAAC,CAAC,GACjC,UAAU,CAAC,CAAC,CAAC,CAkBf"}
@@ -0,0 +1,138 @@
1
+ import type { MessageHeaders } from "../types";
2
+ /**
3
+ * Context passed as the second argument to `SchemaLike.parse()`.
4
+ * Enables schema-registry adapters, version-aware migration, and
5
+ * header-driven parsing without coupling validators to Kafka internals.
6
+ *
7
+ * All fields are optional-friendly — validators that don't need the context
8
+ * can simply ignore the second argument.
9
+ */
10
+ export interface SchemaParseContext {
11
+ /** Topic the message was produced to / consumed from. */
12
+ topic: string;
13
+ /** Decoded message headers (envelope headers included). */
14
+ headers: MessageHeaders;
15
+ /** Value of the `x-schema-version` header, defaults to `1`. */
16
+ version: number;
17
+ }
18
+ /**
19
+ * Any validation library with a `.parse()` method.
20
+ * Works with Zod, Valibot, ArkType, or any custom validator.
21
+ *
22
+ * The optional `ctx` argument carries topic/header/version metadata so
23
+ * validators can perform schema-registry lookups or version-aware migrations.
24
+ * Existing validators that only use the first argument continue to work
25
+ * unchanged — the second argument is silently ignored.
26
+ *
27
+ * @example
28
+ * ```ts
29
+ * import { z } from 'zod';
30
+ * const schema: SchemaLike<{ id: string }> = z.object({ id: z.string() });
31
+ *
32
+ * // Context-aware validator:
33
+ * const schema: SchemaLike<MyType> = {
34
+ * parse(data, ctx) {
35
+ * const version = ctx?.version ?? 1;
36
+ * return version >= 2 ? migrateV1toV2(data) : validateV1(data);
37
+ * }
38
+ * };
39
+ * ```
40
+ */
41
+ export interface SchemaLike<T = any> {
42
+ parse(data: unknown, ctx?: SchemaParseContext): T | Promise<T>;
43
+ }
44
+ /** Infer the output type from a SchemaLike. */
45
+ export type InferSchema<S extends SchemaLike> = S extends SchemaLike<infer T> ? T : never;
46
+ /**
47
+ * A typed topic descriptor that pairs a topic name with its message type.
48
+ * Created via the `topic()` factory function.
49
+ *
50
+ * @typeParam N - The literal topic name string.
51
+ * @typeParam M - The message payload type for this topic.
52
+ */
53
+ export interface TopicDescriptor<N extends string = string, M extends Record<string, any> = Record<string, any>> {
54
+ readonly __topic: N;
55
+ /** @internal Phantom type — never has a real value at runtime. */
56
+ readonly __type: M;
57
+ /** Runtime schema validator. Present only when created via `topic().schema()`. */
58
+ readonly __schema?: SchemaLike<M>;
59
+ /**
60
+ * Partition-key extractor. Present only when created via `.key()`.
61
+ * Applied on every send through this descriptor unless an explicit
62
+ * `key` is passed in `SendOptions` / the batch item.
63
+ *
64
+ * Declared with method syntax (not a function property) so `M` stays
65
+ * bivariant — otherwise narrow descriptors would stop being assignable
66
+ * to `TopicDescriptor<string, Record<string, any>>` parameters.
67
+ */
68
+ __key?(message: M): string;
69
+ }
70
+ /**
71
+ * A `TopicDescriptor` that can still be extended with a `.key()` extractor.
72
+ * Returned by `topic().type()` and `topic().schema()` — usable directly as a
73
+ * descriptor, or chained once more to declare partition affinity.
74
+ */
75
+ export type KeyableTopicDescriptor<N extends string, M extends Record<string, any>> = TopicDescriptor<N, M> & {
76
+ /**
77
+ * Declare a partition-key extractor for this topic. The extractor runs on
78
+ * the ORIGINAL (pre-validation) payload of every message sent through this
79
+ * descriptor, so messages with the same logical key always land on the same
80
+ * partition without passing `key` at each call site.
81
+ *
82
+ * An explicit `SendOptions.key` / batch-item `key` always wins.
83
+ *
84
+ * @example
85
+ * ```ts
86
+ * const OrderCreated = topic('order.created')
87
+ * .type<{ orderId: string; amount: number }>()
88
+ * .key((m) => m.orderId);
89
+ *
90
+ * await kafka.sendMessage(OrderCreated, { orderId: '42', amount: 100 });
91
+ * // → produced with key '42'
92
+ * ```
93
+ */
94
+ key(extractor: (message: M) => string): TopicDescriptor<N, M>;
95
+ };
96
+ /**
97
+ * Define a typed topic descriptor.
98
+ *
99
+ * @example
100
+ * ```ts
101
+ * // Without schema — explicit type via .type<T>():
102
+ * const OrderCreated = topic('order.created').type<{ orderId: string; amount: number }>();
103
+ *
104
+ * // With schema — type inferred from schema:
105
+ * const OrderCreated = topic('order.created').schema(z.object({
106
+ * orderId: z.string(),
107
+ * amount: z.number(),
108
+ * }));
109
+ *
110
+ * // Use with KafkaClient:
111
+ * await kafka.sendMessage(OrderCreated, { orderId: '123', amount: 100 });
112
+ *
113
+ * // Use with @SubscribeTo:
114
+ * @SubscribeTo(OrderCreated)
115
+ * async handleOrder(msg) { ... }
116
+ * ```
117
+ */
118
+ export declare function topic<N extends string>(name: N): {
119
+ /** Provide an explicit message type without a runtime schema. */
120
+ type: <M extends Record<string, any>>() => KeyableTopicDescriptor<N, M>;
121
+ schema: <S extends SchemaLike<Record<string, any>>>(schema: S) => KeyableTopicDescriptor<N, InferSchema<S>>;
122
+ };
123
+ /**
124
+ * Build a topic-message map type from a union of TopicDescriptors.
125
+ *
126
+ * @example
127
+ * ```ts
128
+ * const OrderCreated = topic('order.created').type<{ orderId: string }>();
129
+ * const OrderCompleted = topic('order.completed').type<{ completedAt: string }>();
130
+ *
131
+ * type MyTopics = TopicsFrom<typeof OrderCreated | typeof OrderCompleted>;
132
+ * // { 'order.created': { orderId: string }; 'order.completed': { completedAt: string } }
133
+ * ```
134
+ */
135
+ export type TopicsFrom<D extends TopicDescriptor<any, any>> = {
136
+ [K in D as K["__topic"]]: K["__type"];
137
+ };
138
+ //# sourceMappingURL=topic.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"topic.d.ts","sourceRoot":"","sources":["../../../src/client/message/topic.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAE/C;;;;;;;GAOG;AACH,MAAM,WAAW,kBAAkB;IACjC,yDAAyD;IACzD,KAAK,EAAE,MAAM,CAAC;IACd,2DAA2D;IAC3D,OAAO,EAAE,cAAc,CAAC;IACxB,+DAA+D;IAC/D,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,WAAW,UAAU,CAAC,CAAC,GAAG,GAAG;IACjC,KAAK,CAAC,IAAI,EAAE,OAAO,EAAE,GAAG,CAAC,EAAE,kBAAkB,GAAG,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;CAChE;AAED,+CAA+C;AAC/C,MAAM,MAAM,WAAW,CAAC,CAAC,SAAS,UAAU,IAC1C,CAAC,SAAS,UAAU,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;AAE5C;;;;;;GAMG;AACH,MAAM,WAAW,eAAe,CAC9B,CAAC,SAAS,MAAM,GAAG,MAAM,EACzB,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC;IAEnD,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAC;IACpB,kEAAkE;IAClE,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;IACnB,kFAAkF;IAClF,QAAQ,CAAC,QAAQ,CAAC,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC;IAClC;;;;;;;;OAQG;IACH,KAAK,CAAC,CAAC,OAAO,EAAE,CAAC,GAAG,MAAM,CAAC;CAC5B;AAED;;;;GAIG;AACH,MAAM,MAAM,sBAAsB,CAChC,CAAC,SAAS,MAAM,EAChB,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,IAC3B,eAAe,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG;IAC1B;;;;;;;;;;;;;;;;;OAiBG;IACH,GAAG,CAAC,SAAS,EAAE,CAAC,OAAO,EAAE,CAAC,KAAK,MAAM,GAAG,eAAe,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;CAC/D,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,KAAK,CAAC,CAAC,SAAS,MAAM,EAAE,IAAI,EAAE,CAAC;IAE3C,iEAAiE;WAC1D,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,OAAK,sBAAsB,CAAC,CAAC,EAAE,CAAC,CAAC;aAM5D,CAAC,SAAS,UAAU,CAAC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,UACxC,CAAC,KACR,sBAAsB,CAAC,CAAC,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC;EAO/C;AAeD;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,UAAU,CAAC,CAAC,SAAS,eAAe,CAAC,GAAG,EAAE,GAAG,CAAC,IAAI;KAC3D,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC;CACtC,CAAC"}
@@ -0,0 +1,53 @@
1
+ import type { SchemaLike } from "./topic";
2
+ /**
3
+ * Options for `versionedSchema()`.
4
+ * @typeParam T - The (latest) output type produced after parsing and migration.
5
+ */
6
+ export interface VersionedSchemaOptions<T> {
7
+ /**
8
+ * Called after a message parsed with a non-latest schema version.
9
+ * Receives the parsed data, the version it was parsed with, and the latest
10
+ * registered version. Must return the data in its latest shape.
11
+ *
12
+ * When omitted, older versions are returned as parsed — callers must handle
13
+ * shape differences themselves.
14
+ */
15
+ migrate?: (data: any, fromVersion: number, latestVersion: number) => T | Promise<T>;
16
+ }
17
+ /**
18
+ * Compose per-version validators into a single `SchemaLike` that dispatches on
19
+ * the message's `x-schema-version` header (via `SchemaParseContext.version`).
20
+ *
21
+ * - Consume path: the version comes from the `x-schema-version` header
22
+ * (defaults to `1` when absent).
23
+ * - Send path: the version comes from `SendOptions.schemaVersion`
24
+ * (defaults to `1`).
25
+ * - No parse context at all (direct `.parse(data)` call): the latest
26
+ * registered version is assumed.
27
+ *
28
+ * Throws when a message carries a version with no registered schema — a
29
+ * misconfigured producer fails loudly instead of validating against the
30
+ * wrong shape.
31
+ *
32
+ * @typeParam T - The latest message shape (post-migration).
33
+ * @param versions Map of version number → validator for that version.
34
+ * @param options Optional migration hook to upgrade old shapes to the latest.
35
+ *
36
+ * @example
37
+ * ```ts
38
+ * const OrderSchema = versionedSchema<{ orderId: string; amountMinor: number }>(
39
+ * {
40
+ * 1: z.object({ orderId: z.string(), amount: z.number() }),
41
+ * 2: z.object({ orderId: z.string(), amountMinor: z.number().int() }),
42
+ * },
43
+ * {
44
+ * migrate: (data, from) =>
45
+ * from === 1 ? { orderId: data.orderId, amountMinor: Math.round(data.amount * 100) } : data,
46
+ * },
47
+ * );
48
+ *
49
+ * const OrderCreated = topic('order.created').schema(OrderSchema);
50
+ * ```
51
+ */
52
+ export declare function versionedSchema<T = any>(versions: Record<number, SchemaLike<any>>, options?: VersionedSchemaOptions<T>): SchemaLike<T>;
53
+ //# sourceMappingURL=versioned-schema.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"versioned-schema.d.ts","sourceRoot":"","sources":["../../../src/client/message/versioned-schema.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAsB,MAAM,SAAS,CAAC;AAE9D;;;GAGG;AACH,MAAM,WAAW,sBAAsB,CAAC,CAAC;IACvC;;;;;;;OAOG;IACH,OAAO,CAAC,EAAE,CACR,IAAI,EAAE,GAAG,EACT,WAAW,EAAE,MAAM,EACnB,aAAa,EAAE,MAAM,KAClB,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;CACrB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,wBAAgB,eAAe,CAAC,CAAC,GAAG,GAAG,EACrC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,GAAG,CAAC,CAAC,EACzC,OAAO,CAAC,EAAE,sBAAsB,CAAC,CAAC,CAAC,GAClC,UAAU,CAAC,CAAC,CAAC,CA6Bf"}
@@ -0,0 +1,4 @@
1
+ export * from "./outbox.types";
2
+ export * from "./outbox.store";
3
+ export * from "./outbox.relay";
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/client/outbox/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAC;AAC/B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,gBAAgB,CAAC"}
@@ -0,0 +1,90 @@
1
+ import type { TopicMapConstraint } from "../types";
2
+ import type { OutboxProducer, OutboxRelayHandle, OutboxRelayOptions, OutboxStore } from "./outbox.types";
3
+ /**
4
+ * Start a transactional-outbox relay.
5
+ *
6
+ * The outbox pattern decouples "write my business state" from "publish an event"
7
+ * so the two can never diverge: application code writes an event row into an
8
+ * outbox table **in the same DB transaction** as its business writes; this relay
9
+ * polls that table and publishes the rows to Kafka, marking them published only
10
+ * after Kafka has acked them.
11
+ *
12
+ * ## Poll loop
13
+ * Every `pollIntervalMs` the relay calls {@link OutboxStore.fetchUnpublished}
14
+ * with `batchSize`. An empty result means there is nothing to do — it waits for
15
+ * the next tick. A non-empty batch is published **entirely inside one Kafka
16
+ * transaction** (`kafka.transaction`, one `tx.send` per message), and only after
17
+ * that transaction commits does it call {@link OutboxStore.markPublished} with
18
+ * the row ids.
19
+ *
20
+ * ## Delivery guarantee: at-least-once
21
+ * If the process crashes **after** the Kafka transaction commits but **before**
22
+ * `markPublished` runs, those rows are still unpublished in the store and will be
23
+ * re-published on the next poll. This produces **duplicates**, but each duplicate
24
+ * carries the **same** `x-event-id` (when {@link OutboxMessage.eventId} is set on
25
+ * the row), so consumers can deduplicate — either via this library's Lamport-clock
26
+ * deduplication or an application-level idempotency check keyed on the event id.
27
+ * Persist a stable `eventId` on each outbox row to make this work.
28
+ *
29
+ * ## Failure handling
30
+ * The loop never dies and never leaks an unhandled rejection:
31
+ * - If the publishing transaction throws, `onError` fires, the batch is **not**
32
+ * marked published, and it is retried on the next tick.
33
+ * - If the store throws (either `fetchUnpublished` or `markPublished`), same
34
+ * behaviour: `onError`, no marking, retried next tick.
35
+ *
36
+ * Note the one asymmetry: if `markPublished` throws *after* a successful Kafka
37
+ * commit, the batch is re-published next tick — an intentional consequence of
38
+ * the at-least-once guarantee above.
39
+ *
40
+ * ## Concurrency
41
+ * Iterations never overlap. If an iteration runs longer than `pollIntervalMs`,
42
+ * intervening ticks are skipped (a guard flag) rather than stacked.
43
+ *
44
+ * ## Shutdown
45
+ * `handle.stop()` clears the timer and awaits any in-flight iteration before
46
+ * resolving, so no publish is left half-done. It is idempotent.
47
+ *
48
+ * @param kafka Any producer exposing `transaction()` — a `KafkaClient<T>` or
49
+ * `IKafkaProducer<T>`. Its producer must already be connected.
50
+ * @param store Your DB-backed {@link OutboxStore} implementation.
51
+ * @param options Tuning and observability — see {@link OutboxRelayOptions}.
52
+ *
53
+ * @example
54
+ * ```ts
55
+ * // Pseudo-Postgres outbox store.
56
+ * const store: OutboxStore = {
57
+ * async fetchUnpublished(limit) {
58
+ * const { rows } = await pool.query(
59
+ * `SELECT id, topic, payload, key, correlation_id AS "correlationId",
60
+ * event_id AS "eventId", headers
61
+ * FROM outbox
62
+ * WHERE published_at IS NULL
63
+ * ORDER BY created_at ASC
64
+ * LIMIT $1`,
65
+ * [limit],
66
+ * );
67
+ * return rows;
68
+ * },
69
+ * async markPublished(ids) {
70
+ * await pool.query(
71
+ * `UPDATE outbox SET published_at = now() WHERE id = ANY($1)`,
72
+ * [ids],
73
+ * );
74
+ * },
75
+ * };
76
+ *
77
+ * await kafka.connectProducer();
78
+ * const relay = startOutboxRelay(kafka, store, {
79
+ * pollIntervalMs: 500,
80
+ * batchSize: 200,
81
+ * onPublished: (n) => metrics.increment('outbox.published', n),
82
+ * });
83
+ *
84
+ * // On shutdown:
85
+ * await relay.stop();
86
+ * await kafka.disconnect();
87
+ * ```
88
+ */
89
+ export declare function startOutboxRelay<T extends TopicMapConstraint<T>>(kafka: OutboxProducer<T>, store: OutboxStore, options?: OutboxRelayOptions): OutboxRelayHandle;
90
+ //# sourceMappingURL=outbox.relay.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"outbox.relay.d.ts","sourceRoot":"","sources":["../../../src/client/outbox/outbox.relay.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC;AACnD,OAAO,KAAK,EAEV,cAAc,EACd,iBAAiB,EACjB,kBAAkB,EAClB,WAAW,EACZ,MAAM,gBAAgB,CAAC;AAOxB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqFG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,SAAS,kBAAkB,CAAC,CAAC,CAAC,EAC9D,KAAK,EAAE,cAAc,CAAC,CAAC,CAAC,EACxB,KAAK,EAAE,WAAW,EAClB,OAAO,GAAE,kBAAuB,GAC/B,iBAAiB,CAwEnB"}
@@ -0,0 +1,42 @@
1
+ import type { OutboxMessage, OutboxStore } from "./outbox.types";
2
+ /**
3
+ * In-memory reference implementation of {@link OutboxStore}.
4
+ *
5
+ * Intended for tests and as executable documentation of the expected
6
+ * {@link OutboxStore} semantics — **not** for production use: it provides no
7
+ * durability, so a process restart loses all pending rows and the "same DB
8
+ * transaction as the business write" guarantee (the whole point of the outbox
9
+ * pattern) does not hold. Back a real relay with a persistent store (Postgres,
10
+ * MySQL, …) implementing the same interface.
11
+ *
12
+ * Semantics mirrored:
13
+ * - {@link fetchUnpublished} returns unpublished rows **oldest first** (insertion
14
+ * order), capped at `limit`.
15
+ * - {@link markPublished} is idempotent — unknown ids are ignored.
16
+ *
17
+ * @example
18
+ * ```ts
19
+ * const store = new InMemoryOutboxStore();
20
+ * store.add({ id: '1', topic: 'orders.created', payload: { orderId: 'o1' } });
21
+ *
22
+ * const handle = startOutboxRelay(kafka, store);
23
+ * // ... later
24
+ * await handle.stop();
25
+ * ```
26
+ */
27
+ export declare class InMemoryOutboxStore implements OutboxStore {
28
+ /** Insertion-ordered rows. `published` flips to true after `markPublished`. */
29
+ private readonly rows;
30
+ /**
31
+ * Append a message to the outbox. In a real store this INSERT would run inside
32
+ * the same DB transaction as the corresponding business write.
33
+ */
34
+ add(message: OutboxMessage): void;
35
+ fetchUnpublished(limit: number): Promise<OutboxMessage[]>;
36
+ markPublished(ids: string[]): Promise<void>;
37
+ /** Test helper: count of rows not yet marked published. */
38
+ get pendingCount(): number;
39
+ /** Test helper: count of rows marked published. */
40
+ get publishedCount(): number;
41
+ }
42
+ //# sourceMappingURL=outbox.store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"outbox.store.d.ts","sourceRoot":"","sources":["../../../src/client/outbox/outbox.store.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAEjE;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,qBAAa,mBAAoB,YAAW,WAAW;IACrD,+EAA+E;IAC/E,OAAO,CAAC,QAAQ,CAAC,IAAI,CAChB;IAEL;;;OAGG;IACH,GAAG,CAAC,OAAO,EAAE,aAAa,GAAG,IAAI;IAI3B,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,EAAE,CAAC;IAUzD,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAOjD,2DAA2D;IAC3D,IAAI,YAAY,IAAI,MAAM,CAEzB;IAED,mDAAmD;IACnD,IAAI,cAAc,IAAI,MAAM,CAE3B;CACF"}