@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,314 @@
1
+ /**
2
+ * Gateway Types
3
+ */
4
+ import type { App } from "@agentick/core";
5
+ import type { KernelContext, UserContext } from "@agentick/kernel";
6
+ import type { AuthConfig } from "@agentick/server";
7
+ export type { AuthConfig, AuthResult } from "@agentick/server";
8
+ /**
9
+ * Schema type that works with both Zod 3 and Zod 4.
10
+ * We only need parse() and type inference (_output).
11
+ */
12
+ export interface ZodLikeSchema<T = unknown> {
13
+ parse(data: unknown): T;
14
+ _output: T;
15
+ }
16
+ export type { UserContext } from "@agentick/kernel";
17
+ export interface GatewayConfig {
18
+ /**
19
+ * Port to listen on (ignored in embedded mode)
20
+ * @default 18789
21
+ */
22
+ port?: number;
23
+ /**
24
+ * Host to bind to (ignored in embedded mode)
25
+ * @default "127.0.0.1"
26
+ */
27
+ host?: string;
28
+ /**
29
+ * Gateway ID (auto-generated if not provided)
30
+ */
31
+ id?: string;
32
+ /**
33
+ * App definitions
34
+ */
35
+ apps: Record<string, App>;
36
+ /**
37
+ * Default app to use when session key doesn't specify one
38
+ */
39
+ defaultApp: string;
40
+ /**
41
+ * Authentication configuration
42
+ */
43
+ auth?: AuthConfig;
44
+ /**
45
+ * Run in embedded mode (no standalone server).
46
+ * Use handleRequest() to process requests from your framework.
47
+ * @default false
48
+ */
49
+ embedded?: boolean;
50
+ /**
51
+ * Persistence configuration
52
+ */
53
+ storage?: StorageConfig;
54
+ /**
55
+ * Channel adapters (WhatsApp, Slack, etc.)
56
+ */
57
+ channels?: ChannelAdapter[];
58
+ /**
59
+ * Message routing configuration
60
+ */
61
+ routing?: RoutingConfig;
62
+ /**
63
+ * Transport mode (ignored in embedded mode)
64
+ * - "websocket": WebSocket only (default, good for CLI/native clients)
65
+ * - "http": HTTP/SSE only (good for web browsers)
66
+ * - "both": Both transports on different ports
67
+ * @default "websocket"
68
+ */
69
+ transport?: "websocket" | "http" | "both";
70
+ /**
71
+ * HTTP path prefix (e.g., "/api")
72
+ * @default ""
73
+ */
74
+ httpPathPrefix?: string;
75
+ /**
76
+ * CORS origin for HTTP transport
77
+ * @default "*"
78
+ */
79
+ httpCorsOrigin?: string;
80
+ /**
81
+ * HTTP port when using "both" mode
82
+ * @default port + 1
83
+ */
84
+ httpPort?: number;
85
+ /**
86
+ * Custom methods - runs within Agentick ALS context.
87
+ *
88
+ * Supports:
89
+ * - Simple handlers: `async (params) => result`
90
+ * - Streaming: `async function* (params) { yield value }`
91
+ * - With config: `method({ schema, handler, roles, guard })`
92
+ * - Namespaces: `{ tasks: { list, create, admin: { ... } } }` (recursive)
93
+ *
94
+ * Use method() wrapper for schema validation, roles, guards, etc.
95
+ * ctx param is optional - use Context.get() for idiomatic access.
96
+ */
97
+ methods?: MethodsConfig;
98
+ }
99
+ export interface StorageConfig {
100
+ /**
101
+ * Base directory for storage
102
+ * @default "~/.agentick"
103
+ */
104
+ directory?: string;
105
+ /**
106
+ * Enable session persistence
107
+ * @default true
108
+ */
109
+ sessions?: boolean;
110
+ /**
111
+ * Enable memory persistence
112
+ * @default true
113
+ */
114
+ memory?: boolean;
115
+ }
116
+ export interface ChannelAdapter {
117
+ /**
118
+ * Channel identifier
119
+ */
120
+ id: string;
121
+ /**
122
+ * Human-readable name
123
+ */
124
+ name: string;
125
+ /**
126
+ * Initialize the channel
127
+ */
128
+ initialize(gateway: GatewayContext): Promise<void>;
129
+ /**
130
+ * Clean up resources
131
+ */
132
+ destroy(): Promise<void>;
133
+ }
134
+ export interface GatewayContext {
135
+ /**
136
+ * Send a message to a session
137
+ */
138
+ sendToSession(sessionId: string, message: string): Promise<void>;
139
+ /**
140
+ * Get available apps
141
+ */
142
+ getApps(): string[];
143
+ /**
144
+ * Get or create a session
145
+ */
146
+ getSession(sessionId: string): SessionContext;
147
+ }
148
+ export interface SessionContext {
149
+ id: string;
150
+ appId: string;
151
+ send(message: string): AsyncGenerator<SessionEvent>;
152
+ }
153
+ export interface SessionEvent {
154
+ type: string;
155
+ data: unknown;
156
+ }
157
+ export interface RoutingConfig {
158
+ /**
159
+ * Map channels to agents
160
+ */
161
+ channels?: Record<string, string>;
162
+ /**
163
+ * Custom routing function
164
+ */
165
+ custom?: (message: IncomingMessage, context: RoutingContext) => string | null;
166
+ }
167
+ export interface IncomingMessage {
168
+ text: string;
169
+ channel?: string;
170
+ from?: string;
171
+ metadata?: Record<string, unknown>;
172
+ }
173
+ export interface RoutingContext {
174
+ availableApps: string[];
175
+ defaultApp: string;
176
+ sessionHistory?: Array<{
177
+ role: string;
178
+ content: string;
179
+ }>;
180
+ }
181
+ export interface ClientState {
182
+ id: string;
183
+ connectedAt: Date;
184
+ authenticated: boolean;
185
+ /** Full user context from auth */
186
+ user?: UserContext;
187
+ subscriptions: Set<string>;
188
+ metadata?: Record<string, unknown>;
189
+ }
190
+ export interface SessionState {
191
+ id: string;
192
+ appId: string;
193
+ createdAt: Date;
194
+ lastActivityAt: Date;
195
+ messageCount: number;
196
+ isActive: boolean;
197
+ subscribers: Set<string>;
198
+ }
199
+ export interface GatewayEvents {
200
+ started: {
201
+ port: number;
202
+ host: string;
203
+ };
204
+ stopped: Record<string, never>;
205
+ "client:connected": {
206
+ clientId: string;
207
+ ip?: string;
208
+ };
209
+ "client:disconnected": {
210
+ clientId: string;
211
+ reason?: string;
212
+ };
213
+ "client:authenticated": {
214
+ clientId: string;
215
+ user?: UserContext;
216
+ };
217
+ "session:created": {
218
+ sessionId: string;
219
+ appId: string;
220
+ };
221
+ "session:closed": {
222
+ sessionId: string;
223
+ };
224
+ "session:message": {
225
+ sessionId: string;
226
+ role: "user" | "assistant";
227
+ content: string;
228
+ };
229
+ "app:message": {
230
+ appId: string;
231
+ sessionId: string;
232
+ message: string;
233
+ };
234
+ "channel:message": {
235
+ channel: string;
236
+ from: string;
237
+ message: string;
238
+ };
239
+ "channel:error": {
240
+ channel: string;
241
+ error: Error;
242
+ };
243
+ error: Error;
244
+ }
245
+ /** Symbol for detecting method definitions vs namespaces */
246
+ export declare const METHOD_DEFINITION: unique symbol;
247
+ /**
248
+ * Simple method handler - ctx param is optional since Context.get() works
249
+ */
250
+ export type SimpleMethodHandler<TParams = Record<string, unknown>, TResult = unknown> = (params: TParams, ctx?: KernelContext) => Promise<TResult> | TResult;
251
+ /**
252
+ * Streaming method handler - yields values to client
253
+ */
254
+ export type StreamingMethodHandler<TParams = Record<string, unknown>, TYield = unknown> = (params: TParams, ctx?: KernelContext) => AsyncGenerator<TYield>;
255
+ /**
256
+ * Method definition input (what you pass to method())
257
+ */
258
+ export interface MethodDefinitionInput<TSchema extends ZodLikeSchema = ZodLikeSchema> {
259
+ /** Zod schema for params validation + TypeScript inference */
260
+ schema?: TSchema;
261
+ /** Handler function - receives validated & typed params */
262
+ handler: SimpleMethodHandler<TSchema["_output"]> | StreamingMethodHandler<TSchema["_output"]>;
263
+ /** Required roles - checked before handler */
264
+ roles?: string[];
265
+ /** Custom guard function */
266
+ guard?: (ctx: KernelContext) => boolean | Promise<boolean>;
267
+ /** Method description for discovery */
268
+ description?: string;
269
+ }
270
+ /**
271
+ * Method definition with symbol marker (returned by method())
272
+ */
273
+ export interface MethodDefinition<TSchema extends ZodLikeSchema = ZodLikeSchema> extends MethodDefinitionInput<TSchema> {
274
+ [METHOD_DEFINITION]: true;
275
+ }
276
+ /**
277
+ * Factory function to create a method definition.
278
+ * Stores config (schema, roles, guards) - the gateway creates the
279
+ * actual procedure during initialization with the full inferred path name.
280
+ *
281
+ * @example
282
+ * methods: {
283
+ * tasks: {
284
+ * list: async (params) => { ... }, // Simple - auto-wrapped
285
+ * create: method({ // With config
286
+ * schema: z.object({ title: z.string() }),
287
+ * handler: async (params) => { ... }
288
+ * }),
289
+ * }
290
+ * }
291
+ */
292
+ export declare function method<TSchema extends ZodLikeSchema>(definition: MethodDefinitionInput<TSchema>): MethodDefinition<TSchema>;
293
+ /**
294
+ * Check if a value is a method definition (vs a namespace)
295
+ */
296
+ export declare function isMethodDefinition(value: unknown): value is MethodDefinition;
297
+ /**
298
+ * Method can be:
299
+ * - Simple function: async (params) => result
300
+ * - Streaming function: async function* (params) { yield }
301
+ * - Method definition: method({ schema, handler, roles, ... })
302
+ */
303
+ export type Method = SimpleMethodHandler | StreamingMethodHandler | MethodDefinition<any>;
304
+ /**
305
+ * Method namespace - recursively nested, arbitrary depth
306
+ */
307
+ export type MethodNamespace = {
308
+ [key: string]: Method | MethodNamespace;
309
+ };
310
+ /**
311
+ * Methods config - supports flat or nested namespaces
312
+ */
313
+ export type MethodsConfig = MethodNamespace;
314
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/dist/types.js ADDED
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Gateway Types
3
+ */
4
+ // ============================================================================
5
+ // Custom Methods
6
+ // ============================================================================
7
+ /** Symbol for detecting method definitions vs namespaces */
8
+ export const METHOD_DEFINITION = Symbol.for("agentick:method-definition");
9
+ /**
10
+ * Factory function to create a method definition.
11
+ * Stores config (schema, roles, guards) - the gateway creates the
12
+ * actual procedure during initialization with the full inferred path name.
13
+ *
14
+ * @example
15
+ * methods: {
16
+ * tasks: {
17
+ * list: async (params) => { ... }, // Simple - auto-wrapped
18
+ * create: method({ // With config
19
+ * schema: z.object({ title: z.string() }),
20
+ * handler: async (params) => { ... }
21
+ * }),
22
+ * }
23
+ * }
24
+ */
25
+ export function method(definition) {
26
+ return {
27
+ [METHOD_DEFINITION]: true,
28
+ ...definition,
29
+ };
30
+ }
31
+ /**
32
+ * Check if a value is a method definition (vs a namespace)
33
+ */
34
+ export function isMethodDefinition(value) {
35
+ return typeof value === "object" && value !== null && METHOD_DEFINITION in value;
36
+ }
37
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAkSH,+EAA+E;AAC/E,iBAAiB;AACjB,+EAA+E;AAE/E,4DAA4D;AAC5D,MAAM,CAAC,MAAM,iBAAiB,GAAG,MAAM,CAAC,GAAG,CAAC,4BAA4B,CAAC,CAAC;AA2C1E;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,MAAM,CACpB,UAA0C;IAE1C,OAAO;QACL,CAAC,iBAAiB,CAAC,EAAE,IAAI;QACzB,GAAG,UAAU;KACd,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,kBAAkB,CAAC,KAAc;IAC/C,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,iBAAiB,IAAI,KAAK,CAAC;AACnF,CAAC"}
@@ -0,0 +1,87 @@
1
+ /**
2
+ * WebSocket Server
3
+ *
4
+ * Handles WebSocket connections and message routing.
5
+ */
6
+ import { WebSocket } from "ws";
7
+ import type { ClientMessage, GatewayMessage } from "./transport-protocol.js";
8
+ import type { ClientState, AuthConfig } from "./types.js";
9
+ export interface WSServerConfig {
10
+ port: number;
11
+ host: string;
12
+ auth?: AuthConfig;
13
+ }
14
+ export interface WSServerEvents {
15
+ connection: (client: WSClient) => void;
16
+ disconnect: (clientId: string, reason?: string) => void;
17
+ message: (clientId: string, message: ClientMessage) => void;
18
+ error: (error: Error) => void;
19
+ }
20
+ export declare class WSClient {
21
+ readonly id: string;
22
+ readonly socket: WebSocket;
23
+ readonly state: ClientState;
24
+ private server;
25
+ constructor(id: string, socket: WebSocket, server: WSServer);
26
+ /**
27
+ * Send a message to this client
28
+ */
29
+ send(message: GatewayMessage): void;
30
+ /**
31
+ * Close the connection
32
+ */
33
+ close(code?: number, reason?: string): void;
34
+ /**
35
+ * Check if connected
36
+ */
37
+ get isConnected(): boolean;
38
+ }
39
+ export declare class WSServer {
40
+ private wss;
41
+ private clients;
42
+ private config;
43
+ private handlers;
44
+ private clientIdCounter;
45
+ constructor(config: WSServerConfig);
46
+ /**
47
+ * Start the WebSocket server
48
+ */
49
+ start(): Promise<void>;
50
+ /**
51
+ * Stop the server
52
+ */
53
+ stop(): Promise<void>;
54
+ /**
55
+ * Register event handlers
56
+ */
57
+ on<K extends keyof WSServerEvents>(event: K, handler: WSServerEvents[K]): void;
58
+ /**
59
+ * Get a client by ID
60
+ */
61
+ getClient(id: string): WSClient | undefined;
62
+ /**
63
+ * Get all clients
64
+ */
65
+ getClients(): WSClient[];
66
+ /**
67
+ * Get authenticated clients
68
+ */
69
+ getAuthenticatedClients(): WSClient[];
70
+ /**
71
+ * Broadcast a message to all authenticated clients
72
+ */
73
+ broadcast(message: GatewayMessage): void;
74
+ /**
75
+ * Send a message to clients subscribed to a session
76
+ */
77
+ sendToSubscribers(sessionId: string, message: GatewayMessage): void;
78
+ /**
79
+ * Get connected client count
80
+ */
81
+ get clientCount(): number;
82
+ private handleConnection;
83
+ private handleMessage;
84
+ private handleConnect;
85
+ private validateAuth;
86
+ }
87
+ //# sourceMappingURL=websocket-server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"websocket-server.d.ts","sourceRoot":"","sources":["../src/websocket-server.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAmB,SAAS,EAAE,MAAM,IAAI,CAAC;AAEhD,OAAO,KAAK,EACV,aAAa,EACb,cAAc,EAGf,MAAM,yBAAyB,CAAC;AACjC,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAc,MAAM,YAAY,CAAC;AAEtE,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,UAAU,CAAC;CACnB;AAED,MAAM,WAAW,cAAc;IAC7B,UAAU,EAAE,CAAC,MAAM,EAAE,QAAQ,KAAK,IAAI,CAAC;IACvC,UAAU,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IACxD,OAAO,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,aAAa,KAAK,IAAI,CAAC;IAC5D,KAAK,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;CAC/B;AAED,qBAAa,QAAQ;IACnB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC;IAC3B,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC;IAC5B,OAAO,CAAC,MAAM,CAAW;gBAEb,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ;IAY3D;;OAEG;IACH,IAAI,CAAC,OAAO,EAAE,cAAc,GAAG,IAAI;IAMnC;;OAEG;IACH,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI;IAI3C;;OAEG;IACH,IAAI,WAAW,IAAI,OAAO,CAEzB;CACF;AAED,qBAAa,QAAQ;IACnB,OAAO,CAAC,GAAG,CAAgC;IAC3C,OAAO,CAAC,OAAO,CAA+B;IAC9C,OAAO,CAAC,MAAM,CAAiB;IAC/B,OAAO,CAAC,QAAQ,CAA+B;IAC/C,OAAO,CAAC,eAAe,CAAK;gBAEhB,MAAM,EAAE,cAAc;IAIlC;;OAEG;IACH,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAuBtB;;OAEG;IACH,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAqBrB;;OAEG;IACH,EAAE,CAAC,CAAC,SAAS,MAAM,cAAc,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,cAAc,CAAC,CAAC,CAAC,GAAG,IAAI;IAI9E;;OAEG;IACH,SAAS,CAAC,EAAE,EAAE,MAAM,GAAG,QAAQ,GAAG,SAAS;IAI3C;;OAEG;IACH,UAAU,IAAI,QAAQ,EAAE;IAIxB;;OAEG;IACH,uBAAuB,IAAI,QAAQ,EAAE;IAIrC;;OAEG;IACH,SAAS,CAAC,OAAO,EAAE,cAAc,GAAG,IAAI;IAMxC;;OAEG;IACH,iBAAiB,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,cAAc,GAAG,IAAI;IAQnE;;OAEG;IACH,IAAI,WAAW,IAAI,MAAM,CAExB;IAED,OAAO,CAAC,gBAAgB;YA+BV,aAAa;YA2Bb,aAAa;YAgCb,YAAY;CAyB3B"}
@@ -0,0 +1,245 @@
1
+ /**
2
+ * WebSocket Server
3
+ *
4
+ * Handles WebSocket connections and message routing.
5
+ */
6
+ import { WebSocketServer, WebSocket } from "ws";
7
+ export class WSClient {
8
+ id;
9
+ socket;
10
+ state;
11
+ server;
12
+ constructor(id, socket, server) {
13
+ this.id = id;
14
+ this.socket = socket;
15
+ this.server = server;
16
+ this.state = {
17
+ id,
18
+ connectedAt: new Date(),
19
+ authenticated: false,
20
+ subscriptions: new Set(),
21
+ };
22
+ }
23
+ /**
24
+ * Send a message to this client
25
+ */
26
+ send(message) {
27
+ if (this.socket.readyState === WebSocket.OPEN) {
28
+ this.socket.send(JSON.stringify(message));
29
+ }
30
+ }
31
+ /**
32
+ * Close the connection
33
+ */
34
+ close(code, reason) {
35
+ this.socket.close(code, reason);
36
+ }
37
+ /**
38
+ * Check if connected
39
+ */
40
+ get isConnected() {
41
+ return this.socket.readyState === WebSocket.OPEN;
42
+ }
43
+ }
44
+ export class WSServer {
45
+ wss = null;
46
+ clients = new Map();
47
+ config;
48
+ handlers = {};
49
+ clientIdCounter = 0;
50
+ constructor(config) {
51
+ this.config = config;
52
+ }
53
+ /**
54
+ * Start the WebSocket server
55
+ */
56
+ start() {
57
+ return new Promise((resolve, reject) => {
58
+ try {
59
+ this.wss = new WebSocketServer({
60
+ port: this.config.port,
61
+ host: this.config.host,
62
+ });
63
+ this.wss.on("connection", this.handleConnection.bind(this));
64
+ this.wss.on("error", (error) => {
65
+ this.handlers.error?.(error);
66
+ reject(error);
67
+ });
68
+ this.wss.on("listening", () => {
69
+ resolve();
70
+ });
71
+ }
72
+ catch (error) {
73
+ reject(error);
74
+ }
75
+ });
76
+ }
77
+ /**
78
+ * Stop the server
79
+ */
80
+ stop() {
81
+ return new Promise((resolve) => {
82
+ if (!this.wss) {
83
+ resolve();
84
+ return;
85
+ }
86
+ // Close all client connections
87
+ for (const client of this.clients.values()) {
88
+ client.close(1001, "Server shutting down");
89
+ }
90
+ this.clients.clear();
91
+ // Close the server
92
+ this.wss.close(() => {
93
+ this.wss = null;
94
+ resolve();
95
+ });
96
+ });
97
+ }
98
+ /**
99
+ * Register event handlers
100
+ */
101
+ on(event, handler) {
102
+ this.handlers[event] = handler;
103
+ }
104
+ /**
105
+ * Get a client by ID
106
+ */
107
+ getClient(id) {
108
+ return this.clients.get(id);
109
+ }
110
+ /**
111
+ * Get all clients
112
+ */
113
+ getClients() {
114
+ return Array.from(this.clients.values());
115
+ }
116
+ /**
117
+ * Get authenticated clients
118
+ */
119
+ getAuthenticatedClients() {
120
+ return this.getClients().filter((c) => c.state.authenticated);
121
+ }
122
+ /**
123
+ * Broadcast a message to all authenticated clients
124
+ */
125
+ broadcast(message) {
126
+ for (const client of this.getAuthenticatedClients()) {
127
+ client.send(message);
128
+ }
129
+ }
130
+ /**
131
+ * Send a message to clients subscribed to a session
132
+ */
133
+ sendToSubscribers(sessionId, message) {
134
+ for (const client of this.getAuthenticatedClients()) {
135
+ if (client.state.subscriptions.has(sessionId)) {
136
+ client.send(message);
137
+ }
138
+ }
139
+ }
140
+ /**
141
+ * Get connected client count
142
+ */
143
+ get clientCount() {
144
+ return this.clients.size;
145
+ }
146
+ handleConnection(socket, _request) {
147
+ const clientId = `client-${++this.clientIdCounter}`;
148
+ const client = new WSClient(clientId, socket, this);
149
+ this.clients.set(clientId, client);
150
+ socket.on("message", (data) => {
151
+ try {
152
+ const message = JSON.parse(data.toString());
153
+ this.handleMessage(client, message);
154
+ }
155
+ catch (error) {
156
+ client.send({
157
+ type: "error",
158
+ code: "INVALID_MESSAGE",
159
+ message: "Failed to parse message",
160
+ });
161
+ }
162
+ });
163
+ socket.on("close", () => {
164
+ this.clients.delete(clientId);
165
+ this.handlers.disconnect?.(clientId);
166
+ });
167
+ socket.on("error", (error) => {
168
+ this.handlers.error?.(error);
169
+ });
170
+ // Notify handler of new connection (before auth)
171
+ this.handlers.connection?.(client);
172
+ }
173
+ async handleMessage(client, message) {
174
+ // Handle connect message (authentication)
175
+ if (message.type === "connect") {
176
+ await this.handleConnect(client, message);
177
+ return;
178
+ }
179
+ // Handle ping
180
+ if (message.type === "ping") {
181
+ client.send({ type: "pong", timestamp: message.timestamp });
182
+ return;
183
+ }
184
+ // All other messages require authentication
185
+ if (!client.state.authenticated) {
186
+ client.send({
187
+ type: "error",
188
+ code: "UNAUTHORIZED",
189
+ message: "Authentication required. Send connect message first.",
190
+ });
191
+ return;
192
+ }
193
+ // Forward to message handler
194
+ this.handlers.message?.(client.id, message);
195
+ }
196
+ async handleConnect(client, message) {
197
+ // Validate authentication
198
+ const authResult = await this.validateAuth(message.token);
199
+ if (!authResult.valid) {
200
+ client.send({
201
+ type: "error",
202
+ code: "AUTH_FAILED",
203
+ message: "Authentication failed",
204
+ });
205
+ client.close(4001, "Authentication failed");
206
+ return;
207
+ }
208
+ // Update client state
209
+ client.state.authenticated = true;
210
+ client.state.user = authResult.user;
211
+ client.state.metadata = {
212
+ ...client.state.metadata,
213
+ ...authResult.metadata,
214
+ ...message.metadata,
215
+ };
216
+ // Client ID from message takes precedence
217
+ if (message.clientId) {
218
+ // Update internal tracking if client provides their own ID
219
+ this.clients.delete(client.id);
220
+ client.id = message.clientId;
221
+ this.clients.set(message.clientId, client);
222
+ }
223
+ }
224
+ async validateAuth(token) {
225
+ const auth = this.config.auth;
226
+ // No auth configured
227
+ if (!auth || auth.type === "none") {
228
+ return { valid: true };
229
+ }
230
+ // Token auth
231
+ if (auth.type === "token") {
232
+ return { valid: token === auth.token };
233
+ }
234
+ // JWT auth
235
+ if (auth.type === "jwt") {
236
+ return { valid: false };
237
+ }
238
+ // Custom auth
239
+ if (auth.type === "custom") {
240
+ return await auth.validate(token ?? "");
241
+ }
242
+ return { valid: false };
243
+ }
244
+ }
245
+ //# sourceMappingURL=websocket-server.js.map