@agentxjs/core 1.9.1-dev
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/package.json +31 -0
- package/src/agent/AgentStateMachine.ts +151 -0
- package/src/agent/README.md +296 -0
- package/src/agent/__tests__/AgentStateMachine.test.ts +346 -0
- package/src/agent/__tests__/createAgent.test.ts +728 -0
- package/src/agent/__tests__/engine/internal/messageAssemblerProcessor.test.ts +567 -0
- package/src/agent/__tests__/engine/internal/stateEventProcessor.test.ts +315 -0
- package/src/agent/__tests__/engine/internal/turnTrackerProcessor.test.ts +340 -0
- package/src/agent/__tests__/engine/mealy/Mealy.test.ts +370 -0
- package/src/agent/__tests__/engine/mealy/Store.test.ts +123 -0
- package/src/agent/__tests__/engine/mealy/combinators.test.ts +322 -0
- package/src/agent/createAgent.ts +467 -0
- package/src/agent/engine/AgentProcessor.ts +106 -0
- package/src/agent/engine/MealyMachine.ts +184 -0
- package/src/agent/engine/internal/index.ts +35 -0
- package/src/agent/engine/internal/messageAssemblerProcessor.ts +550 -0
- package/src/agent/engine/internal/stateEventProcessor.ts +313 -0
- package/src/agent/engine/internal/turnTrackerProcessor.ts +239 -0
- package/src/agent/engine/mealy/Mealy.ts +308 -0
- package/src/agent/engine/mealy/Processor.ts +70 -0
- package/src/agent/engine/mealy/Sink.ts +56 -0
- package/src/agent/engine/mealy/Source.ts +51 -0
- package/src/agent/engine/mealy/Store.ts +98 -0
- package/src/agent/engine/mealy/combinators.ts +176 -0
- package/src/agent/engine/mealy/index.ts +45 -0
- package/src/agent/index.ts +106 -0
- package/src/agent/types/engine.ts +395 -0
- package/src/agent/types/event.ts +478 -0
- package/src/agent/types/index.ts +197 -0
- package/src/agent/types/message.ts +387 -0
- package/src/common/index.ts +8 -0
- package/src/common/logger/ConsoleLogger.ts +137 -0
- package/src/common/logger/LoggerFactoryImpl.ts +123 -0
- package/src/common/logger/index.ts +26 -0
- package/src/common/logger/types.ts +98 -0
- package/src/container/Container.ts +185 -0
- package/src/container/index.ts +44 -0
- package/src/container/types.ts +71 -0
- package/src/driver/index.ts +42 -0
- package/src/driver/types.ts +363 -0
- package/src/event/EventBus.ts +260 -0
- package/src/event/README.md +237 -0
- package/src/event/__tests__/EventBus.test.ts +251 -0
- package/src/event/index.ts +46 -0
- package/src/event/types/agent.ts +512 -0
- package/src/event/types/base.ts +241 -0
- package/src/event/types/bus.ts +429 -0
- package/src/event/types/command.ts +749 -0
- package/src/event/types/container.ts +471 -0
- package/src/event/types/driver.ts +452 -0
- package/src/event/types/index.ts +26 -0
- package/src/event/types/session.ts +314 -0
- package/src/image/Image.ts +203 -0
- package/src/image/index.ts +36 -0
- package/src/image/types.ts +77 -0
- package/src/index.ts +20 -0
- package/src/mq/OffsetGenerator.ts +48 -0
- package/src/mq/README.md +166 -0
- package/src/mq/__tests__/OffsetGenerator.test.ts +121 -0
- package/src/mq/index.ts +18 -0
- package/src/mq/types.ts +172 -0
- package/src/network/RpcClient.ts +455 -0
- package/src/network/index.ts +76 -0
- package/src/network/jsonrpc.ts +336 -0
- package/src/network/protocol.ts +90 -0
- package/src/network/types.ts +284 -0
- package/src/persistence/index.ts +27 -0
- package/src/persistence/types.ts +226 -0
- package/src/runtime/AgentXRuntime.ts +501 -0
- package/src/runtime/index.ts +56 -0
- package/src/runtime/types.ts +236 -0
- package/src/session/Session.ts +71 -0
- package/src/session/index.ts +25 -0
- package/src/session/types.ts +77 -0
- package/src/workspace/index.ts +27 -0
- package/src/workspace/types.ts +131 -0
- package/tsconfig.json +10 -0
|
@@ -0,0 +1,336 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JSON-RPC 2.0 Protocol for AgentX Network Communication
|
|
3
|
+
*
|
|
4
|
+
* Uses jsonrpc-lite for message parsing/serialization.
|
|
5
|
+
*
|
|
6
|
+
* Message Types:
|
|
7
|
+
* - Request: Client → Server (has id, expects response)
|
|
8
|
+
* - Response: Server → Client (success or error)
|
|
9
|
+
* - Notification: Server → Client (no id, stream events)
|
|
10
|
+
*
|
|
11
|
+
* @see https://www.jsonrpc.org/specification
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import {
|
|
15
|
+
request as jsonrpcRequest,
|
|
16
|
+
notification as jsonrpcNotification,
|
|
17
|
+
success as jsonrpcSuccess,
|
|
18
|
+
error as jsonrpcError,
|
|
19
|
+
parse as jsonrpcParse,
|
|
20
|
+
parseObject as jsonrpcParseObject,
|
|
21
|
+
JsonRpcError,
|
|
22
|
+
} from "jsonrpc-lite";
|
|
23
|
+
import type { IParsedObject, JsonRpc } from "jsonrpc-lite";
|
|
24
|
+
import type { SystemEvent } from "../event/types/base";
|
|
25
|
+
|
|
26
|
+
// ============================================================================
|
|
27
|
+
// Re-export jsonrpc-lite types and functions
|
|
28
|
+
// ============================================================================
|
|
29
|
+
|
|
30
|
+
export { JsonRpcError };
|
|
31
|
+
export type { IParsedObject, JsonRpc };
|
|
32
|
+
|
|
33
|
+
// ============================================================================
|
|
34
|
+
// RPC Method Names
|
|
35
|
+
// ============================================================================
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* All RPC method names supported by AgentX
|
|
39
|
+
*/
|
|
40
|
+
export type RpcMethod =
|
|
41
|
+
// Container
|
|
42
|
+
| "container.create"
|
|
43
|
+
| "container.get"
|
|
44
|
+
| "container.list"
|
|
45
|
+
// Image
|
|
46
|
+
| "image.create"
|
|
47
|
+
| "image.get"
|
|
48
|
+
| "image.list"
|
|
49
|
+
| "image.delete"
|
|
50
|
+
| "image.run"
|
|
51
|
+
| "image.stop"
|
|
52
|
+
| "image.update"
|
|
53
|
+
| "image.messages"
|
|
54
|
+
// Agent
|
|
55
|
+
| "agent.get"
|
|
56
|
+
| "agent.list"
|
|
57
|
+
| "agent.destroy"
|
|
58
|
+
| "agent.destroyAll"
|
|
59
|
+
| "agent.interrupt"
|
|
60
|
+
// Message
|
|
61
|
+
| "message.send";
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Notification method names (server push)
|
|
65
|
+
*/
|
|
66
|
+
export type NotificationMethod =
|
|
67
|
+
| "stream.event" // Stream events (text_delta, tool_call, etc.)
|
|
68
|
+
| "control.ack"; // ACK for reliable delivery
|
|
69
|
+
|
|
70
|
+
// ============================================================================
|
|
71
|
+
// Request/Response Type Definitions
|
|
72
|
+
// ============================================================================
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* JSON-RPC Request structure
|
|
76
|
+
*/
|
|
77
|
+
export interface RpcRequest<M extends RpcMethod = RpcMethod, P = unknown> {
|
|
78
|
+
jsonrpc: "2.0";
|
|
79
|
+
method: M;
|
|
80
|
+
params: P;
|
|
81
|
+
id: string | number;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* JSON-RPC Success Response structure
|
|
86
|
+
*/
|
|
87
|
+
export interface RpcSuccessResponse<R = unknown> {
|
|
88
|
+
jsonrpc: "2.0";
|
|
89
|
+
result: R;
|
|
90
|
+
id: string | number;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* JSON-RPC Error Response structure
|
|
95
|
+
*/
|
|
96
|
+
export interface RpcErrorResponse {
|
|
97
|
+
jsonrpc: "2.0";
|
|
98
|
+
error: {
|
|
99
|
+
code: number;
|
|
100
|
+
message: string;
|
|
101
|
+
data?: unknown;
|
|
102
|
+
};
|
|
103
|
+
id: string | number | null;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* JSON-RPC Notification structure (no id, no response expected)
|
|
108
|
+
*/
|
|
109
|
+
export interface RpcNotification<M extends NotificationMethod = NotificationMethod, P = unknown> {
|
|
110
|
+
jsonrpc: "2.0";
|
|
111
|
+
method: M;
|
|
112
|
+
params: P;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Stream event notification params
|
|
117
|
+
*/
|
|
118
|
+
export interface StreamEventParams {
|
|
119
|
+
topic: string;
|
|
120
|
+
event: SystemEvent;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Control ACK notification params
|
|
125
|
+
*/
|
|
126
|
+
export interface ControlAckParams {
|
|
127
|
+
msgId: string;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// ============================================================================
|
|
131
|
+
// Standard JSON-RPC Error Codes
|
|
132
|
+
// ============================================================================
|
|
133
|
+
|
|
134
|
+
export const RpcErrorCodes = {
|
|
135
|
+
// Standard JSON-RPC errors
|
|
136
|
+
PARSE_ERROR: -32700,
|
|
137
|
+
INVALID_REQUEST: -32600,
|
|
138
|
+
METHOD_NOT_FOUND: -32601,
|
|
139
|
+
INVALID_PARAMS: -32602,
|
|
140
|
+
INTERNAL_ERROR: -32603,
|
|
141
|
+
// Server errors (reserved: -32000 to -32099)
|
|
142
|
+
SERVER_ERROR: -32000,
|
|
143
|
+
// Application errors (custom)
|
|
144
|
+
NOT_FOUND: 404,
|
|
145
|
+
UNAUTHORIZED: 401,
|
|
146
|
+
FORBIDDEN: 403,
|
|
147
|
+
TIMEOUT: 408,
|
|
148
|
+
} as const;
|
|
149
|
+
|
|
150
|
+
// ============================================================================
|
|
151
|
+
// Helper Functions
|
|
152
|
+
// ============================================================================
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Create a JSON-RPC request
|
|
156
|
+
*/
|
|
157
|
+
export function createRequest(
|
|
158
|
+
id: string | number,
|
|
159
|
+
method: RpcMethod | string,
|
|
160
|
+
params: unknown
|
|
161
|
+
): JsonRpc {
|
|
162
|
+
return jsonrpcRequest(id, method, params as Record<string, unknown>);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Create a JSON-RPC notification (no response expected)
|
|
167
|
+
*/
|
|
168
|
+
export function createNotification(method: NotificationMethod | string, params: unknown): JsonRpc {
|
|
169
|
+
return jsonrpcNotification(method, params as Record<string, unknown>);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Create a stream event notification
|
|
174
|
+
*/
|
|
175
|
+
export function createStreamEvent(topic: string, event: SystemEvent): JsonRpc {
|
|
176
|
+
return jsonrpcNotification("stream.event", { topic, event });
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Create an ACK notification
|
|
181
|
+
*/
|
|
182
|
+
export function createAckNotification(msgId: string): JsonRpc {
|
|
183
|
+
return jsonrpcNotification("control.ack", { msgId });
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Create a success response
|
|
188
|
+
*/
|
|
189
|
+
export function createSuccessResponse(id: string | number, result: unknown): JsonRpc {
|
|
190
|
+
return jsonrpcSuccess(id, result as Record<string, unknown>);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Create an error response
|
|
195
|
+
*/
|
|
196
|
+
export function createErrorResponse(
|
|
197
|
+
id: string | number | null,
|
|
198
|
+
code: number,
|
|
199
|
+
message: string,
|
|
200
|
+
data?: unknown
|
|
201
|
+
): JsonRpc {
|
|
202
|
+
return jsonrpcError(id, new JsonRpcError(message, code, data));
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Parse a JSON-RPC message string
|
|
207
|
+
*/
|
|
208
|
+
export function parseMessage(message: string): IParsedObject | IParsedObject[] {
|
|
209
|
+
return jsonrpcParse(message);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Parse a JSON-RPC message object
|
|
214
|
+
*/
|
|
215
|
+
export function parseMessageObject(obj: unknown): IParsedObject {
|
|
216
|
+
return jsonrpcParseObject(obj);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// ============================================================================
|
|
220
|
+
// Type Guards
|
|
221
|
+
// ============================================================================
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Check if parsed message is a request
|
|
225
|
+
*/
|
|
226
|
+
export function isRequest(parsed: IParsedObject): boolean {
|
|
227
|
+
return parsed.type === "request";
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* Check if parsed message is a notification
|
|
232
|
+
*/
|
|
233
|
+
export function isNotification(parsed: IParsedObject): boolean {
|
|
234
|
+
return parsed.type === "notification";
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* Check if parsed message is a success response
|
|
239
|
+
*/
|
|
240
|
+
export function isSuccessResponse(parsed: IParsedObject): boolean {
|
|
241
|
+
return parsed.type === "success";
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* Check if parsed message is an error response
|
|
246
|
+
*/
|
|
247
|
+
export function isErrorResponse(parsed: IParsedObject): boolean {
|
|
248
|
+
return parsed.type === "error";
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
/**
|
|
252
|
+
* Check if parsed message is invalid
|
|
253
|
+
*/
|
|
254
|
+
export function isInvalid(parsed: IParsedObject): boolean {
|
|
255
|
+
return parsed.type === "invalid";
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
* Check if notification is a stream event
|
|
260
|
+
*/
|
|
261
|
+
export function isStreamEvent(parsed: IParsedObject): parsed is IParsedObject & {
|
|
262
|
+
payload: RpcNotification<"stream.event", StreamEventParams>;
|
|
263
|
+
} {
|
|
264
|
+
if (parsed.type !== "notification") return false;
|
|
265
|
+
const payload = parsed.payload as RpcNotification;
|
|
266
|
+
return payload.method === "stream.event";
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
/**
|
|
270
|
+
* Check if notification is a control ACK
|
|
271
|
+
*/
|
|
272
|
+
export function isControlAck(parsed: IParsedObject): parsed is IParsedObject & {
|
|
273
|
+
payload: RpcNotification<"control.ack", ControlAckParams>;
|
|
274
|
+
} {
|
|
275
|
+
if (parsed.type !== "notification") return false;
|
|
276
|
+
const payload = parsed.payload as RpcNotification;
|
|
277
|
+
return payload.method === "control.ack";
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
// ============================================================================
|
|
281
|
+
// Method Name Mapping (for backward compatibility)
|
|
282
|
+
// ============================================================================
|
|
283
|
+
|
|
284
|
+
/**
|
|
285
|
+
* Map old event type names to new RPC method names
|
|
286
|
+
*/
|
|
287
|
+
export const eventTypeToRpcMethod: Record<string, RpcMethod> = {
|
|
288
|
+
// Container
|
|
289
|
+
container_create_request: "container.create",
|
|
290
|
+
container_get_request: "container.get",
|
|
291
|
+
container_list_request: "container.list",
|
|
292
|
+
// Image
|
|
293
|
+
image_create_request: "image.create",
|
|
294
|
+
image_get_request: "image.get",
|
|
295
|
+
image_list_request: "image.list",
|
|
296
|
+
image_delete_request: "image.delete",
|
|
297
|
+
image_run_request: "image.run",
|
|
298
|
+
image_stop_request: "image.stop",
|
|
299
|
+
image_update_request: "image.update",
|
|
300
|
+
image_messages_request: "image.messages",
|
|
301
|
+
// Agent
|
|
302
|
+
agent_get_request: "agent.get",
|
|
303
|
+
agent_list_request: "agent.list",
|
|
304
|
+
agent_destroy_request: "agent.destroy",
|
|
305
|
+
agent_destroy_all_request: "agent.destroyAll",
|
|
306
|
+
agent_interrupt_request: "agent.interrupt",
|
|
307
|
+
// Message
|
|
308
|
+
message_send_request: "message.send",
|
|
309
|
+
};
|
|
310
|
+
|
|
311
|
+
/**
|
|
312
|
+
* Map RPC method names back to response event types
|
|
313
|
+
*/
|
|
314
|
+
export const rpcMethodToResponseType: Record<RpcMethod, string> = {
|
|
315
|
+
// Container
|
|
316
|
+
"container.create": "container_create_response",
|
|
317
|
+
"container.get": "container_get_response",
|
|
318
|
+
"container.list": "container_list_response",
|
|
319
|
+
// Image
|
|
320
|
+
"image.create": "image_create_response",
|
|
321
|
+
"image.get": "image_get_response",
|
|
322
|
+
"image.list": "image_list_response",
|
|
323
|
+
"image.delete": "image_delete_response",
|
|
324
|
+
"image.run": "image_run_response",
|
|
325
|
+
"image.stop": "image_stop_response",
|
|
326
|
+
"image.update": "image_update_response",
|
|
327
|
+
"image.messages": "image_messages_response",
|
|
328
|
+
// Agent
|
|
329
|
+
"agent.get": "agent_get_response",
|
|
330
|
+
"agent.list": "agent_list_response",
|
|
331
|
+
"agent.destroy": "agent_destroy_response",
|
|
332
|
+
"agent.destroyAll": "agent_destroy_all_response",
|
|
333
|
+
"agent.interrupt": "agent_interrupt_response",
|
|
334
|
+
// Message
|
|
335
|
+
"message.send": "message_send_response",
|
|
336
|
+
};
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reliable Message Protocol
|
|
3
|
+
*
|
|
4
|
+
* Internal protocol for message acknowledgment between server and client.
|
|
5
|
+
* This is transparent to the application layer.
|
|
6
|
+
*
|
|
7
|
+
* Flow:
|
|
8
|
+
* 1. Server sends: { __msgId: "xxx", __payload: "actual message" }
|
|
9
|
+
* 2. Client receives, extracts payload, sends: { __ack: "xxx" }
|
|
10
|
+
* 3. Server receives ACK, triggers onAck callback
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
// ============================================================================
|
|
14
|
+
// Protocol Types
|
|
15
|
+
// ============================================================================
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* ReliableWrapper - Wrapper for reliable messages (server → client)
|
|
19
|
+
*
|
|
20
|
+
* Contains the original message payload with a unique ID for tracking.
|
|
21
|
+
*/
|
|
22
|
+
export interface ReliableWrapper {
|
|
23
|
+
/** Unique message ID for tracking */
|
|
24
|
+
__msgId: string;
|
|
25
|
+
/** Original message payload */
|
|
26
|
+
__payload: string;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* AckMessage - Acknowledgment message (client → server)
|
|
31
|
+
*
|
|
32
|
+
* Sent automatically by client when receiving a reliable message.
|
|
33
|
+
*/
|
|
34
|
+
export interface AckMessage {
|
|
35
|
+
/** Message ID being acknowledged */
|
|
36
|
+
__ack: string;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// ============================================================================
|
|
40
|
+
// Type Guards
|
|
41
|
+
// ============================================================================
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Check if data is a ReliableWrapper
|
|
45
|
+
*/
|
|
46
|
+
export function isReliableWrapper(data: unknown): data is ReliableWrapper {
|
|
47
|
+
return typeof data === "object" && data !== null && "__msgId" in data && "__payload" in data;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Check if data is an AckMessage
|
|
52
|
+
*/
|
|
53
|
+
export function isAckMessage(data: unknown): data is AckMessage {
|
|
54
|
+
return typeof data === "object" && data !== null && "__ack" in data;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// ============================================================================
|
|
58
|
+
// Protocol Helpers
|
|
59
|
+
// ============================================================================
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Wrap a message for reliable delivery
|
|
63
|
+
*/
|
|
64
|
+
export function wrapMessage(msgId: string, payload: string): ReliableWrapper {
|
|
65
|
+
return { __msgId: msgId, __payload: payload };
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Create an ACK message
|
|
70
|
+
*/
|
|
71
|
+
export function createAck(msgId: string): AckMessage {
|
|
72
|
+
return { __ack: msgId };
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Unwrap a reliable message, returning the original payload
|
|
77
|
+
*/
|
|
78
|
+
export function unwrapMessage(wrapper: ReliableWrapper): string {
|
|
79
|
+
return wrapper.__payload;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Generate a unique message ID
|
|
84
|
+
*/
|
|
85
|
+
export function generateMessageId(): string {
|
|
86
|
+
if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
|
|
87
|
+
return crypto.randomUUID();
|
|
88
|
+
}
|
|
89
|
+
return `${Date.now()}-${Math.random().toString(36).slice(2, 11)}`;
|
|
90
|
+
}
|
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Network Types - Channel interfaces for client-server communication
|
|
3
|
+
*
|
|
4
|
+
* Provides transport-agnostic interfaces that can be implemented with:
|
|
5
|
+
* - WebSocket (Node.js, Browser)
|
|
6
|
+
* - Durable Objects WebSocket (Cloudflare Workers)
|
|
7
|
+
* - HTTP/2, gRPC, etc.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
// ============================================================================
|
|
11
|
+
// Common Types
|
|
12
|
+
// ============================================================================
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Unsubscribe function type
|
|
16
|
+
*/
|
|
17
|
+
export type Unsubscribe = () => void;
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Minimal HTTP server interface for attaching WebSocket
|
|
21
|
+
* Avoids Node.js dependency in types package
|
|
22
|
+
*/
|
|
23
|
+
export interface MinimalHTTPServer {
|
|
24
|
+
on(event: "upgrade", listener: (request: unknown, socket: unknown, head: unknown) => void): void;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// ============================================================================
|
|
28
|
+
// Reliable Message Options
|
|
29
|
+
// ============================================================================
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Options for reliable message sending
|
|
33
|
+
*/
|
|
34
|
+
export interface SendReliableOptions {
|
|
35
|
+
/**
|
|
36
|
+
* Callback when client acknowledges receipt
|
|
37
|
+
*/
|
|
38
|
+
onAck?: () => void;
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Timeout in milliseconds (default: 5000)
|
|
42
|
+
*/
|
|
43
|
+
timeout?: number;
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Callback when ACK times out
|
|
47
|
+
*/
|
|
48
|
+
onTimeout?: () => void;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// ============================================================================
|
|
52
|
+
// Channel Connection (Server-side)
|
|
53
|
+
// ============================================================================
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* ChannelConnection - Server-side representation of a client connection
|
|
57
|
+
*/
|
|
58
|
+
export interface ChannelConnection {
|
|
59
|
+
/**
|
|
60
|
+
* Unique connection ID
|
|
61
|
+
*/
|
|
62
|
+
readonly id: string;
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Send message to this client (fire-and-forget)
|
|
66
|
+
*/
|
|
67
|
+
send(message: string): void;
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Send message with acknowledgment
|
|
71
|
+
*
|
|
72
|
+
* The message is wrapped with a unique ID. Client automatically sends ACK
|
|
73
|
+
* when received. Server triggers onAck callback upon receiving ACK.
|
|
74
|
+
*
|
|
75
|
+
* This is handled transparently by the Network layer.
|
|
76
|
+
*/
|
|
77
|
+
sendReliable(message: string, options?: SendReliableOptions): void;
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Register message handler
|
|
81
|
+
*/
|
|
82
|
+
onMessage(handler: (message: string) => void): Unsubscribe;
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Register close handler
|
|
86
|
+
*/
|
|
87
|
+
onClose(handler: () => void): Unsubscribe;
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Register error handler
|
|
91
|
+
*/
|
|
92
|
+
onError(handler: (error: Error) => void): Unsubscribe;
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Close this connection
|
|
96
|
+
*/
|
|
97
|
+
close(): void;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// ============================================================================
|
|
101
|
+
// Channel Server
|
|
102
|
+
// ============================================================================
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* ChannelServer - Accepts client connections
|
|
106
|
+
*/
|
|
107
|
+
export interface ChannelServer {
|
|
108
|
+
/**
|
|
109
|
+
* Start listening on a port (standalone mode)
|
|
110
|
+
*/
|
|
111
|
+
listen(port: number, host?: string): Promise<void>;
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Attach to an existing HTTP server
|
|
115
|
+
*/
|
|
116
|
+
attach(server: MinimalHTTPServer, path?: string): void;
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Register connection handler
|
|
120
|
+
*/
|
|
121
|
+
onConnection(handler: (connection: ChannelConnection) => void): Unsubscribe;
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Broadcast message to all connected clients
|
|
125
|
+
*/
|
|
126
|
+
broadcast(message: string): void;
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Close server and all connections
|
|
130
|
+
*/
|
|
131
|
+
close(): Promise<void>;
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Dispose resources
|
|
135
|
+
*/
|
|
136
|
+
dispose(): Promise<void>;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* ChannelServerOptions - Server configuration
|
|
141
|
+
*/
|
|
142
|
+
export interface ChannelServerOptions {
|
|
143
|
+
/**
|
|
144
|
+
* Enable heartbeat/ping-pong (default: true)
|
|
145
|
+
*/
|
|
146
|
+
heartbeat?: boolean;
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Heartbeat interval in ms (default: 30000)
|
|
150
|
+
*/
|
|
151
|
+
heartbeatInterval?: number;
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Enable debug logging (default: false)
|
|
155
|
+
*/
|
|
156
|
+
debug?: boolean;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// ============================================================================
|
|
160
|
+
// Channel Client
|
|
161
|
+
// ============================================================================
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Connection state
|
|
165
|
+
*/
|
|
166
|
+
export type ConnectionState = "connecting" | "open" | "closing" | "closed";
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* ChannelClient - Connects to server
|
|
170
|
+
*/
|
|
171
|
+
export interface ChannelClient {
|
|
172
|
+
/**
|
|
173
|
+
* Connection state
|
|
174
|
+
*/
|
|
175
|
+
readonly readyState: ConnectionState;
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Connect to server
|
|
179
|
+
*/
|
|
180
|
+
connect(): Promise<void>;
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Send message to server
|
|
184
|
+
*/
|
|
185
|
+
send(message: string): void;
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Register message handler
|
|
189
|
+
*/
|
|
190
|
+
onMessage(handler: (message: string) => void): Unsubscribe;
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Register open handler
|
|
194
|
+
*/
|
|
195
|
+
onOpen(handler: () => void): Unsubscribe;
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Register close handler
|
|
199
|
+
*/
|
|
200
|
+
onClose(handler: () => void): Unsubscribe;
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* Register error handler
|
|
204
|
+
*/
|
|
205
|
+
onError(handler: (error: Error) => void): Unsubscribe;
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Close connection
|
|
209
|
+
*/
|
|
210
|
+
close(): void;
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Dispose resources
|
|
214
|
+
*/
|
|
215
|
+
dispose(): void;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* ChannelClientOptions - Client configuration
|
|
220
|
+
*/
|
|
221
|
+
export interface ChannelClientOptions {
|
|
222
|
+
/**
|
|
223
|
+
* Server URL
|
|
224
|
+
*/
|
|
225
|
+
serverUrl: string;
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* Enable auto-reconnect (default: true in browser, false in Node.js)
|
|
229
|
+
*/
|
|
230
|
+
autoReconnect?: boolean;
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* Min reconnection delay in ms (default: 1000)
|
|
234
|
+
*/
|
|
235
|
+
minReconnectionDelay?: number;
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* Max reconnection delay in ms (default: 10000)
|
|
239
|
+
*/
|
|
240
|
+
maxReconnectionDelay?: number;
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* Max retry attempts (default: Infinity)
|
|
244
|
+
*/
|
|
245
|
+
maxRetries?: number;
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* Connection timeout in ms (default: 4000)
|
|
249
|
+
*/
|
|
250
|
+
connectionTimeout?: number;
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* Enable debug logging (default: false)
|
|
254
|
+
*/
|
|
255
|
+
debug?: boolean;
|
|
256
|
+
|
|
257
|
+
/**
|
|
258
|
+
* Custom headers for WebSocket connection
|
|
259
|
+
*
|
|
260
|
+
* - Node.js: Headers are sent during WebSocket handshake
|
|
261
|
+
* - Browser: Headers are sent in first authentication message
|
|
262
|
+
*/
|
|
263
|
+
headers?:
|
|
264
|
+
| Record<string, string>
|
|
265
|
+
| (() => Record<string, string> | Promise<Record<string, string>>);
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
// ============================================================================
|
|
269
|
+
// Channel Provider
|
|
270
|
+
// ============================================================================
|
|
271
|
+
|
|
272
|
+
/**
|
|
273
|
+
* ChannelServerProvider - Factory for creating ChannelServer instances
|
|
274
|
+
*/
|
|
275
|
+
export interface ChannelServerProvider {
|
|
276
|
+
createServer(options?: ChannelServerOptions): ChannelServer;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
/**
|
|
280
|
+
* ChannelClientProvider - Factory for creating ChannelClient instances
|
|
281
|
+
*/
|
|
282
|
+
export interface ChannelClientProvider {
|
|
283
|
+
createClient(options: ChannelClientOptions): ChannelClient;
|
|
284
|
+
}
|