@phystack/hub-client 4.5.19-dev → 4.5.20-dev

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 (119) hide show
  1. package/dist/index.d.ts +22 -28
  2. package/dist/index.d.ts.map +1 -1
  3. package/dist/index.js +252 -378
  4. package/dist/index.js.map +1 -1
  5. package/dist/peripheral-twin.d.ts +34 -0
  6. package/dist/peripheral-twin.d.ts.map +1 -0
  7. package/dist/peripheral-twin.js +234 -0
  8. package/dist/peripheral-twin.js.map +1 -0
  9. package/dist/services/phyhub-connection.service.d.ts +1 -0
  10. package/dist/services/phyhub-connection.service.d.ts.map +1 -1
  11. package/dist/services/phyhub-connection.service.js +17 -0
  12. package/dist/services/phyhub-connection.service.js.map +1 -1
  13. package/dist/services/phyhub-direct-connection.service.d.ts +21 -0
  14. package/dist/services/phyhub-direct-connection.service.d.ts.map +1 -0
  15. package/dist/services/phyhub-direct-connection.service.js +101 -0
  16. package/dist/services/phyhub-direct-connection.service.js.map +1 -0
  17. package/dist/services/webrtc/data-channel-handler.d.ts +45 -0
  18. package/dist/services/webrtc/data-channel-handler.d.ts.map +1 -0
  19. package/dist/services/webrtc/data-channel-handler.js +260 -0
  20. package/dist/services/webrtc/data-channel-handler.js.map +1 -0
  21. package/dist/services/webrtc/index.d.ts +8 -0
  22. package/dist/services/webrtc/index.d.ts.map +1 -0
  23. package/dist/services/webrtc/index.js +18 -0
  24. package/dist/services/webrtc/index.js.map +1 -0
  25. package/dist/services/webrtc/media-stream-handler.d.ts +57 -0
  26. package/dist/services/webrtc/media-stream-handler.d.ts.map +1 -0
  27. package/dist/services/webrtc/media-stream-handler.js +383 -0
  28. package/dist/services/webrtc/media-stream-handler.js.map +1 -0
  29. package/dist/services/webrtc/peer-connection-manager.d.ts +40 -0
  30. package/dist/services/webrtc/peer-connection-manager.d.ts.map +1 -0
  31. package/dist/services/webrtc/peer-connection-manager.js +336 -0
  32. package/dist/services/webrtc/peer-connection-manager.js.map +1 -0
  33. package/dist/services/webrtc/types.d.ts +134 -0
  34. package/dist/services/webrtc/types.d.ts.map +1 -0
  35. package/dist/services/webrtc/types.js +12 -0
  36. package/dist/services/webrtc/types.js.map +1 -0
  37. package/dist/services/webrtc/webrtc-globals.d.ts +4 -0
  38. package/dist/services/webrtc/webrtc-globals.d.ts.map +1 -0
  39. package/dist/services/webrtc/webrtc-globals.js +72 -0
  40. package/dist/services/webrtc/webrtc-globals.js.map +1 -0
  41. package/dist/services/webrtc/webrtc-manager.d.ts +35 -0
  42. package/dist/services/webrtc/webrtc-manager.d.ts.map +1 -0
  43. package/dist/services/webrtc/webrtc-manager.js +274 -0
  44. package/dist/services/webrtc/webrtc-manager.js.map +1 -0
  45. package/dist/test/communication-comprehensive-test.d.ts +8 -0
  46. package/dist/test/communication-comprehensive-test.d.ts.map +1 -0
  47. package/dist/test/communication-comprehensive-test.js +356 -0
  48. package/dist/test/communication-comprehensive-test.js.map +1 -0
  49. package/dist/test/webrtc-channel-names-test.d.ts +2 -0
  50. package/dist/test/webrtc-channel-names-test.d.ts.map +1 -0
  51. package/dist/test/webrtc-channel-names-test.js +177 -0
  52. package/dist/test/webrtc-channel-names-test.js.map +1 -0
  53. package/dist/test/webrtc-comprehensive-test.d.ts +2 -0
  54. package/dist/test/webrtc-comprehensive-test.d.ts.map +1 -0
  55. package/dist/test/webrtc-comprehensive-test.js +328 -0
  56. package/dist/test/webrtc-comprehensive-test.js.map +1 -0
  57. package/dist/test/webrtc-reconnect-test.d.ts +4 -0
  58. package/dist/test/webrtc-reconnect-test.d.ts.map +1 -0
  59. package/dist/test/webrtc-reconnect-test.js +244 -0
  60. package/dist/test/webrtc-reconnect-test.js.map +1 -0
  61. package/dist/test/webrtc-test-harness.d.ts +4 -0
  62. package/dist/test/webrtc-test-harness.d.ts.map +1 -0
  63. package/dist/test/webrtc-test-harness.js +169 -0
  64. package/dist/test/webrtc-test-harness.js.map +1 -0
  65. package/dist/twin-messaging.d.ts +20 -0
  66. package/dist/twin-messaging.d.ts.map +1 -0
  67. package/dist/twin-messaging.js +94 -0
  68. package/dist/twin-messaging.js.map +1 -0
  69. package/dist/twin-registry.d.ts +9 -0
  70. package/dist/twin-registry.d.ts.map +1 -0
  71. package/dist/twin-registry.js +26 -0
  72. package/dist/twin-registry.js.map +1 -0
  73. package/dist/types/index.d.ts +4 -0
  74. package/dist/types/index.d.ts.map +1 -0
  75. package/dist/types/index.js +20 -0
  76. package/dist/types/index.js.map +1 -0
  77. package/dist/types/twin.types.d.ts +62 -14
  78. package/dist/types/twin.types.d.ts.map +1 -1
  79. package/dist/types/twin.types.js +8 -1
  80. package/dist/types/twin.types.js.map +1 -1
  81. package/docs/webrtc-howto.md +398 -0
  82. package/docs/webrtc-test.md +330 -0
  83. package/package.json +3 -3
  84. package/scripts/webrtc-test.sh +401 -0
  85. package/src/index.ts +378 -568
  86. package/src/peripheral-twin.ts +337 -0
  87. package/src/services/phyhub-connection.service.ts +24 -0
  88. package/src/services/phyhub-direct-connection.service.ts +159 -0
  89. package/src/services/webrtc/data-channel-handler.ts +362 -0
  90. package/src/services/webrtc/index.ts +36 -0
  91. package/src/services/webrtc/media-stream-handler.ts +536 -0
  92. package/src/services/webrtc/peer-connection-manager.ts +467 -0
  93. package/src/services/webrtc/types.ts +273 -0
  94. package/src/services/webrtc/webrtc-globals.ts +108 -0
  95. package/src/services/webrtc/webrtc-manager.ts +490 -0
  96. package/src/test/communication-comprehensive-test.ts +533 -0
  97. package/src/test/webrtc-channel-names-test.ts +266 -0
  98. package/src/test/webrtc-comprehensive-test.ts +494 -0
  99. package/src/test/webrtc-reconnect-test.ts +345 -0
  100. package/src/test/webrtc-test-harness.ts +254 -0
  101. package/src/twin-messaging.ts +184 -0
  102. package/src/twin-registry.ts +39 -0
  103. package/src/types/index.ts +3 -0
  104. package/src/types/twin.types.ts +80 -14
  105. package/dist/services/webrtc/datachannel.d.ts +0 -10
  106. package/dist/services/webrtc/datachannel.d.ts.map +0 -1
  107. package/dist/services/webrtc/datachannel.js +0 -290
  108. package/dist/services/webrtc/datachannel.js.map +0 -1
  109. package/dist/services/webrtc/mediastream.d.ts +0 -10
  110. package/dist/services/webrtc/mediastream.d.ts.map +0 -1
  111. package/dist/services/webrtc/mediastream.js +0 -396
  112. package/dist/services/webrtc/mediastream.js.map +0 -1
  113. package/dist/services/webrtc/peer-connection-ice.d.ts +0 -32
  114. package/dist/services/webrtc/peer-connection-ice.d.ts.map +0 -1
  115. package/dist/services/webrtc/peer-connection-ice.js +0 -483
  116. package/dist/services/webrtc/peer-connection-ice.js.map +0 -1
  117. package/src/services/webrtc/datachannel.ts +0 -421
  118. package/src/services/webrtc/mediastream.ts +0 -602
  119. package/src/services/webrtc/peer-connection-ice.ts +0 -689
