@drarzter/kafka-client 0.9.4 → 0.11.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/README.md +693 -8
- package/dist/chunk-OR7TPAAE.mjs +4760 -0
- package/dist/chunk-OR7TPAAE.mjs.map +1 -0
- package/dist/chunk-PQVBRDNV.mjs +149 -0
- package/dist/chunk-PQVBRDNV.mjs.map +1 -0
- package/dist/cli/dlq.d.ts +119 -0
- package/dist/cli/dlq.d.ts.map +1 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/{chunk-SM4FZKAZ.mjs → cli/index.js} +1073 -309
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/index.mjs +356 -0
- package/dist/cli/index.mjs.map +1 -0
- package/dist/client/config/from-env.d.ts +188 -0
- package/dist/client/config/from-env.d.ts.map +1 -0
- package/dist/client/config/index.d.ts +2 -0
- package/dist/client/config/index.d.ts.map +1 -0
- package/dist/client/errors.d.ts +67 -0
- package/dist/client/errors.d.ts.map +1 -0
- package/dist/client/kafka.client/admin/ops.d.ts +114 -0
- package/dist/client/kafka.client/admin/ops.d.ts.map +1 -0
- package/dist/client/kafka.client/consumer/features/delayed.d.ts +24 -0
- package/dist/client/kafka.client/consumer/features/delayed.d.ts.map +1 -0
- package/dist/client/kafka.client/consumer/features/dlq-replay.d.ts +52 -0
- package/dist/client/kafka.client/consumer/features/dlq-replay.d.ts.map +1 -0
- package/dist/client/kafka.client/consumer/features/routed.d.ts +4 -0
- package/dist/client/kafka.client/consumer/features/routed.d.ts.map +1 -0
- package/dist/client/kafka.client/consumer/features/snapshot.d.ts +10 -0
- package/dist/client/kafka.client/consumer/features/snapshot.d.ts.map +1 -0
- package/dist/client/kafka.client/consumer/features/window.d.ts +5 -0
- package/dist/client/kafka.client/consumer/features/window.d.ts.map +1 -0
- package/dist/client/kafka.client/consumer/handler.d.ts +163 -0
- package/dist/client/kafka.client/consumer/handler.d.ts.map +1 -0
- package/dist/client/kafka.client/consumer/ops.d.ts +64 -0
- package/dist/client/kafka.client/consumer/ops.d.ts.map +1 -0
- package/dist/client/kafka.client/consumer/pipeline.d.ts +168 -0
- package/dist/client/kafka.client/consumer/pipeline.d.ts.map +1 -0
- package/dist/client/kafka.client/consumer/queue.d.ts +37 -0
- package/dist/client/kafka.client/consumer/queue.d.ts.map +1 -0
- package/dist/client/kafka.client/consumer/retry-topic.d.ts +68 -0
- package/dist/client/kafka.client/consumer/retry-topic.d.ts.map +1 -0
- package/dist/client/kafka.client/consumer/setup.d.ts +66 -0
- package/dist/client/kafka.client/consumer/setup.d.ts.map +1 -0
- package/dist/client/kafka.client/consumer/start.d.ts +7 -0
- package/dist/client/kafka.client/consumer/start.d.ts.map +1 -0
- package/dist/client/kafka.client/consumer/stop.d.ts +19 -0
- package/dist/client/kafka.client/consumer/stop.d.ts.map +1 -0
- package/dist/client/kafka.client/consumer/subscribe-retry.d.ts +4 -0
- package/dist/client/kafka.client/consumer/subscribe-retry.d.ts.map +1 -0
- package/dist/client/kafka.client/context.d.ts +75 -0
- package/dist/client/kafka.client/context.d.ts.map +1 -0
- package/dist/client/kafka.client/index.d.ts +155 -0
- package/dist/client/kafka.client/index.d.ts.map +1 -0
- package/dist/client/kafka.client/infra/circuit-breaker.manager.d.ts +61 -0
- package/dist/client/kafka.client/infra/circuit-breaker.manager.d.ts.map +1 -0
- package/dist/client/kafka.client/infra/dedup.store.d.ts +28 -0
- package/dist/client/kafka.client/infra/dedup.store.d.ts.map +1 -0
- package/dist/client/kafka.client/infra/inflight.tracker.d.ts +22 -0
- package/dist/client/kafka.client/infra/inflight.tracker.d.ts.map +1 -0
- package/dist/client/kafka.client/infra/metrics.manager.d.ts +67 -0
- package/dist/client/kafka.client/infra/metrics.manager.d.ts.map +1 -0
- package/dist/client/kafka.client/producer/lifecycle.d.ts +41 -0
- package/dist/client/kafka.client/producer/lifecycle.d.ts.map +1 -0
- package/dist/client/kafka.client/producer/ops.d.ts +79 -0
- package/dist/client/kafka.client/producer/ops.d.ts.map +1 -0
- package/dist/client/kafka.client/producer/send.d.ts +21 -0
- package/dist/client/kafka.client/producer/send.d.ts.map +1 -0
- package/dist/client/kafka.client/validate-options.d.ts +11 -0
- package/dist/client/kafka.client/validate-options.d.ts.map +1 -0
- package/dist/client/message/envelope.d.ts +105 -0
- package/dist/client/message/envelope.d.ts.map +1 -0
- package/dist/client/message/schema-registry.d.ts +124 -0
- package/dist/client/message/schema-registry.d.ts.map +1 -0
- package/dist/client/message/serde.d.ts +68 -0
- package/dist/client/message/serde.d.ts.map +1 -0
- package/dist/client/message/topic.d.ts +159 -0
- package/dist/client/message/topic.d.ts.map +1 -0
- package/dist/client/message/versioned-schema.d.ts +53 -0
- package/dist/client/message/versioned-schema.d.ts.map +1 -0
- package/dist/client/outbox/index.d.ts +4 -0
- package/dist/client/outbox/index.d.ts.map +1 -0
- package/dist/client/outbox/outbox.relay.d.ts +90 -0
- package/dist/client/outbox/outbox.relay.d.ts.map +1 -0
- package/dist/client/outbox/outbox.store.d.ts +42 -0
- package/dist/client/outbox/outbox.store.d.ts.map +1 -0
- package/dist/client/outbox/outbox.types.d.ts +144 -0
- package/dist/client/outbox/outbox.types.d.ts.map +1 -0
- package/dist/client/security/acl.d.ts +108 -0
- package/dist/client/security/acl.d.ts.map +1 -0
- package/dist/client/security/index.d.ts +5 -0
- package/dist/client/security/index.d.ts.map +1 -0
- package/dist/client/security/providers.d.ts +88 -0
- package/dist/client/security/providers.d.ts.map +1 -0
- package/dist/client/security/resolve-security.d.ts +19 -0
- package/dist/client/security/resolve-security.d.ts.map +1 -0
- package/dist/client/security/security.types.d.ts +76 -0
- package/dist/client/security/security.types.d.ts.map +1 -0
- package/dist/client/transport/confluent.transport.d.ts +32 -0
- package/dist/client/transport/confluent.transport.d.ts.map +1 -0
- package/dist/client/transport/transport.interface.d.ts +221 -0
- package/dist/client/transport/transport.interface.d.ts.map +1 -0
- package/dist/client/types/admin.interface.d.ts +174 -0
- package/dist/client/types/admin.interface.d.ts.map +1 -0
- package/dist/client/types/admin.types.d.ts +140 -0
- package/dist/client/types/admin.types.d.ts.map +1 -0
- package/dist/client/types/client.d.ts +21 -0
- package/dist/client/types/client.d.ts.map +1 -0
- package/dist/client/types/common.d.ts +84 -0
- package/dist/client/types/common.d.ts.map +1 -0
- package/dist/client/types/config.types.d.ts +167 -0
- package/dist/client/types/config.types.d.ts.map +1 -0
- package/dist/client/types/consumer.interface.d.ts +115 -0
- package/dist/client/types/consumer.interface.d.ts.map +1 -0
- package/dist/{consumer.types-fFCag3VJ.d.mts → client/types/consumer.types.d.ts} +62 -383
- package/dist/client/types/consumer.types.d.ts.map +1 -0
- package/dist/client/types/dedup.types.d.ts +50 -0
- package/dist/client/types/dedup.types.d.ts.map +1 -0
- package/dist/client/types/lifecycle.interface.d.ts +72 -0
- package/dist/client/types/lifecycle.interface.d.ts.map +1 -0
- package/dist/client/types/producer.interface.d.ts +52 -0
- package/dist/client/types/producer.interface.d.ts.map +1 -0
- package/dist/client/types/producer.types.d.ts +90 -0
- package/dist/client/types/producer.types.d.ts.map +1 -0
- package/dist/client/types.d.ts +8 -0
- package/dist/client/types.d.ts.map +1 -0
- package/dist/core.d.ts +13 -314
- package/dist/core.d.ts.map +1 -0
- package/dist/core.js +1466 -123
- package/dist/core.js.map +1 -1
- package/dist/core.mjs +45 -3
- package/dist/index.d.ts +7 -128
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1483 -123
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +62 -3
- package/dist/index.mjs.map +1 -1
- package/dist/nest/kafka.constants.d.ts +5 -0
- package/dist/nest/kafka.constants.d.ts.map +1 -0
- package/dist/nest/kafka.decorator.d.ts +49 -0
- package/dist/nest/kafka.decorator.d.ts.map +1 -0
- package/dist/nest/kafka.explorer.d.ts +17 -0
- package/dist/nest/kafka.explorer.d.ts.map +1 -0
- package/dist/nest/kafka.health.d.ts +7 -0
- package/dist/nest/kafka.health.d.ts.map +1 -0
- package/dist/nest/kafka.module.d.ts +61 -0
- package/dist/nest/kafka.module.d.ts.map +1 -0
- package/dist/otel.d.ts +83 -5
- package/dist/otel.d.ts.map +1 -0
- package/dist/otel.js +100 -6
- package/dist/otel.js.map +1 -1
- package/dist/otel.mjs +98 -5
- package/dist/otel.mjs.map +1 -1
- package/dist/serde.d.ts +157 -0
- package/dist/serde.d.ts.map +1 -0
- package/dist/serde.js +308 -0
- package/dist/serde.js.map +1 -0
- package/dist/serde.mjs +158 -0
- package/dist/serde.mjs.map +1 -0
- package/dist/testing/client.mock.d.ts +47 -0
- package/dist/testing/client.mock.d.ts.map +1 -0
- package/dist/testing/index.d.ts +4 -0
- package/dist/testing/index.d.ts.map +1 -0
- package/dist/testing/test.container.d.ts +63 -0
- package/dist/testing/test.container.d.ts.map +1 -0
- package/dist/{testing.d.mts → testing/transport.fake.d.ts} +7 -111
- package/dist/testing/transport.fake.d.ts.map +1 -0
- package/dist/testing.d.ts +2 -318
- package/dist/testing.d.ts.map +1 -0
- package/dist/testing.js +26 -0
- package/dist/testing.js.map +1 -1
- package/dist/testing.mjs +26 -0
- package/dist/testing.mjs.map +1 -1
- package/package.json +40 -8
- package/dist/chunk-SM4FZKAZ.mjs.map +0 -1
- package/dist/client-1irhGEu0.d.mts +0 -751
- package/dist/client-BpFjkHhr.d.ts +0 -751
- package/dist/consumer.types-fFCag3VJ.d.ts +0 -958
- package/dist/core.d.mts +0 -314
- package/dist/index.d.mts +0 -128
- package/dist/otel.d.mts +0 -27
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
// src/client/message/serde.ts
|
|
2
|
+
var JsonSerde = class {
|
|
3
|
+
/** JSON-stringify the validated payload. Returns a UTF-8 string. */
|
|
4
|
+
serialize(value) {
|
|
5
|
+
return JSON.stringify(value);
|
|
6
|
+
}
|
|
7
|
+
/** JSON-parse UTF-8 wire bytes into an object. */
|
|
8
|
+
deserialize(data) {
|
|
9
|
+
return JSON.parse(data.toString("utf8"));
|
|
10
|
+
}
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
// src/client/message/schema-registry.ts
|
|
14
|
+
var SchemaRegistryClient = class {
|
|
15
|
+
constructor(options) {
|
|
16
|
+
this.options = options;
|
|
17
|
+
if (!options.baseUrl) {
|
|
18
|
+
throw new Error("SchemaRegistryClient: baseUrl is required");
|
|
19
|
+
}
|
|
20
|
+
this.fetchFn = options.fetchFn ?? fetch;
|
|
21
|
+
this.cacheTtlMs = options.cacheTtlMs ?? 3e5;
|
|
22
|
+
}
|
|
23
|
+
options;
|
|
24
|
+
fetchFn;
|
|
25
|
+
cacheTtlMs;
|
|
26
|
+
latestCache = /* @__PURE__ */ new Map();
|
|
27
|
+
/**
|
|
28
|
+
* `id → schema` cache. Schema ids are immutable in a Confluent-compatible
|
|
29
|
+
* registry (a given id always maps to the same schema string), so entries
|
|
30
|
+
* are cached for the lifetime of the client with no TTL.
|
|
31
|
+
*/
|
|
32
|
+
byIdCache = /* @__PURE__ */ new Map();
|
|
33
|
+
headers() {
|
|
34
|
+
const h = {
|
|
35
|
+
"Content-Type": "application/vnd.schemaregistry.v1+json"
|
|
36
|
+
};
|
|
37
|
+
if (this.options.auth) {
|
|
38
|
+
const { username, password } = this.options.auth;
|
|
39
|
+
h["Authorization"] = "Basic " + Buffer.from(`${username}:${password}`).toString("base64");
|
|
40
|
+
}
|
|
41
|
+
return h;
|
|
42
|
+
}
|
|
43
|
+
async request(method, path, body) {
|
|
44
|
+
const url = `${this.options.baseUrl.replace(/\/$/, "")}${path}`;
|
|
45
|
+
const res = await this.fetchFn(url, {
|
|
46
|
+
method,
|
|
47
|
+
headers: this.headers(),
|
|
48
|
+
...body !== void 0 && { body: JSON.stringify(body) }
|
|
49
|
+
});
|
|
50
|
+
if (!res.ok) {
|
|
51
|
+
const text = await res.text().catch(() => "");
|
|
52
|
+
throw new Error(
|
|
53
|
+
`SchemaRegistry ${method} ${path} failed: ${res.status} ${res.statusText}${text ? ` \u2014 ${text}` : ""}`
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
return await res.json();
|
|
57
|
+
}
|
|
58
|
+
/** Fetch the latest schema registered under `subject`. Cached for `cacheTtlMs`. */
|
|
59
|
+
async getLatestSchema(subject) {
|
|
60
|
+
const cached = this.latestCache.get(subject);
|
|
61
|
+
if (cached && cached.expiresAt > Date.now()) return cached.value;
|
|
62
|
+
const raw = await this.request("GET", `/subjects/${encodeURIComponent(subject)}/versions/latest`);
|
|
63
|
+
const value = {
|
|
64
|
+
id: raw.id,
|
|
65
|
+
version: raw.version,
|
|
66
|
+
schema: raw.schema
|
|
67
|
+
};
|
|
68
|
+
this.latestCache.set(subject, {
|
|
69
|
+
value,
|
|
70
|
+
expiresAt: Date.now() + this.cacheTtlMs
|
|
71
|
+
});
|
|
72
|
+
return value;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Fetch a schema by its globally unique registry id (`GET /schemas/ids/{id}`).
|
|
76
|
+
*
|
|
77
|
+
* Used by the Avro/Protobuf serdes on the deserialize path: the writer schema
|
|
78
|
+
* id is read from the Confluent wire-format prefix, then resolved here. Results
|
|
79
|
+
* are cached forever (schema ids are immutable), so a given id triggers exactly
|
|
80
|
+
* one registry round-trip regardless of how many messages reference it.
|
|
81
|
+
*/
|
|
82
|
+
async getSchemaById(id) {
|
|
83
|
+
const cached = this.byIdCache.get(id);
|
|
84
|
+
if (cached) return cached;
|
|
85
|
+
const raw = await this.request(
|
|
86
|
+
"GET",
|
|
87
|
+
`/schemas/ids/${id}`
|
|
88
|
+
);
|
|
89
|
+
const value = { id, schema: raw.schema, schemaType: raw.schemaType };
|
|
90
|
+
this.byIdCache.set(id, value);
|
|
91
|
+
return value;
|
|
92
|
+
}
|
|
93
|
+
/** Fetch a specific schema version of a subject. */
|
|
94
|
+
async getSchemaVersion(subject, version) {
|
|
95
|
+
const raw = await this.request(
|
|
96
|
+
"GET",
|
|
97
|
+
`/subjects/${encodeURIComponent(subject)}/versions/${version}`
|
|
98
|
+
);
|
|
99
|
+
return { id: raw.id, version: raw.version, schema: raw.schema };
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Register a schema under `subject` (idempotent — re-registering the same
|
|
103
|
+
* schema returns the existing id). Returns the registry-assigned schema id.
|
|
104
|
+
*/
|
|
105
|
+
async registerSchema(subject, schema, schemaType = "JSON") {
|
|
106
|
+
this.latestCache.delete(subject);
|
|
107
|
+
return this.request(
|
|
108
|
+
"POST",
|
|
109
|
+
`/subjects/${encodeURIComponent(subject)}/versions`,
|
|
110
|
+
{ schema, schemaType }
|
|
111
|
+
);
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Test `schema` against the subject's compatibility policy without registering.
|
|
115
|
+
* Returns `true` when the registry reports the schema as compatible.
|
|
116
|
+
*/
|
|
117
|
+
async checkCompatibility(subject, schema, schemaType = "JSON") {
|
|
118
|
+
const res = await this.request(
|
|
119
|
+
"POST",
|
|
120
|
+
`/compatibility/subjects/${encodeURIComponent(subject)}/versions/latest`,
|
|
121
|
+
{ schema, schemaType }
|
|
122
|
+
);
|
|
123
|
+
return res.is_compatible;
|
|
124
|
+
}
|
|
125
|
+
};
|
|
126
|
+
function registrySchema(client, subject, options) {
|
|
127
|
+
const enforceVersion = options?.enforceVersion ?? true;
|
|
128
|
+
return {
|
|
129
|
+
async parse(data, ctx) {
|
|
130
|
+
const latest = await client.getLatestSchema(subject);
|
|
131
|
+
if (enforceVersion && ctx?.version !== void 0 && ctx.version > latest.version) {
|
|
132
|
+
throw new Error(
|
|
133
|
+
`registrySchema: message version ${ctx.version} for subject "${subject}" is newer than the latest registered version ${latest.version} \u2014 register the schema before producing with it`
|
|
134
|
+
);
|
|
135
|
+
}
|
|
136
|
+
if (options?.validator) {
|
|
137
|
+
return options.validator.parse(data, ctx);
|
|
138
|
+
}
|
|
139
|
+
return data;
|
|
140
|
+
}
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
export {
|
|
145
|
+
JsonSerde,
|
|
146
|
+
SchemaRegistryClient,
|
|
147
|
+
registrySchema
|
|
148
|
+
};
|
|
149
|
+
//# sourceMappingURL=chunk-PQVBRDNV.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/client/message/serde.ts","../src/client/message/schema-registry.ts"],"sourcesContent":["import type { MessageHeaders } from \"../types\";\n\n/**\n * Context passed to `MessageSerde.serialize` / `deserialize`.\n *\n * Carries the topic name, decoded message headers, and which side of the\n * record is being (de)serialized. A Confluent Schema Registry serde uses\n * `topic` + `isKey` to derive the subject name (`<topic>-value` / `<topic>-key`)\n * and reads the schema id from the header/magic-byte prefix on `data`.\n */\nexport interface SerdeContext {\n /** Topic the message is produced to / consumed from. */\n topic: string;\n /** Decoded message headers (envelope headers included). */\n headers: MessageHeaders;\n /**\n * Which side of the Kafka record this call is (de)serializing.\n * `false` / omitted → the value (default); `true` → the key.\n * Used by schema-registry serdes to pick the `value` vs `key` subject.\n */\n isKey?: boolean;\n}\n\n/**\n * Pluggable serialization layer for message payloads.\n *\n * A `MessageSerde` converts a validated payload object to the wire form\n * (`Buffer` or `string`) on produce, and back to an object on consume.\n * The default is {@link JsonSerde}, which reproduces the client's historical\n * `JSON.stringify` / `JSON.parse` behaviour exactly.\n *\n * Serde only touches the message VALUE. Envelope metadata\n * (`x-event-id`, `x-correlation-id`, `x-lamport-clock`, `traceparent`, …)\n * always travels in headers and is never serialized through this layer.\n *\n * Set a client-wide serde via `KafkaClientOptions.serde`, or a per-topic\n * override via `topic(...).serde(mySerde)` — the per-topic serde wins for\n * that topic.\n *\n * @example\n * ```ts\n * const kafka = new KafkaClient(id, group, brokers, { serde: new JsonSerde() });\n * ```\n */\nexport interface MessageSerde {\n /**\n * Serialize a validated payload object to wire bytes (`Buffer`) or a\n * `string`. Validation has already run on `value` before this is called.\n */\n serialize(\n value: unknown,\n ctx: SerdeContext,\n ): Buffer | string | Promise<Buffer | string>;\n /**\n * Deserialize raw wire bytes into a payload object. Schema validation\n * (if any) runs on the returned object afterwards.\n */\n deserialize(data: Buffer, ctx: SerdeContext): unknown | Promise<unknown>;\n}\n\n/**\n * Default {@link MessageSerde}: JSON via `JSON.stringify` / `JSON.parse`.\n *\n * Byte-for-byte identical to the client's historical serialization, so it is\n * a zero-behaviour-change default. Produces a UTF-8 `string` on serialize and\n * decodes UTF-8 bytes on deserialize.\n */\nexport class JsonSerde implements MessageSerde {\n /** JSON-stringify the validated payload. Returns a UTF-8 string. */\n serialize(value: unknown): string {\n return JSON.stringify(value);\n }\n\n /** JSON-parse UTF-8 wire bytes into an object. */\n deserialize(data: Buffer): unknown {\n return JSON.parse(data.toString(\"utf8\"));\n }\n}\n","import type { SchemaLike, SchemaParseContext } from \"./topic\";\n\n/** A schema registered in a Confluent-compatible Schema Registry. */\nexport interface RegisteredSchema {\n /** Globally unique schema id assigned by the registry. */\n id: number;\n /** Version of the schema within its subject. */\n version: number;\n /** The schema definition string (JSON Schema / Avro / Protobuf source). */\n schema: string;\n}\n\n/** Options for `SchemaRegistryClient`. */\nexport interface SchemaRegistryClientOptions {\n /** Registry base URL, e.g. `http://localhost:8081` or a Confluent Cloud SR endpoint. */\n baseUrl: string;\n /** HTTP Basic credentials (Confluent Cloud SR API key/secret). */\n auth?: { username: string; password: string };\n /** Cache TTL for subject lookups in ms. Default: `300_000` (5 min). */\n cacheTtlMs?: number;\n /** Injectable fetch implementation (tests). Default: global `fetch`. */\n fetchFn?: typeof fetch;\n}\n\n/** Schema type accepted by Confluent-compatible registries. */\nexport type RegistrySchemaType = \"JSON\" | \"AVRO\" | \"PROTOBUF\";\n\n/**\n * Minimal, dependency-free client for the Confluent Schema Registry REST API\n * (works with Confluent Platform/Cloud, Redpanda, Karapace, AWS Glue SR proxy).\n *\n * Scope: subject/version management, compatibility checks, and id->schema\n * lookups. Used to keep locally-defined schemas in lockstep with a central\n * registry, and as the backing lookup for the Avro/Protobuf serdes in\n * `@drarzter/kafka-client/serde` (which handle the wire-format framing).\n *\n * @example\n * ```ts\n * const registry = new SchemaRegistryClient({ baseUrl: 'http://localhost:8081' });\n * const { id } = await registry.registerSchema(\n * 'order.created-value',\n * JSON.stringify(orderJsonSchema),\n * 'JSON',\n * );\n * ```\n */\nexport class SchemaRegistryClient {\n private readonly fetchFn: typeof fetch;\n private readonly cacheTtlMs: number;\n private readonly latestCache = new Map<\n string,\n { value: RegisteredSchema; expiresAt: number }\n >();\n /**\n * `id → schema` cache. Schema ids are immutable in a Confluent-compatible\n * registry (a given id always maps to the same schema string), so entries\n * are cached for the lifetime of the client with no TTL.\n */\n private readonly byIdCache = new Map<\n number,\n { id: number; schema: string; schemaType?: string }\n >();\n\n constructor(private readonly options: SchemaRegistryClientOptions) {\n if (!options.baseUrl) {\n throw new Error(\"SchemaRegistryClient: baseUrl is required\");\n }\n this.fetchFn = options.fetchFn ?? fetch;\n this.cacheTtlMs = options.cacheTtlMs ?? 300_000;\n }\n\n private headers(): Record<string, string> {\n const h: Record<string, string> = {\n \"Content-Type\": \"application/vnd.schemaregistry.v1+json\",\n };\n if (this.options.auth) {\n const { username, password } = this.options.auth;\n h[\"Authorization\"] =\n \"Basic \" + Buffer.from(`${username}:${password}`).toString(\"base64\");\n }\n return h;\n }\n\n private async request<R>(\n method: \"GET\" | \"POST\",\n path: string,\n body?: unknown,\n ): Promise<R> {\n const url = `${this.options.baseUrl.replace(/\\/$/, \"\")}${path}`;\n const res = await this.fetchFn(url, {\n method,\n headers: this.headers(),\n ...(body !== undefined && { body: JSON.stringify(body) }),\n });\n if (!res.ok) {\n const text = await res.text().catch(() => \"\");\n throw new Error(\n `SchemaRegistry ${method} ${path} failed: ${res.status} ${res.statusText}${text ? ` — ${text}` : \"\"}`,\n );\n }\n return (await res.json()) as R;\n }\n\n /** Fetch the latest schema registered under `subject`. Cached for `cacheTtlMs`. */\n async getLatestSchema(subject: string): Promise<RegisteredSchema> {\n const cached = this.latestCache.get(subject);\n if (cached && cached.expiresAt > Date.now()) return cached.value;\n const raw = await this.request<{\n id: number;\n version: number;\n schema: string;\n }>(\"GET\", `/subjects/${encodeURIComponent(subject)}/versions/latest`);\n const value: RegisteredSchema = {\n id: raw.id,\n version: raw.version,\n schema: raw.schema,\n };\n this.latestCache.set(subject, {\n value,\n expiresAt: Date.now() + this.cacheTtlMs,\n });\n return value;\n }\n\n /**\n * Fetch a schema by its globally unique registry id (`GET /schemas/ids/{id}`).\n *\n * Used by the Avro/Protobuf serdes on the deserialize path: the writer schema\n * id is read from the Confluent wire-format prefix, then resolved here. Results\n * are cached forever (schema ids are immutable), so a given id triggers exactly\n * one registry round-trip regardless of how many messages reference it.\n */\n async getSchemaById(\n id: number,\n ): Promise<{ id: number; schema: string; schemaType?: string }> {\n const cached = this.byIdCache.get(id);\n if (cached) return cached;\n const raw = await this.request<{ schema: string; schemaType?: string }>(\n \"GET\",\n `/schemas/ids/${id}`,\n );\n const value = { id, schema: raw.schema, schemaType: raw.schemaType };\n this.byIdCache.set(id, value);\n return value;\n }\n\n /** Fetch a specific schema version of a subject. */\n async getSchemaVersion(\n subject: string,\n version: number,\n ): Promise<RegisteredSchema> {\n const raw = await this.request<{\n id: number;\n version: number;\n schema: string;\n }>(\n \"GET\",\n `/subjects/${encodeURIComponent(subject)}/versions/${version}`,\n );\n return { id: raw.id, version: raw.version, schema: raw.schema };\n }\n\n /**\n * Register a schema under `subject` (idempotent — re-registering the same\n * schema returns the existing id). Returns the registry-assigned schema id.\n */\n async registerSchema(\n subject: string,\n schema: string,\n schemaType: RegistrySchemaType = \"JSON\",\n ): Promise<{ id: number }> {\n this.latestCache.delete(subject);\n return this.request<{ id: number }>(\n \"POST\",\n `/subjects/${encodeURIComponent(subject)}/versions`,\n { schema, schemaType },\n );\n }\n\n /**\n * Test `schema` against the subject's compatibility policy without registering.\n * Returns `true` when the registry reports the schema as compatible.\n */\n async checkCompatibility(\n subject: string,\n schema: string,\n schemaType: RegistrySchemaType = \"JSON\",\n ): Promise<boolean> {\n const res = await this.request<{ is_compatible: boolean }>(\n \"POST\",\n `/compatibility/subjects/${encodeURIComponent(subject)}/versions/latest`,\n { schema, schemaType },\n );\n return res.is_compatible;\n }\n}\n\n/** Options for `registrySchema()`. */\nexport interface RegistrySchemaOptions<T> {\n /**\n * Local structural validator (Zod/Valibot/…) applied to every message.\n * The registry governs schema *evolution*; this governs runtime *shape*.\n */\n validator?: SchemaLike<T>;\n /**\n * When `true` (default), the message's `x-schema-version` must not be newer\n * than the latest version registered for the subject — a producer publishing\n * an unregistered version fails loudly instead of drifting silently.\n */\n enforceVersion?: boolean;\n}\n\n/**\n * Bridge a Schema Registry subject to this library's `SchemaLike` seam.\n *\n * On each `parse` the adapter resolves the subject's latest registered version\n * (cached), optionally verifies the message's schema version does not exceed\n * it, and delegates structural validation to the provided local validator.\n * Attach the result to a `TopicDescriptor` like any other schema:\n *\n * @example\n * ```ts\n * const registry = new SchemaRegistryClient({ baseUrl: 'http://localhost:8081' });\n *\n * const OrderCreated = topic('order.created').schema(\n * registrySchema(registry, 'order.created-value', {\n * validator: z.object({ orderId: z.string() }),\n * }),\n * );\n * ```\n */\nexport function registrySchema<T = any>(\n client: SchemaRegistryClient,\n subject: string,\n options?: RegistrySchemaOptions<T>,\n): SchemaLike<T> {\n const enforceVersion = options?.enforceVersion ?? true;\n return {\n async parse(data: unknown, ctx?: SchemaParseContext): Promise<T> {\n const latest = await client.getLatestSchema(subject);\n if (enforceVersion && ctx?.version !== undefined && ctx.version > latest.version) {\n throw new Error(\n `registrySchema: message version ${ctx.version} for subject \"${subject}\" ` +\n `is newer than the latest registered version ${latest.version} — ` +\n `register the schema before producing with it`,\n );\n }\n if (options?.validator) {\n return options.validator.parse(data, ctx);\n }\n return data as T;\n },\n };\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import type { EventEnvelope } from "../core";
|
|
2
|
+
import type { DlqReplayOptions } from "../core";
|
|
3
|
+
/** DLQ topic suffix — the CLI operates on `<topic>.dlq`. */
|
|
4
|
+
export declare const DLQ_SUFFIX = ".dlq";
|
|
5
|
+
/** `ls` — list DLQ topics with message counts. */
|
|
6
|
+
export interface LsCommand {
|
|
7
|
+
command: "ls";
|
|
8
|
+
brokers: string[];
|
|
9
|
+
/** Optional topic-name prefix filter (matched against the base topic). */
|
|
10
|
+
prefix?: string;
|
|
11
|
+
}
|
|
12
|
+
/** `peek` — print the first N messages of `<topic>.dlq`. */
|
|
13
|
+
export interface PeekCommand {
|
|
14
|
+
command: "peek";
|
|
15
|
+
brokers: string[];
|
|
16
|
+
/** Base topic name — the CLI reads from `<topic>.dlq`. */
|
|
17
|
+
topic: string;
|
|
18
|
+
/** Maximum number of messages to print. Default: 10. */
|
|
19
|
+
limit: number;
|
|
20
|
+
}
|
|
21
|
+
/** `replay` — re-publish `<topic>.dlq` messages via `KafkaClient.replayDlq`. */
|
|
22
|
+
export interface ReplayCommand {
|
|
23
|
+
command: "replay";
|
|
24
|
+
brokers: string[];
|
|
25
|
+
/** Base topic name — the CLI replays `<topic>.dlq`. */
|
|
26
|
+
topic: string;
|
|
27
|
+
/** Override destination topic (default: read from `x-dlq-original-topic`). */
|
|
28
|
+
target?: string;
|
|
29
|
+
/** Log what would be replayed without publishing. */
|
|
30
|
+
dryRun: boolean;
|
|
31
|
+
/**
|
|
32
|
+
* `true` → full replay of all DLQ messages on every call (ephemeral group).
|
|
33
|
+
* `false` → incremental — only messages since the previous replay (stable group).
|
|
34
|
+
*/
|
|
35
|
+
fromBeginning: boolean;
|
|
36
|
+
}
|
|
37
|
+
/** `help` — print usage. */
|
|
38
|
+
export interface HelpCommand {
|
|
39
|
+
command: "help";
|
|
40
|
+
}
|
|
41
|
+
/** Discriminated union of every parsed CLI invocation. */
|
|
42
|
+
export type ParsedCommand = LsCommand | PeekCommand | ReplayCommand | HelpCommand;
|
|
43
|
+
/** Thrown by `parseArgs` when the argv is invalid. Carries the usage text. */
|
|
44
|
+
export declare class DlqUsageError extends Error {
|
|
45
|
+
constructor(message: string);
|
|
46
|
+
}
|
|
47
|
+
export declare const USAGE = "kafka-client-dlq \u2014 dead-letter queue operations\n\nUsage:\n kafka-client-dlq ls --brokers <b1,b2> [--prefix <name>]\n kafka-client-dlq peek --brokers <b1,b2> --topic <name> [--limit <n>]\n kafka-client-dlq replay --brokers <b1,b2> --topic <name> [--target <t>] [--dry-run] [--from-beginning | --incremental]\n\nCommands:\n ls List DLQ topics (ending in .dlq) with per-topic message counts.\n peek Print up to N messages from <topic>.dlq (offset, x-dlq-* headers, value).\n replay Re-publish <topic>.dlq messages to their original topic (or --target).\n\nOptions:\n --brokers <list> Comma-separated broker addresses (required). e.g. localhost:9092\n --prefix <name> ls: only show DLQ topics whose base name starts with <name>.\n --topic <name> peek/replay: base topic name (the CLI uses <name>.dlq).\n --limit <n> peek: max messages to print (default 10).\n --target <t> replay: override destination topic.\n --dry-run replay: log without publishing.\n --from-beginning replay: full replay every call (default).\n --incremental replay: only messages added since the previous replay.\n -h, --help Show this help.\n\nExamples:\n kafka-client-dlq ls --brokers localhost:9092\n kafka-client-dlq ls --brokers localhost:9092 --prefix orders\n kafka-client-dlq peek --brokers localhost:9092 --topic orders.created --limit 5\n kafka-client-dlq replay --brokers localhost:9092 --topic orders.created --dry-run\n kafka-client-dlq replay --brokers localhost:9092 --topic orders.created --target orders.manual --incremental\n";
|
|
48
|
+
/**
|
|
49
|
+
* Parse the process argv (already sliced past `node <script>`) into a
|
|
50
|
+
* `ParsedCommand`. Pure and synchronous — no I/O — so it is fully unit-testable.
|
|
51
|
+
*
|
|
52
|
+
* @throws {DlqUsageError} on unknown commands, missing/invalid flags.
|
|
53
|
+
*/
|
|
54
|
+
export declare function parseArgs(argv: string[]): ParsedCommand;
|
|
55
|
+
/** Per-partition low/high watermarks for a topic. */
|
|
56
|
+
export interface PartitionWatermarks {
|
|
57
|
+
partition: number;
|
|
58
|
+
low: string;
|
|
59
|
+
high: string;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Minimal client surface the CLI needs. The production factory backs this with
|
|
63
|
+
* a real `KafkaClient` plus its transport admin; tests inject a fake.
|
|
64
|
+
*/
|
|
65
|
+
export interface DlqCliClient {
|
|
66
|
+
/** List all topics visible to the broker (via `checkStatus`). */
|
|
67
|
+
listTopics(): Promise<string[]>;
|
|
68
|
+
/** Per-partition low/high watermarks for a single topic. */
|
|
69
|
+
fetchTopicOffsets(topic: string): Promise<PartitionWatermarks[]>;
|
|
70
|
+
/** Read up to `limit` messages from `dlqTopic`, from the earliest offset. */
|
|
71
|
+
peekMessages(dlqTopic: string, limit: number): Promise<Array<EventEnvelope<unknown>>>;
|
|
72
|
+
/** Delegate to `KafkaClient.replayDlq`. */
|
|
73
|
+
replayDlq(topic: string, options: DlqReplayOptions): Promise<{
|
|
74
|
+
replayed: number;
|
|
75
|
+
skipped: number;
|
|
76
|
+
}>;
|
|
77
|
+
/** Release all connections. */
|
|
78
|
+
close(): Promise<void>;
|
|
79
|
+
}
|
|
80
|
+
/** Injected dependencies for `runDlqCommand`. */
|
|
81
|
+
export interface RunDeps {
|
|
82
|
+
/** Build a connected client for the given brokers. */
|
|
83
|
+
createClient(brokers: string[]): DlqCliClient | Promise<DlqCliClient>;
|
|
84
|
+
/** Sink for human-readable output. Defaults are wired by the bin entrypoint. */
|
|
85
|
+
out: (line: string) => void;
|
|
86
|
+
}
|
|
87
|
+
export interface DlqTopicCount {
|
|
88
|
+
/** The `<name>.dlq` topic. */
|
|
89
|
+
dlqTopic: string;
|
|
90
|
+
/** The base topic (`dlqTopic` without the `.dlq` suffix). */
|
|
91
|
+
baseTopic: string;
|
|
92
|
+
/** Sum over partitions of (high − low). */
|
|
93
|
+
count: number;
|
|
94
|
+
}
|
|
95
|
+
export type RunResult = {
|
|
96
|
+
command: "ls";
|
|
97
|
+
topics: DlqTopicCount[];
|
|
98
|
+
} | {
|
|
99
|
+
command: "peek";
|
|
100
|
+
printed: number;
|
|
101
|
+
} | {
|
|
102
|
+
command: "replay";
|
|
103
|
+
replayed: number;
|
|
104
|
+
skipped: number;
|
|
105
|
+
dryRun: boolean;
|
|
106
|
+
} | {
|
|
107
|
+
command: "help";
|
|
108
|
+
};
|
|
109
|
+
/** Sum (high − low) across a topic's partitions. Negative widths clamp to 0. */
|
|
110
|
+
export declare function countFromWatermarks(watermarks: PartitionWatermarks[]): number;
|
|
111
|
+
/** Truncate a value for display, appending an ellipsis marker when cut. */
|
|
112
|
+
export declare function truncate(value: string, max?: number): string;
|
|
113
|
+
/**
|
|
114
|
+
* Execute a parsed command against injected deps.
|
|
115
|
+
* Returns a structured result; all human-readable output goes through `deps.out`.
|
|
116
|
+
* The client is always closed in a `finally` block.
|
|
117
|
+
*/
|
|
118
|
+
export declare function runDlqCommand(cmd: ParsedCommand, deps: RunDeps): Promise<RunResult>;
|
|
119
|
+
//# sourceMappingURL=dlq.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dlq.d.ts","sourceRoot":"","sources":["../../src/cli/dlq.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":""}
|