@principal-ai/control-tower-core 0.2.0 → 0.2.2
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/dist/abstractions/ConnectedRoomManager.d.ts +22 -0
- package/dist/abstractions/ConnectedRoomManager.d.ts.map +1 -0
- package/dist/abstractions/ConnectedRoomManager.js +56 -0
- package/dist/abstractions/index.d.ts +1 -0
- package/dist/abstractions/index.d.ts.map +1 -1
- package/dist/abstractions/index.js +3 -1
- package/dist/generated/client-connection-auth.types.d.ts +312 -0
- package/dist/generated/client-connection-auth.types.d.ts.map +1 -0
- package/dist/generated/client-connection-auth.types.js +11 -0
- package/dist/generated/control-tower-execution.types.d.ts +445 -0
- package/dist/generated/control-tower-execution.types.d.ts.map +1 -0
- package/dist/generated/control-tower-execution.types.js +11 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +8 -7
- package/dist/index.mjs +180 -99
- package/dist/index.mjs.map +8 -7
- package/dist/server/BaseServer.d.ts +30 -2
- package/dist/server/BaseServer.d.ts.map +1 -1
- package/dist/server/BaseServer.js +77 -8
- package/dist/server/ServerBuilder.d.ts.map +1 -1
- package/dist/server/ServerBuilder.js +11 -0
- package/dist/telemetry/EventValidationIntegration.d.ts +135 -0
- package/dist/telemetry/EventValidationIntegration.d.ts.map +1 -0
- package/dist/telemetry/EventValidationIntegration.js +253 -0
- package/dist/telemetry/EventValidationIntegration.test.d.ts +7 -0
- package/dist/telemetry/EventValidationIntegration.test.d.ts.map +1 -0
- package/dist/telemetry/EventValidationIntegration.test.js +322 -0
- package/dist/telemetry/TelemetryCapture.d.ts +268 -0
- package/dist/telemetry/TelemetryCapture.d.ts.map +1 -0
- package/dist/telemetry/TelemetryCapture.js +263 -0
- package/dist/telemetry/TelemetryCapture.test.d.ts +7 -0
- package/dist/telemetry/TelemetryCapture.test.d.ts.map +1 -0
- package/dist/telemetry/TelemetryCapture.test.js +396 -0
- package/dist/telemetry-example.d.ts +33 -0
- package/dist/telemetry-example.d.ts.map +1 -0
- package/dist/telemetry-example.js +124 -0
- package/package.json +1 -1
- package/dist/adapters/websocket/WebSocketTransportAdapter.d.ts +0 -60
- package/dist/adapters/websocket/WebSocketTransportAdapter.d.ts.map +0 -1
- package/dist/adapters/websocket/WebSocketTransportAdapter.js +0 -386
|
@@ -26,6 +26,12 @@ export interface ServerConfig {
|
|
|
26
26
|
export interface ConnectedClient {
|
|
27
27
|
id: string;
|
|
28
28
|
userId: string;
|
|
29
|
+
/**
|
|
30
|
+
* Device ID for presence tracking.
|
|
31
|
+
* By default equals clientId, but can be overridden via setClientDeviceId()
|
|
32
|
+
* to support multi-window scenarios where multiple clients share a device.
|
|
33
|
+
*/
|
|
34
|
+
deviceId: string;
|
|
29
35
|
/**
|
|
30
36
|
* Set of room IDs the client is currently in
|
|
31
37
|
*
|
|
@@ -204,14 +210,36 @@ export declare class BaseServer extends TypedEventEmitter<ServerEvents> {
|
|
|
204
210
|
* @returns Array of client IDs
|
|
205
211
|
*/
|
|
206
212
|
getClientIdsForUser(userId: string): string[];
|
|
213
|
+
/**
|
|
214
|
+
* Get all client IDs for a user in a specific room
|
|
215
|
+
*
|
|
216
|
+
* @param roomId - Room identifier
|
|
217
|
+
* @param userId - User identifier
|
|
218
|
+
* @returns Array of client IDs
|
|
219
|
+
*/
|
|
220
|
+
getClientIdsInRoom(roomId: string, userId: string): string[];
|
|
207
221
|
/**
|
|
208
222
|
* Get device ID from client ID
|
|
209
223
|
*
|
|
210
|
-
*
|
|
224
|
+
* By default, deviceId === clientId. Use setClientDeviceId() to override
|
|
225
|
+
* for multi-window scenarios where multiple clients share a device.
|
|
211
226
|
*
|
|
212
227
|
* @param clientId - Client identifier
|
|
213
|
-
* @returns Device ID
|
|
228
|
+
* @returns Device ID for this client
|
|
214
229
|
*/
|
|
215
230
|
getDeviceIdFromClientId(clientId: string): string;
|
|
231
|
+
/**
|
|
232
|
+
* Set the device ID for a client
|
|
233
|
+
*
|
|
234
|
+
* Use this to associate a custom deviceId with a client, e.g., when
|
|
235
|
+
* the deviceId comes from a JWT token and differs from the WebSocket clientId.
|
|
236
|
+
* This is useful for multi-window scenarios where multiple WebSocket clients
|
|
237
|
+
* share the same device/user session.
|
|
238
|
+
*
|
|
239
|
+
* @param clientId - Client identifier
|
|
240
|
+
* @param deviceId - Device identifier to associate with this client
|
|
241
|
+
* @returns true if the client was found and updated, false otherwise
|
|
242
|
+
*/
|
|
243
|
+
setClientDeviceId(clientId: string, deviceId: string): boolean;
|
|
216
244
|
}
|
|
217
245
|
//# sourceMappingURL=BaseServer.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BaseServer.d.ts","sourceRoot":"","sources":["../../src/server/BaseServer.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"BaseServer.d.ts","sourceRoot":"","sources":["../../src/server/BaseServer.ts"],"names":[],"mappings":"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"}
|
|
@@ -254,6 +254,7 @@ class BaseServer extends EventEmitter_js_1.TypedEventEmitter {
|
|
|
254
254
|
const client = {
|
|
255
255
|
id: payload.clientId,
|
|
256
256
|
userId: payload.userId || "",
|
|
257
|
+
deviceId: payload.clientId, // Default to clientId, can be overridden via setClientDeviceId()
|
|
257
258
|
roomIds,
|
|
258
259
|
get roomId() {
|
|
259
260
|
return roomIds.size > 0 ? roomIds.values().next().value || null : null;
|
|
@@ -340,6 +341,7 @@ class BaseServer extends EventEmitter_js_1.TypedEventEmitter {
|
|
|
340
341
|
const client = {
|
|
341
342
|
id: clientId,
|
|
342
343
|
userId: "",
|
|
344
|
+
deviceId: clientId, // Default to clientId, can be overridden via setClientDeviceId()
|
|
343
345
|
roomIds,
|
|
344
346
|
get roomId() {
|
|
345
347
|
return roomIds.size > 0 ? roomIds.values().next().value || null : null;
|
|
@@ -371,10 +373,10 @@ class BaseServer extends EventEmitter_js_1.TypedEventEmitter {
|
|
|
371
373
|
// Unregister from presence manager
|
|
372
374
|
if (this.presenceManager?.isEnabled() && client.userId) {
|
|
373
375
|
try {
|
|
374
|
-
const presence = await this.presenceManager.disconnectDevice(client.userId,
|
|
376
|
+
const presence = await this.presenceManager.disconnectDevice(client.userId, client.deviceId);
|
|
375
377
|
await this.emit("presence_device_disconnected", {
|
|
376
378
|
userId: client.userId,
|
|
377
|
-
deviceId:
|
|
379
|
+
deviceId: client.deviceId,
|
|
378
380
|
timestamp: Date.now(),
|
|
379
381
|
});
|
|
380
382
|
// Broadcast presence update if user went offline or into grace period
|
|
@@ -385,7 +387,7 @@ class BaseServer extends EventEmitter_js_1.TypedEventEmitter {
|
|
|
385
387
|
type: "presence:user_offline",
|
|
386
388
|
payload: {
|
|
387
389
|
userId: client.userId,
|
|
388
|
-
deviceId:
|
|
390
|
+
deviceId: client.deviceId,
|
|
389
391
|
status: presence?.status || "offline",
|
|
390
392
|
gracePeriod: presenceConfig.gracePeriod,
|
|
391
393
|
},
|
|
@@ -399,8 +401,23 @@ class BaseServer extends EventEmitter_js_1.TypedEventEmitter {
|
|
|
399
401
|
});
|
|
400
402
|
}
|
|
401
403
|
}
|
|
402
|
-
// Leave all rooms the client is in
|
|
404
|
+
// Leave all rooms the client is in and broadcast to other room members
|
|
403
405
|
for (const roomId of client.roomIds) {
|
|
406
|
+
// Broadcast member_left to other room members
|
|
407
|
+
try {
|
|
408
|
+
await this.experimental.broadcastWhere((c) => c.roomIds.has(roomId) && c.id !== clientId, {
|
|
409
|
+
type: "member_left",
|
|
410
|
+
payload: {
|
|
411
|
+
roomId,
|
|
412
|
+
userId: client.userId,
|
|
413
|
+
clientId,
|
|
414
|
+
timestamp: Date.now(),
|
|
415
|
+
},
|
|
416
|
+
});
|
|
417
|
+
}
|
|
418
|
+
catch {
|
|
419
|
+
// Experimental broadcast not enabled, skip silently
|
|
420
|
+
}
|
|
404
421
|
await this.roomManager.leaveRoom(roomId, client.userId);
|
|
405
422
|
await this.emit("client_left_room", { clientId, roomId });
|
|
406
423
|
}
|
|
@@ -422,7 +439,7 @@ class BaseServer extends EventEmitter_js_1.TypedEventEmitter {
|
|
|
422
439
|
if (this.presenceManager?.isEnabled() &&
|
|
423
440
|
client.userId &&
|
|
424
441
|
client.authenticated) {
|
|
425
|
-
await this.updatePresenceActivity(client.userId,
|
|
442
|
+
await this.updatePresenceActivity(client.userId, client.deviceId, "message");
|
|
426
443
|
}
|
|
427
444
|
switch (message.type) {
|
|
428
445
|
case "authenticate":
|
|
@@ -619,6 +636,22 @@ class BaseServer extends EventEmitter_js_1.TypedEventEmitter {
|
|
|
619
636
|
if (!client.roomIds.has(roomId)) {
|
|
620
637
|
continue;
|
|
621
638
|
}
|
|
639
|
+
// Broadcast to other room members BEFORE removing this client
|
|
640
|
+
// Use experimental broadcast if enabled, otherwise silently skip
|
|
641
|
+
try {
|
|
642
|
+
await this.experimental.broadcastWhere((c) => c.roomIds.has(roomId) && c.id !== clientId, {
|
|
643
|
+
type: "member_left",
|
|
644
|
+
payload: {
|
|
645
|
+
roomId,
|
|
646
|
+
userId: client.userId,
|
|
647
|
+
clientId,
|
|
648
|
+
timestamp: Date.now(),
|
|
649
|
+
},
|
|
650
|
+
});
|
|
651
|
+
}
|
|
652
|
+
catch {
|
|
653
|
+
// Experimental broadcast not enabled, skip silently
|
|
654
|
+
}
|
|
622
655
|
await this.roomManager.leaveRoom(roomId, client.userId);
|
|
623
656
|
client.roomIds.delete(roomId);
|
|
624
657
|
await this.emit("client_left_room", { clientId, roomId });
|
|
@@ -818,16 +851,52 @@ class BaseServer extends EventEmitter_js_1.TypedEventEmitter {
|
|
|
818
851
|
getClientIdsForUser(userId) {
|
|
819
852
|
return Array.from(this.userClientMap.get(userId) || []);
|
|
820
853
|
}
|
|
854
|
+
/**
|
|
855
|
+
* Get all client IDs for a user in a specific room
|
|
856
|
+
*
|
|
857
|
+
* @param roomId - Room identifier
|
|
858
|
+
* @param userId - User identifier
|
|
859
|
+
* @returns Array of client IDs
|
|
860
|
+
*/
|
|
861
|
+
getClientIdsInRoom(roomId, userId) {
|
|
862
|
+
const allClientIds = this.getClientIdsForUser(userId);
|
|
863
|
+
return allClientIds.filter(clientId => {
|
|
864
|
+
const client = this.clients.get(clientId);
|
|
865
|
+
return client && client.roomIds.has(roomId);
|
|
866
|
+
});
|
|
867
|
+
}
|
|
821
868
|
/**
|
|
822
869
|
* Get device ID from client ID
|
|
823
870
|
*
|
|
824
|
-
*
|
|
871
|
+
* By default, deviceId === clientId. Use setClientDeviceId() to override
|
|
872
|
+
* for multi-window scenarios where multiple clients share a device.
|
|
825
873
|
*
|
|
826
874
|
* @param clientId - Client identifier
|
|
827
|
-
* @returns Device ID
|
|
875
|
+
* @returns Device ID for this client
|
|
828
876
|
*/
|
|
829
877
|
getDeviceIdFromClientId(clientId) {
|
|
830
|
-
|
|
878
|
+
const client = this.clients.get(clientId);
|
|
879
|
+
return client?.deviceId ?? clientId;
|
|
880
|
+
}
|
|
881
|
+
/**
|
|
882
|
+
* Set the device ID for a client
|
|
883
|
+
*
|
|
884
|
+
* Use this to associate a custom deviceId with a client, e.g., when
|
|
885
|
+
* the deviceId comes from a JWT token and differs from the WebSocket clientId.
|
|
886
|
+
* This is useful for multi-window scenarios where multiple WebSocket clients
|
|
887
|
+
* share the same device/user session.
|
|
888
|
+
*
|
|
889
|
+
* @param clientId - Client identifier
|
|
890
|
+
* @param deviceId - Device identifier to associate with this client
|
|
891
|
+
* @returns true if the client was found and updated, false otherwise
|
|
892
|
+
*/
|
|
893
|
+
setClientDeviceId(clientId, deviceId) {
|
|
894
|
+
const client = this.clients.get(clientId);
|
|
895
|
+
if (client) {
|
|
896
|
+
client.deviceId = deviceId;
|
|
897
|
+
return true;
|
|
898
|
+
}
|
|
899
|
+
return false;
|
|
831
900
|
}
|
|
832
901
|
}
|
|
833
902
|
exports.BaseServer = BaseServer;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ServerBuilder.d.ts","sourceRoot":"","sources":["../../src/server/ServerBuilder.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,IAAI,UAAU,EAAE,MAAM,MAAM,CAAC;AACjD,OAAO,KAAK,EAAE,MAAM,IAAI,WAAW,EAAE,MAAM,OAAO,CAAC;AACnD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,IAAI,CAAC;AAC1C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;
|
|
1
|
+
{"version":3,"file":"ServerBuilder.d.ts","sourceRoot":"","sources":["../../src/server/ServerBuilder.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,IAAI,UAAU,EAAE,MAAM,MAAM,CAAC;AACjD,OAAO,KAAK,EAAE,MAAM,IAAI,WAAW,EAAE,MAAM,OAAO,CAAC;AACnD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,IAAI,CAAC;AAC1C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;AAGnE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gCAAgC,CAAC;AAClE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oCAAoC,CAAC;AAC1E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gCAAgC,CAAC;AAClE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mCAAmC,CAAC;AACzE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,qCAAqC,CAAC;AAC7E,OAAO,KAAK,EAAE,yBAAyB,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/E,OAAO,EAAE,UAAU,EAAqB,MAAM,iBAAiB,CAAC;AAEhE,qBAAa,aAAa;IACzB,OAAO,CAAC,SAAS,CAAC,CAAoB;IACtC,OAAO,CAAC,IAAI,CAAC,CAAe;IAC5B,OAAO,CAAC,OAAO,CAAC,CAAkB;IAClC,OAAO,CAAC,WAAW,CAAC,CAAc;IAClC,OAAO,CAAC,WAAW,CAAC,CAAc;IAClC,OAAO,CAAC,eAAe,CAAC,CAAkB;IAC1C,OAAO,CAAC,iBAAiB,CAAC,CAAsB;IAChD,OAAO,CAAC,UAAU,CAAC,CAA2B;IAC9C,OAAO,CAAC,aAAa,CAAC,CAAS;IAC/B,OAAO,CAAC,eAAe,CAAC,CAAkB;IAC1C,OAAO,CAAC,oBAAoB,CAAC,CAA4B;IAEzD,aAAa,CAAC,SAAS,EAAE,iBAAiB,GAAG,IAAI;IAKjD,QAAQ,CAAC,IAAI,EAAE,YAAY,GAAG,IAAI;IAKlC,WAAW,CAAC,OAAO,EAAE,eAAe,GAAG,IAAI;IAK3C,eAAe,CAAC,WAAW,EAAE,WAAW,GAAG,IAAI;IAK/C,eAAe,CAAC,WAAW,EAAE,WAAW,GAAG,IAAI;IAK/C;;;;;;;OAOG;IACH,mBAAmB,CAAC,eAAe,EAAE,eAAe,GAAG,IAAI;IAK3D,qBAAqB,CAAC,MAAM,EAAE,OAAO,CAAC,UAAU,CAAC,GAAG,IAAI;IAKxD,cAAc,CAAC,MAAM,EAAE,UAAU,GAAG,WAAW,GAAG,IAAI;IAKtD,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAKrC,mBAAmB,CAAC,GAAG,EAAE,eAAe,GAAG,IAAI;IAK/C;;;;;;;OAOG;IACH,wBAAwB,CAAC,QAAQ,EAAE,yBAAyB,GAAG,IAAI;IAKnE,KAAK,IAAI,UAAU;IAoEnB;;;OAGG;IACH,OAAO,CAAC,0BAA0B;CAyClC"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.ServerBuilder = void 0;
|
|
4
|
+
const ConnectedRoomManager_js_1 = require("../abstractions/ConnectedRoomManager.js");
|
|
4
5
|
const DefaultPresenceManager_js_1 = require("../abstractions/DefaultPresenceManager.js");
|
|
5
6
|
const BaseServer_js_1 = require("./BaseServer.js");
|
|
6
7
|
class ServerBuilder {
|
|
@@ -96,6 +97,16 @@ class ServerBuilder {
|
|
|
96
97
|
},
|
|
97
98
|
};
|
|
98
99
|
const server = new BaseServer_js_1.BaseServer(config);
|
|
100
|
+
// Auto-enhance DefaultRoomManager with broadcasting capabilities
|
|
101
|
+
// This happens after server construction so we have access to server methods
|
|
102
|
+
if (this.roomManager.constructor.name === 'DefaultRoomManager') {
|
|
103
|
+
// Create enhanced room manager with server callbacks
|
|
104
|
+
const connectedManager = new ConnectedRoomManager_js_1.ConnectedRoomManager((clientId, message) => server.sendToClient(clientId, message), (roomId, userId) => server.getClientIdsInRoom(roomId, userId));
|
|
105
|
+
// Copy existing room state
|
|
106
|
+
connectedManager.rooms = this.roomManager.rooms;
|
|
107
|
+
// Replace the room manager in the server
|
|
108
|
+
server.roomManager = connectedManager;
|
|
109
|
+
}
|
|
99
110
|
// Auto-link presence manager to server for broadcasting
|
|
100
111
|
if (this.presenceManager instanceof DefaultPresenceManager_js_1.DefaultPresenceManager) {
|
|
101
112
|
this.presenceManager.setServer(server);
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Event Validation Integration for Control Tower
|
|
3
|
+
*
|
|
4
|
+
* This demonstrates how to integrate event schema validation
|
|
5
|
+
* into the Control Tower server for type-safe telemetry.
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* 1. Install: npm install @principal-ai/principal-view-core
|
|
9
|
+
* 2. Import canvas and types
|
|
10
|
+
* 3. Create validated event emitters
|
|
11
|
+
* 4. Use in server event handlers
|
|
12
|
+
*/
|
|
13
|
+
import type { ExtendedCanvas } from '@principal-ai/principal-view-core';
|
|
14
|
+
import type { WebsocketAdapter, Server, MessageHandler, AuthAdapter, ClientLifecycle, ClientResponse, NodeEmitterByName } from '@generated/client-connection-auth.types';
|
|
15
|
+
/**
|
|
16
|
+
* Control Tower Telemetry Service
|
|
17
|
+
*
|
|
18
|
+
* Provides type-safe, validated event emission for all Control Tower operations.
|
|
19
|
+
*/
|
|
20
|
+
export declare class ControlTowerTelemetry {
|
|
21
|
+
private validator;
|
|
22
|
+
private canvas;
|
|
23
|
+
websocketAdapter: NodeEmitterByName<WebsocketAdapter.Event>;
|
|
24
|
+
server: NodeEmitterByName<Server.Event>;
|
|
25
|
+
messageHandler: NodeEmitterByName<MessageHandler.Event>;
|
|
26
|
+
authAdapter: NodeEmitterByName<AuthAdapter.Event>;
|
|
27
|
+
clientLifecycle: NodeEmitterByName<ClientLifecycle.Event>;
|
|
28
|
+
clientResponse: NodeEmitterByName<ClientResponse.Event>;
|
|
29
|
+
constructor(canvas: ExtendedCanvas, options?: {
|
|
30
|
+
/** Strict mode throws on validation errors (for tests) */
|
|
31
|
+
strict?: boolean;
|
|
32
|
+
/** Custom event handler */
|
|
33
|
+
onEvent?: (nodeId: string, eventName: string, attributes: Record<string, any>) => void;
|
|
34
|
+
});
|
|
35
|
+
/**
|
|
36
|
+
* Get available event names for a component
|
|
37
|
+
*/
|
|
38
|
+
getEventNames(component: 'websocket-adapter' | 'server' | 'message-handler' | 'auth-adapter' | 'client-lifecycle' | 'client-response'): string[];
|
|
39
|
+
/**
|
|
40
|
+
* Validate an event manually (for testing)
|
|
41
|
+
*/
|
|
42
|
+
validate(component: string, eventName: string, attributes: Record<string, any>): any;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Example: Integrating with BaseServer
|
|
46
|
+
*
|
|
47
|
+
* This shows how you would integrate telemetry into the BaseServer class.
|
|
48
|
+
*/
|
|
49
|
+
export declare class TelemetryIntegrationExample {
|
|
50
|
+
private telemetry;
|
|
51
|
+
constructor(canvas: ExtendedCanvas);
|
|
52
|
+
/**
|
|
53
|
+
* Example: Handle WebSocket connection received
|
|
54
|
+
*/
|
|
55
|
+
handleConnectionReceived(connectionId: string, origin?: string): void;
|
|
56
|
+
/**
|
|
57
|
+
* Example: Handle WebSocket connection established
|
|
58
|
+
*/
|
|
59
|
+
handleConnectionEstablished(connectionId: string, transportType: string): void;
|
|
60
|
+
/**
|
|
61
|
+
* Example: Handle client connected to server
|
|
62
|
+
*/
|
|
63
|
+
handleClientConnected(clientId: string, transportType: string): void;
|
|
64
|
+
/**
|
|
65
|
+
* Example: Handle client awaiting authentication
|
|
66
|
+
*/
|
|
67
|
+
handleClientAwaitingAuth(clientId: string, timeoutMs?: number): void;
|
|
68
|
+
/**
|
|
69
|
+
* Example: Handle message received
|
|
70
|
+
*/
|
|
71
|
+
handleMessageReceived(clientId: string, messageType: string, messageSize?: number): void;
|
|
72
|
+
/**
|
|
73
|
+
* Example: Handle message validated
|
|
74
|
+
*/
|
|
75
|
+
handleMessageValidated(clientId: string, messageType: string): void;
|
|
76
|
+
/**
|
|
77
|
+
* Example: Handle message validation failure
|
|
78
|
+
*/
|
|
79
|
+
handleMessageValidationFailed(clientId: string, messageType: string, errorMessage: string, errorField?: string): void;
|
|
80
|
+
/**
|
|
81
|
+
* Example: Handle auth validation started
|
|
82
|
+
*/
|
|
83
|
+
handleAuthValidationStarted(clientId: string, authMethod?: string): void;
|
|
84
|
+
/**
|
|
85
|
+
* Example: Handle auth validation success
|
|
86
|
+
*/
|
|
87
|
+
handleAuthValidationSuccess(clientId: string, userId: string, authMethod?: string, duration?: number): void;
|
|
88
|
+
/**
|
|
89
|
+
* Example: Handle auth validation failure
|
|
90
|
+
*/
|
|
91
|
+
handleAuthValidationFailed(clientId: string, errorCode: string, errorMessage: string): void;
|
|
92
|
+
/**
|
|
93
|
+
* Example: Handle client state changed
|
|
94
|
+
*/
|
|
95
|
+
handleClientStateChanged(clientId: string, fromState: string, toState: string, duration?: number): void;
|
|
96
|
+
/**
|
|
97
|
+
* Example: Handle client authenticated
|
|
98
|
+
*/
|
|
99
|
+
handleClientAuthenticated(clientId: string, userId: string, totalDuration?: number): void;
|
|
100
|
+
/**
|
|
101
|
+
* Example: Handle client disconnected
|
|
102
|
+
*/
|
|
103
|
+
handleClientDisconnected(clientId: string, reason: string, sessionDuration: number, wasAuthenticated: boolean): void;
|
|
104
|
+
/**
|
|
105
|
+
* Example: Handle response sent to client
|
|
106
|
+
*/
|
|
107
|
+
handleResponseSent(clientId: string, responseType: string, size?: number): void;
|
|
108
|
+
/**
|
|
109
|
+
* Example: Handle response send failure
|
|
110
|
+
*/
|
|
111
|
+
handleResponseSendFailed(clientId: string, errorMessage: string): void;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Load canvas from file
|
|
115
|
+
*/
|
|
116
|
+
export declare function loadControlTowerCanvas(): ExtendedCanvas;
|
|
117
|
+
/**
|
|
118
|
+
* Create telemetry service instance
|
|
119
|
+
*
|
|
120
|
+
* @example
|
|
121
|
+
* ```typescript
|
|
122
|
+
* const telemetry = createTelemetryService();
|
|
123
|
+
*
|
|
124
|
+
* telemetry.clientLifecycle('client.connected', {
|
|
125
|
+
* 'client.id': 'abc123',
|
|
126
|
+
* 'transport.type': 'websocket',
|
|
127
|
+
* 'connection.time': Date.now(),
|
|
128
|
+
* });
|
|
129
|
+
* ```
|
|
130
|
+
*/
|
|
131
|
+
export declare function createTelemetryService(options?: {
|
|
132
|
+
strict?: boolean;
|
|
133
|
+
onEvent?: (nodeId: string, eventName: string, attributes: Record<string, any>) => void;
|
|
134
|
+
}): ControlTowerTelemetry;
|
|
135
|
+
//# sourceMappingURL=EventValidationIntegration.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EventValidationIntegration.d.ts","sourceRoot":"","sources":["../../src/telemetry/EventValidationIntegration.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Event Validation Integration for Control Tower
|
|
4
|
+
*
|
|
5
|
+
* This demonstrates how to integrate event schema validation
|
|
6
|
+
* into the Control Tower server for type-safe telemetry.
|
|
7
|
+
*
|
|
8
|
+
* Usage:
|
|
9
|
+
* 1. Install: npm install @principal-ai/principal-view-core
|
|
10
|
+
* 2. Import canvas and types
|
|
11
|
+
* 3. Create validated event emitters
|
|
12
|
+
* 4. Use in server event handlers
|
|
13
|
+
*/
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.TelemetryIntegrationExample = exports.ControlTowerTelemetry = void 0;
|
|
16
|
+
exports.loadControlTowerCanvas = loadControlTowerCanvas;
|
|
17
|
+
exports.createTelemetryService = createTelemetryService;
|
|
18
|
+
const principal_view_core_1 = require("@principal-ai/principal-view-core");
|
|
19
|
+
/**
|
|
20
|
+
* Control Tower Telemetry Service
|
|
21
|
+
*
|
|
22
|
+
* Provides type-safe, validated event emission for all Control Tower operations.
|
|
23
|
+
*/
|
|
24
|
+
class ControlTowerTelemetry {
|
|
25
|
+
constructor(canvas, options = {}) {
|
|
26
|
+
this.canvas = canvas;
|
|
27
|
+
this.validator = new principal_view_core_1.EventValidator(canvas);
|
|
28
|
+
const defaultHandler = (nodeId, eventName, attributes) => {
|
|
29
|
+
// Default: log to console (replace with your telemetry backend)
|
|
30
|
+
console.log(`[${nodeId}] ${eventName}`, attributes);
|
|
31
|
+
};
|
|
32
|
+
const eventHandler = options.onEvent || defaultHandler;
|
|
33
|
+
// Create type-safe emitters for each component
|
|
34
|
+
this.websocketAdapter = (0, principal_view_core_1.createValidatedEmitter)(this.validator, 'websocket-adapter', (eventName, attributes) => eventHandler('websocket-adapter', eventName, attributes), { strict: options.strict ?? false });
|
|
35
|
+
this.server = (0, principal_view_core_1.createValidatedEmitter)(this.validator, 'server', (eventName, attributes) => eventHandler('server', eventName, attributes), { strict: options.strict ?? false });
|
|
36
|
+
this.messageHandler = (0, principal_view_core_1.createValidatedEmitter)(this.validator, 'message-handler', (eventName, attributes) => eventHandler('message-handler', eventName, attributes), { strict: options.strict ?? false });
|
|
37
|
+
this.authAdapter = (0, principal_view_core_1.createValidatedEmitter)(this.validator, 'auth-adapter', (eventName, attributes) => eventHandler('auth-adapter', eventName, attributes), { strict: options.strict ?? false });
|
|
38
|
+
this.clientLifecycle = (0, principal_view_core_1.createValidatedEmitter)(this.validator, 'client-lifecycle', (eventName, attributes) => eventHandler('client-lifecycle', eventName, attributes), { strict: options.strict ?? false });
|
|
39
|
+
this.clientResponse = (0, principal_view_core_1.createValidatedEmitter)(this.validator, 'client-response', (eventName, attributes) => eventHandler('client-response', eventName, attributes), { strict: options.strict ?? false });
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Get available event names for a component
|
|
43
|
+
*/
|
|
44
|
+
getEventNames(component) {
|
|
45
|
+
return this.validator.getNodeEventNames(component);
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Validate an event manually (for testing)
|
|
49
|
+
*/
|
|
50
|
+
validate(component, eventName, attributes) {
|
|
51
|
+
return this.validator.validate(component, eventName, attributes);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
exports.ControlTowerTelemetry = ControlTowerTelemetry;
|
|
55
|
+
/**
|
|
56
|
+
* Example: Integrating with BaseServer
|
|
57
|
+
*
|
|
58
|
+
* This shows how you would integrate telemetry into the BaseServer class.
|
|
59
|
+
*/
|
|
60
|
+
class TelemetryIntegrationExample {
|
|
61
|
+
constructor(canvas) {
|
|
62
|
+
// Create telemetry service
|
|
63
|
+
this.telemetry = new ControlTowerTelemetry(canvas, {
|
|
64
|
+
strict: false, // Permissive in production
|
|
65
|
+
onEvent: (nodeId, eventName, attributes) => {
|
|
66
|
+
// Send to your telemetry backend (OpenTelemetry, DataDog, etc.)
|
|
67
|
+
console.log(`[TELEMETRY] ${nodeId}.${eventName}`, attributes);
|
|
68
|
+
},
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Example: Handle WebSocket connection received
|
|
73
|
+
*/
|
|
74
|
+
handleConnectionReceived(connectionId, origin) {
|
|
75
|
+
this.telemetry.websocketAdapter('connection.received', {
|
|
76
|
+
'connection.id': connectionId,
|
|
77
|
+
'connection.origin': origin,
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Example: Handle WebSocket connection established
|
|
82
|
+
*/
|
|
83
|
+
handleConnectionEstablished(connectionId, transportType) {
|
|
84
|
+
this.telemetry.websocketAdapter('connection.established', {
|
|
85
|
+
'connection.id': connectionId,
|
|
86
|
+
'transport.type': transportType,
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Example: Handle client connected to server
|
|
91
|
+
*/
|
|
92
|
+
handleClientConnected(clientId, transportType) {
|
|
93
|
+
this.telemetry.server('client.connected', {
|
|
94
|
+
'client.id': clientId,
|
|
95
|
+
'transport.type': transportType,
|
|
96
|
+
'connection.timestamp': Date.now(),
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Example: Handle client awaiting authentication
|
|
101
|
+
*/
|
|
102
|
+
handleClientAwaitingAuth(clientId, timeoutMs) {
|
|
103
|
+
this.telemetry.server('client.awaiting_auth', {
|
|
104
|
+
'client.id': clientId,
|
|
105
|
+
'auth.timeout_ms': timeoutMs,
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Example: Handle message received
|
|
110
|
+
*/
|
|
111
|
+
handleMessageReceived(clientId, messageType, messageSize) {
|
|
112
|
+
this.telemetry.messageHandler('message.received', {
|
|
113
|
+
'client.id': clientId,
|
|
114
|
+
'message.type': messageType,
|
|
115
|
+
'message.size_bytes': messageSize,
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Example: Handle message validated
|
|
120
|
+
*/
|
|
121
|
+
handleMessageValidated(clientId, messageType) {
|
|
122
|
+
this.telemetry.messageHandler('message.validated', {
|
|
123
|
+
'client.id': clientId,
|
|
124
|
+
'message.type': messageType,
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Example: Handle message validation failure
|
|
129
|
+
*/
|
|
130
|
+
handleMessageValidationFailed(clientId, messageType, errorMessage, errorField) {
|
|
131
|
+
this.telemetry.messageHandler('message.validation_failed', {
|
|
132
|
+
'client.id': clientId,
|
|
133
|
+
'message.type': messageType,
|
|
134
|
+
'validation.error': errorMessage,
|
|
135
|
+
'validation.field': errorField,
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Example: Handle auth validation started
|
|
140
|
+
*/
|
|
141
|
+
handleAuthValidationStarted(clientId, authMethod) {
|
|
142
|
+
this.telemetry.authAdapter('auth.validation_started', {
|
|
143
|
+
'client.id': clientId,
|
|
144
|
+
'auth.method': authMethod,
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Example: Handle auth validation success
|
|
149
|
+
*/
|
|
150
|
+
handleAuthValidationSuccess(clientId, userId, authMethod, duration) {
|
|
151
|
+
this.telemetry.authAdapter('auth.validation_success', {
|
|
152
|
+
'client.id': clientId,
|
|
153
|
+
'user.id': userId,
|
|
154
|
+
'auth.method': authMethod,
|
|
155
|
+
'validation.duration_ms': duration,
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Example: Handle auth validation failure
|
|
160
|
+
*/
|
|
161
|
+
handleAuthValidationFailed(clientId, errorCode, errorMessage) {
|
|
162
|
+
this.telemetry.authAdapter('auth.validation_failed', {
|
|
163
|
+
'client.id': clientId,
|
|
164
|
+
'auth.error_code': errorCode,
|
|
165
|
+
'auth.error_message': errorMessage,
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Example: Handle client state changed
|
|
170
|
+
*/
|
|
171
|
+
handleClientStateChanged(clientId, fromState, toState, duration) {
|
|
172
|
+
this.telemetry.clientLifecycle('client.state_changed', {
|
|
173
|
+
'client.id': clientId,
|
|
174
|
+
'state.from': fromState,
|
|
175
|
+
'state.to': toState,
|
|
176
|
+
'state.duration_ms': duration,
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Example: Handle client authenticated
|
|
181
|
+
*/
|
|
182
|
+
handleClientAuthenticated(clientId, userId, totalDuration) {
|
|
183
|
+
// ✅ Type-safe: TypeScript knows exact attributes for this event
|
|
184
|
+
this.telemetry.clientLifecycle('client.authenticated', {
|
|
185
|
+
'client.id': clientId,
|
|
186
|
+
'user.id': userId,
|
|
187
|
+
'connection.total_duration_ms': totalDuration,
|
|
188
|
+
});
|
|
189
|
+
// ❌ TypeScript error: missing required field
|
|
190
|
+
// this.telemetry.clientLifecycle('client.authenticated', {
|
|
191
|
+
// 'client.id': clientId,
|
|
192
|
+
// // Missing 'user.id' - TypeScript error!
|
|
193
|
+
// });
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Example: Handle client disconnected
|
|
197
|
+
*/
|
|
198
|
+
handleClientDisconnected(clientId, reason, sessionDuration, wasAuthenticated) {
|
|
199
|
+
this.telemetry.clientLifecycle('client.disconnected', {
|
|
200
|
+
'client.id': clientId,
|
|
201
|
+
'disconnect.reason': reason,
|
|
202
|
+
'session.total_duration_ms': sessionDuration,
|
|
203
|
+
'client.was_authenticated': wasAuthenticated,
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* Example: Handle response sent to client
|
|
208
|
+
*/
|
|
209
|
+
handleResponseSent(clientId, responseType, size) {
|
|
210
|
+
this.telemetry.clientResponse('response.sent', {
|
|
211
|
+
'client.id': clientId,
|
|
212
|
+
'response.type': responseType,
|
|
213
|
+
'response.size_bytes': size,
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* Example: Handle response send failure
|
|
218
|
+
*/
|
|
219
|
+
handleResponseSendFailed(clientId, errorMessage) {
|
|
220
|
+
this.telemetry.clientResponse('response.send_failed', {
|
|
221
|
+
'client.id': clientId,
|
|
222
|
+
'error.message': errorMessage,
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
exports.TelemetryIntegrationExample = TelemetryIntegrationExample;
|
|
227
|
+
/**
|
|
228
|
+
* Load canvas from file
|
|
229
|
+
*/
|
|
230
|
+
function loadControlTowerCanvas() {
|
|
231
|
+
const fs = require('fs');
|
|
232
|
+
const path = require('path');
|
|
233
|
+
const canvasPath = path.join(__dirname, '../../.principal-views/client-connection-auth.otel.canvas');
|
|
234
|
+
return JSON.parse(fs.readFileSync(canvasPath, 'utf-8'));
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* Create telemetry service instance
|
|
238
|
+
*
|
|
239
|
+
* @example
|
|
240
|
+
* ```typescript
|
|
241
|
+
* const telemetry = createTelemetryService();
|
|
242
|
+
*
|
|
243
|
+
* telemetry.clientLifecycle('client.connected', {
|
|
244
|
+
* 'client.id': 'abc123',
|
|
245
|
+
* 'transport.type': 'websocket',
|
|
246
|
+
* 'connection.time': Date.now(),
|
|
247
|
+
* });
|
|
248
|
+
* ```
|
|
249
|
+
*/
|
|
250
|
+
function createTelemetryService(options) {
|
|
251
|
+
const canvas = loadControlTowerCanvas();
|
|
252
|
+
return new ControlTowerTelemetry(canvas, options);
|
|
253
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EventValidationIntegration.test.d.ts","sourceRoot":"","sources":["../../src/telemetry/EventValidationIntegration.test.ts"],"names":[],"mappings":"AAAA;;;;GAIG"}
|