@vibesdotdev/integrations-kafka 0.0.0-stage → 1.0.0-rc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AUDIT-CODE.md +40 -0
- package/AUDIT-SEAL.md +12 -0
- package/LICENSE +126 -0
- package/README.md +76 -2
- package/SEALED.md +13 -0
- package/dist/admin.d.ts +20 -0
- package/dist/admin.d.ts.map +1 -0
- package/dist/admin.js +51 -0
- package/dist/admin.js.map +1 -0
- package/dist/auth/sasl.node.impl.d.ts +18 -0
- package/dist/auth/sasl.node.impl.d.ts.map +1 -0
- package/dist/auth/sasl.node.impl.js +62 -0
- package/dist/auth/sasl.node.impl.js.map +1 -0
- package/dist/chat/realtime-transport/host.d.ts +14 -0
- package/dist/chat/realtime-transport/host.d.ts.map +1 -0
- package/dist/chat/realtime-transport/host.js +7 -0
- package/dist/chat/realtime-transport/host.js.map +1 -0
- package/dist/chat/realtime-transport/index.d.ts +15 -0
- package/dist/chat/realtime-transport/index.d.ts.map +1 -0
- package/dist/chat/realtime-transport/index.js +13 -0
- package/dist/chat/realtime-transport/index.js.map +1 -0
- package/dist/chat/realtime-transport/lifecycle.d.ts +30 -0
- package/dist/chat/realtime-transport/lifecycle.d.ts.map +1 -0
- package/dist/chat/realtime-transport/lifecycle.js +125 -0
- package/dist/chat/realtime-transport/lifecycle.js.map +1 -0
- package/dist/chat/realtime-transport/projection.d.ts +127 -0
- package/dist/chat/realtime-transport/projection.d.ts.map +1 -0
- package/dist/chat/realtime-transport/projection.js +156 -0
- package/dist/chat/realtime-transport/projection.js.map +1 -0
- package/dist/chat/realtime-transport/sse-kafka-bridge.d.ts +32 -0
- package/dist/chat/realtime-transport/sse-kafka-bridge.d.ts.map +1 -0
- package/dist/chat/realtime-transport/sse-kafka-bridge.js +58 -0
- package/dist/chat/realtime-transport/sse-kafka-bridge.js.map +1 -0
- package/dist/chat/realtime-transport/ws-kafka-bridge.d.ts +10 -0
- package/dist/chat/realtime-transport/ws-kafka-bridge.d.ts.map +1 -0
- package/dist/chat/realtime-transport/ws-kafka-bridge.js +13 -0
- package/dist/chat/realtime-transport/ws-kafka-bridge.js.map +1 -0
- package/dist/client.d.ts +16 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +29 -0
- package/dist/client.js.map +1 -0
- package/dist/config/kafka.config.descriptor.d.ts +109 -0
- package/dist/config/kafka.config.descriptor.d.ts.map +1 -0
- package/dist/config/kafka.config.descriptor.js +60 -0
- package/dist/config/kafka.config.descriptor.js.map +1 -0
- package/dist/connections.d.ts +27 -0
- package/dist/connections.d.ts.map +1 -0
- package/dist/connections.js +20 -0
- package/dist/connections.js.map +1 -0
- package/dist/connections.node.impl.d.ts +34 -0
- package/dist/connections.node.impl.d.ts.map +1 -0
- package/dist/connections.node.impl.js +236 -0
- package/dist/connections.node.impl.js.map +1 -0
- package/dist/index.d.ts +22 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +24 -0
- package/dist/index.js.map +1 -0
- package/dist/kafka-client.node.impl.d.ts +9 -0
- package/dist/kafka-client.node.impl.d.ts.map +1 -0
- package/dist/kafka-client.node.impl.js +10 -0
- package/dist/kafka-client.node.impl.js.map +1 -0
- package/dist/kafka-connector.impl.d.ts +53 -0
- package/dist/kafka-connector.impl.d.ts.map +1 -0
- package/dist/kafka-connector.impl.js +97 -0
- package/dist/kafka-connector.impl.js.map +1 -0
- package/dist/kafka-event-adapter.descriptor.d.ts +11 -0
- package/dist/kafka-event-adapter.descriptor.d.ts.map +1 -0
- package/dist/kafka-event-adapter.descriptor.js +20 -0
- package/dist/kafka-event-adapter.descriptor.js.map +1 -0
- package/dist/kafka-event-adapter.impl.d.ts +22 -0
- package/dist/kafka-event-adapter.impl.d.ts.map +1 -0
- package/dist/kafka-event-adapter.impl.js +140 -0
- package/dist/kafka-event-adapter.impl.js.map +1 -0
- package/dist/kafka-substrate.descriptor.d.ts +4 -0
- package/dist/kafka-substrate.descriptor.d.ts.map +1 -0
- package/dist/kafka-substrate.descriptor.js +12 -0
- package/dist/kafka-substrate.descriptor.js.map +1 -0
- package/dist/kafka.d.ts +18 -0
- package/dist/kafka.d.ts.map +1 -0
- package/dist/kafka.js +23 -0
- package/dist/kafka.js.map +1 -0
- package/dist/kafka.node.plugin.d.ts +3 -0
- package/dist/kafka.node.plugin.d.ts.map +1 -0
- package/dist/kafka.node.plugin.js +66 -0
- package/dist/kafka.node.plugin.js.map +1 -0
- package/dist/kafka.plugin.d.ts +10 -0
- package/dist/kafka.plugin.d.ts.map +1 -0
- package/dist/kafka.plugin.js +28 -0
- package/dist/kafka.plugin.js.map +1 -0
- package/dist/logging/kafka.logger.descriptor.d.ts +7 -0
- package/dist/logging/kafka.logger.descriptor.d.ts.map +1 -0
- package/dist/logging/kafka.logger.descriptor.js +13 -0
- package/dist/logging/kafka.logger.descriptor.js.map +1 -0
- package/dist/message-schemas.d.ts +94 -0
- package/dist/message-schemas.d.ts.map +1 -0
- package/dist/message-schemas.js +68 -0
- package/dist/message-schemas.js.map +1 -0
- package/dist/request-queue-timeout-guard.d.ts +29 -0
- package/dist/request-queue-timeout-guard.d.ts.map +1 -0
- package/dist/request-queue-timeout-guard.js +245 -0
- package/dist/request-queue-timeout-guard.js.map +1 -0
- package/dist/schemas/contracts.d.ts +190 -0
- package/dist/schemas/contracts.d.ts.map +1 -0
- package/dist/schemas/contracts.js +85 -0
- package/dist/schemas/contracts.js.map +1 -0
- package/dist/schemas/kafka.d.ts +116 -0
- package/dist/schemas/kafka.d.ts.map +1 -0
- package/dist/schemas/kafka.js +13 -0
- package/dist/schemas/kafka.js.map +1 -0
- package/dist/schemas/realtime.d.ts +135 -0
- package/dist/schemas/realtime.d.ts.map +1 -0
- package/dist/schemas/realtime.js +44 -0
- package/dist/schemas/realtime.js.map +1 -0
- package/dist/schemas/worker-context.d.ts +14 -0
- package/dist/schemas/worker-context.d.ts.map +1 -0
- package/dist/schemas/worker-context.js +26 -0
- package/dist/schemas/worker-context.js.map +1 -0
- package/dist/topics.d.ts +85 -0
- package/dist/topics.d.ts.map +1 -0
- package/dist/topics.js +90 -0
- package/dist/topics.js.map +1 -0
- package/dist/workers/adapter/db-ops.d.ts +28 -0
- package/dist/workers/adapter/db-ops.d.ts.map +1 -0
- package/dist/workers/adapter/db-ops.js +14 -0
- package/dist/workers/adapter/db-ops.js.map +1 -0
- package/dist/workers/adapter/index.d.ts +16 -0
- package/dist/workers/adapter/index.d.ts.map +1 -0
- package/dist/workers/adapter/index.js +15 -0
- package/dist/workers/adapter/index.js.map +1 -0
- package/dist/workers/adapter/provider.d.ts +151 -0
- package/dist/workers/adapter/provider.d.ts.map +1 -0
- package/dist/workers/adapter/provider.js +654 -0
- package/dist/workers/adapter/provider.js.map +1 -0
- package/dist/workers/adapter/worker-adapter.kafka.descriptor.d.ts +36 -0
- package/dist/workers/adapter/worker-adapter.kafka.descriptor.d.ts.map +1 -0
- package/dist/workers/adapter/worker-adapter.kafka.descriptor.js +22 -0
- package/dist/workers/adapter/worker-adapter.kafka.descriptor.js.map +1 -0
- package/dist/workers/adapter/worker-adapter.kafka.impl.d.ts +36 -0
- package/dist/workers/adapter/worker-adapter.kafka.impl.d.ts.map +1 -0
- package/dist/workers/adapter/worker-adapter.kafka.impl.js +84 -0
- package/dist/workers/adapter/worker-adapter.kafka.impl.js.map +1 -0
- package/dist/workers/adapter/workers-kafka.db.context.d.ts +6 -0
- package/dist/workers/adapter/workers-kafka.db.context.d.ts.map +1 -0
- package/dist/workers/adapter/workers-kafka.db.context.descriptor.d.ts +43 -0
- package/dist/workers/adapter/workers-kafka.db.context.descriptor.d.ts.map +1 -0
- package/dist/workers/adapter/workers-kafka.db.context.descriptor.js +20 -0
- package/dist/workers/adapter/workers-kafka.db.context.descriptor.js.map +1 -0
- package/dist/workers/adapter/workers-kafka.db.context.js +5 -0
- package/dist/workers/adapter/workers-kafka.db.context.js.map +1 -0
- package/dist/workers/index.d.ts +8 -0
- package/dist/workers/index.d.ts.map +1 -0
- package/dist/workers/index.js +9 -0
- package/dist/workers/index.js.map +1 -0
- package/dist/workers/provider-jobs.sqlite-schema.d.ts +438 -0
- package/dist/workers/provider-jobs.sqlite-schema.d.ts.map +1 -0
- package/dist/workers/provider-jobs.sqlite-schema.js +37 -0
- package/dist/workers/provider-jobs.sqlite-schema.js.map +1 -0
- package/dist/workers/workers-kafka.consumer.plugin.d.ts +4 -0
- package/dist/workers/workers-kafka.consumer.plugin.d.ts.map +1 -0
- package/dist/workers/workers-kafka.consumer.plugin.js +11 -0
- package/dist/workers/workers-kafka.consumer.plugin.js.map +1 -0
- package/dist/workers/workers-kafka.plugin.d.ts +9 -0
- package/dist/workers/workers-kafka.plugin.d.ts.map +1 -0
- package/dist/workers/workers-kafka.plugin.js +27 -0
- package/dist/workers/workers-kafka.plugin.js.map +1 -0
- package/package.json +176 -4
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { CapabilityError, settleNow, valueFreeFailure } from '@vibesdotdev/kernel';
|
|
2
|
+
import { createRuntimePlugin } from '@vibesdotdev/kernel/factory';
|
|
3
|
+
import { getLogger } from '@vibesdotdev/logging';
|
|
4
|
+
import { getKafkaClient } from "../../client.js";
|
|
5
|
+
import { KafkaConnectionPurpose } from "../../connections.js";
|
|
6
|
+
import { readKafkaConsumerGroupPrefix } from "../../kafka.js";
|
|
7
|
+
import { KAFKA_TOPICS as T } from "../../topics.js";
|
|
8
|
+
import { RealtimeProjection } from "./projection.js";
|
|
9
|
+
export class BridgeLifecycle {
|
|
10
|
+
runtime;
|
|
11
|
+
projection;
|
|
12
|
+
surface;
|
|
13
|
+
closeConnections;
|
|
14
|
+
consumers = new Map();
|
|
15
|
+
owner;
|
|
16
|
+
starting;
|
|
17
|
+
stopping;
|
|
18
|
+
registered = false;
|
|
19
|
+
active = false;
|
|
20
|
+
closed = false;
|
|
21
|
+
id = `kafka-realtime-${crypto.randomUUID()}`;
|
|
22
|
+
constructor(runtime, projection, surface, closeConnections) {
|
|
23
|
+
this.runtime = runtime;
|
|
24
|
+
this.projection = projection;
|
|
25
|
+
this.surface = surface;
|
|
26
|
+
this.closeConnections = closeConnections;
|
|
27
|
+
}
|
|
28
|
+
start() {
|
|
29
|
+
if (this.closed || this.runtime.lifecycle.signal.aborted)
|
|
30
|
+
return Promise.reject(new CapabilityError('Realtime bridge is disposed.', 'UNAVAILABLE', { reason: 'kafka-realtime-disposed' }));
|
|
31
|
+
if (this.stopping)
|
|
32
|
+
return this.stopping.then(() => this.start());
|
|
33
|
+
if (this.active)
|
|
34
|
+
return Promise.resolve();
|
|
35
|
+
return this.starting ??= this.activate();
|
|
36
|
+
}
|
|
37
|
+
async activate() {
|
|
38
|
+
try {
|
|
39
|
+
const [startup] = await Promise.allSettled([this.acquire()]);
|
|
40
|
+
if (startup.status === 'rejected') {
|
|
41
|
+
const cleanup = await Promise.allSettled([this.release()]);
|
|
42
|
+
const failures = cleanup.flatMap(result => result.status === 'rejected' ? [result.reason] : []);
|
|
43
|
+
throw new AggregateError([startup.reason, ...failures], 'Realtime startup failed');
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
finally {
|
|
47
|
+
this.starting = undefined;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
async acquire() {
|
|
51
|
+
if (!this.registered) {
|
|
52
|
+
await this.runtime.registerPlugin(createRuntimePlugin({
|
|
53
|
+
id: this.id,
|
|
54
|
+
onDispose: async () => { this.closed = true; await this.stop(); }
|
|
55
|
+
}));
|
|
56
|
+
this.registered = true;
|
|
57
|
+
}
|
|
58
|
+
await this.runtime.runOutsideInvocation(async () => {
|
|
59
|
+
const client = await getKafkaClient(this.runtime);
|
|
60
|
+
this.owner = client;
|
|
61
|
+
const prefix = await readKafkaConsumerGroupPrefix(this.runtime, `${this.surface}-bridge`);
|
|
62
|
+
const groups = [
|
|
63
|
+
{ purpose: KafkaConnectionPurpose.CHAT, topics: this.surface === 'sse'
|
|
64
|
+
? [T.CHAT_MESSAGES, T.CHAT_TYPING, T.CHAT_PRESENCE, T.CHAT_ROOMS]
|
|
65
|
+
: [T.CHAT_MESSAGES, T.CHAT_TYPING, T.CHAT_PRESENCE] },
|
|
66
|
+
{ purpose: KafkaConnectionPurpose.WORKERS, topics: this.surface === 'sse'
|
|
67
|
+
? [T.WORKER_JOBS, T.WORKER_HEALTH, T.TEXT_GENERATION_BUBBLES, T.TEXT_GENERATION_JOBS]
|
|
68
|
+
: [T.WORKER_JOBS, T.WORKER_HEALTH, T.TEXT_GENERATION_BUBBLES] }
|
|
69
|
+
];
|
|
70
|
+
for (const group of groups) {
|
|
71
|
+
const consumer = await client.connections.createCustomConsumer(group.purpose, `${prefix}-${group.purpose}`);
|
|
72
|
+
if (!consumer)
|
|
73
|
+
throw new CapabilityError('Kafka is unavailable in build scope.', 'UNAVAILABLE', { reason: 'kafka-build-scope' });
|
|
74
|
+
this.consumers.set(group.purpose === KafkaConnectionPurpose.CHAT && this.surface === 'sse' ? 'unified-chat' : group.purpose, consumer);
|
|
75
|
+
await consumer.subscribe({ topics: group.topics, fromBeginning: false });
|
|
76
|
+
await consumer.run({
|
|
77
|
+
autoCommit: group.purpose === KafkaConnectionPurpose.CHAT,
|
|
78
|
+
eachMessage: async ({ topic, message }) => {
|
|
79
|
+
const parsed = settleNow(() => this.projection.parse(topic, message.value?.toString() ?? ''));
|
|
80
|
+
if (!parsed.ok) {
|
|
81
|
+
getLogger('kafka:realtime', this.runtime).warn('Malformed Kafka realtime message', {
|
|
82
|
+
topic, failure: valueFreeFailure(parsed.cause)
|
|
83
|
+
});
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
await this.projection.project(parsed.value);
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
this.active = true;
|
|
92
|
+
}
|
|
93
|
+
async release() {
|
|
94
|
+
if (!this.consumers.size) {
|
|
95
|
+
this.active = false;
|
|
96
|
+
this.closeConnections();
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
const outcomes = await Promise.allSettled(Array.from(this.consumers.values(), consumer => this.owner.connections.releaseCustomConsumer(consumer)));
|
|
100
|
+
this.consumers.clear();
|
|
101
|
+
this.active = false;
|
|
102
|
+
this.closeConnections();
|
|
103
|
+
const failures = outcomes.flatMap(result => result.status === 'rejected' ? [result.reason] : []);
|
|
104
|
+
if (failures.length)
|
|
105
|
+
throw new AggregateError(failures, 'Realtime consumer cleanup failed');
|
|
106
|
+
}
|
|
107
|
+
stop() {
|
|
108
|
+
return this.stopping ??= this.deactivate();
|
|
109
|
+
}
|
|
110
|
+
async deactivate() {
|
|
111
|
+
try {
|
|
112
|
+
const startup = this.starting ? await Promise.allSettled([this.starting]) : [];
|
|
113
|
+
const cleanup = await Promise.allSettled([this.release()]);
|
|
114
|
+
const failures = [...startup, ...cleanup].flatMap(result => result.status === 'rejected' ? [result.reason] : []);
|
|
115
|
+
if (failures.length)
|
|
116
|
+
throw new AggregateError(failures, 'Realtime shutdown failed');
|
|
117
|
+
}
|
|
118
|
+
finally {
|
|
119
|
+
this.stopping = undefined;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
isRunning() { return this.active; }
|
|
123
|
+
getStats() { return { active: this.active, consumers: Array.from(this.consumers.keys()), consumerCount: this.consumers.size }; }
|
|
124
|
+
}
|
|
125
|
+
//# sourceMappingURL=lifecycle.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lifecycle.js","sourceRoot":"","sources":["../../../src/chat/realtime-transport/lifecycle.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { type SseMessage, type MessagePersistence } from '../../schemas/realtime.ts';
|
|
2
|
+
export declare function mapKafkaAgentEventType(type: string): string;
|
|
3
|
+
export declare class RealtimeProjection {
|
|
4
|
+
private readonly deliver;
|
|
5
|
+
private readonly websocket;
|
|
6
|
+
persistence?: MessagePersistence;
|
|
7
|
+
constructor(deliver: (channel: string, message: SseMessage) => void, websocket?: boolean);
|
|
8
|
+
private emit;
|
|
9
|
+
parse(topic: string, raw: string): {
|
|
10
|
+
readonly kind: "message";
|
|
11
|
+
readonly event: {
|
|
12
|
+
eventType: string;
|
|
13
|
+
data: {
|
|
14
|
+
[x: string]: import("@vibesdotdev/kernel/bootstrap").JsonValue;
|
|
15
|
+
chatRoomId: string;
|
|
16
|
+
userId?: string | undefined;
|
|
17
|
+
};
|
|
18
|
+
};
|
|
19
|
+
readonly payload?: undefined;
|
|
20
|
+
} | {
|
|
21
|
+
readonly kind: "typing";
|
|
22
|
+
readonly event: {
|
|
23
|
+
data: {
|
|
24
|
+
[x: string]: import("@vibesdotdev/kernel/bootstrap").JsonValue;
|
|
25
|
+
chatRoomId: string;
|
|
26
|
+
userId: string;
|
|
27
|
+
isTyping: boolean;
|
|
28
|
+
agentId?: string | undefined;
|
|
29
|
+
typingStartedAt?: string | undefined;
|
|
30
|
+
};
|
|
31
|
+
};
|
|
32
|
+
readonly payload?: undefined;
|
|
33
|
+
} | {
|
|
34
|
+
readonly kind: "presence";
|
|
35
|
+
readonly event: {
|
|
36
|
+
data: {
|
|
37
|
+
[x: string]: import("@vibesdotdev/kernel/bootstrap").JsonValue;
|
|
38
|
+
userId: string;
|
|
39
|
+
status: string;
|
|
40
|
+
lastSeen: string;
|
|
41
|
+
activeRooms?: string[] | undefined;
|
|
42
|
+
};
|
|
43
|
+
};
|
|
44
|
+
readonly payload?: undefined;
|
|
45
|
+
} | {
|
|
46
|
+
readonly kind: "room";
|
|
47
|
+
readonly event: {
|
|
48
|
+
data: {
|
|
49
|
+
[x: string]: import("@vibesdotdev/kernel/bootstrap").JsonValue;
|
|
50
|
+
id: string;
|
|
51
|
+
};
|
|
52
|
+
};
|
|
53
|
+
readonly payload?: undefined;
|
|
54
|
+
} | {
|
|
55
|
+
readonly kind: "worker";
|
|
56
|
+
readonly event: {
|
|
57
|
+
[x: string]: import("@vibesdotdev/kernel/bootstrap").JsonValue;
|
|
58
|
+
jobId: string;
|
|
59
|
+
jobType: string;
|
|
60
|
+
workerId: string;
|
|
61
|
+
timestamp: string;
|
|
62
|
+
type: "job.queued" | "job.created" | "job.started" | "job.progress" | "job.completed" | "job.failed" | "job.retrying" | "job.cancelled" | "tool.event";
|
|
63
|
+
id?: string | undefined;
|
|
64
|
+
payload?: import("@vibesdotdev/kernel/bootstrap").JsonValue | undefined;
|
|
65
|
+
progress?: number | Record<string, import("@vibesdotdev/kernel/bootstrap").JsonValue> | undefined;
|
|
66
|
+
envelope?: {
|
|
67
|
+
toolId: string;
|
|
68
|
+
toolCallId: string;
|
|
69
|
+
toolCallEventId: string;
|
|
70
|
+
payload: import("@vibesdotdev/kernel/bootstrap").JsonValue;
|
|
71
|
+
} | undefined;
|
|
72
|
+
metadata?: Record<string, import("@vibesdotdev/kernel/bootstrap").JsonValue> | undefined;
|
|
73
|
+
attemptNumber?: number | undefined;
|
|
74
|
+
error?: string | undefined;
|
|
75
|
+
result?: import("@vibesdotdev/kernel/bootstrap").JsonValue | undefined;
|
|
76
|
+
};
|
|
77
|
+
readonly payload: {
|
|
78
|
+
[x: string]: import("@vibesdotdev/kernel/bootstrap").JsonValue;
|
|
79
|
+
crawlId?: string | undefined;
|
|
80
|
+
id?: string | undefined;
|
|
81
|
+
crawl?: {
|
|
82
|
+
[x: string]: import("@vibesdotdev/kernel/bootstrap").JsonValue;
|
|
83
|
+
id?: string | undefined;
|
|
84
|
+
} | undefined;
|
|
85
|
+
sessionId?: string | undefined;
|
|
86
|
+
promptId?: string | undefined;
|
|
87
|
+
} | undefined;
|
|
88
|
+
} | {
|
|
89
|
+
readonly kind: "bubble";
|
|
90
|
+
readonly event: {
|
|
91
|
+
[x: string]: import("@vibesdotdev/kernel/bootstrap").JsonValue;
|
|
92
|
+
channel: string;
|
|
93
|
+
payload: {
|
|
94
|
+
[x: string]: import("@vibesdotdev/kernel/bootstrap").JsonValue;
|
|
95
|
+
chatRoomId?: string | undefined;
|
|
96
|
+
bubble?: {
|
|
97
|
+
[x: string]: import("@vibesdotdev/kernel/bootstrap").JsonValue;
|
|
98
|
+
type: string;
|
|
99
|
+
content?: string | undefined;
|
|
100
|
+
bubbleId?: string | undefined;
|
|
101
|
+
metadata?: {
|
|
102
|
+
[x: string]: import("@vibesdotdev/kernel/bootstrap").JsonValue;
|
|
103
|
+
messageId?: string | undefined;
|
|
104
|
+
agentId?: string | undefined;
|
|
105
|
+
toolName?: string | undefined;
|
|
106
|
+
toolCallId?: string | undefined;
|
|
107
|
+
toolArgs?: import("@vibesdotdev/kernel/bootstrap").JsonValue | undefined;
|
|
108
|
+
toolResult?: import("@vibesdotdev/kernel/bootstrap").JsonValue | undefined;
|
|
109
|
+
toolError?: import("@vibesdotdev/kernel/bootstrap").JsonValue | undefined;
|
|
110
|
+
timestamp?: string | undefined;
|
|
111
|
+
} | undefined;
|
|
112
|
+
} | undefined;
|
|
113
|
+
};
|
|
114
|
+
};
|
|
115
|
+
readonly payload?: undefined;
|
|
116
|
+
} | {
|
|
117
|
+
readonly kind: "health";
|
|
118
|
+
readonly event: import("@vibesdotdev/kernel/schemas/json").JsonObject;
|
|
119
|
+
readonly payload?: undefined;
|
|
120
|
+
} | {
|
|
121
|
+
readonly kind: "job";
|
|
122
|
+
readonly event: import("@vibesdotdev/kernel/schemas/json").JsonObject;
|
|
123
|
+
readonly payload?: undefined;
|
|
124
|
+
};
|
|
125
|
+
project(parsed: ReturnType<RealtimeProjection['parse']>): Promise<void>;
|
|
126
|
+
}
|
|
127
|
+
//# sourceMappingURL=projection.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"projection.d.ts","sourceRoot":"","sources":["../../../src/chat/realtime-transport/projection.ts"],"names":[],"mappings":"AAEA,OAAO,EAGN,KAAK,UAAU,EAAE,KAAK,kBAAkB,EACxC,MAAM,2BAA2B,CAAC;AAGnC,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAM3D;AAED,qBAAa,kBAAkB;IAGlB,OAAO,CAAC,QAAQ,CAAC,OAAO;IAAkD,OAAO,CAAC,QAAQ,CAAC,SAAS;IAFhH,WAAW,CAAC,EAAE,kBAAkB,CAAC;gBAEJ,OAAO,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,KAAK,IAAI,EAAmB,SAAS,UAAQ;IAExH,OAAO,CAAC,IAAI;IAKZ,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAqB1B,OAAO,CAAC,MAAM,EAAE,UAAU,CAAC,kBAAkB,CAAC,OAAO,CAAC,CAAC;CA0F7D"}
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import { CapabilityError } from '@vibesdotdev/kernel';
|
|
2
|
+
import { JsonValueFromReaderSchema } from '@vibesdotdev/kernel/schemas/json';
|
|
3
|
+
import { ChatMessageSchema, TypingSchema, PresenceSchema, RoomSchema, WorkerEventSchema, WorkerPayloadSchema, BubbleEventSchema, JsonObjectSchema, SseMessageSchema } from "../../schemas/realtime.js";
|
|
4
|
+
import { KAFKA_TOPICS as T } from "../../topics.js";
|
|
5
|
+
export function mapKafkaAgentEventType(type) {
|
|
6
|
+
return new Map([
|
|
7
|
+
['chat.agent.chunk', 'agent_chunk'], ['chat.agent.thinking', 'agent_thinking'],
|
|
8
|
+
['chat.agent.tool_call', 'agent_tool_call'], ['chat.agent.complete', 'agent_complete'],
|
|
9
|
+
['chat.agent.error', 'agent_error']
|
|
10
|
+
]).get(type) ?? 'agent_event';
|
|
11
|
+
}
|
|
12
|
+
export class RealtimeProjection {
|
|
13
|
+
deliver;
|
|
14
|
+
websocket;
|
|
15
|
+
persistence;
|
|
16
|
+
constructor(deliver, websocket = false) {
|
|
17
|
+
this.deliver = deliver;
|
|
18
|
+
this.websocket = websocket;
|
|
19
|
+
}
|
|
20
|
+
emit(channel, type, data) {
|
|
21
|
+
this.deliver(channel, SseMessageSchema.parse({ type, data: JsonValueFromReaderSchema.parse(data) }));
|
|
22
|
+
}
|
|
23
|
+
// Parse the wire payload before entering project(). Handler/persistence errors are never parse errors.
|
|
24
|
+
parse(topic, raw) {
|
|
25
|
+
const value = JSON.parse(raw);
|
|
26
|
+
switch (topic) {
|
|
27
|
+
case T.CHAT_MESSAGES: return { kind: 'message', event: ChatMessageSchema.parse(value) };
|
|
28
|
+
case T.CHAT_TYPING: return { kind: 'typing', event: TypingSchema.parse(value) };
|
|
29
|
+
case T.CHAT_PRESENCE: return { kind: 'presence', event: PresenceSchema.parse(value) };
|
|
30
|
+
case T.CHAT_ROOMS: return { kind: 'room', event: RoomSchema.parse(value) };
|
|
31
|
+
case T.WORKER_JOBS: {
|
|
32
|
+
const event = WorkerEventSchema.parse(value);
|
|
33
|
+
// Validate routing payloads here, while malformed input is still distinguishable.
|
|
34
|
+
const payload = event.jobType === 'crawl' || event.jobType === 'prompt-test'
|
|
35
|
+
? WorkerPayloadSchema.parse(event.payload ?? {}) : undefined;
|
|
36
|
+
return { kind: 'worker', event, payload };
|
|
37
|
+
}
|
|
38
|
+
case T.TEXT_GENERATION_BUBBLES: return { kind: 'bubble', event: BubbleEventSchema.parse(value) };
|
|
39
|
+
case T.WORKER_HEALTH: return { kind: 'health', event: JsonObjectSchema.parse(value) };
|
|
40
|
+
case T.TEXT_GENERATION_JOBS: return { kind: 'job', event: JsonObjectSchema.parse(value) };
|
|
41
|
+
default: throw new CapabilityError('Unsupported realtime topic.', 'INVALID_INPUT', { reason: 'kafka-realtime-topic-invalid' });
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
async project(parsed) {
|
|
45
|
+
switch (parsed.kind) {
|
|
46
|
+
case 'message': {
|
|
47
|
+
const { eventType, data } = parsed.event;
|
|
48
|
+
if (eventType !== 'chat.message' && !eventType.startsWith('chat.agent.'))
|
|
49
|
+
return;
|
|
50
|
+
if (this.websocket && eventType !== 'chat.message')
|
|
51
|
+
return;
|
|
52
|
+
const type = eventType === 'chat.message' ? 'message' : mapKafkaAgentEventType(eventType);
|
|
53
|
+
this.emit(`chat:${data.chatRoomId}:messages`, type, data);
|
|
54
|
+
if (!this.websocket && eventType === 'chat.message' && data.userId)
|
|
55
|
+
this.emit(`user:${data.userId}:messages`, type, data);
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
case 'typing':
|
|
59
|
+
this.emit(`chat:${parsed.event.data.chatRoomId}:typing`, 'typing', parsed.event.data);
|
|
60
|
+
return;
|
|
61
|
+
case 'presence': {
|
|
62
|
+
const data = parsed.event.data;
|
|
63
|
+
this.emit('global:presence', 'presence', data);
|
|
64
|
+
for (const room of data.activeRooms ?? []) {
|
|
65
|
+
this.emit(`chat:${room}:presence`, 'presence', this.websocket ? data : { userId: data.userId, status: data.status, lastSeen: data.lastSeen });
|
|
66
|
+
}
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
case 'room':
|
|
70
|
+
this.emit(`chat:${parsed.event.data.id}:room`, 'room', parsed.event.data);
|
|
71
|
+
return;
|
|
72
|
+
case 'health':
|
|
73
|
+
this.emit('workers:health', 'worker_health', parsed.event);
|
|
74
|
+
return;
|
|
75
|
+
case 'job':
|
|
76
|
+
this.emit('workers:text-generation', 'job_status', parsed.event);
|
|
77
|
+
return;
|
|
78
|
+
case 'worker': {
|
|
79
|
+
const { event, payload } = parsed;
|
|
80
|
+
if (this.websocket) {
|
|
81
|
+
const crawlId = payload?.crawlId ?? payload?.id;
|
|
82
|
+
if (crawlId)
|
|
83
|
+
this.emit(`ingest:crawl:${crawlId}`, event.type || 'crawl_event', event);
|
|
84
|
+
this.emit('ingest:crawls', event.type || 'crawl_event', { crawlId: payload?.crawlId, jobId: event.jobId });
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
if (event.type === 'tool.event' && event.envelope) {
|
|
88
|
+
this.emit('studio:tools', 'tool.event', { envelope: event.envelope, metadata: {
|
|
89
|
+
...event.metadata, jobId: event.jobId, jobType: event.jobType, workerId: event.workerId, timestamp: event.timestamp
|
|
90
|
+
} });
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
if (event.jobType === 'prompt-test') {
|
|
94
|
+
if (!payload?.sessionId || !payload.promptId)
|
|
95
|
+
return;
|
|
96
|
+
const type = new Map([
|
|
97
|
+
['job.created', 'test_created'], ['job.started', 'test_started'], ['job.progress', 'test_chunk'],
|
|
98
|
+
['job.completed', 'test_completed'], ['job.failed', 'test_failed'], ['job.retrying', 'test_retrying']
|
|
99
|
+
]).get(event.type) ?? 'test_event';
|
|
100
|
+
this.emit(`prompt-test:${payload.sessionId}`, type, {
|
|
101
|
+
jobId: event.jobId, promptId: payload.promptId, sessionId: payload.sessionId,
|
|
102
|
+
chunk: payload.chunk, totalContent: payload.totalContent, tokens: payload.tokens,
|
|
103
|
+
responseText: payload.responseText, duration: payload.duration, promptContent: payload.promptContent,
|
|
104
|
+
messageChain: payload.messageChain, testResult: payload.testResult, error: event.error, timestamp: event.timestamp
|
|
105
|
+
});
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
if (event.jobType !== 'crawl')
|
|
109
|
+
return;
|
|
110
|
+
const crawlId = payload?.crawlId ?? payload?.id ?? payload?.crawl?.id;
|
|
111
|
+
if (!crawlId)
|
|
112
|
+
return;
|
|
113
|
+
const type = new Map([
|
|
114
|
+
['job.queued', 'crawl_queued'], ['job.created', 'crawl_created'], ['job.started', 'crawl_started'],
|
|
115
|
+
['job.progress', 'crawl_progress'], ['job.completed', 'crawl_completed'], ['job.failed', 'crawl_failed'],
|
|
116
|
+
['job.retrying', 'crawl_retrying'], ['tool.event', 'crawl_tool_event']
|
|
117
|
+
]).get(event.type) ?? 'crawl_event';
|
|
118
|
+
this.emit(`ingest:crawl:${crawlId}`, type, {
|
|
119
|
+
crawlId, jobId: event.jobId, progress: event.progress, payload: event.payload,
|
|
120
|
+
error: event.error, attemptNumber: event.attemptNumber, timestamp: event.timestamp
|
|
121
|
+
});
|
|
122
|
+
this.emit('ingest:crawls', type, { crawlId, jobId: event.jobId, jobType: event.jobType, progress: event.progress, timestamp: event.timestamp });
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
case 'bubble': {
|
|
126
|
+
const event = parsed.event;
|
|
127
|
+
const { chatRoomId, bubble } = event.payload;
|
|
128
|
+
if (!chatRoomId)
|
|
129
|
+
return;
|
|
130
|
+
if (this.websocket) {
|
|
131
|
+
this.emit(`chat:${chatRoomId}:messages`, 'agent_chunk', event);
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
if (event.channel !== 'chat' || !bubble)
|
|
135
|
+
return;
|
|
136
|
+
const metadata = bubble.metadata ?? {};
|
|
137
|
+
const { content, type } = bubble;
|
|
138
|
+
const data = { chatRoomId, messageId: metadata.messageId, agentId: metadata.agentId, content };
|
|
139
|
+
if (type === 'complete') {
|
|
140
|
+
if (this.persistence && metadata.messageId && content)
|
|
141
|
+
await this.persistence.updateMessage(metadata.messageId, content);
|
|
142
|
+
this.emit(`chat:${chatRoomId}:messages`, 'agent_complete', { ...data, metadata });
|
|
143
|
+
}
|
|
144
|
+
else if (type === 'error') {
|
|
145
|
+
this.emit(`chat:${chatRoomId}:messages`, 'agent_error', { ...data, error: content, metadata });
|
|
146
|
+
}
|
|
147
|
+
else if (['thinking', 'tool_call', 'tool_response', 'content'].includes(type)) {
|
|
148
|
+
this.emit(`chat:${chatRoomId}:messages`, 'agent_chunk', {
|
|
149
|
+
...data, metadata: { chunkType: type, bubbleId: bubble.bubbleId ?? `${Date.now()}`, ...metadata }
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
//# sourceMappingURL=projection.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"projection.js","sourceRoot":"","sources":["../../../src/chat/realtime-transport/projection.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { type VibesRuntime } from '@vibesdotdev/kernel';
|
|
2
|
+
import type { ReadonlyJsonObject } from '@vibesdotdev/kernel/schemas/json';
|
|
3
|
+
import { type MessagePersistence, type SseMessage } from '../../schemas/realtime.ts';
|
|
4
|
+
import { type SseBridgeHost } from './host.ts';
|
|
5
|
+
export { mapKafkaAgentEventType } from './projection.ts';
|
|
6
|
+
export type { SseMessage } from '../../schemas/realtime.ts';
|
|
7
|
+
export interface SseBridgeConnection {
|
|
8
|
+
accepts(channel: string, message: SseMessage): boolean;
|
|
9
|
+
push(channel: string, message: SseMessage): void;
|
|
10
|
+
}
|
|
11
|
+
export declare class SSEKafkaBridge {
|
|
12
|
+
private readonly runtime;
|
|
13
|
+
private host;
|
|
14
|
+
private readonly connections;
|
|
15
|
+
private readonly projection;
|
|
16
|
+
private readonly lifecycle;
|
|
17
|
+
constructor(runtime: VibesRuntime, host?: SseBridgeHost);
|
|
18
|
+
openConnection(runtime: VibesRuntime, connection: SseBridgeConnection): () => void;
|
|
19
|
+
private deliver;
|
|
20
|
+
setHost(host: SseBridgeHost): void;
|
|
21
|
+
/** Persistence is optional. Legacy database objects cannot pretend to persist. */
|
|
22
|
+
configure(deps: MessagePersistence | ReadonlyJsonObject): void;
|
|
23
|
+
start(): Promise<void>;
|
|
24
|
+
stop(): Promise<void>;
|
|
25
|
+
isRunning(): boolean;
|
|
26
|
+
getStats(): {
|
|
27
|
+
active: boolean;
|
|
28
|
+
consumers: string[];
|
|
29
|
+
consumerCount: number;
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=sse-kafka-bridge.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sse-kafka-bridge.d.ts","sourceRoot":"","sources":["../../../src/chat/realtime-transport/sse-kafka-bridge.ts"],"names":[],"mappings":"AAAA,OAAO,EAA2E,KAAK,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACjI,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,kCAAkC,CAAC;AAC3E,OAAO,EAA4B,KAAK,kBAAkB,EAAE,KAAK,UAAU,EAAE,MAAM,2BAA2B,CAAC;AAC/G,OAAO,EAA4B,KAAK,aAAa,EAAE,MAAM,WAAW,CAAC;AAIzE,OAAO,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAC;AACzD,YAAY,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AAE5D,MAAM,WAAW,mBAAmB;IACnC,OAAO,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC;IACvD,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,GAAG,IAAI,CAAC;CACjD;AAMD,qBAAa,cAAc;IAKd,OAAO,CAAC,QAAQ,CAAC,OAAO;IAAgB,OAAO,CAAC,IAAI;IAJhE,OAAO,CAAC,QAAQ,CAAC,WAAW,CAA6B;IACzD,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAqB;IAChD,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAkB;gBAEf,OAAO,EAAE,YAAY,EAAU,IAAI,GAAE,aAAwC;IAK1G,cAAc,CAAC,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,mBAAmB,GAAG,MAAM,IAAI;IAMlF,OAAO,CAAC,OAAO;IAkBf,OAAO,CAAC,IAAI,EAAE,aAAa;IAE3B,kFAAkF;IAClF,SAAS,CAAC,IAAI,EAAE,kBAAkB,GAAG,kBAAkB,GAAG,IAAI;IAM9D,KAAK;IACL,IAAI;IACJ,SAAS;IACT,QAAQ;;;;;CACR"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { CapabilityError, settleNow } from '@vibesdotdev/kernel';
|
|
2
|
+
import { MessagePersistenceSchema } from "../../schemas/realtime.js";
|
|
3
|
+
import { unavailableSseBridgeHost } from "./host.js";
|
|
4
|
+
import { RealtimeProjection } from "./projection.js";
|
|
5
|
+
import { BridgeLifecycle } from "./lifecycle.js";
|
|
6
|
+
export { mapKafkaAgentEventType } from "./projection.js";
|
|
7
|
+
export class SSEKafkaBridge {
|
|
8
|
+
runtime;
|
|
9
|
+
host;
|
|
10
|
+
connections = new Set();
|
|
11
|
+
projection;
|
|
12
|
+
lifecycle;
|
|
13
|
+
constructor(runtime, host = unavailableSseBridgeHost) {
|
|
14
|
+
this.runtime = runtime;
|
|
15
|
+
this.host = host;
|
|
16
|
+
this.projection = new RealtimeProjection((channel, message) => this.deliver(channel, message));
|
|
17
|
+
this.lifecycle = new BridgeLifecycle(runtime, this.projection, 'sse', () => this.connections.clear());
|
|
18
|
+
}
|
|
19
|
+
openConnection(runtime, connection) {
|
|
20
|
+
const open = { connection, invocation: runtime.captureInvocation() };
|
|
21
|
+
this.connections.add(open);
|
|
22
|
+
return () => { this.connections.delete(open); };
|
|
23
|
+
}
|
|
24
|
+
deliver(channel, message) {
|
|
25
|
+
// Synchronous connection delivery must visit every connection even when one fails.
|
|
26
|
+
const failures = [];
|
|
27
|
+
const host = settleNow(() => this.host.broadcastToChannel(channel, message));
|
|
28
|
+
if (!host.ok)
|
|
29
|
+
failures.push(host.cause);
|
|
30
|
+
for (const open of this.connections) {
|
|
31
|
+
const delivery = settleNow(() => open.invocation.run(() => {
|
|
32
|
+
if (open.connection.accepts(channel, message))
|
|
33
|
+
open.connection.push(channel, message);
|
|
34
|
+
}));
|
|
35
|
+
if (!delivery.ok) {
|
|
36
|
+
this.connections.delete(open);
|
|
37
|
+
failures.push(delivery.cause);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
if (failures.length === 1)
|
|
41
|
+
throw failures[0];
|
|
42
|
+
if (failures.length)
|
|
43
|
+
throw new AggregateError(failures, 'Realtime delivery failed');
|
|
44
|
+
}
|
|
45
|
+
setHost(host) { this.host = host; }
|
|
46
|
+
/** Persistence is optional. Legacy database objects cannot pretend to persist. */
|
|
47
|
+
configure(deps) {
|
|
48
|
+
const parsed = MessagePersistenceSchema.safeParse(deps);
|
|
49
|
+
if (!parsed.success)
|
|
50
|
+
throw new CapabilityError('Supply the message persistence owner capability.', 'UNAVAILABLE', { reason: 'kafka-realtime-persistence-unavailable' });
|
|
51
|
+
this.projection.persistence = parsed.data;
|
|
52
|
+
}
|
|
53
|
+
start() { return this.lifecycle.start(); }
|
|
54
|
+
stop() { return this.lifecycle.stop(); }
|
|
55
|
+
isRunning() { return this.lifecycle.isRunning(); }
|
|
56
|
+
getStats() { return this.lifecycle.getStats(); }
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=sse-kafka-bridge.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sse-kafka-bridge.js","sourceRoot":"","sources":["../../../src/chat/realtime-transport/sse-kafka-bridge.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { VibesRuntime } from '@vibesdotdev/kernel';
|
|
2
|
+
import type { WebSocketBridgeHost } from './host.ts';
|
|
3
|
+
export declare class WSKafkaBridge {
|
|
4
|
+
private readonly lifecycle;
|
|
5
|
+
constructor(runtime: VibesRuntime, adapter: WebSocketBridgeHost);
|
|
6
|
+
start(): Promise<void>;
|
|
7
|
+
stop(): Promise<void>;
|
|
8
|
+
isRunning(): boolean;
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=ws-kafka-bridge.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ws-kafka-bridge.d.ts","sourceRoot":"","sources":["../../../src/chat/realtime-transport/ws-kafka-bridge.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAC;AAIrD,qBAAa,aAAa;IACzB,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAkB;gBAChC,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE,mBAAmB;IAI/D,KAAK;IACL,IAAI;IACJ,SAAS;CACT"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { RealtimeProjection } from "./projection.js";
|
|
2
|
+
import { BridgeLifecycle } from "./lifecycle.js";
|
|
3
|
+
export class WSKafkaBridge {
|
|
4
|
+
lifecycle;
|
|
5
|
+
constructor(runtime, adapter) {
|
|
6
|
+
const projection = new RealtimeProjection((channel, message) => { adapter.broadcast(channel, message); }, true);
|
|
7
|
+
this.lifecycle = new BridgeLifecycle(runtime, projection, 'ws', () => { });
|
|
8
|
+
}
|
|
9
|
+
start() { return this.lifecycle.start(); }
|
|
10
|
+
stop() { return this.lifecycle.stop(); }
|
|
11
|
+
isRunning() { return this.lifecycle.isRunning(); }
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=ws-kafka-bridge.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ws-kafka-bridge.js","sourceRoot":"","sources":["../../../src/chat/realtime-transport/ws-kafka-bridge.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AACrD,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAEjD,MAAM,OAAO,aAAa;IACR,SAAS,CAAkB;IAC5C,YAAY,OAAqB,EAAE,OAA4B;QAC9D,MAAM,UAAU,GAAG,IAAI,kBAAkB,CAAC,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE,GAAG,OAAO,CAAC,SAAS,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC;QAChH,IAAI,CAAC,SAAS,GAAG,IAAI,eAAe,CAAC,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;IAC3E,CAAC;IACD,KAAK,KAAK,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;IAC1C,IAAI,KAAK,OAAO,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;IACxC,SAAS,KAAK,OAAO,IAAI,CAAC,SAAS,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC;CAClD"}
|
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { type VibesRuntime, type RuntimeRef } from '@vibesdotdev/kernel';
|
|
2
|
+
import { BaseRuntimeClient } from '@vibesdotdev/kernel/client';
|
|
3
|
+
import type { EventAdapter } from '@vibesdotdev/kernel/events';
|
|
4
|
+
import type { KafkaConnections } from './connections.node.impl.ts';
|
|
5
|
+
import { KafkaAdmin } from './admin.ts';
|
|
6
|
+
/** Semantic owner; the Node plugin supplies its connection implementation. */
|
|
7
|
+
export declare abstract class KafkaClient extends BaseRuntimeClient<VibesRuntime> {
|
|
8
|
+
abstract readonly connections: KafkaConnections;
|
|
9
|
+
readonly admin: KafkaAdmin;
|
|
10
|
+
private readonly adapters;
|
|
11
|
+
ownAdapter(adapter: EventAdapter): void;
|
|
12
|
+
protected onDispose(): Promise<void>;
|
|
13
|
+
}
|
|
14
|
+
export declare const getKafkaClient: (runtime: RuntimeRef) => Promise<KafkaClient>;
|
|
15
|
+
export declare function requireKafkaClient(runtime: VibesRuntime): KafkaClient;
|
|
16
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAmB,KAAK,YAAY,EAAE,KAAK,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAC1F,OAAO,EAAE,iBAAiB,EAAqC,MAAM,4BAA4B,CAAC;AAClG,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAC/D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AACnE,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAExC,8EAA8E;AAC9E,8BAAsB,WAAY,SAAQ,iBAAiB,CAAC,YAAY,CAAC;IACxE,QAAQ,CAAC,QAAQ,CAAC,WAAW,EAAE,gBAAgB,CAAC;IAChD,QAAQ,CAAC,KAAK,aAAgC;IAC9C,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAA2B;IAEpD,UAAU,CAAC,OAAO,EAAE,YAAY,GAAG,IAAI;cAKvB,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC;CAO1C;AAED,eAAO,MAAM,cAAc,GAAI,SAAS,UAAU,yBAAkD,CAAC;AAErG,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,YAAY,GAAG,WAAW,CAIrE"}
|
package/dist/client.js
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { CapabilityError } from '@vibesdotdev/kernel';
|
|
2
|
+
import { BaseRuntimeClient, getVibesClient, tryGetVibesClient } from '@vibesdotdev/kernel/client';
|
|
3
|
+
import { KafkaAdmin } from "./admin.js";
|
|
4
|
+
/** Semantic owner; the Node plugin supplies its connection implementation. */
|
|
5
|
+
export class KafkaClient extends BaseRuntimeClient {
|
|
6
|
+
admin = new KafkaAdmin(this.runtime);
|
|
7
|
+
adapters = new Set();
|
|
8
|
+
ownAdapter(adapter) {
|
|
9
|
+
if (this.runtime.lifecycle.signal.aborted)
|
|
10
|
+
throw new CapabilityError('Kafka runtime is disposed.', 'UNAVAILABLE', { reason: 'kafka-client-disposed' });
|
|
11
|
+
this.adapters.add(adapter);
|
|
12
|
+
}
|
|
13
|
+
async onDispose() {
|
|
14
|
+
const outcomes = await Promise.allSettled(Array.from(this.adapters, adapter => adapter.disconnect()));
|
|
15
|
+
this.adapters.clear();
|
|
16
|
+
const connections = await Promise.allSettled([this.connections.dispose()]);
|
|
17
|
+
const failures = [...outcomes, ...connections].flatMap(outcome => outcome.status === 'rejected' ? [outcome.reason] : []);
|
|
18
|
+
if (failures.length)
|
|
19
|
+
throw new AggregateError(failures, 'Kafka runtime cleanup failed');
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
export const getKafkaClient = (runtime) => getVibesClient('kafka', runtime);
|
|
23
|
+
export function requireKafkaClient(runtime) {
|
|
24
|
+
const client = tryGetVibesClient('kafka', runtime);
|
|
25
|
+
if (!client)
|
|
26
|
+
throw new CapabilityError('Activate the Kafka runtime client before synchronous access.', 'UNAVAILABLE', { reason: 'kafka-client-not-active' });
|
|
27
|
+
return client;
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=client.js.map
|