@principal-ai/control-tower-core 0.2.1 → 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.
Files changed (31) hide show
  1. package/dist/generated/client-connection-auth.types.d.ts +312 -0
  2. package/dist/generated/client-connection-auth.types.d.ts.map +1 -0
  3. package/dist/generated/client-connection-auth.types.js +11 -0
  4. package/dist/generated/control-tower-execution.types.d.ts +445 -0
  5. package/dist/generated/control-tower-execution.types.d.ts.map +1 -0
  6. package/dist/generated/control-tower-execution.types.js +11 -0
  7. package/dist/index.js.map +3 -3
  8. package/dist/index.mjs +39 -6
  9. package/dist/index.mjs.map +3 -3
  10. package/dist/server/BaseServer.d.ts +22 -2
  11. package/dist/server/BaseServer.d.ts.map +1 -1
  12. package/dist/server/BaseServer.js +63 -8
  13. package/dist/telemetry/EventValidationIntegration.d.ts +135 -0
  14. package/dist/telemetry/EventValidationIntegration.d.ts.map +1 -0
  15. package/dist/telemetry/EventValidationIntegration.js +253 -0
  16. package/dist/telemetry/EventValidationIntegration.test.d.ts +7 -0
  17. package/dist/telemetry/EventValidationIntegration.test.d.ts.map +1 -0
  18. package/dist/telemetry/EventValidationIntegration.test.js +322 -0
  19. package/dist/telemetry/TelemetryCapture.d.ts +268 -0
  20. package/dist/telemetry/TelemetryCapture.d.ts.map +1 -0
  21. package/dist/telemetry/TelemetryCapture.js +263 -0
  22. package/dist/telemetry/TelemetryCapture.test.d.ts +7 -0
  23. package/dist/telemetry/TelemetryCapture.test.d.ts.map +1 -0
  24. package/dist/telemetry/TelemetryCapture.test.js +396 -0
  25. package/dist/telemetry-example.d.ts +33 -0
  26. package/dist/telemetry-example.d.ts.map +1 -0
  27. package/dist/telemetry-example.js +124 -0
  28. package/package.json +1 -1
  29. package/dist/adapters/websocket/WebSocketTransportAdapter.d.ts +0 -60
  30. package/dist/adapters/websocket/WebSocketTransportAdapter.d.ts.map +0 -1
  31. 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
  *
@@ -215,11 +221,25 @@ export declare class BaseServer extends TypedEventEmitter<ServerEvents> {
215
221
  /**
216
222
  * Get device ID from client ID
217
223
  *
218
- * In Control Tower architecture, clientId === deviceId
224
+ * By default, deviceId === clientId. Use setClientDeviceId() to override
225
+ * for multi-window scenarios where multiple clients share a device.
219
226
  *
220
227
  * @param clientId - Client identifier
221
- * @returns Device ID (same as clientId)
228
+ * @returns Device ID for this client
222
229
  */
223
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;
224
244
  }
225
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, clientId);
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: clientId,
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: clientId,
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, clientId, "message");
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 });
@@ -835,13 +868,35 @@ class BaseServer extends EventEmitter_js_1.TypedEventEmitter {
835
868
  /**
836
869
  * Get device ID from client ID
837
870
  *
838
- * In Control Tower architecture, clientId === deviceId
871
+ * By default, deviceId === clientId. Use setClientDeviceId() to override
872
+ * for multi-window scenarios where multiple clients share a device.
839
873
  *
840
874
  * @param clientId - Client identifier
841
- * @returns Device ID (same as clientId)
875
+ * @returns Device ID for this client
842
876
  */
843
877
  getDeviceIdFromClientId(clientId) {
844
- return clientId;
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;
845
900
  }
846
901
  }
847
902
  exports.BaseServer = BaseServer;
@@ -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,7 @@
1
+ /**
2
+ * Event Validation Integration Tests
3
+ *
4
+ * Demonstrates the Control Tower telemetry integration working end-to-end.
5
+ */
6
+ export {};
7
+ //# sourceMappingURL=EventValidationIntegration.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EventValidationIntegration.test.d.ts","sourceRoot":"","sources":["../../src/telemetry/EventValidationIntegration.test.ts"],"names":[],"mappings":"AAAA;;;;GAIG"}