@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,249 @@
1
+ /**
2
+ * Gateway Protocol Types
3
+ *
4
+ * Defines the WebSocket message protocol between clients and the gateway.
5
+ */
6
+
7
+ // ============================================================================
8
+ // Client → Gateway Messages
9
+ // ============================================================================
10
+
11
+ export interface ConnectMessage {
12
+ type: "connect";
13
+ clientId: string;
14
+ token?: string;
15
+ metadata?: Record<string, unknown>;
16
+ }
17
+
18
+ export interface RequestMessage {
19
+ type: "req";
20
+ id: string;
21
+ method: GatewayMethod;
22
+ params: Record<string, unknown>;
23
+ }
24
+
25
+ export interface PingMessage {
26
+ type: "ping";
27
+ timestamp: number;
28
+ }
29
+
30
+ export type ClientMessage = ConnectMessage | RequestMessage | PingMessage;
31
+
32
+ // ============================================================================
33
+ // Gateway → Client Messages
34
+ // ============================================================================
35
+
36
+ export interface ConnectedMessage {
37
+ type: "connected";
38
+ gatewayId: string;
39
+ apps: string[];
40
+ sessions: string[];
41
+ }
42
+
43
+ export interface ResponseMessage {
44
+ type: "res";
45
+ id: string;
46
+ ok: boolean;
47
+ payload?: unknown;
48
+ error?: {
49
+ code: string;
50
+ message: string;
51
+ details?: unknown;
52
+ };
53
+ }
54
+
55
+ export interface EventMessage {
56
+ type: "event";
57
+ event: GatewayEventType;
58
+ sessionId: string;
59
+ data: unknown;
60
+ }
61
+
62
+ export interface PongMessage {
63
+ type: "pong";
64
+ timestamp: number;
65
+ }
66
+
67
+ export interface ErrorMessage {
68
+ type: "error";
69
+ code: string;
70
+ message: string;
71
+ }
72
+
73
+ export type GatewayMessage =
74
+ | ConnectedMessage
75
+ | ResponseMessage
76
+ | EventMessage
77
+ | PongMessage
78
+ | ErrorMessage;
79
+
80
+ // ============================================================================
81
+ // RPC Methods
82
+ // ============================================================================
83
+
84
+ /**
85
+ * Built-in gateway methods with autocomplete support.
86
+ */
87
+ export type BuiltInMethod =
88
+ | "send" // Send message to session
89
+ | "abort" // Abort current execution
90
+ | "status" // Get gateway/session status
91
+ | "history" // Get conversation history
92
+ | "reset" // Reset a session
93
+ | "close" // Close a session
94
+ | "apps" // List available apps
95
+ | "sessions" // List sessions
96
+ | "subscribe" // Subscribe to session events
97
+ | "unsubscribe"; // Unsubscribe from events
98
+
99
+ /**
100
+ * Gateway method - built-in methods or custom method strings.
101
+ * The (string & {}) allows any string while preserving autocomplete for built-in methods.
102
+ */
103
+ export type GatewayMethod = BuiltInMethod | (string & {});
104
+
105
+ // ============================================================================
106
+ // Event Types
107
+ // ============================================================================
108
+
109
+ export type GatewayEventType =
110
+ | "content_delta"
111
+ | "content_block_start"
112
+ | "content_block_end"
113
+ | "tool_call_start"
114
+ | "tool_call_delta"
115
+ | "tool_result"
116
+ | "message_start"
117
+ | "message_end"
118
+ | "error";
119
+
120
+ // ============================================================================
121
+ // Method Parameters
122
+ // ============================================================================
123
+
124
+ export interface SendParams {
125
+ sessionId: string;
126
+ message: string;
127
+ attachments?: Array<{
128
+ type: "image" | "file";
129
+ data: string;
130
+ mimeType: string;
131
+ name?: string;
132
+ }>;
133
+ }
134
+
135
+ export interface AbortParams {
136
+ sessionId: string;
137
+ }
138
+
139
+ export interface StatusParams {
140
+ sessionId?: string;
141
+ }
142
+
143
+ export interface HistoryParams {
144
+ sessionId: string;
145
+ limit?: number;
146
+ before?: string;
147
+ }
148
+
149
+ export interface ResetParams {
150
+ sessionId: string;
151
+ }
152
+
153
+ export interface CloseParams {
154
+ sessionId: string;
155
+ }
156
+
157
+ export interface SubscribeParams {
158
+ sessionId: string;
159
+ }
160
+
161
+ export interface UnsubscribeParams {
162
+ sessionId: string;
163
+ }
164
+
165
+ // ============================================================================
166
+ // Response Payloads
167
+ // ============================================================================
168
+
169
+ export interface StatusPayload {
170
+ gateway: {
171
+ id: string;
172
+ uptime: number;
173
+ clients: number;
174
+ sessions: number;
175
+ apps: string[];
176
+ };
177
+ session?: {
178
+ id: string;
179
+ appId: string;
180
+ messageCount: number;
181
+ createdAt: string;
182
+ lastActivityAt: string;
183
+ isActive: boolean;
184
+ };
185
+ }
186
+
187
+ export interface HistoryPayload {
188
+ messages: Array<{
189
+ id: string;
190
+ role: "user" | "assistant" | "system";
191
+ content: string;
192
+ timestamp: string;
193
+ toolCalls?: Array<{
194
+ name: string;
195
+ input: unknown;
196
+ output?: unknown;
197
+ }>;
198
+ }>;
199
+ hasMore: boolean;
200
+ }
201
+
202
+ export interface AppsPayload {
203
+ apps: Array<{
204
+ id: string;
205
+ name: string;
206
+ description?: string;
207
+ isDefault: boolean;
208
+ }>;
209
+ }
210
+
211
+ export interface SessionsPayload {
212
+ sessions: Array<{
213
+ id: string;
214
+ appId: string;
215
+ createdAt: string;
216
+ lastActivityAt: string;
217
+ messageCount: number;
218
+ }>;
219
+ }
220
+
221
+ // ============================================================================
222
+ // Session Key Format
223
+ // ============================================================================
224
+
225
+ /**
226
+ * Session keys follow the format: [app:]name
227
+ *
228
+ * Examples:
229
+ * - "main" → default app, "main" session
230
+ * - "chat:main" → "chat" app, "main" session
231
+ * - "research:task-123" → "research" app, "task-123" session
232
+ * - "whatsapp:+1234567890" → WhatsApp channel session
233
+ */
234
+ export interface SessionKey {
235
+ appId: string;
236
+ sessionName: string;
237
+ }
238
+
239
+ export function parseSessionKey(key: string, defaultApp: string): SessionKey {
240
+ const parts = key.split(":");
241
+ if (parts.length === 1) {
242
+ return { appId: defaultApp, sessionName: parts[0] };
243
+ }
244
+ return { appId: parts[0], sessionName: parts.slice(1).join(":") };
245
+ }
246
+
247
+ export function formatSessionKey(key: SessionKey): string {
248
+ return `${key.appId}:${key.sessionName}`;
249
+ }
@@ -0,0 +1,191 @@
1
+ /**
2
+ * Gateway Transport Interface
3
+ *
4
+ * Abstracts the transport layer (WebSocket, HTTP/SSE) from gateway business logic.
5
+ * This allows the same GatewayCore to serve clients via different protocols.
6
+ */
7
+
8
+ import type { Message } from "@agentick/shared";
9
+ import { validateAuth, type AuthResult } from "@agentick/server";
10
+ import type { GatewayMessage, ClientMessage } from "./transport-protocol.js";
11
+ import type { AuthConfig, ClientState, UserContext } from "./types.js";
12
+
13
+ // ============================================================================
14
+ // Transport Interface
15
+ // ============================================================================
16
+
17
+ /**
18
+ * A connected client from the transport's perspective.
19
+ */
20
+ export interface TransportClient {
21
+ /** Unique client identifier */
22
+ readonly id: string;
23
+
24
+ /** Client state (auth, subscriptions, etc.) */
25
+ readonly state: ClientState;
26
+
27
+ /** Send a message to this client */
28
+ send(message: GatewayMessage): void;
29
+
30
+ /** Close the connection */
31
+ close(code?: number, reason?: string): void;
32
+
33
+ /** Check if connected */
34
+ readonly isConnected: boolean;
35
+ }
36
+
37
+ /**
38
+ * Events emitted by a transport.
39
+ */
40
+ export interface TransportEvents {
41
+ /** Client connected (may not be authenticated yet) */
42
+ connection: (client: TransportClient) => void;
43
+
44
+ /** Client disconnected */
45
+ disconnect: (clientId: string, reason?: string) => void;
46
+
47
+ /** Message received from authenticated client */
48
+ message: (clientId: string, message: ClientMessage) => void;
49
+
50
+ /** Transport error */
51
+ error: (error: Error) => void;
52
+ }
53
+
54
+ /**
55
+ * Transport configuration.
56
+ */
57
+ export interface TransportConfig {
58
+ /** Port to listen on */
59
+ port: number;
60
+
61
+ /** Host to bind to */
62
+ host: string;
63
+
64
+ /** Authentication configuration */
65
+ auth?: AuthConfig;
66
+
67
+ /**
68
+ * Direct send handler for HTTP transport.
69
+ * Called instead of routing through message handler when streaming response is needed.
70
+ * Accepts full Message object to support multimodal content (images, audio, video, docs).
71
+ */
72
+ onDirectSend?: (
73
+ sessionId: string,
74
+ message: Message,
75
+ ) => AsyncIterable<{ type: string; data?: unknown }>;
76
+
77
+ /**
78
+ * Method invocation handler for HTTP transport.
79
+ * Called to execute custom gateway methods.
80
+ * Returns the method result directly (no streaming).
81
+ */
82
+ onInvoke?: (
83
+ method: string,
84
+ params: Record<string, unknown>,
85
+ user?: UserContext,
86
+ ) => Promise<unknown>;
87
+ }
88
+
89
+ /** Transport type identifier */
90
+ export type TransportType = "websocket" | "http" | "sse";
91
+
92
+ /**
93
+ * Transport interface - abstracts WebSocket vs HTTP/SSE.
94
+ */
95
+ export interface Transport {
96
+ /** Transport type identifier */
97
+ readonly type: TransportType;
98
+
99
+ /** Start the transport server */
100
+ start(): Promise<void>;
101
+
102
+ /** Stop the transport server */
103
+ stop(): Promise<void>;
104
+
105
+ /** Register event handlers */
106
+ on<K extends keyof TransportEvents>(event: K, handler: TransportEvents[K]): void;
107
+
108
+ /** Get a client by ID */
109
+ getClient(id: string): TransportClient | undefined;
110
+
111
+ /** Get all connected clients */
112
+ getClients(): TransportClient[];
113
+
114
+ /** Get authenticated clients */
115
+ getAuthenticatedClients(): TransportClient[];
116
+
117
+ /** Broadcast to all authenticated clients */
118
+ broadcast(message: GatewayMessage): void;
119
+
120
+ /** Send to clients subscribed to a session */
121
+ sendToSubscribers(sessionId: string, message: GatewayMessage): void;
122
+
123
+ /** Number of connected clients */
124
+ readonly clientCount: number;
125
+ }
126
+
127
+ // ============================================================================
128
+ // Base Transport Implementation (shared logic)
129
+ // ============================================================================
130
+
131
+ /**
132
+ * Base class with shared transport functionality.
133
+ */
134
+ export abstract class BaseTransport implements Transport {
135
+ /** Transport type - must be set by subclass */
136
+ abstract readonly type: TransportType;
137
+
138
+ protected clients = new Map<string, TransportClient>();
139
+ protected handlers: Partial<TransportEvents> = {};
140
+ protected config: TransportConfig;
141
+ protected clientIdCounter = 0;
142
+
143
+ constructor(config: TransportConfig) {
144
+ this.config = config;
145
+ }
146
+
147
+ abstract start(): Promise<void>;
148
+ abstract stop(): Promise<void>;
149
+
150
+ on<K extends keyof TransportEvents>(event: K, handler: TransportEvents[K]): void {
151
+ this.handlers[event] = handler;
152
+ }
153
+
154
+ getClient(id: string): TransportClient | undefined {
155
+ return this.clients.get(id);
156
+ }
157
+
158
+ getClients(): TransportClient[] {
159
+ return Array.from(this.clients.values());
160
+ }
161
+
162
+ getAuthenticatedClients(): TransportClient[] {
163
+ return this.getClients().filter((c) => c.state.authenticated);
164
+ }
165
+
166
+ broadcast(message: GatewayMessage): void {
167
+ for (const client of this.getAuthenticatedClients()) {
168
+ client.send(message);
169
+ }
170
+ }
171
+
172
+ sendToSubscribers(sessionId: string, message: GatewayMessage): void {
173
+ for (const client of this.getAuthenticatedClients()) {
174
+ if (client.state.subscriptions.has(sessionId)) {
175
+ client.send(message);
176
+ }
177
+ }
178
+ }
179
+
180
+ get clientCount(): number {
181
+ return this.clients.size;
182
+ }
183
+
184
+ protected generateClientId(): string {
185
+ return `client-${++this.clientIdCounter}`;
186
+ }
187
+
188
+ protected validateAuth(token?: string): Promise<AuthResult> {
189
+ return validateAuth(token, this.config.auth);
190
+ }
191
+ }