@@ -0,0 +1,273 @@
1
+ /**
2
+ * WebRTC Type Definitions
3
+ *
4
+ * Contains all types for the WebRTC Manager system.
5
+ */
6
+
7
+ // =============================================================================
8
+ // Twin Messaging Interface (dependency injection)
9
+ // =============================================================================
10
+
11
+ /**
12
+ * Interface for twin messaging that the WebRTC system depends on.
13
+ * This allows the WebRTC system to be decoupled from PhyHubClient.
14
+ */
15
+ export interface TwinMessagingInterface {
16
+ /** Send a message to a specific twin */
17
+ sendMessage(targetTwinId: string, data: any): Promise<void>;
18
+
19
+ /** Subscribe to receive messages from a twin */
20
+ subscribe(twinId: string): Promise<void>;
21
+
22
+ /** Register a callback for messages from a twin */
23
+ onMessage(twinId: string, callback: (msg: any) => void): void;
24
+
25
+ /** Unregister a callback for messages from a twin */
26
+ offMessage(twinId: string, callback: (msg: any) => void): void;
27
+
28
+ /** Get the ID of the local twin */
29
+ getOwnTwinId(): string;
30
+ }
31
+
32
+ // =============================================================================
33
+ // WebRTC Manager Options
34
+ // =============================================================================
35
+
36
+ export interface WebRTCManagerOptions {
37
+ /** Enable verbose logging and additional events. Default: false */
38
+ verbose?: boolean;
39
+
40
+ /** Use STUN servers for NAT traversal. Default: true */
41
+ useStun?: boolean;
42
+
43
+ /** STUN server URLs. Default: Google's public STUN servers */
44
+ stunServers?: string[];
45
+
46
+ /** Connection timeout in milliseconds. Default: 15000 */
47
+ connectionTimeout?: number;
48
+
49
+ /** Initial retry delay in milliseconds. Default: 1000 */
50
+ initialRetryDelay?: number;
51
+
52
+ /** Maximum retry delay in milliseconds. Default: 30000 */
53
+ maxRetryDelay?: number;
54
+ }
55
+
56
+ export const DEFAULT_WEBRTC_OPTIONS: Required<WebRTCManagerOptions> = {
57
+ verbose: false,
58
+ useStun: true,
59
+ stunServers: ['stun:stun.l.google.com:19302', 'stun:stun1.l.google.com:19302'],
60
+ connectionTimeout: 15000,
61
+ initialRetryDelay: 1000,
62
+ maxRetryDelay: 30000,
63
+ };
64
+
65
+ // =============================================================================
66
+ // Event Types
67
+ // =============================================================================
68
+
69
+ /** Standard events (always available) */
70
+ export type WebRTCStandardEvent = 'connected' | 'disconnected' | 'error';
71
+
72
+ /** Verbose events (opt-in via options.verbose) */
73
+ export type WebRTCVerboseEvent =
74
+ | 'reconnecting'
75
+ | 'reconnected'
76
+ | 'ice-state-change'
77
+ | 'signaling-state-change'
78
+ | 'ice-candidate';
79
+
80
+ export type WebRTCEvent = WebRTCStandardEvent | WebRTCVerboseEvent;
81
+
82
+ export interface WebRTCEventData {
83
+ connected: { targetTwinId: string; connectionType: 'datachannel' | 'mediastream' };
84
+ disconnected: { targetTwinId: string; connectionType: 'datachannel' | 'mediastream' };
85
+ error: { targetTwinId?: string; error: Error };
86
+ reconnecting: { targetTwinId: string; attempt: number };
87
+ reconnected: { targetTwinId: string; attempt: number };
88
+ 'ice-state-change': { targetTwinId: string; state: RTCIceConnectionState };
89
+ 'signaling-state-change': { targetTwinId: string; state: RTCSignalingState };
90
+ 'ice-candidate': { targetTwinId: string; candidate: RTCIceCandidate | null };
91
+ }
92
+
93
+ export type WebRTCEventCallback<E extends WebRTCEvent = WebRTCEvent> = (
94
+ data: WebRTCEventData[E]
95
+ ) => void;
96
+
97
+ // =============================================================================
98
+ // DataChannel Types
99
+ // =============================================================================
100
+
101
+ /**
102
+ * Abstraction over RTCDataChannel that provides:
103
+ * - Automatic reconnection handling
104
+ * - Message buffering during reconnection
105
+ * - Simplified event API
106
+ */
107
+ export interface PhygridDataChannel {
108
+ /** Send data through the channel. Accepts string, ArrayBuffer, or objects (auto-serialized to JSON) */
109
+ send(data: string | ArrayBuffer | object): void;
110
+
111
+ /** Register a callback for incoming messages */
112
+ onMessage(callback: (data: any) => void): void;
113
+
114
+ /** Unregister a message callback */
115
+ offMessage(callback: (data: any) => void): void;
116
+
117
+ /** Register a callback for channel close */
118
+ onClose(callback: () => void): void;
119
+
120
+ /** Unregister a close callback */
121
+ offClose(callback: () => void): void;
122
+
123
+ /** Close the data channel */
124
+ close(): void;
125
+
126
+ /** Check if the channel is currently open */
127
+ isOpen(): boolean;
128
+
129
+ /** Check if the channel is currently connecting/reconnecting */
130
+ isConnecting(): boolean;
131
+
132
+ /** Get the target twin ID this channel is connected to */
133
+ getTargetTwinId(): string;
134
+
135
+ /** Get the channel name (for multiple channels to same peer) */
136
+ getChannelName(): string;
137
+ }
138
+
139
+ // =============================================================================
140
+ // MediaStream Types
141
+ // =============================================================================
142
+
143
+ /**
144
+ * Extended MediaStreamTrack with optional frame callback (Node.js @roamhq/wrtc)
145
+ */
146
+ export interface ExtendedMediaStreamTrack extends MediaStreamTrack {
147
+ onFrame?: (frame: any) => void;
148
+ }
149
+
150
+ export interface MediaStreamOptions {
151
+ /** Direction for media. Default: 'recvonly' for initiator */
152
+ direction?: RTCRtpTransceiverDirection;
153
+
154
+ /** Local stream to send (for sendrecv or sendonly) */
155
+ localStream?: MediaStream;
156
+
157
+ /** Optional channel name for multiple streams to same peer (default: 'default') */
158
+ channelName?: string;
159
+ }
160
+
161
+ /**
162
+ * Abstraction over MediaStream that provides:
163
+ * - Automatic reconnection handling
164
+ * - Track lifecycle management
165
+ * - Frame activity monitoring
166
+ */
167
+ export interface PhygridMediaStream {
168
+ /** Get all current tracks */
169
+ getTracks(): MediaStreamTrack[];
170
+
171
+ /** Get the underlying MediaStream object (for use as video srcObject) */
172
+ getStream(): MediaStream | null;
173
+
174
+ /** Add a track to send to the remote peer */
175
+ addTrack(track: MediaStreamTrack): void;
176
+
177
+ /** Register a callback for when a track is received */
178
+ onTrack(callback: (track: MediaStreamTrack) => void): void;
179
+
180
+ /** Unregister a track callback */
181
+ offTrack(callback: (track: MediaStreamTrack) => void): void;
182
+
183
+ /** Register a callback for frame data (if available, Node.js only) */
184
+ onFrame(callback: (frameData: any) => void): void;
185
+
186
+ /** Unregister a frame callback */
187
+ offFrame(callback: (frameData: any) => void): void;
188
+
189
+ /** Register a callback for stream close */
190
+ onClose(callback: () => void): void;
191
+
192
+ /** Unregister a close callback */
193
+ offClose(callback: () => void): void;
194
+
195
+ /** Close the media stream */
196
+ close(): void;
197
+
198
+ /** Check if the stream is currently receiving frames */
199
+ isReceivingFrames(): boolean;
200
+
201
+ /** Check if the stream is currently connecting or reconnecting */
202
+ isConnecting(): boolean;
203
+
204
+ /** Get the target twin ID this stream is connected to */
205
+ getTargetTwinId(): string;
206
+
207
+ /** Get the channel name (for multiple streams to same peer) */
208
+ getChannelName(): string;
209
+ }
210
+
211
+ // =============================================================================
212
+ // Connection State Types
213
+ // =============================================================================
214
+
215
+ export type ConnectionType = 'datachannel' | 'mediastream';
216
+
217
+ export interface ConnectionState {
218
+ targetTwinId: string;
219
+ connectionType: ConnectionType;
220
+ isInitiator: boolean;
221
+ pc: RTCPeerConnection | null;
222
+ isConnected: boolean;
223
+ isReconnecting: boolean;
224
+ reconnectAttempts: number;
225
+ }
226
+
227
+ // =============================================================================
228
+ // Signaling Message Types
229
+ // =============================================================================
230
+
231
+ export type SignalingMessageType = 'offer' | 'answer' | 'ice';
232
+
233
+ export interface SignalingMessage {
234
+ type: string; // Format: {channelPrefix}-{targetTwinId}:{messageType}
235
+ data: RTCSessionDescriptionInit | RTCIceCandidateInit;
236
+ }
237
+
238
+ // =============================================================================
239
+ // Internal Types (for handler classes)
240
+ // =============================================================================
241
+
242
+ export interface PeerConnectionConfig {
243
+ targetTwinId: string;
244
+ isInitiator: boolean;
245
+ connectionType: ConnectionType;
246
+ channelPrefix: string;
247
+ useStun: boolean;
248
+ stunServers: string[];
249
+ onConnected: () => void;
250
+ onDisconnected: () => void;
251
+ onError: (error: Error) => void;
252
+ onReconnecting?: (attempt: number) => void;
253
+ onReconnected?: (attempt: number) => void;
254
+ onIceStateChange?: (state: RTCIceConnectionState) => void;
255
+ onSignalingStateChange?: (state: RTCSignalingState) => void;
256
+ onIceCandidate?: (candidate: RTCIceCandidate | null) => void;
257
+ // Called after peer connection is created but before offer is sent
258
+ // Use this to add data channels or media tracks that should be in the offer
259
+ onPeerConnectionCreated?: (pc: RTCPeerConnection) => void | Promise<void>;
260
+ }
261
+
262
+ export interface DataChannelConfig extends PeerConnectionConfig {
263
+ onMessage: (data: any) => void;
264
+ onOpen: () => void;
265
+ onClose: () => void;
266
+ }
267
+
268
+ export interface MediaStreamConfig extends PeerConnectionConfig {
269
+ direction: RTCRtpTransceiverDirection;
270
+ localStream?: MediaStream;
271
+ onTrack: (track: MediaStreamTrack) => void;
272
+ onFrameInactive?: () => void;
273
+ }
@@ -0,0 +1,108 @@
1
+ /**
2
+ * WebRTC Globals Initialization
3
+ *
4
+ * Single initialization point for WebRTC globals.
5
+ * Handles both browser and Node.js environments.
6
+ */
7
+
8
+ // Track initialization state
9
+ let isInitialized = false;
10
+ let initializationPromise: Promise<void> | null = null;
11
+
12
+ /**
13
+ * Ensures WebRTC globals are available in the current environment.
14
+ * In browsers, these are already available globally.
15
+ * In Node.js, we polyfill them from @roamhq/wrtc.
16
+ *
17
+ * This function is idempotent - safe to call multiple times.
18
+ */
19
+ export async function ensureWebRTCGlobals(): Promise<void> {
20
+ // Already initialized
21
+ if (isInitialized) {
22
+ return;
23
+ }
24
+
25
+ // Initialization in progress - wait for it
26
+ if (initializationPromise) {
27
+ return initializationPromise;
28
+ }
29
+
30
+ initializationPromise = doInitialize();
31
+ await initializationPromise;
32
+ }
33
+
34
+ async function doInitialize(): Promise<void> {
35
+ // Browser environment - WebRTC is already available
36
+ if (typeof window !== 'undefined') {
37
+ if (typeof RTCPeerConnection === 'undefined') {
38
+ throw new Error('WebRTC is not supported in this browser');
39
+ }
40
+ isInitialized = true;
41
+ return;
42
+ }
43
+
44
+ // Node.js environment - need to polyfill
45
+ try {
46
+ const wrtc = require('@roamhq/wrtc');
47
+
48
+ if (typeof global.MediaStream === 'undefined' && wrtc.MediaStream) {
49
+ global.MediaStream = wrtc.MediaStream;
50
+ }
51
+
52
+ if (typeof (global as any).RTCDataChannel === 'undefined' && wrtc.RTCDataChannel) {
53
+ (global as any).RTCDataChannel = wrtc.RTCDataChannel;
54
+ }
55
+
56
+ if (typeof global.RTCPeerConnection === 'undefined' && wrtc.RTCPeerConnection) {
57
+ global.RTCPeerConnection = wrtc.RTCPeerConnection;
58
+ }
59
+
60
+ if (typeof global.RTCSessionDescription === 'undefined' && wrtc.RTCSessionDescription) {
61
+ global.RTCSessionDescription = wrtc.RTCSessionDescription;
62
+ }
63
+
64
+ if (typeof global.RTCIceCandidate === 'undefined' && wrtc.RTCIceCandidate) {
65
+ global.RTCIceCandidate = wrtc.RTCIceCandidate;
66
+ }
67
+
68
+ if (typeof (global as any).RTCVideoSource === 'undefined' && wrtc.nonstandard?.RTCVideoSource) {
69
+ (global as any).RTCVideoSource = wrtc.nonstandard.RTCVideoSource;
70
+ }
71
+
72
+ isInitialized = true;
73
+ } catch (error) {
74
+ throw new Error(
75
+ `Failed to initialize WebRTC in Node.js environment. ` +
76
+ `Ensure @roamhq/wrtc is installed: ${error}`
77
+ );
78
+ }
79
+ }
80
+
81
+ /**
82
+ * Check if WebRTC globals have been initialized.
83
+ */
84
+ export function isWebRTCInitialized(): boolean {
85
+ return isInitialized;
86
+ }
87
+
88
+ /**
89
+ * Check if WebRTC is available in the current environment.
90
+ * Does not initialize - just checks availability.
91
+ */
92
+ export function isWebRTCAvailable(): boolean {
93
+ if (typeof window !== 'undefined') {
94
+ return typeof RTCPeerConnection !== 'undefined';
95
+ }
96
+
97
+ // In Node.js, check if already initialized or if wrtc is available
98
+ if (isInitialized) {
99
+ return true;
100
+ }
101
+
102
+ try {
103
+ require.resolve('@roamhq/wrtc');
104
+ return true;
105
+ } catch {
106
+ return false;
107
+ }
108
+ }