youeduc-sdk-messaging 0.0.0 → 0.5.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 (81) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +218 -0
  3. package/dist/admin.d.ts +61 -0
  4. package/dist/admin.js +143 -0
  5. package/dist/admin.js.map +1 -0
  6. package/dist/config.d.ts +74 -0
  7. package/dist/config.js +128 -0
  8. package/dist/config.js.map +1 -0
  9. package/dist/consumer-client.d.ts +155 -0
  10. package/dist/consumer-client.js +299 -0
  11. package/dist/consumer-client.js.map +1 -0
  12. package/dist/consumer.d.ts +156 -0
  13. package/dist/consumer.js +1228 -0
  14. package/dist/consumer.js.map +1 -0
  15. package/dist/contracts/index.d.ts +16 -0
  16. package/dist/contracts/index.js +42 -0
  17. package/dist/contracts/index.js.map +1 -0
  18. package/dist/contracts/schemas.d.ts +570 -0
  19. package/dist/contracts/schemas.js +902 -0
  20. package/dist/contracts/schemas.js.map +1 -0
  21. package/dist/contracts/usuarios.d.ts +163 -0
  22. package/dist/contracts/usuarios.js +5 -0
  23. package/dist/contracts/usuarios.js.map +1 -0
  24. package/dist/dedup.d.ts +29 -0
  25. package/dist/dedup.js +65 -0
  26. package/dist/dedup.js.map +1 -0
  27. package/dist/dlq.d.ts +161 -0
  28. package/dist/dlq.js +341 -0
  29. package/dist/dlq.js.map +1 -0
  30. package/dist/errors.d.ts +72 -0
  31. package/dist/errors.js +95 -0
  32. package/dist/errors.js.map +1 -0
  33. package/dist/headers.d.ts +92 -0
  34. package/dist/headers.js +144 -0
  35. package/dist/headers.js.map +1 -0
  36. package/dist/index.d.ts +30 -0
  37. package/dist/index.js +32 -0
  38. package/dist/index.js.map +1 -0
  39. package/dist/integrations/redis.d.ts +118 -0
  40. package/dist/integrations/redis.js +272 -0
  41. package/dist/integrations/redis.js.map +1 -0
  42. package/dist/integrations/runtime.d.ts +232 -0
  43. package/dist/integrations/runtime.js +554 -0
  44. package/dist/integrations/runtime.js.map +1 -0
  45. package/dist/logger.d.ts +37 -0
  46. package/dist/logger.js +49 -0
  47. package/dist/logger.js.map +1 -0
  48. package/dist/messaging.d.ts +145 -0
  49. package/dist/messaging.js +164 -0
  50. package/dist/messaging.js.map +1 -0
  51. package/dist/naming.d.ts +64 -0
  52. package/dist/naming.js +167 -0
  53. package/dist/naming.js.map +1 -0
  54. package/dist/payload.d.ts +8 -0
  55. package/dist/payload.js +32 -0
  56. package/dist/payload.js.map +1 -0
  57. package/dist/publisher.d.ts +50 -0
  58. package/dist/publisher.js +199 -0
  59. package/dist/publisher.js.map +1 -0
  60. package/dist/retry.d.ts +24 -0
  61. package/dist/retry.js +42 -0
  62. package/dist/retry.js.map +1 -0
  63. package/dist/schema.d.ts +83 -0
  64. package/dist/schema.js +676 -0
  65. package/dist/schema.js.map +1 -0
  66. package/dist/telemetry.d.ts +52 -0
  67. package/dist/telemetry.js +221 -0
  68. package/dist/telemetry.js.map +1 -0
  69. package/dist/transport.d.ts +130 -0
  70. package/dist/transport.js +283 -0
  71. package/dist/transport.js.map +1 -0
  72. package/dist/types.d.ts +148 -0
  73. package/dist/types.js +35 -0
  74. package/dist/types.js.map +1 -0
  75. package/dist/util.d.ts +38 -0
  76. package/dist/util.js +112 -0
  77. package/dist/util.js.map +1 -0
  78. package/dist/w3c.d.ts +16 -0
  79. package/dist/w3c.js +119 -0
  80. package/dist/w3c.js.map +1 -0
  81. package/package.json +74 -1
