@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.
Files changed (108) hide show
  1. package/dist/index.d.ts +18 -25
  2. package/dist/index.d.ts.map +1 -1
  3. package/dist/index.js +252 -188
  4. package/dist/index.js.map +1 -1
  5. package/dist/peripheral-twin.d.ts +10 -9
  6. package/dist/peripheral-twin.d.ts.map +1 -1
  7. package/dist/peripheral-twin.js +24 -54
  8. package/dist/peripheral-twin.js.map +1 -1
  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 +367 -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 +335 -0
  32. package/dist/services/webrtc/peer-connection-manager.js.map +1 -0
  33. package/dist/services/webrtc/types.d.ts +133 -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 +23 -0
  66. package/dist/twin-messaging.d.ts.map +1 -0
  67. package/dist/twin-messaging.js +96 -0
  68. package/dist/twin-messaging.js.map +1 -0
  69. package/dist/types/twin.types.d.ts +36 -20
  70. package/dist/types/twin.types.d.ts.map +1 -1
  71. package/dist/types/twin.types.js.map +1 -1
  72. package/docs/webrtc-howto.md +398 -0
  73. package/docs/webrtc-test.md +330 -0
  74. package/package.json +3 -3
  75. package/scripts/webrtc-test.sh +401 -0
  76. package/src/index.ts +370 -259
  77. package/src/peripheral-twin.ts +44 -67
  78. package/src/services/phyhub-connection.service.ts +24 -0
  79. package/src/services/phyhub-direct-connection.service.ts +159 -0
  80. package/src/services/webrtc/data-channel-handler.ts +362 -0
  81. package/src/services/webrtc/index.ts +36 -0
  82. package/src/services/webrtc/media-stream-handler.ts +515 -0
  83. package/src/services/webrtc/peer-connection-manager.ts +463 -0
  84. package/src/services/webrtc/types.ts +270 -0
  85. package/src/services/webrtc/webrtc-globals.ts +108 -0
  86. package/src/services/webrtc/webrtc-manager.ts +490 -0
  87. package/src/test/communication-comprehensive-test.ts +533 -0
  88. package/src/test/webrtc-channel-names-test.ts +266 -0
  89. package/src/test/webrtc-comprehensive-test.ts +494 -0
  90. package/src/test/webrtc-reconnect-test.ts +345 -0
  91. package/src/test/webrtc-test-harness.ts +254 -0
  92. package/src/twin-messaging.ts +193 -0
  93. package/src/types/twin.types.ts +59 -20
  94. package/dist/services/webrtc/datachannel.d.ts +0 -10
  95. package/dist/services/webrtc/datachannel.d.ts.map +0 -1
  96. package/dist/services/webrtc/datachannel.js +0 -290
  97. package/dist/services/webrtc/datachannel.js.map +0 -1
  98. package/dist/services/webrtc/mediastream.d.ts +0 -10
  99. package/dist/services/webrtc/mediastream.d.ts.map +0 -1
  100. package/dist/services/webrtc/mediastream.js +0 -396
  101. package/dist/services/webrtc/mediastream.js.map +0 -1
  102. package/dist/services/webrtc/peer-connection-ice.d.ts +0 -32
  103. package/dist/services/webrtc/peer-connection-ice.d.ts.map +0 -1
  104. package/dist/services/webrtc/peer-connection-ice.js +0 -483
  105. package/dist/services/webrtc/peer-connection-ice.js.map +0 -1
  106. package/src/services/webrtc/datachannel.ts +0 -421
  107. package/src/services/webrtc/mediastream.ts +0 -602
  108. package/src/services/webrtc/peer-connection-ice.ts +0 -689
@@ -1,5 +1,6 @@
1
1
  import { EventPayload, PhygridDataChannel, PhygridMediaStream, PhyHubClient } from ".";
2
- import { Instance, TwinResponse, TwinTypeEnum } from "./types/twin.types";
2
+ import { Instance, TwinMessageResult, TwinResponse, TwinTypeEnum } from "./types/twin.types";
3
+ import { createTwinMessaging, TwinMessagingMethods } from "./twin-messaging";
3
4
 
