@voltro/plugin-queue 0.53.0 → 0.54.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.
- package/CHANGELOG.md +195 -0
- package/THIRD-PARTY-NOTICES.md +4333 -26
- package/dist/index.d.ts +2 -0
- package/dist/index.js +176 -132
- package/package.json +4 -3
package/dist/index.d.ts
CHANGED
|
@@ -154,6 +154,8 @@ export declare interface QueueIncomingMessage {
|
|
|
154
154
|
/** Per-process counters, keyed by topic — the inspect endpoint reads them. */
|
|
155
155
|
export declare const queueMetrics: () => QueueMetricsSlot;
|
|
156
156
|
|
|
157
|
+
/** Per-topic counters the inspect endpoint renders. Cumulative for the life of
|
|
158
|
+
* THIS process — the dashboard's live view, not the alerting source. */
|
|
157
159
|
declare interface QueueMetricsSlot {
|
|
158
160
|
consumed: Record<string, number>;
|
|
159
161
|
dlq: Record<string, number>;
|
package/dist/index.js
CHANGED
|
@@ -1,27 +1,62 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { definePlugin as
|
|
3
|
-
import { Kafka as
|
|
1
|
+
import { Cause as e, Context as t, Effect as n, Exit as r, Layer as i, Metric as a, Schema as o } from "effect";
|
|
2
|
+
import { definePlugin as s } from "@voltro/protocol";
|
|
3
|
+
import { Kafka as c, logLevel as l } from "kafkajs";
|
|
4
|
+
import { externalSpanFromTraceparent as u, withServerTracer as d } from "@voltro/runtime";
|
|
4
5
|
//#region src/consumer.ts
|
|
5
|
-
var
|
|
6
|
+
var f = Symbol.for("@voltro/plugin-queue:consumers"), p = () => {
|
|
6
7
|
let e = globalThis;
|
|
7
|
-
return e[
|
|
8
|
-
},
|
|
8
|
+
return e[f] ??= /* @__PURE__ */ new Map();
|
|
9
|
+
}, m = (e) => {
|
|
9
10
|
if (e.topic.trim() === "") throw Error("defineQueueConsumer: `topic` must be a non-empty name");
|
|
10
11
|
if (e.maxAttempts !== void 0 && e.maxAttempts < 1) throw Error(`defineQueueConsumer("${e.topic}"): maxAttempts must be >= 1`);
|
|
11
|
-
let t = `${e.topic}|${e.groupId ?? ""}`, n =
|
|
12
|
+
let t = `${e.topic}|${e.groupId ?? ""}`, n = p().get(t);
|
|
12
13
|
if (n !== void 0 && n !== e) throw Error(`defineQueueConsumer: topic '${e.topic}'${e.groupId ? ` group '${e.groupId}'` : ""} is declared twice — two consumers in one group on one topic would split its partitions unpredictably. Use a distinct groupId for an independent consumer.`);
|
|
13
|
-
return
|
|
14
|
-
},
|
|
15
|
-
|
|
16
|
-
},
|
|
14
|
+
return p().set(t, e), e;
|
|
15
|
+
}, h = () => [...p().values()], g = () => {
|
|
16
|
+
p().clear();
|
|
17
|
+
}, _ = Symbol.for("@voltro/plugin-queue:metrics"), v = () => {
|
|
18
|
+
let e = globalThis;
|
|
19
|
+
return e[_] ??= {
|
|
20
|
+
consumed: {},
|
|
21
|
+
dlq: {},
|
|
22
|
+
retried: {},
|
|
23
|
+
lastError: {},
|
|
24
|
+
produced: {}
|
|
25
|
+
};
|
|
26
|
+
}, y = (e, t, n = 1) => {
|
|
27
|
+
e[t] = (e[t] ?? 0) + n;
|
|
28
|
+
}, b = a.counter("voltro_queue_consumed_total", { description: "Messages a consumer finished with, by topic and outcome (ok | dead-lettered)." }), x = a.counter("voltro_queue_retries_total", { description: "In-process handler retries, by topic. A retry BLOCKS its partition." }), S = a.counter("voltro_queue_produced_total", { description: "Messages produced through the outbox bridge, by topic." }), C = a.gauge("voltro_queue_lag_messages", { description: "Messages between the offset just picked up and the partition high watermark, by topic and partition. Sampled at pickup; holds its last value for an idle or revoked partition." }), w = [], T = /* @__PURE__ */ new Map(), E = /* @__PURE__ */ new Map(), D = /* @__PURE__ */ new Map(), O = /* @__PURE__ */ new Map(), k = (e, t, n) => {
|
|
29
|
+
let r = e.get(t);
|
|
30
|
+
if (r !== void 0) return r;
|
|
31
|
+
let i = n();
|
|
32
|
+
return e.set(t, i), i;
|
|
33
|
+
}, A = (e) => {
|
|
34
|
+
y(v().consumed, e), k(T, `ok\u0000${e}`, () => a.tagged(a.tagged(b, "topic", e), "outcome", "ok")).unsafeUpdate(1, w);
|
|
35
|
+
}, j = (e, t) => {
|
|
36
|
+
let n = v();
|
|
37
|
+
y(n.dlq, e), n.lastError[e] = t.slice(0, 500), k(T, `dlq\u0000${e}`, () => a.tagged(a.tagged(b, "topic", e), "outcome", "dead-lettered")).unsafeUpdate(1, w);
|
|
38
|
+
}, M = (e) => {
|
|
39
|
+
y(v().retried, e), k(E, e, () => a.tagged(x, "topic", e)).unsafeUpdate(1, w);
|
|
40
|
+
}, N = (e, t) => {
|
|
41
|
+
t <= 0 || (y(v().produced, e, t), k(D, e, () => a.tagged(S, "topic", e)).unsafeUpdate(t, w));
|
|
42
|
+
}, P = (e, t, n, r) => {
|
|
43
|
+
let i;
|
|
44
|
+
try {
|
|
45
|
+
let e = BigInt(n) - BigInt(r) - 1n;
|
|
46
|
+
i = e < 0n ? 0 : Number(e);
|
|
47
|
+
} catch {
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
k(O, `${e}\u0000${t}`, () => a.tagged(a.tagged(C, "topic", e), "partition", String(t))).unsafeUpdate(i, w);
|
|
51
|
+
}, F = (e) => {
|
|
17
52
|
let t = {};
|
|
18
53
|
for (let [n, r] of Object.entries(e ?? {})) r != null && (t[n] = Buffer.isBuffer(r) ? r.toString("utf8") : String(r));
|
|
19
54
|
return t;
|
|
20
|
-
},
|
|
21
|
-
let t = new
|
|
55
|
+
}, I = (e) => {
|
|
56
|
+
let t = new c({
|
|
22
57
|
clientId: e.clientId ?? "voltro",
|
|
23
58
|
brokers: [...e.brokers],
|
|
24
|
-
logLevel:
|
|
59
|
+
logLevel: l.ERROR,
|
|
25
60
|
...e.ssl === void 0 ? {} : { ssl: e.ssl },
|
|
26
61
|
...e.sasl === void 0 ? {} : { sasl: e.sasl }
|
|
27
62
|
}), n = null, r = /* @__PURE__ */ new Set();
|
|
@@ -78,10 +113,10 @@ var s = Symbol.for("@voltro/plugin-queue:consumers"), c = () => {
|
|
|
78
113
|
offset: s.offset,
|
|
79
114
|
key: s.key === null ? null : s.key.toString("utf8"),
|
|
80
115
|
value: s.value === null ? null : s.value.toString("utf8"),
|
|
81
|
-
headers:
|
|
116
|
+
headers: F(s.headers),
|
|
82
117
|
timestamp: s.timestamp
|
|
83
118
|
};
|
|
84
|
-
await n.onMessage(c, {
|
|
119
|
+
P(e.topic, e.partition, e.highWatermark, s.offset), await n.onMessage(c, {
|
|
85
120
|
heartbeat: i,
|
|
86
121
|
isStale: o
|
|
87
122
|
}), t(s.offset), await r();
|
|
@@ -92,123 +127,134 @@ var s = Symbol.for("@voltro/plugin-queue:consumers"), c = () => {
|
|
|
92
127
|
} };
|
|
93
128
|
}
|
|
94
129
|
};
|
|
95
|
-
},
|
|
96
|
-
let
|
|
97
|
-
return e
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
130
|
+
}, L = "queue.consume", R = (e, t) => (r) => {
|
|
131
|
+
let i = u(e.traceparent);
|
|
132
|
+
return r.pipe(n.tap((e) => t === void 0 ? n.void : n.annotateCurrentSpan(t(e))), n.withSpan(L, {
|
|
133
|
+
attributes: {
|
|
134
|
+
"messaging.system": e.system,
|
|
135
|
+
"messaging.operation": "process",
|
|
136
|
+
"messaging.destination.name": e.topic,
|
|
137
|
+
"messaging.consumer.group.name": e.groupId,
|
|
138
|
+
"messaging.destination.partition.id": e.partition,
|
|
139
|
+
"messaging.message.offset": e.offset
|
|
140
|
+
},
|
|
141
|
+
...i ? { parent: i } : {}
|
|
142
|
+
}));
|
|
143
|
+
}, z = async (t, i, a) => {
|
|
144
|
+
let o, s = await n.runPromiseExit(n.tryPromise({
|
|
145
|
+
try: i,
|
|
146
|
+
catch: (e) => (o = { value: e }, e)
|
|
147
|
+
}).pipe(R(t, a), d));
|
|
148
|
+
if (r.isSuccess(s)) return s.value;
|
|
149
|
+
throw o === void 0 ? e.squash(s.cause) : o.value;
|
|
150
|
+
}, B = (e) => new Promise((t) => setTimeout(t, e)), V = async (e) => {
|
|
151
|
+
let { provider: t, log: n } = e, r = { current: !1 }, i = /* @__PURE__ */ new Set(), a = async (r) => {
|
|
152
|
+
let i = r.groupId ?? `${e.appName}.${r.topic}`, a = r.dlqTopic ?? `${r.topic}.dlq`, s = r.maxAttempts ?? 3, c = o.decodeUnknownEither(r.schema), l = async (e, i, o) => {
|
|
153
|
+
j(r.topic, `${e}: ${i}`), n.warn("queue: dead-lettered", {
|
|
154
|
+
topic: r.topic,
|
|
155
|
+
dlqTopic: a,
|
|
112
156
|
reason: e,
|
|
113
157
|
partition: o.partition,
|
|
114
158
|
offset: o.offset
|
|
115
|
-
}), await t.produce(
|
|
159
|
+
}), await t.produce(a, [{
|
|
116
160
|
...o.key === null ? {} : { key: o.key },
|
|
117
161
|
value: o.value ?? "",
|
|
118
162
|
headers: {
|
|
119
163
|
...o.headers,
|
|
120
164
|
"x-voltro-dlq-reason": e,
|
|
121
|
-
"x-voltro-dlq-detail":
|
|
165
|
+
"x-voltro-dlq-detail": i.slice(0, 500),
|
|
122
166
|
"x-voltro-dlq-source-topic": o.topic,
|
|
123
167
|
"x-voltro-dlq-source-partition": String(o.partition),
|
|
124
168
|
"x-voltro-dlq-source-offset": o.offset
|
|
125
169
|
}
|
|
126
170
|
}]);
|
|
127
|
-
},
|
|
128
|
-
topic:
|
|
129
|
-
groupId:
|
|
130
|
-
...
|
|
131
|
-
onMessage: async (
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
await u("decode-failed", String(s.left), t);
|
|
142
|
-
return;
|
|
143
|
-
}
|
|
144
|
-
for (let o = 1; o <= c; o++) {
|
|
145
|
-
if (r.isStale()) return;
|
|
171
|
+
}, u = await t.consume({
|
|
172
|
+
topic: r.topic,
|
|
173
|
+
groupId: i,
|
|
174
|
+
...r.fromBeginning === void 0 ? {} : { fromBeginning: r.fromBeginning },
|
|
175
|
+
onMessage: async (a, o) => {
|
|
176
|
+
await z({
|
|
177
|
+
system: t.name,
|
|
178
|
+
topic: r.topic,
|
|
179
|
+
groupId: i,
|
|
180
|
+
partition: a.partition,
|
|
181
|
+
offset: a.offset,
|
|
182
|
+
traceparent: a.headers.traceparent
|
|
183
|
+
}, async () => {
|
|
184
|
+
let t;
|
|
146
185
|
try {
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
186
|
+
t = a.value === null ? null : JSON.parse(a.value);
|
|
187
|
+
} catch (e) {
|
|
188
|
+
return await l("decode-failed", `invalid JSON: ${e instanceof Error ? e.message : String(e)}`, a), "dead-lettered";
|
|
189
|
+
}
|
|
190
|
+
let i = c(t);
|
|
191
|
+
if (i._tag === "Left") return await l("decode-failed", String(i.left), a), "dead-lettered";
|
|
192
|
+
for (let t = 1; t <= s; t++) {
|
|
193
|
+
if (o.isStale()) return "stale";
|
|
194
|
+
try {
|
|
195
|
+
return await r.handler(i.right, {
|
|
196
|
+
topic: a.topic,
|
|
197
|
+
partition: a.partition,
|
|
198
|
+
offset: a.offset,
|
|
199
|
+
key: a.key,
|
|
200
|
+
headers: a.headers,
|
|
201
|
+
attempt: t,
|
|
202
|
+
...a.headers.traceparent === void 0 ? {} : { traceparent: a.headers.traceparent },
|
|
203
|
+
get store() {
|
|
204
|
+
let t = e.store();
|
|
205
|
+
if (t === null) throw Error("queue: store not bound yet — the retry loop absorbs a message arriving before boot finished");
|
|
206
|
+
return t;
|
|
207
|
+
}
|
|
208
|
+
}), A(r.topic), "ok";
|
|
209
|
+
} catch (i) {
|
|
210
|
+
let c = i instanceof Error ? i.message : String(i);
|
|
211
|
+
if (t >= s) return await l("handler-failed", c, a), "dead-lettered";
|
|
212
|
+
M(r.topic), n.warn("queue: handler failed, retrying", {
|
|
213
|
+
topic: r.topic,
|
|
214
|
+
attempt: t,
|
|
215
|
+
maxAttempts: s,
|
|
216
|
+
detail: c
|
|
217
|
+
}), await o.heartbeat().catch(() => {}), await B((e.retryBaseMs ?? 1e3) * 2 ** (t - 1));
|
|
167
218
|
}
|
|
168
|
-
g(i.retried, a.topic), n.warn("queue: handler failed, retrying", {
|
|
169
|
-
topic: a.topic,
|
|
170
|
-
attempt: o,
|
|
171
|
-
maxAttempts: c,
|
|
172
|
-
detail: l
|
|
173
|
-
}), await r.heartbeat().catch(() => {}), await _((e.retryBaseMs ?? 1e3) * 2 ** (o - 1));
|
|
174
219
|
}
|
|
175
|
-
|
|
220
|
+
return "stale";
|
|
221
|
+
}, (e) => ({ "voltro.queue.outcome": e }));
|
|
176
222
|
}
|
|
177
223
|
});
|
|
178
224
|
return n.info("queue: consumer started", {
|
|
179
|
-
topic:
|
|
180
|
-
groupId:
|
|
181
|
-
dlqTopic:
|
|
182
|
-
}),
|
|
183
|
-
},
|
|
184
|
-
let t = { handle: null },
|
|
185
|
-
|
|
186
|
-
if (
|
|
225
|
+
topic: r.topic,
|
|
226
|
+
groupId: i,
|
|
227
|
+
dlqTopic: a
|
|
228
|
+
}), u;
|
|
229
|
+
}, s = e.consumers.map((e) => {
|
|
230
|
+
let t = { handle: null }, o = () => {
|
|
231
|
+
a(e).then((e) => {
|
|
232
|
+
if (r.current) {
|
|
187
233
|
e.stop();
|
|
188
234
|
return;
|
|
189
235
|
}
|
|
190
236
|
t.handle = e;
|
|
191
237
|
}).catch((t) => {
|
|
192
|
-
if (
|
|
238
|
+
if (r.current) return;
|
|
193
239
|
n.warn("queue: consumer start failed — retrying in 5s", {
|
|
194
240
|
topic: e.topic,
|
|
195
241
|
detail: t instanceof Error ? t.message : String(t)
|
|
196
242
|
});
|
|
197
|
-
let
|
|
198
|
-
|
|
243
|
+
let a = setTimeout(() => {
|
|
244
|
+
i.delete(a), o();
|
|
199
245
|
}, 5e3);
|
|
200
|
-
|
|
246
|
+
i.add(a);
|
|
201
247
|
});
|
|
202
248
|
};
|
|
203
|
-
return
|
|
249
|
+
return o(), t;
|
|
204
250
|
});
|
|
205
251
|
return { stop: async () => {
|
|
206
|
-
|
|
207
|
-
for (let e of
|
|
208
|
-
|
|
252
|
+
r.current = !0;
|
|
253
|
+
for (let e of i) clearTimeout(e);
|
|
254
|
+
i.clear(), await Promise.all(s.map((e) => e.handle?.stop() ?? Promise.resolve()));
|
|
209
255
|
} };
|
|
210
|
-
},
|
|
211
|
-
let t = () => e.provider ??
|
|
256
|
+
}, H = (e) => {
|
|
257
|
+
let t = () => e.provider ?? K();
|
|
212
258
|
return {
|
|
213
259
|
name: `kafka(${e.topic})`,
|
|
214
260
|
...e.provider !== void 0 && e.provider.hosts[0] !== void 0 ? { outboundHost: e.provider.hosts[0] } : {},
|
|
@@ -225,64 +271,62 @@ var s = Symbol.for("@voltro/plugin-queue:consumers"), c = () => {
|
|
|
225
271
|
})));
|
|
226
272
|
}
|
|
227
273
|
};
|
|
228
|
-
},
|
|
274
|
+
}, U = class extends t.Tag("@voltro/plugin-queue/QueueService")() {}, W = Symbol.for("@voltro/plugin-queue:active-provider"), G = () => {
|
|
229
275
|
let e = globalThis;
|
|
230
|
-
return e[
|
|
231
|
-
},
|
|
232
|
-
let e =
|
|
276
|
+
return e[W] ??= { current: null };
|
|
277
|
+
}, K = () => {
|
|
278
|
+
let e = G().current;
|
|
233
279
|
if (e === null) throw Error("[voltro] no active queue provider — is queuePlugin({...}) in this app's plugins? The outbox handler and kafkaSink need the plugin's connected provider.");
|
|
234
280
|
return e;
|
|
235
|
-
},
|
|
281
|
+
}, q = () => ({
|
|
236
282
|
effect: "queue.produce",
|
|
237
283
|
maxAttempts: 8,
|
|
238
284
|
handler: async ({ payload: e }) => {
|
|
239
285
|
let t = e.topic, n = e.messages;
|
|
240
286
|
if (typeof t != "string" || !Array.isArray(n)) throw Error("queue.produce payload must be { topic: string, messages: QueueOutgoingMessage[] }");
|
|
241
|
-
await
|
|
242
|
-
let r = h();
|
|
243
|
-
r.produced[t] = (r.produced[t] ?? 0) + n.length;
|
|
287
|
+
await K().produce(t, n), N(t, n.length);
|
|
244
288
|
}
|
|
245
|
-
}),
|
|
246
|
-
let
|
|
247
|
-
return
|
|
248
|
-
name:
|
|
289
|
+
}), J = (e) => {
|
|
290
|
+
let t = e.name ?? "queue", r = I(e), a = ["inspect:read", ...r.hosts.map((e) => `network:outbound:${e}`)], o = null, c = { current: null };
|
|
291
|
+
return s({
|
|
292
|
+
name: t,
|
|
249
293
|
baseName: "queue",
|
|
250
294
|
description: "Queue interop — consume and produce against an existing Kafka: Schema-decoded consumers (at-least-once, serial per partition, retry + dead-letter), batched producing via a handler service or transactionally through the outbox, and a kafkaSink for plugin-cdc-out.",
|
|
251
|
-
permissions:
|
|
252
|
-
services:
|
|
295
|
+
permissions: a,
|
|
296
|
+
services: i.succeed(U, { produce: (e, t) => r.produce(e, t) }),
|
|
253
297
|
bindDataStore: (e) => {
|
|
254
298
|
c.current = e;
|
|
255
299
|
},
|
|
256
|
-
onActivate: (
|
|
257
|
-
await
|
|
258
|
-
let
|
|
259
|
-
|
|
260
|
-
provider:
|
|
261
|
-
consumers:
|
|
262
|
-
appName: e.groupPrefix ??
|
|
263
|
-
log:
|
|
300
|
+
onActivate: (t) => n.tryPromise(async () => {
|
|
301
|
+
await r.connect(), G().current = r;
|
|
302
|
+
let n = h();
|
|
303
|
+
o = await V({
|
|
304
|
+
provider: r,
|
|
305
|
+
consumers: n,
|
|
306
|
+
appName: e.groupPrefix ?? t.app.name,
|
|
307
|
+
log: t.logger,
|
|
264
308
|
store: () => c.current,
|
|
265
309
|
...e.retryBaseMs === void 0 ? {} : { retryBaseMs: e.retryBaseMs }
|
|
266
|
-
}),
|
|
267
|
-
brokers:
|
|
268
|
-
consumers:
|
|
310
|
+
}), t.logger.info("queue: connected", {
|
|
311
|
+
brokers: r.hosts,
|
|
312
|
+
consumers: n.length
|
|
269
313
|
});
|
|
270
314
|
}),
|
|
271
|
-
onDeactivate: () =>
|
|
272
|
-
await
|
|
315
|
+
onDeactivate: () => n.tryPromise(async () => {
|
|
316
|
+
await o?.stop(), o = null, G().current === r && (G().current = null), await r.disconnect();
|
|
273
317
|
}),
|
|
274
318
|
inspectEndpoints: [{
|
|
275
319
|
method: "GET",
|
|
276
320
|
path: "/consumers",
|
|
277
321
|
description: "Registered consumers + per-topic consumed/retried/dead-lettered/produced counters (this replica).",
|
|
278
|
-
handler: () =>
|
|
279
|
-
let e =
|
|
322
|
+
handler: () => n.sync(() => {
|
|
323
|
+
let e = v();
|
|
280
324
|
return {
|
|
281
325
|
kind: "json",
|
|
282
326
|
data: {
|
|
283
|
-
connected:
|
|
284
|
-
brokers:
|
|
285
|
-
consumers:
|
|
327
|
+
connected: G().current !== null,
|
|
328
|
+
brokers: r.hosts,
|
|
329
|
+
consumers: h().map((t) => ({
|
|
286
330
|
topic: t.topic,
|
|
287
331
|
groupId: t.groupId ?? null,
|
|
288
332
|
dlqTopic: t.dlqTopic ?? `${t.topic}.dlq`,
|
|
@@ -300,4 +344,4 @@ var s = Symbol.for("@voltro/plugin-queue:consumers"), c = () => {
|
|
|
300
344
|
});
|
|
301
345
|
};
|
|
302
346
|
//#endregion
|
|
303
|
-
export {
|
|
347
|
+
export { U as QueueService, K as activeQueueProvider, m as defineQueueConsumer, I as kafkaProvider, H as kafkaSink, v as queueMetrics, q as queueOutboxHandler, J as queuePlugin, h as registeredQueueConsumers, g as resetQueueConsumersForTest, V as startQueueConsumers };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@voltro/plugin-queue",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.54.0",
|
|
4
4
|
"description": "Queue interop — consume and produce against an existing Kafka: Schema-decoded consumers via defineQueueConsumer (*.consumer.ts; at-least-once, serial per partition, retry + dead-letter), batched producing via QueueService or transactionally through the outbox (queueOutboxHandler), and a kafkaSink for plugin-cdc-out.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"voltro",
|
|
@@ -33,9 +33,10 @@
|
|
|
33
33
|
"node": ">=24.0.0"
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
|
-
"@voltro/protocol": "0.
|
|
36
|
+
"@voltro/protocol": "0.54.0",
|
|
37
37
|
"kafkajs": "^2.2.4",
|
|
38
|
-
"@voltro/database": "0.
|
|
38
|
+
"@voltro/database": "0.54.0",
|
|
39
|
+
"@voltro/runtime": "0.54.0"
|
|
39
40
|
},
|
|
40
41
|
"peerDependencies": {
|
|
41
42
|
"effect": "^3.22.0"
|