@phystack/hub-client 4.4.53 → 4.4.55
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/index.d.ts +18 -25
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +252 -188
- package/dist/index.js.map +1 -1
- package/dist/peripheral-twin.d.ts +10 -9
- package/dist/peripheral-twin.d.ts.map +1 -1
- package/dist/peripheral-twin.js +24 -54
- package/dist/peripheral-twin.js.map +1 -1
- package/dist/services/phyhub-connection.service.d.ts +1 -0
- package/dist/services/phyhub-connection.service.d.ts.map +1 -1
- package/dist/services/phyhub-connection.service.js +17 -0
- package/dist/services/phyhub-connection.service.js.map +1 -1
- package/dist/services/phyhub-direct-connection.service.d.ts +21 -0
- package/dist/services/phyhub-direct-connection.service.d.ts.map +1 -0
- package/dist/services/phyhub-direct-connection.service.js +101 -0
- package/dist/services/phyhub-direct-connection.service.js.map +1 -0
- package/dist/services/webrtc/data-channel-handler.d.ts +45 -0
- package/dist/services/webrtc/data-channel-handler.d.ts.map +1 -0
- package/dist/services/webrtc/data-channel-handler.js +260 -0
- package/dist/services/webrtc/data-channel-handler.js.map +1 -0
- package/dist/services/webrtc/index.d.ts +8 -0
- package/dist/services/webrtc/index.d.ts.map +1 -0
- package/dist/services/webrtc/index.js +18 -0
- package/dist/services/webrtc/index.js.map +1 -0
- package/dist/services/webrtc/media-stream-handler.d.ts +57 -0
- package/dist/services/webrtc/media-stream-handler.d.ts.map +1 -0
- package/dist/services/webrtc/media-stream-handler.js +367 -0
- package/dist/services/webrtc/media-stream-handler.js.map +1 -0
- package/dist/services/webrtc/peer-connection-manager.d.ts +40 -0
- package/dist/services/webrtc/peer-connection-manager.d.ts.map +1 -0
- package/dist/services/webrtc/peer-connection-manager.js +335 -0
- package/dist/services/webrtc/peer-connection-manager.js.map +1 -0
- package/dist/services/webrtc/types.d.ts +133 -0
- package/dist/services/webrtc/types.d.ts.map +1 -0
- package/dist/services/webrtc/types.js +12 -0
- package/dist/services/webrtc/types.js.map +1 -0
- package/dist/services/webrtc/webrtc-globals.d.ts +4 -0
- package/dist/services/webrtc/webrtc-globals.d.ts.map +1 -0
- package/dist/services/webrtc/webrtc-globals.js +72 -0
- package/dist/services/webrtc/webrtc-globals.js.map +1 -0
- package/dist/services/webrtc/webrtc-manager.d.ts +35 -0
- package/dist/services/webrtc/webrtc-manager.d.ts.map +1 -0
- package/dist/services/webrtc/webrtc-manager.js +274 -0
- package/dist/services/webrtc/webrtc-manager.js.map +1 -0
- package/dist/test/communication-comprehensive-test.d.ts +8 -0
- package/dist/test/communication-comprehensive-test.d.ts.map +1 -0
- package/dist/test/communication-comprehensive-test.js +356 -0
- package/dist/test/communication-comprehensive-test.js.map +1 -0
- package/dist/test/webrtc-channel-names-test.d.ts +2 -0
- package/dist/test/webrtc-channel-names-test.d.ts.map +1 -0
- package/dist/test/webrtc-channel-names-test.js +177 -0
- package/dist/test/webrtc-channel-names-test.js.map +1 -0
- package/dist/test/webrtc-comprehensive-test.d.ts +2 -0
- package/dist/test/webrtc-comprehensive-test.d.ts.map +1 -0
- package/dist/test/webrtc-comprehensive-test.js +328 -0
- package/dist/test/webrtc-comprehensive-test.js.map +1 -0
- package/dist/test/webrtc-reconnect-test.d.ts +4 -0
- package/dist/test/webrtc-reconnect-test.d.ts.map +1 -0
- package/dist/test/webrtc-reconnect-test.js +244 -0
- package/dist/test/webrtc-reconnect-test.js.map +1 -0
- package/dist/test/webrtc-test-harness.d.ts +4 -0
- package/dist/test/webrtc-test-harness.d.ts.map +1 -0
- package/dist/test/webrtc-test-harness.js +169 -0
- package/dist/test/webrtc-test-harness.js.map +1 -0
- package/dist/twin-messaging.d.ts +23 -0
- package/dist/twin-messaging.d.ts.map +1 -0
- package/dist/twin-messaging.js +96 -0
- package/dist/twin-messaging.js.map +1 -0
- package/dist/types/twin.types.d.ts +36 -20
- package/dist/types/twin.types.d.ts.map +1 -1
- package/dist/types/twin.types.js.map +1 -1
- package/docs/webrtc-howto.md +398 -0
- package/docs/webrtc-test.md +330 -0
- package/package.json +3 -3
- package/scripts/webrtc-test.sh +401 -0
- package/src/index.ts +370 -259
- package/src/peripheral-twin.ts +44 -67
- package/src/services/phyhub-connection.service.ts +24 -0
- package/src/services/phyhub-direct-connection.service.ts +159 -0
- package/src/services/webrtc/data-channel-handler.ts +362 -0
- package/src/services/webrtc/index.ts +36 -0
- package/src/services/webrtc/media-stream-handler.ts +515 -0
- package/src/services/webrtc/peer-connection-manager.ts +463 -0
- package/src/services/webrtc/types.ts +270 -0
- package/src/services/webrtc/webrtc-globals.ts +108 -0
- package/src/services/webrtc/webrtc-manager.ts +490 -0
- package/src/test/communication-comprehensive-test.ts +533 -0
- package/src/test/webrtc-channel-names-test.ts +266 -0
- package/src/test/webrtc-comprehensive-test.ts +494 -0
- package/src/test/webrtc-reconnect-test.ts +345 -0
- package/src/test/webrtc-test-harness.ts +254 -0
- package/src/twin-messaging.ts +193 -0
- package/src/types/twin.types.ts +59 -20
- package/dist/services/webrtc/datachannel.d.ts +0 -10
- package/dist/services/webrtc/datachannel.d.ts.map +0 -1
- package/dist/services/webrtc/datachannel.js +0 -290
- package/dist/services/webrtc/datachannel.js.map +0 -1
- package/dist/services/webrtc/mediastream.d.ts +0 -10
- package/dist/services/webrtc/mediastream.d.ts.map +0 -1
- package/dist/services/webrtc/mediastream.js +0 -396
- package/dist/services/webrtc/mediastream.js.map +0 -1
- package/dist/services/webrtc/peer-connection-ice.d.ts +0 -32
- package/dist/services/webrtc/peer-connection-ice.d.ts.map +0 -1
- package/dist/services/webrtc/peer-connection-ice.js +0 -483
- package/dist/services/webrtc/peer-connection-ice.js.map +0 -1
- package/src/services/webrtc/datachannel.ts +0 -421
- package/src/services/webrtc/mediastream.ts +0 -602
- package/src/services/webrtc/peer-connection-ice.ts +0 -689
package/src/index.ts
CHANGED
|
@@ -13,88 +13,20 @@ import {
|
|
|
13
13
|
TwinMessageResult,
|
|
14
14
|
TwinMessageResultStatus,
|
|
15
15
|
} from './types/twin.types';
|
|
16
|
-
import {
|
|
17
|
-
PhygridDataChannel,
|
|
18
|
-
PhygridMediaStream,
|
|
19
|
-
WebRTCConnectionOptions,
|
|
20
|
-
} from './types/webrtc.types';
|
|
21
16
|
import { PhyHubConnection } from './services/phyhub-connection.service';
|
|
17
|
+
import { PhyHubDirectConnection } from './services/phyhub-direct-connection.service';
|
|
22
18
|
import { SignalsService } from './services/signals.service';
|
|
23
19
|
import { DataRequestTypeEnum, InitSignalPayload } from './types/signal.types';
|
|
24
20
|
import {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
} from './services/webrtc
|
|
21
|
+
WebRTCManager,
|
|
22
|
+
TwinMessagingInterface,
|
|
23
|
+
PhygridDataChannel,
|
|
24
|
+
PhygridMediaStream,
|
|
25
|
+
WebRTCManagerOptions,
|
|
26
|
+
MediaStreamOptions,
|
|
27
|
+
} from './services/webrtc';
|
|
32
28
|
import { TwinRegistry } from './twin-registry';
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
export * from './types';
|
|
36
|
-
|
|
37
|
-
// Define WebRTC types that might not be available in all environments
|
|
38
|
-
declare global {
|
|
39
|
-
// In browsers, these are standard WebRTC interfaces
|
|
40
|
-
// In Node.js, we polyfill them from @roamhq/wrtc
|
|
41
|
-
interface Window {
|
|
42
|
-
RTCVideoSource?: any;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
namespace NodeJS {
|
|
46
|
-
interface Global {
|
|
47
|
-
MediaStream?: any;
|
|
48
|
-
RTCPeerConnection?: any;
|
|
49
|
-
RTCSessionDescription?: any;
|
|
50
|
-
RTCIceCandidate?: any;
|
|
51
|
-
RTCVideoSource?: any;
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
// Make RTCVideoSource available in function scope when used
|
|
56
|
-
var RTCVideoSource: any;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
(async function initializeWebRTCGlobals() {
|
|
60
|
-
// Only run in Node environment
|
|
61
|
-
if (typeof window !== 'undefined') return;
|
|
62
|
-
|
|
63
|
-
try {
|
|
64
|
-
// Dynamically import wrtc
|
|
65
|
-
const wrtc = require('@roamhq/wrtc');
|
|
66
|
-
|
|
67
|
-
// Set all WebRTC globals
|
|
68
|
-
if (typeof global.MediaStream === 'undefined' && wrtc.MediaStream) {
|
|
69
|
-
global.MediaStream = wrtc.MediaStream;
|
|
70
|
-
console.log('Global MediaStream initialized');
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
if (typeof global.RTCPeerConnection === 'undefined' && wrtc.RTCPeerConnection) {
|
|
74
|
-
global.RTCPeerConnection = wrtc.RTCPeerConnection;
|
|
75
|
-
console.log('Global RTCPeerConnection initialized');
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
if (typeof global.RTCSessionDescription === 'undefined' && wrtc.RTCSessionDescription) {
|
|
79
|
-
global.RTCSessionDescription = wrtc.RTCSessionDescription;
|
|
80
|
-
console.log('Global RTCSessionDescription initialized');
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
if (typeof global.RTCIceCandidate === 'undefined' && wrtc.RTCIceCandidate) {
|
|
84
|
-
global.RTCIceCandidate = wrtc.RTCIceCandidate;
|
|
85
|
-
console.log('Global RTCIceCandidate initialized');
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
if (typeof (global as any).RTCVideoSource === 'undefined' && wrtc.nonstandard.RTCVideoSource) {
|
|
89
|
-
(global as any).RTCVideoSource = wrtc.nonstandard.RTCVideoSource;
|
|
90
|
-
console.log('Global RTCVideoSource initialized');
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
console.log('WebRTC globals successfully initialized');
|
|
94
|
-
} catch (error) {
|
|
95
|
-
console.error('Failed to initialize WebRTC globals:', error);
|
|
96
|
-
}
|
|
97
|
-
})().catch(err => console.error('Error in WebRTC globals initialization:', err));
|
|
29
|
+
import { createTwinMessaging } from './twin-messaging';
|
|
98
30
|
|
|
99
31
|
export interface EventPayload<T = any> {
|
|
100
32
|
twinId?: string;
|
|
@@ -122,6 +54,7 @@ export class PhyHubClient {
|
|
|
122
54
|
private instances: Map<string, Instance> = new Map();
|
|
123
55
|
private twinUpdateListeners: { [key: string]: Set<(twin: TwinResponse) => void> } = {};
|
|
124
56
|
private twinInstancesRegistry: TwinRegistry | null = null;
|
|
57
|
+
private webrtcManager: WebRTCManager | null = null;
|
|
125
58
|
|
|
126
59
|
private readonly EVENTS = {
|
|
127
60
|
PING: 'ping',
|
|
@@ -210,6 +143,11 @@ export class PhyHubClient {
|
|
|
210
143
|
}
|
|
211
144
|
);
|
|
212
145
|
|
|
146
|
+
// In direct connection mode, fetch our device twin to get the actual twinId (ObjectId)
|
|
147
|
+
if (PhyHubDirectConnection.isEnabled()) {
|
|
148
|
+
await this.initializeDirectConnectionTwin();
|
|
149
|
+
}
|
|
150
|
+
|
|
213
151
|
return this;
|
|
214
152
|
} catch (err) {
|
|
215
153
|
this.socket = null;
|
|
@@ -267,38 +205,50 @@ export class PhyHubClient {
|
|
|
267
205
|
this.socketConnected = false;
|
|
268
206
|
});
|
|
269
207
|
|
|
270
|
-
this.socket.on(this.EVENTS.TWIN_MESSAGE, (payload: EventPayload, callback
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
208
|
+
this.socket.on(this.EVENTS.TWIN_MESSAGE, (payload: EventPayload, callback?: (response: TwinMessageResult | null) => void) => {
|
|
209
|
+
console.log('[TWIN_MESSAGE] Received:', {
|
|
210
|
+
twinId: payload.twinId,
|
|
211
|
+
sourceTwinId: payload.sourceTwinId,
|
|
212
|
+
dataType: payload.data?.type,
|
|
213
|
+
});
|
|
274
214
|
|
|
275
215
|
let result: TwinMessageResult | null = null;
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
//
|
|
279
|
-
//
|
|
280
|
-
|
|
281
|
-
const
|
|
216
|
+
|
|
217
|
+
if (payload.data) {
|
|
218
|
+
// Try to find listeners by sourceTwinId (messages FROM this twin)
|
|
219
|
+
// This is the correct lookup - we register for a peer's twin ID to receive messages FROM them
|
|
220
|
+
const sourceTwinId = payload.sourceTwinId;
|
|
221
|
+
const targetTwinId = payload.twinId;
|
|
222
|
+
|
|
223
|
+
// First try sourceTwinId (the sender) - this is what onTwinMessage registers for
|
|
224
|
+
let listeners = sourceTwinId ? this.twinMessageListeners[sourceTwinId] : undefined;
|
|
225
|
+
|
|
226
|
+
// Also check targetTwinId for backwards compatibility
|
|
227
|
+
if (!listeners && targetTwinId) {
|
|
228
|
+
listeners = this.twinMessageListeners[targetTwinId];
|
|
229
|
+
}
|
|
230
|
+
|
|
282
231
|
if (listeners?.size) {
|
|
283
|
-
|
|
232
|
+
console.log(`[TWIN_MESSAGE] Executing ${listeners.size} listeners`);
|
|
284
233
|
listeners.forEach(listener => {
|
|
285
|
-
// console.log('Executing listener for twin:', listener);
|
|
286
234
|
try {
|
|
287
235
|
listener(payload);
|
|
288
236
|
result = { status: TwinMessageResultStatus.Success, message: 'Action completed' };
|
|
289
237
|
} catch (error) {
|
|
290
|
-
console.error(`Error in
|
|
238
|
+
console.error(`[TWIN_MESSAGE] Error in listener:`, error);
|
|
291
239
|
result = { status: TwinMessageResultStatus.Error, message: (error as Error)?.message || 'An error occurred' };
|
|
292
240
|
}
|
|
293
241
|
});
|
|
294
242
|
} else {
|
|
295
|
-
|
|
296
|
-
result = { status: TwinMessageResultStatus.Warning, message: `No listeners found
|
|
243
|
+
console.log(`[TWIN_MESSAGE] No listeners found for source=${sourceTwinId} or target=${targetTwinId}`);
|
|
244
|
+
result = { status: TwinMessageResultStatus.Warning, message: `No listeners found` };
|
|
297
245
|
}
|
|
298
246
|
|
|
299
|
-
callback
|
|
247
|
+
if (callback) {
|
|
248
|
+
callback(result);
|
|
249
|
+
}
|
|
300
250
|
} else {
|
|
301
|
-
|
|
251
|
+
console.log('[TWIN_MESSAGE] Invalid payload (no data):', payload);
|
|
302
252
|
}
|
|
303
253
|
});
|
|
304
254
|
|
|
@@ -460,88 +410,109 @@ export class PhyHubClient {
|
|
|
460
410
|
});
|
|
461
411
|
}
|
|
462
412
|
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
channelPrefix: 'channel',
|
|
473
|
-
mediaOptions: { isMediaConnection: false },
|
|
474
|
-
};
|
|
475
|
-
|
|
476
|
-
const result = (await createWebRTCDataChannelConnection(options)) as WebRTCDataChannelResult;
|
|
477
|
-
return result.dataChannel;
|
|
413
|
+
/**
|
|
414
|
+
* Get a DataChannel connection to a target twin.
|
|
415
|
+
* Initiates a WebRTC DataChannel connection for peer-to-peer messaging.
|
|
416
|
+
* @param targetTwinId - The twin ID to connect to
|
|
417
|
+
* @param channelName - Optional channel name for multiple channels to same peer (default: 'default')
|
|
418
|
+
*/
|
|
419
|
+
public getDataChannel = async (targetTwinId: string, channelName?: string): Promise<PhygridDataChannel> => {
|
|
420
|
+
const manager = await this.getWebRTCManager();
|
|
421
|
+
return manager.createDataChannel(targetTwinId, channelName);
|
|
478
422
|
};
|
|
479
423
|
|
|
424
|
+
/**
|
|
425
|
+
* Listen for an incoming DataChannel from a specific twin.
|
|
426
|
+
* Call this when you expect another twin to initiate a connection.
|
|
427
|
+
* @param sourceTwinId - The twin ID that will initiate the connection
|
|
428
|
+
* @param callback - Called when the channel is established
|
|
429
|
+
* @param channelName - Optional channel name for multiple channels (default: 'default')
|
|
430
|
+
*/
|
|
480
431
|
public onDataChannel = async (
|
|
481
432
|
sourceTwinId: string,
|
|
482
|
-
callback: (dc: PhygridDataChannel) => void
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
onTwinMessage: this.onTwinMessage.bind(this),
|
|
489
|
-
offTwinMessage: this.offTwinMessage.bind(this),
|
|
490
|
-
useStun: true,
|
|
491
|
-
isInitiator: false,
|
|
492
|
-
channelPrefix: 'channel',
|
|
493
|
-
mediaOptions: { isMediaConnection: false },
|
|
494
|
-
};
|
|
495
|
-
|
|
496
|
-
const result = (await createWebRTCDataChannelConnection(options)) as WebRTCDataChannelResult;
|
|
497
|
-
callback(result.dataChannel);
|
|
433
|
+
callback: (dc: PhygridDataChannel) => void,
|
|
434
|
+
channelName?: string
|
|
435
|
+
): Promise<void> => {
|
|
436
|
+
const manager = await this.getWebRTCManager();
|
|
437
|
+
const channel = await manager.acceptDataChannel(sourceTwinId, channelName);
|
|
438
|
+
callback(channel);
|
|
498
439
|
};
|
|
499
440
|
|
|
500
|
-
|
|
441
|
+
/**
|
|
442
|
+
* Get a MediaStream connection to a target twin.
|
|
443
|
+
* Initiates a WebRTC MediaStream connection for peer-to-peer media.
|
|
444
|
+
* @param targetTwinId - The twin ID to connect to
|
|
445
|
+
* @param options - Optional MediaStream options (including channelName for multiple streams)
|
|
446
|
+
*/
|
|
447
|
+
public async getMediaStream(
|
|
448
|
+
targetTwinId: string,
|
|
449
|
+
options?: MediaStreamOptions
|
|
450
|
+
): Promise<{
|
|
501
451
|
stream: PhygridMediaStream;
|
|
502
452
|
close: () => void;
|
|
503
453
|
}> {
|
|
504
|
-
const
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
subscribeTwin: this.subscribeTwin.bind(this),
|
|
508
|
-
onTwinMessage: this.onTwinMessage.bind(this),
|
|
509
|
-
offTwinMessage: this.offTwinMessage.bind(this),
|
|
510
|
-
isInitiator: true,
|
|
511
|
-
channelPrefix: 'media',
|
|
512
|
-
mediaOptions: {
|
|
513
|
-
isMediaConnection: true,
|
|
514
|
-
mediaDirection: 'recvonly',
|
|
515
|
-
},
|
|
516
|
-
};
|
|
517
|
-
const result: WebRTCMediaStreamResult = await createWebRTCMediaStreamConnection(options);
|
|
454
|
+
const manager = await this.getWebRTCManager();
|
|
455
|
+
const channelName = options?.channelName ?? 'default';
|
|
456
|
+
const stream = await manager.createMediaStream(targetTwinId, options, channelName);
|
|
518
457
|
return {
|
|
519
|
-
stream
|
|
520
|
-
close:
|
|
458
|
+
stream,
|
|
459
|
+
close: () => stream.close(),
|
|
521
460
|
};
|
|
522
461
|
}
|
|
523
462
|
|
|
463
|
+
/**
|
|
464
|
+
* Listen for an incoming MediaStream from a specific twin.
|
|
465
|
+
* Call this when you expect another twin to initiate a media connection.
|
|
466
|
+
* @param sourceTwinId - The twin ID that will initiate the connection
|
|
467
|
+
* @param callback - Callback when stream is received
|
|
468
|
+
* @param options - Optional MediaStream options (including channelName for multiple streams)
|
|
469
|
+
*/
|
|
524
470
|
public onMediaStream = async (
|
|
525
471
|
sourceTwinId: string,
|
|
526
|
-
callback: (stream: PhygridMediaStream) => void
|
|
472
|
+
callback: (stream: PhygridMediaStream) => void,
|
|
473
|
+
options?: MediaStreamOptions
|
|
527
474
|
): Promise<void> => {
|
|
528
|
-
const
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
onTwinMessage: this.onTwinMessage.bind(this),
|
|
533
|
-
offTwinMessage: this.offTwinMessage.bind(this),
|
|
534
|
-
isInitiator: false,
|
|
535
|
-
channelPrefix: 'media',
|
|
536
|
-
mediaOptions: {
|
|
537
|
-
isMediaConnection: true,
|
|
538
|
-
},
|
|
539
|
-
};
|
|
540
|
-
|
|
541
|
-
const result: WebRTCMediaStreamResult = await createWebRTCMediaStreamConnection(options);
|
|
542
|
-
callback(result.mediaStream);
|
|
475
|
+
const manager = await this.getWebRTCManager();
|
|
476
|
+
const channelName = options?.channelName ?? 'default';
|
|
477
|
+
const stream = await manager.acceptMediaStream(sourceTwinId, options, channelName);
|
|
478
|
+
callback(stream);
|
|
543
479
|
};
|
|
544
480
|
|
|
481
|
+
/**
|
|
482
|
+
* Get the WebRTCManager for advanced control over WebRTC connections.
|
|
483
|
+
* Provides access to events, connection state, and more.
|
|
484
|
+
*/
|
|
485
|
+
public async getWebRTCManager(options?: WebRTCManagerOptions): Promise<WebRTCManager> {
|
|
486
|
+
if (!this.webrtcManager) {
|
|
487
|
+
await this.assureSocketConnection();
|
|
488
|
+
|
|
489
|
+
// Create TwinMessagingInterface adapter
|
|
490
|
+
const twinMessaging: TwinMessagingInterface = {
|
|
491
|
+
sendMessage: async (targetTwinId: string, data: any) => {
|
|
492
|
+
await this.sendTwinMessage(targetTwinId, data);
|
|
493
|
+
},
|
|
494
|
+
subscribe: async (twinId: string) => {
|
|
495
|
+
await this.subscribeTwin(twinId);
|
|
496
|
+
},
|
|
497
|
+
onMessage: (twinId: string, callback: (msg: any) => void) => {
|
|
498
|
+
this.onTwinMessage(twinId, callback);
|
|
499
|
+
},
|
|
500
|
+
offMessage: (twinId: string, callback: (msg: any) => void) => {
|
|
501
|
+
this.offTwinMessage(twinId, callback);
|
|
502
|
+
},
|
|
503
|
+
getOwnTwinId: () => {
|
|
504
|
+
if (!this.instanceId) {
|
|
505
|
+
throw new Error('Instance ID not set');
|
|
506
|
+
}
|
|
507
|
+
return this.instanceId;
|
|
508
|
+
},
|
|
509
|
+
};
|
|
510
|
+
|
|
511
|
+
this.webrtcManager = new WebRTCManager(twinMessaging, options);
|
|
512
|
+
}
|
|
513
|
+
return this.webrtcManager;
|
|
514
|
+
}
|
|
515
|
+
|
|
545
516
|
// TODO properties should automatically be updated when the edge twin is updated
|
|
546
517
|
// We could do a refresh method and call that on reconnect like we handle the resubscribes for peripherals
|
|
547
518
|
public async getInstance(): Promise<Instance> {
|
|
@@ -558,50 +529,14 @@ export class PhyHubClient {
|
|
|
558
529
|
let instance: Instance | undefined;
|
|
559
530
|
|
|
560
531
|
let instanceTwin = await this.getTwinById(this.instanceId);
|
|
561
|
-
// console.log('getTwinById response', instanceTwin);
|
|
562
|
-
|
|
563
|
-
const edgeInstanceTypePrefix = 'edgeInstance';
|
|
564
|
-
|
|
565
|
-
const edgeTwinEmit = (type: string, payload: any) => {
|
|
566
|
-
// console.log('edgeTwinEmit', type, payload);
|
|
567
|
-
const { id: twinId } = instanceTwin;
|
|
568
|
-
const edgeTwinMessagePayload = {
|
|
569
|
-
type: `${edgeInstanceTypePrefix}:${type}`,
|
|
570
|
-
sourceTwinId: twinId,
|
|
571
|
-
sourceDeviceId: instanceTwin.deviceId,
|
|
572
|
-
data: payload,
|
|
573
|
-
};
|
|
574
|
-
// console.log('edgeTwinEmit', edgeTwinMessagePayload);
|
|
575
|
-
this.sendTwinMessage(twinId, edgeTwinMessagePayload);
|
|
576
|
-
};
|
|
577
|
-
|
|
578
|
-
const edgeTwinOn = (type: string, callback: (message: any) => void) => {
|
|
579
|
-
const { id: twinId } = instanceTwin;
|
|
580
|
-
const onEdgeTwinMessage = (payload: any) => {
|
|
581
|
-
// console.log('onEdgeTwinMessage callback', payload);
|
|
582
|
-
const messageType = payload.data?.type || payload.type;
|
|
583
|
-
if (messageType === `${edgeInstanceTypePrefix}:${type}`) {
|
|
584
|
-
// console.log('onEdgeTwinMessage', payload.data?.data || payload.data);
|
|
585
|
-
callback(payload.data?.data || payload.data);
|
|
586
|
-
} else {
|
|
587
|
-
// console.log('onEdgeTwinMessage', 'ignoring', messageType);
|
|
588
|
-
}
|
|
589
|
-
};
|
|
590
|
-
this.onTwinMessage(twinId, onEdgeTwinMessage);
|
|
591
|
-
};
|
|
592
532
|
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
data: payload,
|
|
601
|
-
};
|
|
602
|
-
// console.log('edgeTwinEmit', edgeTwinMessagePayload);
|
|
603
|
-
this.sendTwinMessage(targetTwinId, edgeTwinMessagePayload);
|
|
604
|
-
},
|
|
533
|
+
// Create messaging methods using the shared factory
|
|
534
|
+
const messaging = createTwinMessaging({
|
|
535
|
+
sendEvent: (targetTwinId, payload) => this.sendEvent(targetTwinId, payload),
|
|
536
|
+
onTwinMessage: (twinId, callback) => this.onTwinMessage(twinId, callback),
|
|
537
|
+
twinId: instanceTwin.id,
|
|
538
|
+
deviceId: instanceTwin.deviceId,
|
|
539
|
+
typePrefix: 'edgeInstance',
|
|
605
540
|
});
|
|
606
541
|
|
|
607
542
|
const getPeripheralTwins = async (): Promise<PeripheralTwinResponse[]> => {
|
|
@@ -663,27 +598,26 @@ export class PhyHubClient {
|
|
|
663
598
|
});
|
|
664
599
|
};
|
|
665
600
|
|
|
666
|
-
const getDataChannel = async () => {
|
|
667
|
-
return await this.getDataChannel(instanceTwin.id);
|
|
601
|
+
const getDataChannel = async (channelName?: string) => {
|
|
602
|
+
return await this.getDataChannel(instanceTwin.id, channelName);
|
|
668
603
|
};
|
|
669
604
|
|
|
670
|
-
const onDataChannel = async (callback: (dc: PhygridDataChannel) => void) => {
|
|
671
|
-
return await this.onDataChannel(instanceTwin.id, callback);
|
|
605
|
+
const onDataChannel = async (callback: (dc: PhygridDataChannel) => void, channelName?: string) => {
|
|
606
|
+
return await this.onDataChannel(instanceTwin.id, callback, channelName);
|
|
672
607
|
};
|
|
673
608
|
|
|
674
|
-
const getMediaStream = async () => {
|
|
609
|
+
const getMediaStream = async (channelName?: string) => {
|
|
675
610
|
if (!instance) {
|
|
676
611
|
throw new Error('Instance not initialized');
|
|
677
612
|
}
|
|
678
|
-
return await this.getMediaStream(instance.id);
|
|
613
|
+
return await this.getMediaStream(instance.id, { channelName });
|
|
679
614
|
};
|
|
680
615
|
|
|
681
|
-
const onMediaStream = async (callback: (stream: PhygridMediaStream) => void): Promise<void> => {
|
|
616
|
+
const onMediaStream = async (callback: (stream: PhygridMediaStream) => void, channelName?: string): Promise<void> => {
|
|
682
617
|
if (!instance) {
|
|
683
618
|
throw new Error('Instance not initialized');
|
|
684
619
|
}
|
|
685
|
-
await this.onMediaStream(instance.id, callback);
|
|
686
|
-
// Return void to match the expected return type
|
|
620
|
+
await this.onMediaStream(instance.id, callback, { channelName });
|
|
687
621
|
};
|
|
688
622
|
|
|
689
623
|
const updateReported = async (properties: Record<string, any>) => {
|
|
@@ -697,9 +631,9 @@ export class PhyHubClient {
|
|
|
697
631
|
|
|
698
632
|
instance = {
|
|
699
633
|
...instanceTwin,
|
|
700
|
-
emit:
|
|
701
|
-
on:
|
|
702
|
-
to:
|
|
634
|
+
emit: messaging.emit,
|
|
635
|
+
on: messaging.on,
|
|
636
|
+
to: messaging.to,
|
|
703
637
|
createPeripheralTwin,
|
|
704
638
|
updateReported,
|
|
705
639
|
getPeripheralTwins,
|
|
@@ -746,7 +680,7 @@ export class PhyHubClient {
|
|
|
746
680
|
}
|
|
747
681
|
if (currentWindow.parent === currentWindow) break;
|
|
748
682
|
currentWindow = currentWindow.parent as Window & typeof globalThis;
|
|
749
|
-
} catch
|
|
683
|
+
} catch {
|
|
750
684
|
break;
|
|
751
685
|
}
|
|
752
686
|
}
|
|
@@ -833,11 +767,22 @@ export class PhyHubClient {
|
|
|
833
767
|
return;
|
|
834
768
|
}
|
|
835
769
|
|
|
836
|
-
const event = this.instanceId;
|
|
837
770
|
const callback = typeof args[args.length - 1] === 'function' ? args.pop() : undefined;
|
|
838
|
-
const payload = { method, ...args[0] };
|
|
839
771
|
|
|
840
|
-
|
|
772
|
+
let emitArgs: any[];
|
|
773
|
+
|
|
774
|
+
// In direct connection mode, emit directly to the event name
|
|
775
|
+
// In normal mode, emit to instanceId channel with method in payload (for phyos routing)
|
|
776
|
+
if (PhyHubDirectConnection.isEnabled()) {
|
|
777
|
+
// Direct mode: emit to event name directly
|
|
778
|
+
const payload = args[0] || {};
|
|
779
|
+
emitArgs = [method, payload];
|
|
780
|
+
} else {
|
|
781
|
+
// Normal mode: emit to instanceId channel with method in payload
|
|
782
|
+
const event = this.instanceId;
|
|
783
|
+
const payload = { method, ...args[0] };
|
|
784
|
+
emitArgs = [event, payload];
|
|
785
|
+
}
|
|
841
786
|
|
|
842
787
|
if (callback) {
|
|
843
788
|
emitArgs.push(callback);
|
|
@@ -914,27 +859,63 @@ export class PhyHubClient {
|
|
|
914
859
|
return result;
|
|
915
860
|
}
|
|
916
861
|
|
|
917
|
-
|
|
862
|
+
/**
|
|
863
|
+
* Send a fire-and-forget event to a twin.
|
|
864
|
+
* This is the standard way to send events - no response is expected.
|
|
865
|
+
*/
|
|
866
|
+
public sendEvent(targetTwinId: string, data: any): void {
|
|
867
|
+
// console.log('[sendEvent] Sending to:', targetTwinId, 'data type:', data?.type || 'unknown');
|
|
868
|
+
|
|
869
|
+
// For fire-and-forget, we need to get the instance synchronously if possible
|
|
870
|
+
// or queue the message. We'll use a simpler approach here.
|
|
871
|
+
const instanceId = this.instanceId;
|
|
872
|
+
if (!instanceId) {
|
|
873
|
+
console.error('[sendEvent] Instance ID not set, cannot send event');
|
|
874
|
+
return;
|
|
875
|
+
}
|
|
876
|
+
|
|
877
|
+
// Get deviceId from cached instance if available
|
|
878
|
+
const cachedInstance = this.instances.get(instanceId);
|
|
879
|
+
const deviceId = cachedInstance?.deviceId || this.lastDeviceStatusResponse?.deviceId;
|
|
880
|
+
|
|
881
|
+
if (!deviceId) {
|
|
882
|
+
console.error('[sendEvent] Device ID not available, cannot send event');
|
|
883
|
+
return;
|
|
884
|
+
}
|
|
885
|
+
|
|
886
|
+
const payload: EventPayload = {
|
|
887
|
+
twinId: targetTwinId,
|
|
888
|
+
sourceTwinId: instanceId,
|
|
889
|
+
sourceDeviceId: deviceId,
|
|
890
|
+
data,
|
|
891
|
+
};
|
|
892
|
+
|
|
893
|
+
// Fire-and-forget: just emit, no callback, no promise
|
|
894
|
+
this.emit(this.EVENTS.TWIN_MESSAGE, payload);
|
|
895
|
+
}
|
|
896
|
+
|
|
897
|
+
/**
|
|
898
|
+
* @deprecated Use instance.request() or instance.to(twinId).request() instead.
|
|
899
|
+
* This method uses socket.io acknowledgements which may not work in all scenarios.
|
|
900
|
+
* The instance API uses a more reliable emit/on pattern for request-response.
|
|
901
|
+
*/
|
|
902
|
+
public async request(
|
|
918
903
|
targetTwinId: string,
|
|
919
904
|
data: any,
|
|
920
|
-
callback?: (response:
|
|
921
|
-
)
|
|
922
|
-
|
|
923
|
-
// targetTwinId,
|
|
924
|
-
// data,
|
|
925
|
-
// hasCallback: !!callback
|
|
926
|
-
// });
|
|
905
|
+
callback?: (response: TwinMessageResult) => void
|
|
906
|
+
): Promise<TwinMessageResult | undefined> {
|
|
907
|
+
console.log('[request] Sending to:', targetTwinId, 'data type:', data?.type || 'unknown');
|
|
927
908
|
|
|
928
909
|
const edgeInstance = await this.getInstance();
|
|
929
910
|
if (!edgeInstance) {
|
|
930
|
-
console.error('
|
|
911
|
+
console.error('[request] Edge instance not found');
|
|
931
912
|
throw new Error('Edge instance not found');
|
|
932
913
|
}
|
|
933
914
|
|
|
934
915
|
const { id: edgeTwinId, deviceId } = edgeInstance;
|
|
935
916
|
|
|
936
917
|
if (!deviceId) {
|
|
937
|
-
console.error('
|
|
918
|
+
console.error('[request] Device ID not available');
|
|
938
919
|
throw new Error('Device ID not available - ensure device is connected');
|
|
939
920
|
}
|
|
940
921
|
|
|
@@ -945,48 +926,92 @@ export class PhyHubClient {
|
|
|
945
926
|
data,
|
|
946
927
|
};
|
|
947
928
|
|
|
948
|
-
// console.log('sendTwinMessage prepared payload:', JSON.stringify(payload, null, 2));
|
|
949
|
-
|
|
950
929
|
if (callback) {
|
|
951
|
-
//
|
|
952
|
-
this.emit(this.EVENTS.TWIN_MESSAGE, payload, (response:
|
|
953
|
-
// console.log('sendTwinMessage callback received response:', response);
|
|
930
|
+
// Callback pattern: use socket.io acknowledgement
|
|
931
|
+
this.emit(this.EVENTS.TWIN_MESSAGE, payload, (response: TwinMessageResult) => {
|
|
954
932
|
callback(response);
|
|
955
933
|
});
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
934
|
+
return;
|
|
935
|
+
}
|
|
936
|
+
|
|
937
|
+
// Promise pattern: wait for response with timeout
|
|
938
|
+
return new Promise((resolve, reject) => {
|
|
939
|
+
const ACTION_TIMEOUT = 10 * 1000;
|
|
940
|
+
const timeoutId = setTimeout(() => {
|
|
941
|
+
if (this.socket) {
|
|
942
|
+
this.socket?.off(payload.data.type);
|
|
943
|
+
}
|
|
944
|
+
reject({
|
|
945
|
+
status: TwinMessageResultStatus.Error,
|
|
946
|
+
message: `Request timed out after ${ACTION_TIMEOUT}ms`
|
|
947
|
+
});
|
|
948
|
+
}, ACTION_TIMEOUT);
|
|
959
949
|
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
if (
|
|
950
|
+
if (this.socket) {
|
|
951
|
+
this.socket.on(payload.data.type, (response: TwinMessageResult) => {
|
|
952
|
+
if (response && response.status !== TwinMessageResultStatus.Warning) {
|
|
953
|
+
clearTimeout(timeoutId);
|
|
963
954
|
this.socket?.off(payload.data.type);
|
|
955
|
+
resolve(response);
|
|
964
956
|
}
|
|
957
|
+
});
|
|
958
|
+
}
|
|
965
959
|
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
960
|
+
this.emit(this.EVENTS.TWIN_MESSAGE, payload, (response: TwinMessageResult) => {
|
|
961
|
+
// Socket.io acknowledgement received
|
|
962
|
+
clearTimeout(timeoutId);
|
|
969
963
|
if (this.socket) {
|
|
970
|
-
this.socket
|
|
971
|
-
if (response && response.status !== TwinMessageResultStatus.Warning) {
|
|
972
|
-
// clear timeout on receiving twinMessage result when response status is not warning
|
|
973
|
-
clearTimeout(twinMessageTimeoutId);
|
|
974
|
-
|
|
975
|
-
this.socket?.off(payload.data.type);
|
|
976
|
-
resolve(response);
|
|
977
|
-
}
|
|
978
|
-
});
|
|
964
|
+
this.socket?.off(payload.data.type);
|
|
979
965
|
}
|
|
966
|
+
resolve(response);
|
|
967
|
+
});
|
|
980
968
|
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
969
|
+
this.socket?.on('error', (error: any) => {
|
|
970
|
+
clearTimeout(timeoutId);
|
|
971
|
+
console.error('[request] Socket error:', error);
|
|
972
|
+
reject(error);
|
|
973
|
+
});
|
|
974
|
+
});
|
|
975
|
+
}
|
|
984
976
|
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
977
|
+
/**
|
|
978
|
+
* @deprecated Use sendEvent() for fire-and-forget events, or request() for request-response.
|
|
979
|
+
* This method is kept for backwards compatibility.
|
|
980
|
+
*/
|
|
981
|
+
public async sendTwinMessage(
|
|
982
|
+
targetTwinId: string,
|
|
983
|
+
data: any,
|
|
984
|
+
callback?: (response: any) => void
|
|
985
|
+
): Promise<void> {
|
|
986
|
+
console.log('[sendTwinMessage] Sending to:', targetTwinId, 'data type:', data?.type || 'unknown');
|
|
987
|
+
|
|
988
|
+
const edgeInstance = await this.getInstance();
|
|
989
|
+
if (!edgeInstance) {
|
|
990
|
+
console.error('sendTwinMessage failed: Edge instance not found');
|
|
991
|
+
throw new Error('Edge instance not found');
|
|
992
|
+
}
|
|
993
|
+
|
|
994
|
+
const { id: edgeTwinId, deviceId } = edgeInstance;
|
|
995
|
+
|
|
996
|
+
if (!deviceId) {
|
|
997
|
+
console.error('sendTwinMessage failed: Device ID not available');
|
|
998
|
+
throw new Error('Device ID not available - ensure device is connected');
|
|
999
|
+
}
|
|
1000
|
+
|
|
1001
|
+
const payload: EventPayload = {
|
|
1002
|
+
twinId: targetTwinId,
|
|
1003
|
+
sourceTwinId: edgeTwinId,
|
|
1004
|
+
sourceDeviceId: deviceId,
|
|
1005
|
+
data,
|
|
1006
|
+
};
|
|
1007
|
+
|
|
1008
|
+
if (callback) {
|
|
1009
|
+
this.emit(this.EVENTS.TWIN_MESSAGE, payload, (response: any) => {
|
|
1010
|
+
callback(response);
|
|
989
1011
|
});
|
|
1012
|
+
} else {
|
|
1013
|
+
// Fire-and-forget for backwards compatibility (no timeout/rejection)
|
|
1014
|
+
this.emit(this.EVENTS.TWIN_MESSAGE, payload);
|
|
990
1015
|
}
|
|
991
1016
|
}
|
|
992
1017
|
|
|
@@ -1096,12 +1121,14 @@ export class PhyHubClient {
|
|
|
1096
1121
|
}
|
|
1097
1122
|
|
|
1098
1123
|
public async getTwinById(twinId: string): Promise<TwinResponse> {
|
|
1124
|
+
console.log(`[getTwinById] Fetching twin: ${twinId}`);
|
|
1099
1125
|
const payload: EventPayload<{ twinId: string }> = {
|
|
1100
1126
|
data: { twinId },
|
|
1101
1127
|
};
|
|
1102
1128
|
|
|
1103
1129
|
return new Promise((resolve, reject) => {
|
|
1104
1130
|
this.emit(this.EVENTS.GET_TWIN_BY_ID, payload, (response: any) => {
|
|
1131
|
+
console.log(`[getTwinById] Response for ${twinId}:`, response);
|
|
1105
1132
|
const { twin } = response;
|
|
1106
1133
|
if (!twin) {
|
|
1107
1134
|
reject(new Error(`Twin with id ${twinId} not found`));
|
|
@@ -1111,6 +1138,7 @@ export class PhyHubClient {
|
|
|
1111
1138
|
});
|
|
1112
1139
|
|
|
1113
1140
|
this.socket?.on('error', (error: any) => {
|
|
1141
|
+
console.error(`[getTwinById] Socket error for ${twinId}:`, error);
|
|
1114
1142
|
reject(error);
|
|
1115
1143
|
});
|
|
1116
1144
|
});
|
|
@@ -1162,16 +1190,99 @@ export class PhyHubClient {
|
|
|
1162
1190
|
});
|
|
1163
1191
|
});
|
|
1164
1192
|
}
|
|
1193
|
+
|
|
1194
|
+
/**
|
|
1195
|
+
* Initialize the device twin in direct connection mode.
|
|
1196
|
+
* Waits for deviceAuthenticated, then calls connectDevice to get all twins
|
|
1197
|
+
* for this device, including the device twin which provides the actual twinId.
|
|
1198
|
+
*/
|
|
1199
|
+
private async initializeDirectConnectionTwin(): Promise<void> {
|
|
1200
|
+
console.log('[initializeDirectConnectionTwin] Waiting for authentication...');
|
|
1201
|
+
|
|
1202
|
+
// First wait for deviceAuthenticated event from server
|
|
1203
|
+
await new Promise<void>((resolve, reject) => {
|
|
1204
|
+
const timeout = setTimeout(() => {
|
|
1205
|
+
reject(new Error('Timeout waiting for deviceAuthenticated'));
|
|
1206
|
+
}, 10000);
|
|
1207
|
+
|
|
1208
|
+
this.socket?.once('deviceAuthenticated', (data: any) => {
|
|
1209
|
+
clearTimeout(timeout);
|
|
1210
|
+
console.log('[initializeDirectConnectionTwin] Authenticated:', data);
|
|
1211
|
+
resolve();
|
|
1212
|
+
});
|
|
1213
|
+
});
|
|
1214
|
+
|
|
1215
|
+
console.log('[initializeDirectConnectionTwin] Calling connectDevice...');
|
|
1216
|
+
|
|
1217
|
+
return new Promise((resolve, reject) => {
|
|
1218
|
+
const timeout = setTimeout(() => {
|
|
1219
|
+
reject(new Error('Timeout waiting for connectDevice response'));
|
|
1220
|
+
}, 10000);
|
|
1221
|
+
|
|
1222
|
+
// Use connectDevice to get all twins for this device
|
|
1223
|
+
this.socket?.emit(
|
|
1224
|
+
'connectDevice',
|
|
1225
|
+
(response: any) => {
|
|
1226
|
+
clearTimeout(timeout);
|
|
1227
|
+
console.log('[initializeDirectConnectionTwin] connectDevice response:', JSON.stringify(response, null, 2));
|
|
1228
|
+
|
|
1229
|
+
if (response?.status === 'success' && response?.twins?.length > 0) {
|
|
1230
|
+
// Find the device twin from the array (type is "Device" with capital D)
|
|
1231
|
+
const deviceTwin = response.twins.find((t: any) => t.type === 'Device');
|
|
1232
|
+
|
|
1233
|
+
if (deviceTwin) {
|
|
1234
|
+
const actualTwinId = deviceTwin.id || deviceTwin._id;
|
|
1235
|
+
console.log(
|
|
1236
|
+
`[initializeDirectConnectionTwin] Got device twin. DeviceId: ${deviceTwin.deviceId}, TwinId: ${actualTwinId}`
|
|
1237
|
+
);
|
|
1238
|
+
this.instanceId = actualTwinId;
|
|
1239
|
+
resolve();
|
|
1240
|
+
} else {
|
|
1241
|
+
console.error('[initializeDirectConnectionTwin] No device twin found in twins array');
|
|
1242
|
+
reject(new Error('No device twin found for this device'));
|
|
1243
|
+
}
|
|
1244
|
+
} else if (response?.status === 'error') {
|
|
1245
|
+
const errorMessage = response?.message || 'Unknown error';
|
|
1246
|
+
console.error('[initializeDirectConnectionTwin] connectDevice failed:', errorMessage);
|
|
1247
|
+
|
|
1248
|
+
// Provide more helpful error messages
|
|
1249
|
+
if (errorMessage.includes('Failed to find device twin')) {
|
|
1250
|
+
console.error('\n=== DEVICE TWIN NOT FOUND ===');
|
|
1251
|
+
console.error('This device exists in the legacy database but has not been');
|
|
1252
|
+
console.error('properly migrated to PhyHub. The device twins need to be created.');
|
|
1253
|
+
console.error('');
|
|
1254
|
+
console.error('To fix this:');
|
|
1255
|
+
console.error('1. Reset isMigratedToPhyhub flag in legacy DB, OR');
|
|
1256
|
+
console.error('2. Use a different device that has been properly migrated');
|
|
1257
|
+
console.error('==============================\n');
|
|
1258
|
+
}
|
|
1259
|
+
|
|
1260
|
+
reject(new Error(errorMessage));
|
|
1261
|
+
} else {
|
|
1262
|
+
console.error('[initializeDirectConnectionTwin] Unexpected response:', response);
|
|
1263
|
+
reject(new Error('Failed to connect device'));
|
|
1264
|
+
}
|
|
1265
|
+
}
|
|
1266
|
+
);
|
|
1267
|
+
});
|
|
1268
|
+
}
|
|
1165
1269
|
}
|
|
1166
1270
|
|
|
1167
1271
|
export const connectPhyClient = (
|
|
1168
1272
|
params: { instanceId?: string; moduleName?: string; dataResidency?: string } = {}
|
|
1169
1273
|
) => PhyHubClient.connect(params);
|
|
1170
1274
|
|
|
1171
|
-
export type { EdgeTwinResponse, Instance, PeripheralInstance };
|
|
1275
|
+
export type { EdgeTwinResponse, Instance, PeripheralInstance, IPeripheralTwinInstance, TwinMessageResult };
|
|
1276
|
+
export { TwinMessageResultStatus };
|
|
1172
1277
|
|
|
1173
1278
|
export default {
|
|
1174
1279
|
connectPhyClient,
|
|
1175
1280
|
};
|
|
1176
1281
|
|
|
1177
|
-
export
|
|
1282
|
+
// Re-export WebRTC types for convenience
|
|
1283
|
+
export type { PhygridDataChannel, PhygridMediaStream, WebRTCManagerOptions, MediaStreamOptions };
|
|
1284
|
+
export { WebRTCManager } from './services/webrtc';
|
|
1285
|
+
|
|
1286
|
+
// Re-export twin messaging types for custom implementations
|
|
1287
|
+
export type { TwinMessagingContext, TwinMessagingMethods } from './twin-messaging';
|
|
1288
|
+
export { createTwinMessaging } from './twin-messaging';
|