package/dist/dlq.js ADDED
@@ -0,0 +1,341 @@
1
+ /**
2
+ * Replay of a consumer group's DLQ (spec §9; Python `dlq.py`).
3
+ *
4
+ * The message goes back through the group's **first current retry topic**, with the retry/DLQ
5
+ * state removed from the headers (`x-retry-count`, `x-retry-due-at`, `x-dlq-reason`,
6
+ * `x-last-error`, `x-last-error-type`). Without `x-retry-due-at` it is due immediately and the
7
+ * group's consumer processes it with `retryCount = 0`. Only that group receives it: the shared
8
+ * main topic is never touched.
9
+ *
10
+ * Deduplication does not get in the way: the consumer never marks a key on a DLQ outcome.
11
+ *
12
+ * With `resourcePrefix` (spec §2.7) the DLQ, the target and the reader's group id use the prefixed
13
+ * names (`hmg.enrollment.events.v1.learning-worker.dlq`, `hmg.learning-worker.dlq-replay`).
14
+ *
15
+ * Progress: the reader uses its own group id `{group}.dlq-replay` and commits `offset + 1` of each
16
+ * record **after** the send was acknowledged (synchronous commit: a failure propagates). A new run
17
+ * continues where the previous one stopped. The commit is a position: records skipped (outside
18
+ * `reasons`) before a replayed record stay behind in that group id.
19
+ *
20
+ * The end offsets are captured at the start: what comes back to the DLQ during the replay (a new
21
+ * failure) is not read again in the same run.
22
+ */
23
+ import { partitionKey } from './consumer-client.js';
24
+ import * as hdr from './headers.js';
25
+ import { defaultLogger } from './logger.js';
26
+ import * as naming from './naming.js';
27
+ import { RetryPolicy } from './retry.js';
28
+ import { producerClientConfig, toProducerHeaders } from './transport.js';
29
+ import { DLQ_REASONS } from './types.js';
30
+ import { pyRepr } from './util.js';
31
+ const DEFAULT_RETRY_POLICY = new RetryPolicy();
32
+ const ALL_REASONS = new Set(DLQ_REASONS);
33
+ const DEFAULT_EXCLUDED = new Set(['invalid_payload']);
34
+ const STRIPPED_HEADERS = new Set([
35
+ hdr.RETRY_COUNT,
36
+ hdr.RETRY_DUE_AT,
37
+ hdr.DLQ_REASON,
38
+ hdr.LAST_ERROR,
39
+ hdr.LAST_ERROR_TYPE,
40
+ ]);
41
+ const REPLAY_GROUP_SUFFIX = '.dlq-replay';
42
+ /** Safe characters for a group.id (same alphabet as topic names). */
43
+ const GROUP_ID_RE = /^[a-zA-Z0-9._-]{1,249}$/;
44
+ const POLL_TIMEOUT_MS = 500;
45
+ const MAX_POLL_RECORDS = 500;
46
+ /** group.id of the replay reader: `{group}.dlq-replay` (with a prefix, `{prefix}.{group}.dlq-replay`). */
47
+ export function replayGroupId(group, options) {
48
+ const groupId = naming.consumerGroup(group, options) + REPLAY_GROUP_SUFFIX;
49
+ if (!GROUP_ID_RE.test(groupId))
50
+ throw new TypeError(`invalid replay group id ${pyRepr(groupId)}`);
51
+ return groupId;
52
+ }
53
+ /** Headers of the replayed record: no retry/DLQ state, everything else preserved. */
54
+ export function replayHeaders(headers) {
55
+ const result = {};
56
+ for (const [name, value] of Object.entries(headers)) {
57
+ if (!STRIPPED_HEADERS.has(name))
58
+ result[name] = value;
59
+ }
60
+ return result;
61
+ }
62
+ /** `null` = every reason except `invalid_payload` (includes records without a reason). */
63
+ function selectedReasons(reasons) {
64
+ if (reasons === null || reasons === undefined)
65
+ return null;
66
+ if (typeof reasons === 'string') {
67
+ throw new TypeError("'reasons' must be an iterable of DLQ reasons, not a string");
68
+ }
69
+ const selected = new Set(reasons);
70
+ if (selected.size === 0)
71
+ throw new TypeError("'reasons' must not be empty (use null for the default)");
72
+ const unknown = [...selected].filter((reason) => !ALL_REASONS.has(reason)).sort();
73
+ if (unknown.length > 0) {
74
+ throw new TypeError(`unknown DLQ reason(s) [${unknown.map((r) => pyRepr(String(r))).join(', ')}];` +
75
+ ` valid: [${[...ALL_REASONS].sort().map(pyRepr).join(', ')}]`);
76
+ }
77
+ return selected;
78
+ }
79
+ function isSelected(reason, selected) {
80
+ if (selected === null)
81
+ return reason === undefined || !DEFAULT_EXCLUDED.has(reason);
82
+ return reason !== undefined && selected.has(reason);
83
+ }
84
+ /**
85
+ * Resends DLQ messages of the group to its first retry topic.
86
+ *
87
+ * `dryRun: true` (default) only counts what would be resent: nothing is sent nor committed.
88
+ * `maxMessages` limits the resends (or `wouldReplay`) of this run. A send failure propagates;
89
+ * that record is not committed.
90
+ */
91
+ export async function replayDlq(config, options) {
92
+ const prefix = { resourcePrefix: options.resourcePrefix };
93
+ const main = naming.topic(options.domain, options.version, prefix);
94
+ const dlq = naming.dlqTopic(main, options.group);
95
+ const groupId = replayGroupId(options.group, prefix);
96
+ const retryPolicy = options.retryPolicy ?? DEFAULT_RETRY_POLICY;
97
+ const firstDelay = retryPolicy.delaysMs[0];
98
+ if (firstDelay === undefined) {
99
+ throw new TypeError('retryPolicy has no delays: there is no retry topic to replay into');
100
+ }
101
+ const target = naming.retryTopic(main, options.group, firstDelay);
102
+ const selected = selectedReasons(options.reasons);
103
+ const maxMessages = options.maxMessages ?? null;
104
+ if (maxMessages !== null &&
105
+ (typeof maxMessages !== 'number' || !Number.isInteger(maxMessages) || maxMessages < 1)) {
106
+ throw new RangeError(`'maxMessages' must be an integer >= 1; got ${String(maxMessages)}`);
107
+ }
108
+ const dryRun = options.dryRun ?? true;
109
+ const logger = options.logger ?? defaultLogger();
110
+ const consumer = await (options.consumerFactory ?? createConfluentReplayConsumer)({
111
+ ...config.clientConfig(),
112
+ 'group.id': groupId,
113
+ 'enable.auto.commit': false,
114
+ 'enable.auto.offset.store': false,
115
+ 'auto.offset.reset': 'earliest',
116
+ });
117
+ // Same producer settings as KafkaProducerSender (partitioner, idempotence, acks, size limit, §11).
118
+ const producer = await (options.producerFactory ?? createConfluentReplayProducer)(producerClientConfig(config));
119
+ let replayed = 0;
120
+ let skipped = 0;
121
+ let wouldReplay = 0;
122
+ const logCtx = { dlq_topic: dlq, target_topic: target, group_id: groupId, dry_run: dryRun };
123
+ logger.info('dlq_replay_started', {
124
+ messaging: {
125
+ ...logCtx,
126
+ reasons: selected === null ? null : [...selected].sort(),
127
+ max_messages: maxMessages,
128
+ },
129
+ });
130
+ const limitReached = () => maxMessages !== null && replayed + wouldReplay >= maxMessages;
131
+ try {
132
+ await producer.connect();
133
+ await consumer.connect();
134
+ // Fails when the DLQ does not exist.
135
+ const partitionIds = [...(await producer.partitionsFor(dlq))].sort((a, b) => a - b);
136
+ const partitions = partitionIds.map((partition) => ({ topic: dlq, partition }));
137
+ consumer.assign(partitions);
138
+ const ends = await consumer.endOffsets(partitions);
139
+ const pending = new Map();
140
+ for (const [index, tp] of partitions.entries()) {
141
+ const end = ends[index] ?? 0;
142
+ if ((await consumer.position(tp)) < end)
143
+ pending.set(partitionKey(tp), { tp, end });
144
+ else
145
+ consumer.pause([tp]);
146
+ }
147
+ while (pending.size > 0 && !limitReached()) {
148
+ const records = await consumer.poll({
149
+ partitions: [...pending.values()].map((entry) => entry.tp),
150
+ timeoutMs: POLL_TIMEOUT_MS,
151
+ });
152
+ const byPartition = new Map();
153
+ for (const record of records) {
154
+ const key = partitionKey(record);
155
+ const list = byPartition.get(key);
156
+ if (list === undefined)
157
+ byPartition.set(key, [record]);
158
+ else
159
+ list.push(record);
160
+ }
161
+ for (const [key, list] of byPartition) {
162
+ const entry = pending.get(key);
163
+ if (entry === undefined)
164
+ continue;
165
+ for (const record of [...list].sort((a, b) => a.offset - b.offset)) {
166
+ if (record.offset >= entry.end || limitReached())
167
+ break;
168
+ const headers = hdr.decode(record.headers);
169
+ const reason = headers[hdr.DLQ_REASON];
170
+ const fields = {
171
+ ...logCtx,
172
+ partition: record.partition,
173
+ offset: record.offset,
174
+ message_id: headers[hdr.MESSAGE_ID] ?? '',
175
+ event_type: headers[hdr.EVENT_TYPE] ?? '',
176
+ dlq_reason: reason ?? null,
177
+ };
178
+ if (record.value === null || !isSelected(reason, selected)) {
179
+ skipped += 1;
180
+ logger.info('dlq_record_skipped', {
181
+ messaging: fields,
182
+ skip_cause: record.value === null ? 'null_value' : 'reason_not_selected',
183
+ });
184
+ continue;
185
+ }
186
+ if (dryRun) {
187
+ wouldReplay += 1;
188
+ logger.info('dlq_record_replayed', { messaging: fields });
189
+ continue;
190
+ }
191
+ await producer.send(target, record.value, {
192
+ key: record.key,
193
+ headers: hdr.encode(replayHeaders(headers)),
194
+ });
195
+ // Only after the ack: a crash here resends at most this record.
196
+ await consumer.commit([
197
+ { topic: record.topic, partition: record.partition, offset: record.offset + 1 },
198
+ ]);
199
+ replayed += 1;
200
+ logger.info('dlq_record_replayed', { messaging: fields });
201
+ }
202
+ }
203
+ // End of the partition by position (covers offset gaps, e.g. compaction).
204
+ for (const [key, entry] of [...pending]) {
205
+ if ((await consumer.position(entry.tp)) >= entry.end) {
206
+ pending.delete(key);
207
+ consumer.pause([entry.tp]);
208
+ }
209
+ }
210
+ }
211
+ }
212
+ finally {
213
+ try {
214
+ await consumer.disconnect();
215
+ }
216
+ finally {
217
+ await producer.disconnect();
218
+ }
219
+ }
220
+ const report = Object.freeze({ targetTopic: target, replayed, skipped, wouldReplay });
221
+ logger.info('dlq_replay_finished', {
222
+ messaging: logCtx,
223
+ replayed: report.replayed,
224
+ skipped: report.skipped,
225
+ would_replay: report.wouldReplay,
226
+ });
227
+ return report;
228
+ }
229
+ // ------------------------------------------------------------------------------ default clients
230
+ const OFFSET_INVALID = -1001;
231
+ const TIMEOUT_MS = 10_000;
232
+ function promisify(fn) {
233
+ return new Promise((resolve, reject) => {
234
+ try {
235
+ fn((error, value) => (error ? reject(error) : resolve(value)));
236
+ }
237
+ catch (error) {
238
+ reject(error);
239
+ }
240
+ });
241
+ }
242
+ /** DLQ reader over the callback `KafkaConsumer` (manual assignment, synchronous commits). */
243
+ export class ConfluentReplayConsumer {
244
+ #raw;
245
+ constructor(raw) {
246
+ this.#raw = raw;
247
+ }
248
+ connect() {
249
+ return new Promise((resolve, reject) => {
250
+ this.#raw.connect(null, (error) => (error ? reject(error) : resolve()));
251
+ });
252
+ }
253
+ assign(partitions) {
254
+ this.#raw.assign(partitions.map((tp) => ({ topic: tp.topic, partition: tp.partition })));
255
+ }
256
+ async endOffsets(partitions) {
257
+ return Promise.all(partitions.map(async (tp) => {
258
+ const marks = await promisify((cb) => this.#raw.queryWatermarkOffsets(tp.topic, tp.partition, TIMEOUT_MS, cb));
259
+ return marks.highOffset;
260
+ }));
261
+ }
262
+ async position(partition) {
263
+ const current = this.#raw.position([{ topic: partition.topic, partition: partition.partition }])[0]
264
+ ?.offset;
265
+ if (typeof current === 'number' && current >= 0)
266
+ return current;
267
+ // Nothing fetched yet: the start is the committed offset (else, or when out of range, earliest).
268
+ const [committed] = await promisify((cb) => this.#raw.committed([{ topic: partition.topic, partition: partition.partition }], TIMEOUT_MS, cb));
269
+ const marks = await promisify((cb) => this.#raw.queryWatermarkOffsets(partition.topic, partition.partition, TIMEOUT_MS, cb));
270
+ const start = committed?.offset ?? OFFSET_INVALID;
271
+ return start >= marks.lowOffset ? start : marks.lowOffset;
272
+ }
273
+ pause(partitions) {
274
+ this.#raw.pause(partitions.map((tp) => ({ topic: tp.topic, partition: tp.partition })));
275
+ }
276
+ async poll(options) {
277
+ const wanted = new Set(options.partitions.map(partitionKey));
278
+ this.#raw.setDefaultConsumeTimeout(options.timeoutMs);
279
+ const messages = await promisify((cb) => this.#raw.consume(MAX_POLL_RECORDS, cb));
280
+ return (messages ?? [])
281
+ .filter((message) => wanted.has(partitionKey(message)))
282
+ .map((message) => {
283
+ const headers = [];
284
+ for (const header of message.headers ?? []) {
285
+ for (const [name, value] of Object.entries(header))
286
+ headers.push([name, value]);
287
+ }
288
+ const key = message.key;
289
+ return {
290
+ topic: message.topic,
291
+ partition: message.partition,
292
+ offset: message.offset,
293
+ key: key === null || key === undefined ? null : typeof key === 'string' ? Buffer.from(key) : key,
294
+ value: message.value ?? null,
295
+ headers,
296
+ };
297
+ });
298
+ }
299
+ async commit(offsets) {
300
+ this.#raw.commitSync(offsets.map((o) => ({ topic: o.topic, partition: o.partition, offset: o.offset })));
301
+ }
302
+ async disconnect() {
303
+ if (!this.#raw.isConnected())
304
+ return;
305
+ await new Promise((resolve) => {
306
+ this.#raw.disconnect(() => resolve());
307
+ });
308
+ }
309
+ }
310
+ /** Default reader: the callback `KafkaConsumer` of `@confluentinc/kafka-javascript`. */
311
+ export const createConfluentReplayConsumer = async (config) => {
312
+ const kafka = (await import('@confluentinc/kafka-javascript')).default;
313
+ return new ConfluentReplayConsumer(new kafka.KafkaConsumer(config));
314
+ };
315
+ /** Default producer: idempotent KafkaJS producer (acks=all); partitions from its metadata. */
316
+ export const createConfluentReplayProducer = async (config) => {
317
+ const { KafkaJS } = (await import('@confluentinc/kafka-javascript')).default;
318
+ const producer = new KafkaJS.Kafka({}).producer(config);
319
+ return {
320
+ connect: () => producer.connect(),
321
+ disconnect: () => producer.disconnect(),
322
+ async partitionsFor(topic) {
323
+ const admin = producer.dependentAdmin();
324
+ await admin.connect();
325
+ try {
326
+ const [metadata] = await admin.fetchTopicMetadata({ topics: [topic], timeout: TIMEOUT_MS });
327
+ return (metadata?.partitions ?? []).map((p) => p.partitionId);
328
+ }
329
+ finally {
330
+ await admin.disconnect();
331
+ }
332
+ },
333
+ async send(topic, value, options) {
334
+ await producer.send({
335
+ topic,
336
+ messages: [{ key: options.key, value, headers: toProducerHeaders(options.headers) }],
337
+ });
338
+ },
339
+ };
340
+ };
341
+ //# sourceMappingURL=dlq.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dlq.js","sourceRoot":"","sources":["../src/dlq.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,72 @@
1
+ /**
2
+ * SDK errors. Same names and messages as the Python SDK (`exceptions.py`, plus the errors that
3
+ * Python defines in `consumer.py` and `integrations/redis.py`).
4
+ *
5
+ * Every class sets `name` to its own class name, so `error.name` (and the `x-last-error-type`
6
+ * header) matches Python's `type(exc).__name__`.
7
+ */
8
+ /** Base of every SDK error. */
9
+ export declare class MessagingError extends Error {
10
+ constructor(message?: string, options?: ErrorOptions);
11
+ }
12
+ /** The operation requires a started component (`start()`) that was not stopped yet. */
13
+ export declare class NotStartedError extends MessagingError {
14
+ }
15
+ /** Thrown by a handler to flag a non-recoverable error: the message goes straight to the DLQ. */
16
+ export declare class PermanentProcessingError extends MessagingError {
17
+ }
18
+ /**
19
+ * Payload rejected by the JSON Schema (or not serializable as JSON, or the schema itself is
20
+ * invalid). `field` is a JSON pointer (`""` = root); `reason` never contains payload values.
21
+ */
22
+ export declare class SchemaValidationError extends MessagingError {
23
+ readonly field: string;
24
+ readonly reason: string;
25
+ constructor(field: string, reason: string);
26
+ }
27
+ /** No schema for `{domain}/{event}/{version}.json` (`event` is the slug, `student-enrolled`). */
28
+ export declare class SchemaNotFoundError extends MessagingError {
29
+ readonly domain: string;
30
+ readonly event: string;
31
+ readonly version: string;
32
+ constructor(domain: string, event: string, version: string);
33
+ }
34
+ /**
35
+ * The broker did not acknowledge the send (acks=all) within the timeout, or the client failed.
36
+ *
37
+ * `retriable === false` flags a deterministic error (message too large, not authorized,
38
+ * invalid topic): repeating the same send will not work. A timeout (`retriable === true`) does
39
+ * not guarantee that the message was not written.
40
+ */
41
+ export declare class PublishError extends MessagingError {
42
+ readonly topic: string;
43
+ readonly reason: string;
44
+ readonly retriable: boolean;
45
+ constructor(topic: string, reason: string, options?: {
46
+ retriable?: boolean;
47
+ cause?: unknown;
48
+ });
49
+ }
50
+ /** Payload missing, not UTF-8 JSON or not a JSON object. The message never carries payload values. */
51
+ export declare class InvalidPayloadError extends MessagingError {
52
+ }
53
+ /** The handler itself ended cancelled/aborted (without the consumer cancelling it). */
54
+ export declare class HandlerCancelledError extends MessagingError {
55
+ constructor(message?: string, options?: ErrorOptions);
56
+ }
57
+ /** Misconfigured handler (could not be called, did not return a promise): goes to the DLQ. */
58
+ export declare class InvalidHandlerError extends PermanentProcessingError {
59
+ }
60
+ /**
61
+ * The deduplication store did not answer in time or failed. The message never contains the
62
+ * dedup key (it may be PII); the original error is kept in `cause`.
63
+ */
64
+ export declare class DedupUnavailableError extends MessagingError {
65
+ readonly operation: string;
66
+ readonly namespace: string;
67
+ readonly group: string;
68
+ readonly reason: string;
69
+ constructor(operation: string, namespace: string, group: string, reason: string, options?: {
70
+ cause?: unknown;
71
+ });
72
+ }
package/dist/errors.js ADDED
@@ -0,0 +1,95 @@
1
+ /**
2
+ * SDK errors. Same names and messages as the Python SDK (`exceptions.py`, plus the errors that
3
+ * Python defines in `consumer.py` and `integrations/redis.py`).
4
+ *
5
+ * Every class sets `name` to its own class name, so `error.name` (and the `x-last-error-type`
6
+ * header) matches Python's `type(exc).__name__`.
7
+ */
8
+ import { pyRepr } from './util.js';
9
+ /** Base of every SDK error. */
10
+ export class MessagingError extends Error {
11
+ constructor(message, options) {
12
+ super(message, options);
13
+ this.name = new.target.name;
14
+ }
15
+ }
16
+ /** The operation requires a started component (`start()`) that was not stopped yet. */
17
+ export class NotStartedError extends MessagingError {
18
+ }
19
+ /** Thrown by a handler to flag a non-recoverable error: the message goes straight to the DLQ. */
20
+ export class PermanentProcessingError extends MessagingError {
21
+ }
22
+ /**
23
+ * Payload rejected by the JSON Schema (or not serializable as JSON, or the schema itself is
24
+ * invalid). `field` is a JSON pointer (`""` = root); `reason` never contains payload values.
25
+ */
26
+ export class SchemaValidationError extends MessagingError {
27
+ field;
28
+ reason;
29
+ constructor(field, reason) {
30
+ const location = field ? ` at ${pyRepr(field)}` : '';
31
+ super(`schema validation error${location}: ${reason}`);
32
+ this.field = field;
33
+ this.reason = reason;
34
+ }
35
+ }
36
+ /** No schema for `{domain}/{event}/{version}.json` (`event` is the slug, `student-enrolled`). */
37
+ export class SchemaNotFoundError extends MessagingError {
38
+ domain;
39
+ event;
40
+ version;
41
+ constructor(domain, event, version) {
42
+ super(`schema not found: ${domain}/${event}/${version}.json`);
43
+ this.domain = domain;
44
+ this.event = event;
45
+ this.version = version;
46
+ }
47
+ }
48
+ /**
49
+ * The broker did not acknowledge the send (acks=all) within the timeout, or the client failed.
50
+ *
51
+ * `retriable === false` flags a deterministic error (message too large, not authorized,
52
+ * invalid topic): repeating the same send will not work. A timeout (`retriable === true`) does
53
+ * not guarantee that the message was not written.
54
+ */
55
+ export class PublishError extends MessagingError {
56
+ topic;
57
+ reason;
58
+ retriable;
59
+ constructor(topic, reason, options = {}) {
60
+ super(`failed to publish to topic ${pyRepr(topic)}: ${reason}`, options.cause === undefined ? undefined : { cause: options.cause });
61
+ this.topic = topic;
62
+ this.reason = reason;
63
+ this.retriable = options.retriable ?? true;
64
+ }
65
+ }
66
+ /** Payload missing, not UTF-8 JSON or not a JSON object. The message never carries payload values. */
67
+ export class InvalidPayloadError extends MessagingError {
68
+ }
69
+ /** The handler itself ended cancelled/aborted (without the consumer cancelling it). */
70
+ export class HandlerCancelledError extends MessagingError {
71
+ constructor(message = 'handler task was cancelled', options) {
72
+ super(message, options);
73
+ }
74
+ }
75
+ /** Misconfigured handler (could not be called, did not return a promise): goes to the DLQ. */
76
+ export class InvalidHandlerError extends PermanentProcessingError {
77
+ }
78
+ /**
79
+ * The deduplication store did not answer in time or failed. The message never contains the
80
+ * dedup key (it may be PII); the original error is kept in `cause`.
81
+ */
82
+ export class DedupUnavailableError extends MessagingError {
83
+ operation;
84
+ namespace;
85
+ group;
86
+ reason;
87
+ constructor(operation, namespace, group, reason, options) {
88
+ super(`dedup store unavailable: ${operation} failed (namespace=${pyRepr(namespace)}, group=${pyRepr(group)}): ${reason}`, options?.cause === undefined ? undefined : { cause: options.cause });
89
+ this.operation = operation;
90
+ this.namespace = namespace;
91
+ this.group = group;
92
+ this.reason = reason;
93
+ }
94
+ }
95
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AAEnC,+BAA+B;AAC/B,MAAM,OAAO,cAAe,SAAQ,KAAK;IACvC,YAAY,OAAgB,EAAE,OAAsB;QAClD,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QACxB,IAAI,CAAC,IAAI,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC;IAC9B,CAAC;CACF;AAED,uFAAuF;AACvF,MAAM,OAAO,eAAgB,SAAQ,cAAc;CAAG;AAEtD,iGAAiG;AACjG,MAAM,OAAO,wBAAyB,SAAQ,cAAc;CAAG;AAE/D;;;GAGG;AACH,MAAM,OAAO,qBAAsB,SAAQ,cAAc;IAC9C,KAAK,CAAS;IACd,MAAM,CAAS;IAExB,YAAY,KAAa,EAAE,MAAc;QACvC,MAAM,QAAQ,GAAG,KAAK,CAAC,CAAC,CAAC,OAAO,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACrD,KAAK,CAAC,0BAA0B,QAAQ,KAAK,MAAM,EAAE,CAAC,CAAC;QACvD,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,CAAC;CACF;AAED,iGAAiG;AACjG,MAAM,OAAO,mBAAoB,SAAQ,cAAc;IAC5C,MAAM,CAAS;IACf,KAAK,CAAS;IACd,OAAO,CAAS;IAEzB,YAAY,MAAc,EAAE,KAAa,EAAE,OAAe;QACxD,KAAK,CAAC,qBAAqB,MAAM,IAAI,KAAK,IAAI,OAAO,OAAO,CAAC,CAAC;QAC9D,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;IACzB,CAAC;CACF;AAED;;;;;;GAMG;AACH,MAAM,OAAO,YAAa,SAAQ,cAAc;IACrC,KAAK,CAAS;IACd,MAAM,CAAS;IACf,SAAS,CAAU;IAE5B,YAAY,KAAa,EAAE,MAAc,EAAE,OAAO,GAA6C,EAAE;QAC/F,KAAK,CACH,8BAA8B,MAAM,CAAC,KAAK,CAAC,KAAK,MAAM,EAAE,EACxD,OAAO,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,CACnE,CAAC;QACF,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,SAAS,GAAG,OAAO,CAAC,SAAS,IAAI,IAAI,CAAC;IAC7C,CAAC;CACF;AAED,sGAAsG;AACtG,MAAM,OAAO,mBAAoB,SAAQ,cAAc;CAAG;AAE1D,uFAAuF;AACvF,MAAM,OAAO,qBAAsB,SAAQ,cAAc;IACvD,YAAY,OAAO,GAAG,4BAA4B,EAAE,OAAsB;QACxE,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IAC1B,CAAC;CACF;AAED,8FAA8F;AAC9F,MAAM,OAAO,mBAAoB,SAAQ,wBAAwB;CAAG;AAEpE;;;GAGG;AACH,MAAM,OAAO,qBAAsB,SAAQ,cAAc;IAC9C,SAAS,CAAS;IAClB,SAAS,CAAS;IAClB,KAAK,CAAS;IACd,MAAM,CAAS;IAExB,YACE,SAAiB,EACjB,SAAiB,EACjB,KAAa,EACb,MAAc,EACd,OAA6B;QAE7B,KAAK,CACH,4BAA4B,SAAS,sBAAsB,MAAM,CAAC,SAAS,CAAC,WAAW,MAAM,CAAC,KAAK,CAAC,MAAM,MAAM,EAAE,EAClH,OAAO,EAAE,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,CACpE,CAAC;QACF,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;QAC3B,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;QAC3B,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,CAAC;CACF"}
@@ -0,0 +1,92 @@
1
+ /**
2
+ * Message headers. In Kafka headers are bytes; in the SDK they travel as a `string → string`
3
+ * map, (de)coded as UTF-8 at the edge. Header names and value formats are protocol: identical
4
+ * to the Python SDK.
5
+ */
6
+ export declare const MESSAGE_ID = "message_id";
7
+ export declare const EVENT_TYPE = "event_type";
8
+ export declare const SCHEMA_VERSION = "schema_version";
9
+ export declare const PUBLISHED_AT = "published_at";
10
+ export declare const PRODUCER = "producer";
11
+ export declare const CORRELATION_ID = "correlation_id";
12
+ export declare const IDEMPOTENCY_KEY = "idempotency_key";
13
+ export declare const TENANT_ID = "x-tenant-id";
14
+ export declare const RETRY_COUNT = "x-retry-count";
15
+ /** Epoch in milliseconds. */
16
+ export declare const RETRY_DUE_AT = "x-retry-due-at";
17
+ export declare const FIRST_FAILED_AT = "x-first-failed-at";
18
+ export declare const LAST_ERROR = "x-last-error";
19
+ export declare const LAST_ERROR_TYPE = "x-last-error-type";
20
+ export declare const ORIGINAL_TOPIC = "x-original-topic";
21
+ export declare const ORIGINAL_PARTITION = "x-original-partition";
22
+ export declare const ORIGINAL_OFFSET = "x-original-offset";
23
+ export declare const DLQ_REASON = "x-dlq-reason";
24
+ /** Error messages are truncated (in characters / code points, like Python) to keep headers small. */
25
+ export declare const MAX_ERROR_LENGTH = 1024;
26
+ /** Headers in the SDK: name → UTF-8 text. */
27
+ export type MessageHeaders = Record<string, string>;
28
+ /** Headers on the wire, in order (the equivalent of Python's `list[tuple[str, bytes]]`). */
29
+ export type KafkaHeaders = ReadonlyArray<readonly [name: string, value: Buffer]>;
30
+ type RawHeaderValue = Buffer | Uint8Array | string | null | undefined;
31
+ /**
32
+ * Headers as received from a Kafka client: a list of `[name, value]` pairs or the KafkaJS
33
+ * object form (`{name: Buffer | Buffer[]}`, repeated names become arrays).
34
+ */
35
+ export type RawHeaders = ReadonlyArray<readonly [string, RawHeaderValue]> | Readonly<Record<string, RawHeaderValue | readonly RawHeaderValue[]>> | null | undefined;
36
+ /** Clock in epoch milliseconds (injectable for tests). */
37
+ export type EpochClock = () => number;
38
+ /** Epoch milliseconds now. */
39
+ export declare function nowMs(): number;
40
+ /** `MessageHeaders` → wire format (UTF-8), keeping insertion order. */
41
+ export declare function encode(headers: Readonly<MessageHeaders>): Array<[string, Buffer]>;
42
+ /**
43
+ * Last occurrence wins; invalid UTF-8 is replaced (U+FFFD); `null` values become `''`.
44
+ * The result has no prototype, so a header named `__proto__` is kept as a plain entry.
45
+ */
46
+ export declare function decode(raw: RawHeaders): MessageHeaders;
47
+ /** Integer header (`x-retry-count`, `x-retry-due-at`): absent, empty or invalid → 0. */
48
+ export declare function parseHeaderInt(value: string | undefined): number;
49
+ /** Reads `x-retry-count` tolerating absence/invalid values (→ 0); negative → 0. */
50
+ export declare function retryCount(headers: Readonly<MessageHeaders>): number;
51
+ /** Reads `x-retry-due-at` (epoch ms); absent or invalid → 0 (= already due). */
52
+ export declare function retryDueAtMs(headers: Readonly<MessageHeaders>): number;
53
+ /**
54
+ * Dedup key (spec §8.1): `idempotency_key` if not empty, else `message_id` if not empty, else
55
+ * `null` (no dedup). Used verbatim.
56
+ */
57
+ export declare function dedupKey(headers: Readonly<MessageHeaders>): string | null;
58
+ export interface PublishHeadersInit {
59
+ eventType: string;
60
+ schemaVersion: string;
61
+ producer: string;
62
+ correlationId?: string | null | undefined;
63
+ idempotencyKey?: string | null | undefined;
64
+ tenantId?: string | null | undefined;
65
+ /** Clock (epoch ms) for `published_at`. Default `Date.now`. */
66
+ clock?: EpochClock | undefined;
67
+ /** UUID generator for `message_id`/`correlation_id`. Default `crypto.randomUUID`. */
68
+ newId?: (() => string) | undefined;
69
+ }
70
+ /** Headers of a new publication: fresh UUID4 `message_id`, `correlation_id` given or new. */
71
+ export declare function buildPublishHeaders(init: PublishHeadersInit): MessageHeaders;
72
+ /** Position of the consumption that failed. */
73
+ export interface FailurePosition {
74
+ topic: string;
75
+ partition: number;
76
+ offset: number;
77
+ /** Clock (epoch ms) for `x-first-failed-at`. Default `Date.now`. */
78
+ clock?: EpochClock | undefined;
79
+ }
80
+ export interface RetryHeadersInit extends FailurePosition {
81
+ /** When the retry becomes due, epoch milliseconds (truncated to an integer). */
82
+ dueAtMs: number;
83
+ }
84
+ /** Headers for the next retry: increments `x-retry-count`, sets `x-retry-due-at` (epoch ms). */
85
+ export declare function buildRetryHeaders(headers: Readonly<MessageHeaders>, error: unknown, init: RetryHeadersInit): MessageHeaders;
86
+ export interface DlqHeadersInit extends FailurePosition {
87
+ /** `x-dlq-reason` (`permanent_error`, `max_retries`, ...). */
88
+ reason: string;
89
+ }
90
+ /** Headers for the DLQ: removes `x-retry-due-at`, sets `x-dlq-reason`, keeps `x-retry-count`. */
91
+ export declare function buildDlqHeaders(headers: Readonly<MessageHeaders>, error: unknown, init: DlqHeadersInit): MessageHeaders;
92
+ export {};