@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.
Files changed (78) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +477 -0
  3. package/dist/agent-registry.d.ts +51 -0
  4. package/dist/agent-registry.d.ts.map +1 -0
  5. package/dist/agent-registry.js +78 -0
  6. package/dist/agent-registry.js.map +1 -0
  7. package/dist/app-registry.d.ts +51 -0
  8. package/dist/app-registry.d.ts.map +1 -0
  9. package/dist/app-registry.js +78 -0
  10. package/dist/app-registry.js.map +1 -0
  11. package/dist/bin.d.ts +8 -0
  12. package/dist/bin.d.ts.map +1 -0
  13. package/dist/bin.js +37 -0
  14. package/dist/bin.js.map +1 -0
  15. package/dist/gateway.d.ts +165 -0
  16. package/dist/gateway.d.ts.map +1 -0
  17. package/dist/gateway.js +1339 -0
  18. package/dist/gateway.js.map +1 -0
  19. package/dist/http-transport.d.ts +65 -0
  20. package/dist/http-transport.d.ts.map +1 -0
  21. package/dist/http-transport.js +517 -0
  22. package/dist/http-transport.js.map +1 -0
  23. package/dist/index.d.ts +16 -0
  24. package/dist/index.d.ts.map +1 -0
  25. package/dist/index.js +23 -0
  26. package/dist/index.js.map +1 -0
  27. package/dist/protocol.d.ts +162 -0
  28. package/dist/protocol.d.ts.map +1 -0
  29. package/dist/protocol.js +16 -0
  30. package/dist/protocol.js.map +1 -0
  31. package/dist/session-manager.d.ts +101 -0
  32. package/dist/session-manager.d.ts.map +1 -0
  33. package/dist/session-manager.js +208 -0
  34. package/dist/session-manager.js.map +1 -0
  35. package/dist/testing.d.ts +92 -0
  36. package/dist/testing.d.ts.map +1 -0
  37. package/dist/testing.js +129 -0
  38. package/dist/testing.js.map +1 -0
  39. package/dist/transport-protocol.d.ts +162 -0
  40. package/dist/transport-protocol.d.ts.map +1 -0
  41. package/dist/transport-protocol.js +16 -0
  42. package/dist/transport-protocol.js.map +1 -0
  43. package/dist/transport.d.ts +115 -0
  44. package/dist/transport.d.ts.map +1 -0
  45. package/dist/transport.js +56 -0
  46. package/dist/transport.js.map +1 -0
  47. package/dist/types.d.ts +314 -0
  48. package/dist/types.d.ts.map +1 -0
  49. package/dist/types.js +37 -0
  50. package/dist/types.js.map +1 -0
  51. package/dist/websocket-server.d.ts +87 -0
  52. package/dist/websocket-server.d.ts.map +1 -0
  53. package/dist/websocket-server.js +245 -0
  54. package/dist/websocket-server.js.map +1 -0
  55. package/dist/ws-transport.d.ts +17 -0
  56. package/dist/ws-transport.d.ts.map +1 -0
  57. package/dist/ws-transport.js +174 -0
  58. package/dist/ws-transport.js.map +1 -0
  59. package/package.json +51 -0
  60. package/src/__tests__/custom-methods.spec.ts +220 -0
  61. package/src/__tests__/gateway-methods.spec.ts +262 -0
  62. package/src/__tests__/gateway.spec.ts +404 -0
  63. package/src/__tests__/guards.spec.ts +235 -0
  64. package/src/__tests__/protocol.spec.ts +58 -0
  65. package/src/__tests__/session-manager.spec.ts +220 -0
  66. package/src/__tests__/ws-transport.spec.ts +246 -0
  67. package/src/app-registry.ts +103 -0
  68. package/src/bin.ts +38 -0
  69. package/src/gateway.ts +1712 -0
  70. package/src/http-transport.ts +623 -0
  71. package/src/index.ts +94 -0
  72. package/src/session-manager.ts +272 -0
  73. package/src/testing.ts +236 -0
  74. package/src/transport-protocol.ts +249 -0
  75. package/src/transport.ts +191 -0
  76. package/src/types.ts +392 -0
  77. package/src/websocket-server.ts +303 -0
  78. 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
+ }