4
5
  export class PeripheralTwinInstance {
5
6
  public phyHubClient: PhyHubClient;
@@ -7,7 +8,7 @@ export class PeripheralTwinInstance {
7
8
  public edgeInstance: Instance | null = null;
8
9
  public peripheralTwinResponse: TwinResponse | null = null;
9
10
 
10
- private instanceTypePrefix = 'peripheralInstance';
11
+ private messaging: TwinMessagingMethods | null = null;
11
12
 
12
13
  constructor(phyHubClient: PhyHubClient, twinId: string) {
13
14
  this.phyHubClient = phyHubClient;
@@ -36,82 +37,58 @@ export class PeripheralTwinInstance {
36
37
 
37
38
  this.peripheralTwinResponse = peripheralTwinResponse;
38
39
 
39
- await this.phyHubClient.subscribeTwin(this.twinId);
40
- }
40
+ // Create messaging methods using the shared factory
41
+ this.messaging = createTwinMessaging({
42
+ sendEvent: (targetTwinId, payload) => this.phyHubClient.sendEvent(targetTwinId, payload),
43
+ onTwinMessage: (twinId, callback) => this.phyHubClient.onTwinMessage(twinId, callback),
44
+ twinId: peripheralTwinResponse.id,
45
+ deviceId: edgeInstance.deviceId,
46
+ typePrefix: `peripheralInstance:${peripheralTwinResponse.id}`,
47
+ });
41
48
 
42
- // alias to sendEvent()
43
- async emit(eventType: string, payload: any) {
44
- return await this.sendEvent(eventType, payload);
49
+ await this.phyHubClient.subscribeTwin(this.twinId);
45
50
  }
46
51
 
47
- async sendEvent(eventType: string, payload: any) {
48
- return await this.peripheralTwinEmit(eventType, payload);
52
+ private ensureInitialized(): void {
53
+ if (!this.messaging) {
54
+ throw new Error('[PeripheralTwinInstance] Not initialized. Call initialize() first.');
55
+ }
49
56
  }
50
57
 
51
- private async peripheralTwinEmit(eventType: string, payload: any) {
52
- if (!this.edgeInstance || !this.peripheralTwinResponse) {
53
- throw new Error('Object is not initialized correctly');
58
+ /**
59
+ * Send a message to the twin.
60
+ * - Without callback: Fire-and-forget (returns void)
61
+ * - With callback: Request-response pattern (returns Promise)
62
+ */
63
+ emit(eventType: string, payload: any): void;
64
+ emit(eventType: string, payload: any, callback: (response: TwinMessageResult) => void): Promise<TwinMessageResult>;
65
+ emit(
66
+ eventType: string,
67
+ payload: any,
68
+ callback?: (response: TwinMessageResult) => void
69
+ ): void | Promise<TwinMessageResult> {
70
+ this.ensureInitialized();
71
+ if (callback) {
72
+ return this.messaging!.emit(eventType, payload, callback);
73
+ } else {
74
+ this.messaging!.emit(eventType, payload);
54
75
  }
55
-
56
- const messagePayload = {
57
- type: `${this.instanceTypePrefix}:${this.peripheralTwinResponse.id}:${eventType}`,
58
- sourceTwinId: this.peripheralTwinResponse.id,
59
- sourceDeviceId: this.edgeInstance.deviceId,
60
- data: payload,
61
- };
62
-
63
- const result = await this.phyHubClient.sendTwinMessage(this.peripheralTwinResponse.id, messagePayload);
64
- return result;
65
- };
66
-
67
- // alias to onEvent()
68
- on(eventType: string, callback: (message: any) => void) {
69
- return this.onEvent(eventType, callback);
70
76
  }
71
77
 
72
- onEvent(eventType: string, callback: (message: any) => void) {
73
- return this.peripheralTwinOn(eventType, callback);
78
+ /**
79
+ * Listen for events, with optional respond callback for request-response
80
+ */
81
+ on(
82
+ eventType: string,
83
+ callback: (message: any, respond?: (result: TwinMessageResult) => void) => void
84
+ ) {
85
+ this.ensureInitialized();
86
+ this.messaging!.on(eventType, callback);
74
87
  }
75
88
 
76
- private peripheralTwinOn(eventType: string, callback: (message: any) => void) {
77
- console.log(`Setting up listener for peripheral ${this.twinId} event: ${eventType}`);
78
-
79
- if (!this.peripheralTwinResponse) {
80
- console.error('Object is not initialized correctly');
81
- return;
82
- }
83
-
84
- const onMessage = (payload: any) => {
85
- // console.log(`Received message for peripheral ${peripheralTwinId}:`, payload);
86
- const messageType = payload.data?.type || payload.type;
87
- if (messageType === `${this.instanceTypePrefix}:${this.peripheralTwinResponse!.id}:${eventType}`) {
88
- // console.log('Processing matching message type');
89
- callback(payload.data?.data || payload.data);
90
- } else {
91
- // console.log('Ignoring non-matching message type:', messageType);
92
- }
93
- };
94
-
95
- this.phyHubClient.onTwinMessage(this.peripheralTwinResponse.id, onMessage);
96
- };
97
-
98
89
  to(targetTwinId: string) {
99
- return {
100
- emit: async (eventType: string, payload: any) => {
101
- if (!this.edgeInstance || !this.peripheralTwinResponse) {
102
- throw new Error('Object is not initialized correctly');
103
- }
104
-
105
- const messagePayload = {
106
- type: `${this.instanceTypePrefix}:${this.peripheralTwinResponse.id}:${eventType}`,
107
- sourceTwinId: this.edgeInstance.id,
108
- sourceDeviceId: this.edgeInstance.deviceId,
109
- data: payload,
110
- };
111
-
112
- return await this.phyHubClient.sendTwinMessage(targetTwinId, messagePayload);
113
- }
114
- }
90
+ this.ensureInitialized();
91
+ return this.messaging!.to(targetTwinId);
115
92
  }
116
93
 
117
94
  async getDataChannel() {
@@ -2,6 +2,8 @@ import { Socket } from 'socket.io-client';
2
2
  import { get } from 'lodash';
3
3
  import { isBrowser } from '../helpers/browser.helper';
4
4
  import { getSocketIOWithProxy } from '@phystack/socket.io-proxy';
5
+ import { PhyHubDirectConnection } from './phyhub-direct-connection.service';
6
+
5
7
  interface UrlConfig {
6
8
  url: string;
7
9
  timeout: number;
@@ -14,12 +16,26 @@ export class PhyHubConnection {
14
16
  private socketUrls: UrlConfig[] = [];
15
17
  private instanceId: string | undefined;
16
18
  private moduleName: string | undefined;
19
+ private directConnection: PhyHubDirectConnection | null = null;
17
20
 
18
21
  private constructor(
19
22
  params: { instanceId?: string; moduleName?: string; dataResidency?: string } = {}
20
23
  ) {
21
24
  this.instanceId = params.instanceId;
22
25
  this.moduleName = params.moduleName;
26
+
27
+ // Check for direct connection mode (for testing)
28
+ if (PhyHubDirectConnection.isEnabled()) {
29
+ this.directConnection = PhyHubDirectConnection.fromEnv();
30
+ if (this.directConnection) {
31
+ console.log('[PhyHubConnection] Direct connection mode enabled');
32
+ // Use device ID as instance ID if not provided
33
+ if (!this.instanceId) {
34
+ this.instanceId = this.directConnection.getInstanceId();
35
+ }
36
+ }
37
+ }
38
+
23
39
  this.setSocketUrls(params.dataResidency);
24
40
  this.fetchPhygridSocketInstance();
25
41
  }
@@ -137,6 +153,14 @@ export class PhyHubConnection {
137
153
  public async getPhyHubSocket(): Promise<Socket> {
138
154
  console.info(`getPhyHubSocket(): Getting phyhub socket`);
139
155
 
156
+ // Use direct connection if enabled (for testing)
157
+ if (this.directConnection) {
158
+ console.log('[PhyHubConnection] Using direct connection');
159
+ const socket = await this.directConnection.connect();
160
+ this.phygridSocketSingleton = socket;
161
+ return socket;
162
+ }
163
+
140
164
  // Always check top window first
141
165
  if (isBrowser) {
142
166
  const topWindow = this.getTopWindow();
@@ -0,0 +1,159 @@
1
+ /**
2
+ * PhyHub Direct Connection Service
3
+ *
4
+ * Allows direct connection to PhyHub for testing purposes,
5
+ * bypassing the phyos layer that normally runs on devices.
6
+ *
7
+ * Usage:
8
+ * - Set PHYHUB_DIRECT=true to enable direct connection
9
+ * - Provide DEVICE_ID and ACCESS_KEY environment variables
10
+ * - Optionally set PHYHUB_URL (defaults to EU region)
11
+ */
12
+
13
+ import { Socket } from 'socket.io-client';
14
+ import { getSocketIOWithProxy } from '@phystack/socket.io-proxy';
15
+
16
+ export interface DirectConnectionConfig {
17
+ deviceId: string;
18
+ accessKey: string;
19
+ phyhubUrl?: string;
20
+ instanceId?: string; // Optional: override the twin ID to use
21
+ }
22
+
23
+ const DEFAULT_PHYHUB_URLS: Record<string, string> = {
24
+ eu: 'https://phyhub.eu.omborigrid.net',
25
+ us: 'https://phyhub.us.omborigrid.net',
26
+ uae: 'https://phyhub.uae.omborigrid.net',
27
+ au: 'https://phyhub.au.omborigrid.net',
28
+ in: 'https://phyhub.in.omborigrid.net',
29
+ qa: 'https://phyhub.qa.omborigrid.net',
30
+ dev: 'https://phyhub.dev.omborigrid.net',
31
+ local: 'http://localhost:3000',
32
+ };
33
+
34
+ export class PhyHubDirectConnection {
35
+ private socket: Socket | null = null;
36
+ private config: DirectConnectionConfig;
37
+
38
+ constructor(config: DirectConnectionConfig) {
39
+ this.config = {
40
+ ...config,
41
+ phyhubUrl: config.phyhubUrl || DEFAULT_PHYHUB_URLS.eu,
42
+ };
43
+ }
44
+
45
+ /**
46
+ * Create a direct connection from environment variables
47
+ * @throws Error if required environment variables are missing
48
+ */
49
+ static fromEnv(): PhyHubDirectConnection {
50
+ const deviceId = process.env.DEVICE_ID || process.env.PHYGRID_DEVICE_ID;
51
+ const accessKey = process.env.ACCESS_KEY || process.env.PHYGRID_DEVICE_KEY;
52
+
53
+ if (!deviceId) {
54
+ throw new Error('[PhyHubDirectConnection] DEVICE_ID or PHYGRID_DEVICE_ID env var required');
55
+ }
56
+ if (!accessKey) {
57
+ throw new Error('[PhyHubDirectConnection] ACCESS_KEY or PHYGRID_DEVICE_KEY env var required');
58
+ }
59
+
60
+ const region = process.env.PHYHUB_REGION?.toLowerCase();
61
+ const phyhubUrl = process.env.PHYHUB_URL || (region ? DEFAULT_PHYHUB_URLS[region] : undefined);
62
+
63
+ if (!phyhubUrl) {
64
+ throw new Error(`[PhyHubDirectConnection] PHYHUB_URL or valid PHYHUB_REGION required. Valid regions: ${Object.keys(DEFAULT_PHYHUB_URLS).join(', ')}`);
65
+ }
66
+
67
+ return new PhyHubDirectConnection({
68
+ deviceId,
69
+ accessKey,
70
+ phyhubUrl,
71
+ instanceId: process.env.TWIN_ID || process.env.INSTANCE_ID,
72
+ });
73
+ }
74
+
75
+ /**
76
+ * Check if direct connection mode is enabled
77
+ */
78
+ static isEnabled(): boolean {
79
+ return process.env.PHYHUB_DIRECT === 'true' || process.env.PHYHUB_DIRECT === '1';
80
+ }
81
+
82
+ /**
83
+ * Get the device ID (also used as the primary twin ID)
84
+ */
85
+ getDeviceId(): string {
86
+ return this.config.deviceId;
87
+ }
88
+
89
+ /**
90
+ * Get the instance/twin ID to use
91
+ */
92
+ getInstanceId(): string {
93
+ return this.config.instanceId || this.config.deviceId;
94
+ }
95
+
96
+ /**
97
+ * Connect directly to PhyHub
98
+ */
99
+ async connect(): Promise<Socket> {
100
+ if (this.socket?.connected) {
101
+ return this.socket;
102
+ }
103
+
104
+ const { deviceId, accessKey, phyhubUrl } = this.config;
105
+
106
+ console.log(`[PhyHubDirectConnection] Connecting to ${phyhubUrl}`);
107
+ console.log(`[PhyHubDirectConnection] Device ID: ${deviceId}`);
108
+
109
+ this.socket = await getSocketIOWithProxy(phyhubUrl!, {
110
+ auth: {
111
+ deviceId,
112
+ accessKey,
113
+ },
114
+ reconnection: true,
115
+ reconnectionAttempts: 5,
116
+ reconnectionDelay: 1000,
117
+ timeout: 10000,
118
+ });
119
+
120
+ await new Promise<void>((resolve, reject) => {
121
+ const timeout = setTimeout(() => {
122
+ reject(new Error('Connection timeout'));
123
+ }, 15000);
124
+
125
+ this.socket!.on('connect', () => {
126
+ clearTimeout(timeout);
127
+ console.log(`[PhyHubDirectConnection] Connected successfully`);
128
+ resolve();
129
+ });
130
+
131
+ this.socket!.on('connect_error', (error) => {
132
+ clearTimeout(timeout);
133
+ console.error(`[PhyHubDirectConnection] Connection error:`, error.message);
134
+ reject(error);
135
+ });
136
+ });
137
+
138
+ return this.socket;
139
+ }
140
+
141
+ /**
142
+ * Disconnect from PhyHub
143
+ */
144
+ disconnect(): void {
145
+ if (this.socket) {
146
+ this.socket.disconnect();
147
+ this.socket = null;
148
+ }
149
+ }
150
+
151
+ /**
152
+ * Get the socket instance
153
+ */
154
+ getSocket(): Socket | null {
155
+ return this.socket;
156
+ }
157
+ }
158
+
159
+ export default PhyHubDirectConnection;