@agentick/gateway 0.0.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/LICENSE +21 -0
- package/README.md +477 -0
- package/dist/agent-registry.d.ts +51 -0
- package/dist/agent-registry.d.ts.map +1 -0
- package/dist/agent-registry.js +78 -0
- package/dist/agent-registry.js.map +1 -0
- package/dist/app-registry.d.ts +51 -0
- package/dist/app-registry.d.ts.map +1 -0
- package/dist/app-registry.js +78 -0
- package/dist/app-registry.js.map +1 -0
- package/dist/bin.d.ts +8 -0
- package/dist/bin.d.ts.map +1 -0
- package/dist/bin.js +37 -0
- package/dist/bin.js.map +1 -0
- package/dist/gateway.d.ts +165 -0
- package/dist/gateway.d.ts.map +1 -0
- package/dist/gateway.js +1339 -0
- package/dist/gateway.js.map +1 -0
- package/dist/http-transport.d.ts +65 -0
- package/dist/http-transport.d.ts.map +1 -0
- package/dist/http-transport.js +517 -0
- package/dist/http-transport.js.map +1 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +23 -0
- package/dist/index.js.map +1 -0
- package/dist/protocol.d.ts +162 -0
- package/dist/protocol.d.ts.map +1 -0
- package/dist/protocol.js +16 -0
- package/dist/protocol.js.map +1 -0
- package/dist/session-manager.d.ts +101 -0
- package/dist/session-manager.d.ts.map +1 -0
- package/dist/session-manager.js +208 -0
- package/dist/session-manager.js.map +1 -0
- package/dist/testing.d.ts +92 -0
- package/dist/testing.d.ts.map +1 -0
- package/dist/testing.js +129 -0
- package/dist/testing.js.map +1 -0
- package/dist/transport-protocol.d.ts +162 -0
- package/dist/transport-protocol.d.ts.map +1 -0
- package/dist/transport-protocol.js +16 -0
- package/dist/transport-protocol.js.map +1 -0
- package/dist/transport.d.ts +115 -0
- package/dist/transport.d.ts.map +1 -0
- package/dist/transport.js +56 -0
- package/dist/transport.js.map +1 -0
- package/dist/types.d.ts +314 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +37 -0
- package/dist/types.js.map +1 -0
- package/dist/websocket-server.d.ts +87 -0
- package/dist/websocket-server.d.ts.map +1 -0
- package/dist/websocket-server.js +245 -0
- package/dist/websocket-server.js.map +1 -0
- package/dist/ws-transport.d.ts +17 -0
- package/dist/ws-transport.d.ts.map +1 -0
- package/dist/ws-transport.js +174 -0
- package/dist/ws-transport.js.map +1 -0
- package/package.json +51 -0
- package/src/__tests__/custom-methods.spec.ts +220 -0
- package/src/__tests__/gateway-methods.spec.ts +262 -0
- package/src/__tests__/gateway.spec.ts +404 -0
- package/src/__tests__/guards.spec.ts +235 -0
- package/src/__tests__/protocol.spec.ts +58 -0
- package/src/__tests__/session-manager.spec.ts +220 -0
- package/src/__tests__/ws-transport.spec.ts +246 -0
- package/src/app-registry.ts +103 -0
- package/src/bin.ts +38 -0
- package/src/gateway.ts +1712 -0
- package/src/http-transport.ts +623 -0
- package/src/index.ts +94 -0
- package/src/session-manager.ts +272 -0
- package/src/testing.ts +236 -0
- package/src/transport-protocol.ts +249 -0
- package/src/transport.ts +191 -0
- package/src/types.ts +392 -0
- package/src/websocket-server.ts +303 -0
- package/src/ws-transport.ts +205 -0
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WebSocket Transport
|
|
3
|
+
*
|
|
4
|
+
* Implements the Transport interface using WebSocket connections.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { WebSocketServer, WebSocket } from "ws";
|
|
8
|
+
import type { IncomingMessage } from "http";
|
|
9
|
+
import type { ClientMessage, GatewayMessage, ConnectMessage } from "./transport-protocol.js";
|
|
10
|
+
import type { ClientState } from "./types.js";
|
|
11
|
+
import { BaseTransport, type TransportClient, type TransportConfig } from "./transport.js";
|
|
12
|
+
|
|
13
|
+
// ============================================================================
|
|
14
|
+
// WebSocket Client
|
|
15
|
+
// ============================================================================
|
|
16
|
+
|
|
17
|
+
class WSClientImpl implements TransportClient {
|
|
18
|
+
readonly id: string;
|
|
19
|
+
readonly socket: WebSocket;
|
|
20
|
+
readonly state: ClientState;
|
|
21
|
+
private transport: WSTransport;
|
|
22
|
+
|
|
23
|
+
constructor(id: string, socket: WebSocket, transport: WSTransport) {
|
|
24
|
+
this.id = id;
|
|
25
|
+
this.socket = socket;
|
|
26
|
+
this.transport = transport;
|
|
27
|
+
this.state = {
|
|
28
|
+
id,
|
|
29
|
+
connectedAt: new Date(),
|
|
30
|
+
authenticated: false,
|
|
31
|
+
subscriptions: new Set(),
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
send(message: GatewayMessage): void {
|
|
36
|
+
if (this.socket.readyState === WebSocket.OPEN) {
|
|
37
|
+
this.socket.send(JSON.stringify(message));
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
close(code?: number, reason?: string): void {
|
|
42
|
+
this.socket.close(code, reason);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
get isConnected(): boolean {
|
|
46
|
+
return this.socket.readyState === WebSocket.OPEN;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/** @internal - Update client ID (for custom client IDs) */
|
|
50
|
+
_setId(newId: string): void {
|
|
51
|
+
(this as { id: string }).id = newId;
|
|
52
|
+
(this.state as { id: string }).id = newId;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// ============================================================================
|
|
57
|
+
// WebSocket Transport
|
|
58
|
+
// ============================================================================
|
|
59
|
+
|
|
60
|
+
export class WSTransport extends BaseTransport {
|
|
61
|
+
readonly type = "websocket" as const;
|
|
62
|
+
private wss: WebSocketServer | null = null;
|
|
63
|
+
|
|
64
|
+
override start(): Promise<void> {
|
|
65
|
+
return new Promise((resolve, reject) => {
|
|
66
|
+
try {
|
|
67
|
+
this.wss = new WebSocketServer({
|
|
68
|
+
port: this.config.port,
|
|
69
|
+
host: this.config.host,
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
this.wss.on("connection", this.handleConnection.bind(this));
|
|
73
|
+
this.wss.on("error", (error) => {
|
|
74
|
+
this.handlers.error?.(error);
|
|
75
|
+
reject(error);
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
this.wss.on("listening", () => {
|
|
79
|
+
resolve();
|
|
80
|
+
});
|
|
81
|
+
} catch (error) {
|
|
82
|
+
reject(error);
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
override stop(): Promise<void> {
|
|
88
|
+
return new Promise((resolve) => {
|
|
89
|
+
if (!this.wss) {
|
|
90
|
+
resolve();
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Close all client connections
|
|
95
|
+
for (const client of this.clients.values()) {
|
|
96
|
+
client.close(1001, "Server shutting down");
|
|
97
|
+
}
|
|
98
|
+
this.clients.clear();
|
|
99
|
+
|
|
100
|
+
// Close the server
|
|
101
|
+
this.wss.close(() => {
|
|
102
|
+
this.wss = null;
|
|
103
|
+
resolve();
|
|
104
|
+
});
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
private handleConnection(socket: WebSocket, _request: IncomingMessage): void {
|
|
109
|
+
const clientId = this.generateClientId();
|
|
110
|
+
const client = new WSClientImpl(clientId, socket, this);
|
|
111
|
+
this.clients.set(clientId, client);
|
|
112
|
+
|
|
113
|
+
socket.on("message", (data) => {
|
|
114
|
+
try {
|
|
115
|
+
const message = JSON.parse(data.toString()) as ClientMessage;
|
|
116
|
+
this.handleMessage(client, message);
|
|
117
|
+
} catch (_error) {
|
|
118
|
+
client.send({
|
|
119
|
+
type: "error",
|
|
120
|
+
code: "INVALID_MESSAGE",
|
|
121
|
+
message: "Failed to parse message",
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
socket.on("close", () => {
|
|
127
|
+
this.clients.delete(client.id);
|
|
128
|
+
this.handlers.disconnect?.(client.id);
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
socket.on("error", (error) => {
|
|
132
|
+
this.handlers.error?.(error);
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
// Notify handler of new connection (before auth)
|
|
136
|
+
this.handlers.connection?.(client);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
private async handleMessage(client: WSClientImpl, message: ClientMessage): Promise<void> {
|
|
140
|
+
// Handle connect message (authentication)
|
|
141
|
+
if (message.type === "connect") {
|
|
142
|
+
await this.handleConnect(client, message);
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// Handle ping
|
|
147
|
+
if (message.type === "ping") {
|
|
148
|
+
client.send({ type: "pong", timestamp: message.timestamp });
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// All other messages require authentication
|
|
153
|
+
if (!client.state.authenticated) {
|
|
154
|
+
client.send({
|
|
155
|
+
type: "error",
|
|
156
|
+
code: "UNAUTHORIZED",
|
|
157
|
+
message: "Authentication required. Send connect message first.",
|
|
158
|
+
});
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// Forward to message handler
|
|
163
|
+
this.handlers.message?.(client.id, message);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
private async handleConnect(client: WSClientImpl, message: ConnectMessage): Promise<void> {
|
|
167
|
+
// Validate authentication
|
|
168
|
+
const authResult = await this.validateAuth(message.token);
|
|
169
|
+
|
|
170
|
+
if (!authResult.valid) {
|
|
171
|
+
client.send({
|
|
172
|
+
type: "error",
|
|
173
|
+
code: "AUTH_FAILED",
|
|
174
|
+
message: "Authentication failed",
|
|
175
|
+
});
|
|
176
|
+
client.close(4001, "Authentication failed");
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// Update client state
|
|
181
|
+
client.state.authenticated = true;
|
|
182
|
+
client.state.user = authResult.user;
|
|
183
|
+
client.state.metadata = {
|
|
184
|
+
...client.state.metadata,
|
|
185
|
+
...authResult.metadata,
|
|
186
|
+
...message.metadata,
|
|
187
|
+
};
|
|
188
|
+
|
|
189
|
+
// Client ID from message takes precedence
|
|
190
|
+
if (message.clientId) {
|
|
191
|
+
// Update internal tracking if client provides their own ID
|
|
192
|
+
this.clients.delete(client.id);
|
|
193
|
+
client._setId(message.clientId);
|
|
194
|
+
this.clients.set(message.clientId, client);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// ============================================================================
|
|
200
|
+
// Factory Function
|
|
201
|
+
// ============================================================================
|
|
202
|
+
|
|
203
|
+
export function createWSTransport(config: TransportConfig): WSTransport {
|
|
204
|
+
return new WSTransport(config);
|
|
205
|
+
}
|