@healthcloudai/hc-patient-telehealth 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +62 -0
- package/dist/index.cjs +850 -0
- package/dist/index.d.cts +57 -0
- package/dist/index.d.ts +57 -0
- package/dist/index.js +840 -0
- package/package.json +87 -0
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,850 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __esm = (fn, res) => function __init() {
|
|
9
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
10
|
+
};
|
|
11
|
+
var __export = (target, all) => {
|
|
12
|
+
for (var name in all)
|
|
13
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
14
|
+
};
|
|
15
|
+
var __copyProps = (to, from, except, desc) => {
|
|
16
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
17
|
+
for (let key of __getOwnPropNames(from))
|
|
18
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
19
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
20
|
+
}
|
|
21
|
+
return to;
|
|
22
|
+
};
|
|
23
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
24
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
25
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
26
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
27
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
28
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
29
|
+
mod
|
|
30
|
+
));
|
|
31
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
32
|
+
|
|
33
|
+
// src/theme/defaultTheme.ts
|
|
34
|
+
var defaultTheme;
|
|
35
|
+
var init_defaultTheme = __esm({
|
|
36
|
+
"src/theme/defaultTheme.ts"() {
|
|
37
|
+
"use strict";
|
|
38
|
+
defaultTheme = {
|
|
39
|
+
colors: {
|
|
40
|
+
primary: "#003C71",
|
|
41
|
+
btnPrimary: "#1e90ff",
|
|
42
|
+
success: "#2ecc71",
|
|
43
|
+
danger: "#e74c3c",
|
|
44
|
+
darkBackground: "#000",
|
|
45
|
+
lightBackground: "#fff",
|
|
46
|
+
text: "#fff",
|
|
47
|
+
iconColor: "#fff",
|
|
48
|
+
textDark: "#000"
|
|
49
|
+
},
|
|
50
|
+
fonts: {
|
|
51
|
+
regular: "System",
|
|
52
|
+
bold: "System-Bold",
|
|
53
|
+
size: {
|
|
54
|
+
small: 14,
|
|
55
|
+
medium: 18,
|
|
56
|
+
large: 24
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
// src/services/AgoraService/index.web.ts
|
|
64
|
+
var index_web_exports = {};
|
|
65
|
+
__export(index_web_exports, {
|
|
66
|
+
default: () => index_web_default
|
|
67
|
+
});
|
|
68
|
+
var AgoraRTC, client, appId, localAudioTrack, localVideoTrack, webAgoraService, index_web_default;
|
|
69
|
+
var init_index_web = __esm({
|
|
70
|
+
"src/services/AgoraService/index.web.ts"() {
|
|
71
|
+
"use strict";
|
|
72
|
+
AgoraRTC = null;
|
|
73
|
+
client = null;
|
|
74
|
+
appId = "";
|
|
75
|
+
localAudioTrack = null;
|
|
76
|
+
localVideoTrack = null;
|
|
77
|
+
webAgoraService = {
|
|
78
|
+
// INIT SDK + CLIENT
|
|
79
|
+
async init(appIdParam) {
|
|
80
|
+
if (typeof window === "undefined") return;
|
|
81
|
+
if (!AgoraRTC) {
|
|
82
|
+
const mod = await import("agora-rtc-sdk-ng");
|
|
83
|
+
AgoraRTC = mod.default;
|
|
84
|
+
}
|
|
85
|
+
appId = appIdParam;
|
|
86
|
+
if (!client) {
|
|
87
|
+
client = AgoraRTC.createClient({ mode: "rtc", codec: "vp8" });
|
|
88
|
+
console.log("WEB Agora client created");
|
|
89
|
+
this.setupEventListeners();
|
|
90
|
+
}
|
|
91
|
+
},
|
|
92
|
+
// JOIN CHANNEL
|
|
93
|
+
async joinChannel(tokenParam, channel, uidParam) {
|
|
94
|
+
if (!client) throw new Error("Client not initialized");
|
|
95
|
+
await client.join(appId, channel, tokenParam, uidParam);
|
|
96
|
+
console.log(" LOCAL JOIN SUCCESS", {
|
|
97
|
+
localUid: uidParam
|
|
98
|
+
});
|
|
99
|
+
await this.createLocalTracks();
|
|
100
|
+
await this.publishLocalTracks();
|
|
101
|
+
console.log(" LOCAL TRACKS PUBLISHED", {
|
|
102
|
+
audio: localAudioTrack,
|
|
103
|
+
video: localVideoTrack
|
|
104
|
+
});
|
|
105
|
+
},
|
|
106
|
+
// CREATE LOCAL TRACKS
|
|
107
|
+
async createLocalTracks() {
|
|
108
|
+
localAudioTrack = await AgoraRTC.createMicrophoneAudioTrack();
|
|
109
|
+
localVideoTrack = await AgoraRTC.createCameraVideoTrack();
|
|
110
|
+
console.log("LOCAL TRACKS CREATED", {
|
|
111
|
+
uid: null
|
|
112
|
+
});
|
|
113
|
+
},
|
|
114
|
+
// PUBLISH LOCAL TRACKS
|
|
115
|
+
async publishLocalTracks() {
|
|
116
|
+
await client.publish([localAudioTrack, localVideoTrack]);
|
|
117
|
+
},
|
|
118
|
+
// EVENTS (REMOTE USERS)
|
|
119
|
+
setupEventListeners() {
|
|
120
|
+
client.on("user-joined", (user) => {
|
|
121
|
+
console.log(" REMOTE USER JOINED", {
|
|
122
|
+
remoteUid: user.uid
|
|
123
|
+
});
|
|
124
|
+
});
|
|
125
|
+
client.on("user-published", async (user, mediaType) => {
|
|
126
|
+
console.log(" REMOTE USER PUBLISHED", {
|
|
127
|
+
remoteUid: user.uid,
|
|
128
|
+
mediaType
|
|
129
|
+
});
|
|
130
|
+
await client.subscribe(user, mediaType);
|
|
131
|
+
console.log("SUBSCRIBED TO REMOTE", {
|
|
132
|
+
remoteUid: user.uid,
|
|
133
|
+
mediaType
|
|
134
|
+
});
|
|
135
|
+
});
|
|
136
|
+
client.on("user-unpublished", (user, mediaType) => {
|
|
137
|
+
console.log("REMOTE UNPUBLISHED", {
|
|
138
|
+
remoteUid: user.uid,
|
|
139
|
+
mediaType
|
|
140
|
+
});
|
|
141
|
+
});
|
|
142
|
+
client.on("user-left", (user) => {
|
|
143
|
+
console.log(" REMOTE USER LEFT", {
|
|
144
|
+
remoteUid: user.uid
|
|
145
|
+
});
|
|
146
|
+
});
|
|
147
|
+
},
|
|
148
|
+
// UI GETTERS
|
|
149
|
+
getClient() {
|
|
150
|
+
return client;
|
|
151
|
+
},
|
|
152
|
+
getLocalTracks() {
|
|
153
|
+
return {
|
|
154
|
+
audio: localAudioTrack,
|
|
155
|
+
video: localVideoTrack
|
|
156
|
+
};
|
|
157
|
+
},
|
|
158
|
+
// LEAVE CHANNEL
|
|
159
|
+
async leaveChannel() {
|
|
160
|
+
console.log(" LEAVING CHANNEL");
|
|
161
|
+
localAudioTrack == null ? void 0 : localAudioTrack.close();
|
|
162
|
+
localVideoTrack == null ? void 0 : localVideoTrack.close();
|
|
163
|
+
localAudioTrack = null;
|
|
164
|
+
localVideoTrack = null;
|
|
165
|
+
if (client) {
|
|
166
|
+
await client.leave();
|
|
167
|
+
}
|
|
168
|
+
console.log(" LEFT CHANNEL");
|
|
169
|
+
}
|
|
170
|
+
};
|
|
171
|
+
index_web_default = webAgoraService;
|
|
172
|
+
}
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
// src/services/AgoraService/index.native.ts
|
|
176
|
+
var index_native_exports = {};
|
|
177
|
+
__export(index_native_exports, {
|
|
178
|
+
default: () => index_native_default
|
|
179
|
+
});
|
|
180
|
+
var nativeAgoraService, index_native_default;
|
|
181
|
+
var init_index_native = __esm({
|
|
182
|
+
"src/services/AgoraService/index.native.ts"() {
|
|
183
|
+
"use strict";
|
|
184
|
+
nativeAgoraService = {
|
|
185
|
+
init: async () => {
|
|
186
|
+
},
|
|
187
|
+
joinChannel: async () => {
|
|
188
|
+
throw new Error("AgoraService is not available on native. Use VideoElement.native.");
|
|
189
|
+
},
|
|
190
|
+
getLocalTracks: () => ({ audio: null, video: null }),
|
|
191
|
+
createLocalTracks: async () => {
|
|
192
|
+
},
|
|
193
|
+
publishLocalTracks: async () => {
|
|
194
|
+
},
|
|
195
|
+
getClient: () => null,
|
|
196
|
+
setupEventListeners: () => {
|
|
197
|
+
},
|
|
198
|
+
leaveChannel: async () => {
|
|
199
|
+
}
|
|
200
|
+
};
|
|
201
|
+
index_native_default = nativeAgoraService;
|
|
202
|
+
}
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
// src/services/AgoraService/index.ts
|
|
206
|
+
var import_react_native, AgoraServiceImpl, AgoraService_default;
|
|
207
|
+
var init_AgoraService = __esm({
|
|
208
|
+
"src/services/AgoraService/index.ts"() {
|
|
209
|
+
"use strict";
|
|
210
|
+
import_react_native = require("react-native");
|
|
211
|
+
AgoraServiceImpl = import_react_native.Platform.OS === "web" ? (init_index_web(), __toCommonJS(index_web_exports)).default : (init_index_native(), __toCommonJS(index_native_exports)).default;
|
|
212
|
+
AgoraService_default = AgoraServiceImpl;
|
|
213
|
+
console.info("[hc-patient-telehealth] AgoraService platform", import_react_native.Platform.OS);
|
|
214
|
+
}
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
// src/VideoElement/VideoElement.web.tsx
|
|
218
|
+
var VideoElement_web_exports = {};
|
|
219
|
+
__export(VideoElement_web_exports, {
|
|
220
|
+
default: () => VideoElement
|
|
221
|
+
});
|
|
222
|
+
function VideoElement({
|
|
223
|
+
tokenClient,
|
|
224
|
+
autoJoin,
|
|
225
|
+
onJoinedChange,
|
|
226
|
+
onError
|
|
227
|
+
}) {
|
|
228
|
+
console.info("[hc-patient-telehealth] VideoElement.web render", {
|
|
229
|
+
hasTokenClient: !!tokenClient,
|
|
230
|
+
autoJoin
|
|
231
|
+
});
|
|
232
|
+
const localRef = (0, import_react.useRef)(null);
|
|
233
|
+
const remoteRef = (0, import_react.useRef)(null);
|
|
234
|
+
const [micOn, setMicOn] = (0, import_react.useState)(true);
|
|
235
|
+
const [cameraOn, setCameraOn] = (0, import_react.useState)(true);
|
|
236
|
+
const [chatOpen, setChatOpen] = (0, import_react.useState)(false);
|
|
237
|
+
const [joined, setJoined] = (0, import_react.useState)(false);
|
|
238
|
+
const join = async () => {
|
|
239
|
+
if (joined) return;
|
|
240
|
+
try {
|
|
241
|
+
console.info("[hc-patient-telehealth] VideoElement.web join start");
|
|
242
|
+
const session = await tokenClient.connectToTokenServer();
|
|
243
|
+
console.info("[hc-patient-telehealth] VideoElement.web session", {
|
|
244
|
+
hasToken: !!(session == null ? void 0 : session.token),
|
|
245
|
+
channelName: session == null ? void 0 : session.channelName,
|
|
246
|
+
uid: session == null ? void 0 : session.uid
|
|
247
|
+
});
|
|
248
|
+
await AgoraService_default.init(session.appId);
|
|
249
|
+
await AgoraService_default.joinChannel(session.token, session.channelName, session.uid);
|
|
250
|
+
const client2 = AgoraService_default.getClient();
|
|
251
|
+
client2.remoteUsers.forEach(async (user) => {
|
|
252
|
+
console.log("EXISTING REMOTE USER FOUND", {
|
|
253
|
+
remoteUid: user.uid,
|
|
254
|
+
hasVideo: !!user.videoTrack
|
|
255
|
+
});
|
|
256
|
+
if (user.hasVideo) {
|
|
257
|
+
await client2.subscribe(user, "video");
|
|
258
|
+
if (remoteRef.current) {
|
|
259
|
+
user.videoTrack.play(remoteRef.current);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
if (user.hasAudio) {
|
|
263
|
+
await client2.subscribe(user, "audio");
|
|
264
|
+
user.audioTrack.play();
|
|
265
|
+
}
|
|
266
|
+
});
|
|
267
|
+
client2.on("user-published", async (user, mediaType) => {
|
|
268
|
+
console.log("REMOTE PUBLISHED", {
|
|
269
|
+
remoteUid: user.uid,
|
|
270
|
+
mediaType
|
|
271
|
+
});
|
|
272
|
+
await client2.subscribe(user, mediaType);
|
|
273
|
+
if (mediaType === "video" && remoteRef.current) {
|
|
274
|
+
user.videoTrack.play(remoteRef.current);
|
|
275
|
+
}
|
|
276
|
+
if (mediaType === "audio") {
|
|
277
|
+
user.audioTrack.play();
|
|
278
|
+
}
|
|
279
|
+
});
|
|
280
|
+
setJoined(true);
|
|
281
|
+
onJoinedChange == null ? void 0 : onJoinedChange(true);
|
|
282
|
+
} catch (err) {
|
|
283
|
+
console.error("[hc-patient-telehealth] VideoElement.web join error", err);
|
|
284
|
+
onError == null ? void 0 : onError(err);
|
|
285
|
+
}
|
|
286
|
+
};
|
|
287
|
+
(0, import_react.useEffect)(() => {
|
|
288
|
+
if (joined) {
|
|
289
|
+
const tracks = AgoraService_default.getLocalTracks();
|
|
290
|
+
const localVideoTrack2 = tracks == null ? void 0 : tracks.video;
|
|
291
|
+
const localAudioTrack2 = tracks == null ? void 0 : tracks.audio;
|
|
292
|
+
if (localVideoTrack2 && localRef.current) {
|
|
293
|
+
localVideoTrack2.play(localRef.current);
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
}, [joined]);
|
|
297
|
+
const leave = async () => {
|
|
298
|
+
console.info("[hc-patient-telehealth] VideoElement.web leave");
|
|
299
|
+
await AgoraService_default.leaveChannel();
|
|
300
|
+
setJoined(false);
|
|
301
|
+
onJoinedChange == null ? void 0 : onJoinedChange(false);
|
|
302
|
+
remoteRef.current && (remoteRef.current.innerHTML = "");
|
|
303
|
+
localRef.current && (localRef.current.innerHTML = "");
|
|
304
|
+
};
|
|
305
|
+
(0, import_react.useEffect)(() => {
|
|
306
|
+
return () => {
|
|
307
|
+
AgoraService_default.leaveChannel().catch(() => {
|
|
308
|
+
});
|
|
309
|
+
};
|
|
310
|
+
}, []);
|
|
311
|
+
const toggleMic = async () => {
|
|
312
|
+
const tracks = AgoraService_default.getLocalTracks();
|
|
313
|
+
if (!(tracks == null ? void 0 : tracks.audio)) return;
|
|
314
|
+
const next = !micOn;
|
|
315
|
+
await tracks.audio.setEnabled(next);
|
|
316
|
+
console.log("MIC", next ? "ON" : "OFF");
|
|
317
|
+
setMicOn(next);
|
|
318
|
+
};
|
|
319
|
+
const toggleCamera = async () => {
|
|
320
|
+
const tracks = AgoraService_default.getLocalTracks();
|
|
321
|
+
if (!(tracks == null ? void 0 : tracks.video)) return;
|
|
322
|
+
const next = !cameraOn;
|
|
323
|
+
await tracks.video.setEnabled(next);
|
|
324
|
+
console.log("CAMERA", next ? "ON" : "OFF");
|
|
325
|
+
setCameraOn(next);
|
|
326
|
+
if (!next && localRef.current) {
|
|
327
|
+
localRef.current.innerHTML = "";
|
|
328
|
+
} else if (next && localRef.current) {
|
|
329
|
+
tracks.video.play(localRef.current);
|
|
330
|
+
}
|
|
331
|
+
};
|
|
332
|
+
const toggleChat = () => {
|
|
333
|
+
setChatOpen((prev) => !prev);
|
|
334
|
+
};
|
|
335
|
+
(0, import_react.useEffect)(() => {
|
|
336
|
+
if (autoJoin) {
|
|
337
|
+
join().catch(() => {
|
|
338
|
+
});
|
|
339
|
+
}
|
|
340
|
+
}, [autoJoin]);
|
|
341
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: styles.root, children: [
|
|
342
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { ref: remoteRef, style: styles.remote }),
|
|
343
|
+
joined && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { ref: localRef, style: styles.local, id: "local" }),
|
|
344
|
+
chatOpen && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: styles.chat, children: "Chat" }),
|
|
345
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: styles.footer, children: !joined ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
346
|
+
"button",
|
|
347
|
+
{
|
|
348
|
+
style: { ...styles.iconBtn, background: defaultTheme.colors.success },
|
|
349
|
+
onClick: join,
|
|
350
|
+
children: "Join"
|
|
351
|
+
}
|
|
352
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
353
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { style: styles.iconBtn, onClick: toggleMic, children: micOn ? "Mic On" : "Mic Off" }),
|
|
354
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { style: styles.iconBtn, onClick: toggleCamera, children: cameraOn ? "Cam On" : "Cam Off" }),
|
|
355
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { style: styles.iconBtn, onClick: toggleChat, children: "Chat" }),
|
|
356
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
357
|
+
"button",
|
|
358
|
+
{
|
|
359
|
+
style: { ...styles.iconBtn, background: defaultTheme.colors.danger },
|
|
360
|
+
onClick: leave,
|
|
361
|
+
children: "Leave"
|
|
362
|
+
}
|
|
363
|
+
)
|
|
364
|
+
] }) }) })
|
|
365
|
+
] });
|
|
366
|
+
}
|
|
367
|
+
var import_react, import_jsx_runtime, styles;
|
|
368
|
+
var init_VideoElement_web = __esm({
|
|
369
|
+
"src/VideoElement/VideoElement.web.tsx"() {
|
|
370
|
+
"use strict";
|
|
371
|
+
import_react = require("react");
|
|
372
|
+
init_defaultTheme();
|
|
373
|
+
init_AgoraService();
|
|
374
|
+
import_jsx_runtime = require("react/jsx-runtime");
|
|
375
|
+
styles = {
|
|
376
|
+
root: {
|
|
377
|
+
width: "100vw",
|
|
378
|
+
height: "100vh",
|
|
379
|
+
position: "relative",
|
|
380
|
+
background: defaultTheme.colors.darkBackground,
|
|
381
|
+
overflow: "hidden"
|
|
382
|
+
},
|
|
383
|
+
remote: {
|
|
384
|
+
width: "100%",
|
|
385
|
+
height: "100%",
|
|
386
|
+
background: defaultTheme.colors.darkBackground
|
|
387
|
+
},
|
|
388
|
+
iconBtn: {
|
|
389
|
+
width: 50,
|
|
390
|
+
height: 50,
|
|
391
|
+
borderRadius: "50%",
|
|
392
|
+
background: defaultTheme.colors.btnPrimary,
|
|
393
|
+
border: "none",
|
|
394
|
+
color: defaultTheme.colors.iconColor,
|
|
395
|
+
cursor: "pointer",
|
|
396
|
+
display: "flex",
|
|
397
|
+
alignItems: "center",
|
|
398
|
+
justifyContent: "center",
|
|
399
|
+
fontSize: 24
|
|
400
|
+
},
|
|
401
|
+
chat: {
|
|
402
|
+
position: "absolute",
|
|
403
|
+
right: 0,
|
|
404
|
+
left: 0,
|
|
405
|
+
bottom: 0,
|
|
406
|
+
borderRadius: 20,
|
|
407
|
+
top: 40,
|
|
408
|
+
background: defaultTheme.colors.lightBackground,
|
|
409
|
+
color: defaultTheme.colors.darkBackground,
|
|
410
|
+
padding: 16
|
|
411
|
+
},
|
|
412
|
+
local: {
|
|
413
|
+
width: 180,
|
|
414
|
+
height: 180,
|
|
415
|
+
position: "absolute",
|
|
416
|
+
top: 16,
|
|
417
|
+
right: 16,
|
|
418
|
+
borderRadius: 12,
|
|
419
|
+
overflow: "hidden",
|
|
420
|
+
background: defaultTheme.colors.darkBackground,
|
|
421
|
+
boxShadow: "0 0 12px rgba(0,0,0,0.6)"
|
|
422
|
+
},
|
|
423
|
+
footer: {
|
|
424
|
+
position: "absolute",
|
|
425
|
+
bottom: 24,
|
|
426
|
+
width: "100%",
|
|
427
|
+
display: "flex",
|
|
428
|
+
justifyContent: "center",
|
|
429
|
+
gap: 16
|
|
430
|
+
},
|
|
431
|
+
btn: {
|
|
432
|
+
width: 64,
|
|
433
|
+
height: 64,
|
|
434
|
+
borderRadius: "50%",
|
|
435
|
+
border: "none",
|
|
436
|
+
fontSize: 14,
|
|
437
|
+
fontWeight: 600,
|
|
438
|
+
cursor: "pointer"
|
|
439
|
+
}
|
|
440
|
+
};
|
|
441
|
+
}
|
|
442
|
+
});
|
|
443
|
+
|
|
444
|
+
// src/VideoElement/VideoElement.native.tsx
|
|
445
|
+
var VideoElement_native_exports = {};
|
|
446
|
+
__export(VideoElement_native_exports, {
|
|
447
|
+
default: () => VideoElement_native_default
|
|
448
|
+
});
|
|
449
|
+
var import_react2, import_react_native2, import_react_native_agora, import_jsx_runtime2, App, styles2, getPermission, VideoElement_native_default;
|
|
450
|
+
var init_VideoElement_native = __esm({
|
|
451
|
+
"src/VideoElement/VideoElement.native.tsx"() {
|
|
452
|
+
"use strict";
|
|
453
|
+
import_react2 = require("react");
|
|
454
|
+
init_defaultTheme();
|
|
455
|
+
import_react_native2 = require("react-native");
|
|
456
|
+
import_react_native_agora = require("react-native-agora");
|
|
457
|
+
import_jsx_runtime2 = require("react/jsx-runtime");
|
|
458
|
+
App = ({
|
|
459
|
+
tokenClient,
|
|
460
|
+
autoJoin,
|
|
461
|
+
onJoinedChange,
|
|
462
|
+
onError
|
|
463
|
+
}) => {
|
|
464
|
+
console.info("[hc-patient-telehealth] VideoElement.native render", {
|
|
465
|
+
hasTokenClient: !!tokenClient,
|
|
466
|
+
autoJoin
|
|
467
|
+
});
|
|
468
|
+
const agoraEngineRef = (0, import_react2.useRef)(null);
|
|
469
|
+
const [isJoined, setIsJoined] = (0, import_react2.useState)(false);
|
|
470
|
+
const [isHost, setIsHost] = (0, import_react2.useState)(true);
|
|
471
|
+
const [remoteUid, setRemoteUid] = (0, import_react2.useState)(0);
|
|
472
|
+
const [message, setMessage] = (0, import_react2.useState)("");
|
|
473
|
+
const eventHandler = (0, import_react2.useRef)(null);
|
|
474
|
+
const [appId2, setAppId] = (0, import_react2.useState)("");
|
|
475
|
+
const [token, setToken] = (0, import_react2.useState)("");
|
|
476
|
+
const [channelName, setChannelName] = (0, import_react2.useState)("");
|
|
477
|
+
const [localUid, setLocalUid] = (0, import_react2.useState)(0);
|
|
478
|
+
const [micOn, setMicOn] = (0, import_react2.useState)(true);
|
|
479
|
+
const [camOn, setCamOn] = (0, import_react2.useState)(true);
|
|
480
|
+
const [chatOpen, setChatOpen] = (0, import_react2.useState)(false);
|
|
481
|
+
const [remoteVideoOn, setRemoteVideoOn] = (0, import_react2.useState)(true);
|
|
482
|
+
const [ready, setReady] = (0, import_react2.useState)(false);
|
|
483
|
+
const fetchTelehealthSession = async () => {
|
|
484
|
+
console.info("[hc-patient-telehealth] VideoElement.native fetch session");
|
|
485
|
+
const data = await tokenClient.connectToTokenServer();
|
|
486
|
+
console.info("[hc-patient-telehealth] VideoElement.native session", {
|
|
487
|
+
hasToken: !!(data == null ? void 0 : data.token),
|
|
488
|
+
channelName: data == null ? void 0 : data.channelName,
|
|
489
|
+
uid: data == null ? void 0 : data.uid
|
|
490
|
+
});
|
|
491
|
+
console.log("TELEHEALTH SESSION:", data);
|
|
492
|
+
setAppId(data.appId);
|
|
493
|
+
setToken(data.token);
|
|
494
|
+
setChannelName(data.channelName);
|
|
495
|
+
setLocalUid(data.uid);
|
|
496
|
+
return data;
|
|
497
|
+
};
|
|
498
|
+
(0, import_react2.useEffect)(() => {
|
|
499
|
+
const init = async () => {
|
|
500
|
+
try {
|
|
501
|
+
const session = await fetchTelehealthSession();
|
|
502
|
+
await setupVideoSDKEngine(session.appId);
|
|
503
|
+
setupEventHandler();
|
|
504
|
+
setReady(true);
|
|
505
|
+
} catch (err) {
|
|
506
|
+
onError == null ? void 0 : onError(err);
|
|
507
|
+
}
|
|
508
|
+
};
|
|
509
|
+
init().catch(() => {
|
|
510
|
+
});
|
|
511
|
+
return () => {
|
|
512
|
+
cleanupAgoraEngine();
|
|
513
|
+
};
|
|
514
|
+
}, []);
|
|
515
|
+
const setupEventHandler = () => {
|
|
516
|
+
var _a;
|
|
517
|
+
eventHandler.current = {
|
|
518
|
+
onJoinChannelSuccess: () => {
|
|
519
|
+
setMessage("Successfully joined channel: " + channelName);
|
|
520
|
+
setupLocalVideo();
|
|
521
|
+
setIsJoined(true);
|
|
522
|
+
onJoinedChange == null ? void 0 : onJoinedChange(true);
|
|
523
|
+
},
|
|
524
|
+
// onUserJoined: (_connection: RtcConnection, uid: number) => {
|
|
525
|
+
onUserJoined: (_connection, uid) => {
|
|
526
|
+
setMessage("Remote user " + uid + " joined");
|
|
527
|
+
setRemoteUid(uid);
|
|
528
|
+
setRemoteVideoOn(true);
|
|
529
|
+
},
|
|
530
|
+
// onUserOffline: (_connection: RtcConnection, uid: number) => {
|
|
531
|
+
onUserOffline: (_connection, uid) => {
|
|
532
|
+
setMessage("Remote user " + uid + " left the channel");
|
|
533
|
+
setRemoteUid(uid);
|
|
534
|
+
setRemoteVideoOn(false);
|
|
535
|
+
},
|
|
536
|
+
// onUserStateChanged: (_connection, uid, state) => {
|
|
537
|
+
onUserStateChanged: (_connection, uid, state) => {
|
|
538
|
+
if (uid === remoteUid) {
|
|
539
|
+
setRemoteVideoOn(state !== 0);
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
};
|
|
543
|
+
(_a = agoraEngineRef.current) == null ? void 0 : _a.registerEventHandler(eventHandler.current);
|
|
544
|
+
};
|
|
545
|
+
const setupVideoSDKEngine = async (appIdParam) => {
|
|
546
|
+
try {
|
|
547
|
+
if (import_react_native2.Platform.OS === "android") {
|
|
548
|
+
await getPermission();
|
|
549
|
+
}
|
|
550
|
+
agoraEngineRef.current = (0, import_react_native_agora.createAgoraRtcEngine)();
|
|
551
|
+
const agoraEngine = agoraEngineRef.current;
|
|
552
|
+
await agoraEngine.initialize({ appId: appIdParam });
|
|
553
|
+
} catch (e) {
|
|
554
|
+
console.error(e);
|
|
555
|
+
}
|
|
556
|
+
};
|
|
557
|
+
const setupLocalVideo = () => {
|
|
558
|
+
var _a;
|
|
559
|
+
(_a = agoraEngineRef.current) == null ? void 0 : _a.enableVideo();
|
|
560
|
+
};
|
|
561
|
+
const join = async () => {
|
|
562
|
+
var _a, _b;
|
|
563
|
+
if (isJoined) {
|
|
564
|
+
return;
|
|
565
|
+
}
|
|
566
|
+
try {
|
|
567
|
+
console.info("[hc-patient-telehealth] VideoElement.native join start");
|
|
568
|
+
if (!token || !appId2 || !channelName || !localUid) {
|
|
569
|
+
const session = await fetchTelehealthSession();
|
|
570
|
+
if (!(session == null ? void 0 : session.token)) {
|
|
571
|
+
throw new Error("Telehealth session token missing");
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
if (isHost) {
|
|
575
|
+
(_a = agoraEngineRef.current) == null ? void 0 : _a.joinChannel(token, channelName, localUid, {
|
|
576
|
+
// Set channel profile to live broadcast
|
|
577
|
+
channelProfile: import_react_native_agora.ChannelProfileType.ChannelProfileCommunication,
|
|
578
|
+
// Set user role to broadcaster
|
|
579
|
+
clientRoleType: import_react_native_agora.ClientRoleType.ClientRoleBroadcaster,
|
|
580
|
+
// Publish audio collected by the microphone
|
|
581
|
+
publishMicrophoneTrack: true,
|
|
582
|
+
// Publish video collected by the camera
|
|
583
|
+
publishCameraTrack: true,
|
|
584
|
+
// Automatically subscribe to all audio streams
|
|
585
|
+
autoSubscribeAudio: true,
|
|
586
|
+
// Automatically subscribe to all video streams
|
|
587
|
+
autoSubscribeVideo: true
|
|
588
|
+
});
|
|
589
|
+
} else {
|
|
590
|
+
(_b = agoraEngineRef.current) == null ? void 0 : _b.joinChannel(token, channelName, localUid, {
|
|
591
|
+
// Set channel profile to live broadcast
|
|
592
|
+
channelProfile: import_react_native_agora.ChannelProfileType.ChannelProfileCommunication,
|
|
593
|
+
// Set user role to audience
|
|
594
|
+
clientRoleType: import_react_native_agora.ClientRoleType.ClientRoleAudience,
|
|
595
|
+
// Do not publish audio collected by the microphone
|
|
596
|
+
publishMicrophoneTrack: false,
|
|
597
|
+
// Do not publish video collected by the camera
|
|
598
|
+
publishCameraTrack: false,
|
|
599
|
+
// Automatically subscribe to all audio streams
|
|
600
|
+
autoSubscribeAudio: true,
|
|
601
|
+
// Automatically subscribe to all video streams
|
|
602
|
+
autoSubscribeVideo: true
|
|
603
|
+
});
|
|
604
|
+
}
|
|
605
|
+
} catch (e) {
|
|
606
|
+
console.log(e);
|
|
607
|
+
onError == null ? void 0 : onError(e);
|
|
608
|
+
}
|
|
609
|
+
};
|
|
610
|
+
const leave = () => {
|
|
611
|
+
var _a;
|
|
612
|
+
try {
|
|
613
|
+
console.info("[hc-patient-telehealth] VideoElement.native leave");
|
|
614
|
+
(_a = agoraEngineRef.current) == null ? void 0 : _a.leaveChannel();
|
|
615
|
+
setRemoteUid(0);
|
|
616
|
+
setIsJoined(false);
|
|
617
|
+
showMessage("Left the channel");
|
|
618
|
+
onJoinedChange == null ? void 0 : onJoinedChange(false);
|
|
619
|
+
} catch (e) {
|
|
620
|
+
console.log(e);
|
|
621
|
+
}
|
|
622
|
+
};
|
|
623
|
+
const toggleCamera = async () => {
|
|
624
|
+
if (!agoraEngineRef.current) return;
|
|
625
|
+
const nextCamState = !camOn;
|
|
626
|
+
console.log("CAMERA", nextCamState ? "ON" : "OFF");
|
|
627
|
+
try {
|
|
628
|
+
await agoraEngineRef.current.enableLocalVideo(nextCamState);
|
|
629
|
+
const options = {
|
|
630
|
+
publishCameraTrack: nextCamState
|
|
631
|
+
};
|
|
632
|
+
await agoraEngineRef.current.updateChannelMediaOptions(options);
|
|
633
|
+
setCamOn(nextCamState);
|
|
634
|
+
} catch (e) {
|
|
635
|
+
console.error("Camera toggle error:", e);
|
|
636
|
+
}
|
|
637
|
+
};
|
|
638
|
+
const toggleMic = async () => {
|
|
639
|
+
if (!agoraEngineRef.current) return;
|
|
640
|
+
await agoraEngineRef.current.muteLocalAudioStream(micOn);
|
|
641
|
+
setMicOn(!micOn);
|
|
642
|
+
};
|
|
643
|
+
const toggleChat = () => {
|
|
644
|
+
setChatOpen((prev) => !prev);
|
|
645
|
+
};
|
|
646
|
+
const cleanupAgoraEngine = () => {
|
|
647
|
+
var _a, _b;
|
|
648
|
+
(_a = agoraEngineRef.current) == null ? void 0 : _a.unregisterEventHandler(eventHandler.current);
|
|
649
|
+
(_b = agoraEngineRef.current) == null ? void 0 : _b.release();
|
|
650
|
+
};
|
|
651
|
+
(0, import_react2.useEffect)(() => {
|
|
652
|
+
if (autoJoin && ready) {
|
|
653
|
+
join().catch(() => {
|
|
654
|
+
});
|
|
655
|
+
}
|
|
656
|
+
}, [autoJoin, ready]);
|
|
657
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react_native2.SafeAreaView, { style: styles2.root, children: [
|
|
658
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native2.View, { style: styles2.remoteContainer, children: isJoined && remoteUid !== 0 && remoteVideoOn ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
659
|
+
import_react_native_agora.RtcSurfaceView,
|
|
660
|
+
{
|
|
661
|
+
canvas: { uid: remoteUid, sourceType: import_react_native_agora.VideoSourceType.VideoSourceRemote },
|
|
662
|
+
style: styles2.remoteVideo
|
|
663
|
+
}
|
|
664
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native2.View, { style: styles2.remotePlaceholder }) }),
|
|
665
|
+
isJoined && camOn && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native2.View, { style: styles2.localContainer, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
666
|
+
import_react_native_agora.RtcSurfaceView,
|
|
667
|
+
{
|
|
668
|
+
canvas: { uid: localUid, sourceType: import_react_native_agora.VideoSourceType.VideoSourceCamera },
|
|
669
|
+
style: styles2.localVideo
|
|
670
|
+
}
|
|
671
|
+
) }),
|
|
672
|
+
isJoined && !camOn && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native2.View, { style: [styles2.localContainer, { backgroundColor: defaultTheme.colors.darkBackground }] }),
|
|
673
|
+
chatOpen && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native2.View, { style: styles2.chatPanel, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native2.Text, { style: { color: defaultTheme.colors.textDark, textAlign: "center" }, children: "Chat" }) }),
|
|
674
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native2.View, { style: styles2.footer, children: !isJoined ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native2.Text, { style: [styles2.button, styles2.join], onPress: join, children: "Join" }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
|
|
675
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native2.Text, { style: styles2.iconBtn, onPress: toggleMic, children: micOn ? "Mic On" : "Mic Off" }),
|
|
676
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native2.Text, { style: styles2.iconBtn, onPress: toggleCamera, children: camOn ? "Cam On" : "Cam Off" }),
|
|
677
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
678
|
+
import_react_native2.Text,
|
|
679
|
+
{
|
|
680
|
+
style: [
|
|
681
|
+
styles2.iconBtn,
|
|
682
|
+
chatOpen && { backgroundColor: defaultTheme.colors.btnPrimary }
|
|
683
|
+
],
|
|
684
|
+
onPress: toggleChat,
|
|
685
|
+
children: "Chat"
|
|
686
|
+
}
|
|
687
|
+
),
|
|
688
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native2.Text, { style: [styles2.button, styles2.leave], onPress: leave, children: "Leave" })
|
|
689
|
+
] }) })
|
|
690
|
+
] });
|
|
691
|
+
function showMessage(msg) {
|
|
692
|
+
setMessage(msg);
|
|
693
|
+
}
|
|
694
|
+
};
|
|
695
|
+
styles2 = import_react_native2.StyleSheet.create({
|
|
696
|
+
root: {
|
|
697
|
+
flex: 1,
|
|
698
|
+
backgroundColor: defaultTheme.colors.darkBackground
|
|
699
|
+
},
|
|
700
|
+
/* REMOTE */
|
|
701
|
+
remoteContainer: {
|
|
702
|
+
flex: 1,
|
|
703
|
+
backgroundColor: defaultTheme.colors.darkBackground
|
|
704
|
+
},
|
|
705
|
+
remoteVideo: {
|
|
706
|
+
width: "100%",
|
|
707
|
+
height: "100%"
|
|
708
|
+
},
|
|
709
|
+
remotePlaceholder: {
|
|
710
|
+
flex: 1,
|
|
711
|
+
backgroundColor: defaultTheme.colors.darkBackground
|
|
712
|
+
},
|
|
713
|
+
/* LOCAL */
|
|
714
|
+
localContainer: {
|
|
715
|
+
position: "absolute",
|
|
716
|
+
top: 16,
|
|
717
|
+
right: 16,
|
|
718
|
+
width: 180,
|
|
719
|
+
height: 180,
|
|
720
|
+
borderRadius: 12,
|
|
721
|
+
overflow: "hidden",
|
|
722
|
+
backgroundColor: defaultTheme.colors.darkBackground,
|
|
723
|
+
elevation: 8
|
|
724
|
+
},
|
|
725
|
+
localVideo: {
|
|
726
|
+
width: "100%",
|
|
727
|
+
height: "100%"
|
|
728
|
+
},
|
|
729
|
+
/* FOOTER */
|
|
730
|
+
footer: {
|
|
731
|
+
position: "absolute",
|
|
732
|
+
bottom: 24,
|
|
733
|
+
width: "100%",
|
|
734
|
+
flexDirection: "row",
|
|
735
|
+
justifyContent: "space-evenly",
|
|
736
|
+
paddingVertical: 40,
|
|
737
|
+
paddingHorizontal: 30
|
|
738
|
+
},
|
|
739
|
+
button: {
|
|
740
|
+
width: 50,
|
|
741
|
+
height: 50,
|
|
742
|
+
borderRadius: 36,
|
|
743
|
+
textAlign: "center",
|
|
744
|
+
textAlignVertical: "center",
|
|
745
|
+
color: defaultTheme.colors.text,
|
|
746
|
+
fontWeight: "600",
|
|
747
|
+
fontSize: 14,
|
|
748
|
+
overflow: "hidden"
|
|
749
|
+
},
|
|
750
|
+
join: {
|
|
751
|
+
backgroundColor: defaultTheme.colors.success
|
|
752
|
+
},
|
|
753
|
+
leave: {
|
|
754
|
+
backgroundColor: defaultTheme.colors.danger
|
|
755
|
+
},
|
|
756
|
+
iconBtn: {
|
|
757
|
+
width: 50,
|
|
758
|
+
height: 50,
|
|
759
|
+
borderRadius: 25,
|
|
760
|
+
backgroundColor: defaultTheme.colors.btnPrimary,
|
|
761
|
+
marginHorizontal: 10,
|
|
762
|
+
textAlign: "center",
|
|
763
|
+
textAlignVertical: "center"
|
|
764
|
+
},
|
|
765
|
+
chatPanel: {
|
|
766
|
+
position: "absolute",
|
|
767
|
+
right: 0,
|
|
768
|
+
top: 30,
|
|
769
|
+
bottom: 0,
|
|
770
|
+
width: "100%",
|
|
771
|
+
backgroundColor: defaultTheme.colors.lightBackground,
|
|
772
|
+
padding: 16,
|
|
773
|
+
borderRadius: 20,
|
|
774
|
+
elevation: 12
|
|
775
|
+
}
|
|
776
|
+
});
|
|
777
|
+
getPermission = async () => {
|
|
778
|
+
if (import_react_native2.Platform.OS === "android") {
|
|
779
|
+
await import_react_native2.PermissionsAndroid.requestMultiple([
|
|
780
|
+
import_react_native2.PermissionsAndroid.PERMISSIONS.RECORD_AUDIO,
|
|
781
|
+
import_react_native2.PermissionsAndroid.PERMISSIONS.CAMERA
|
|
782
|
+
]);
|
|
783
|
+
}
|
|
784
|
+
};
|
|
785
|
+
VideoElement_native_default = App;
|
|
786
|
+
}
|
|
787
|
+
});
|
|
788
|
+
|
|
789
|
+
// src/index.ts
|
|
790
|
+
var index_exports = {};
|
|
791
|
+
__export(index_exports, {
|
|
792
|
+
AuthError: () => AuthError,
|
|
793
|
+
ConfigError: () => ConfigError,
|
|
794
|
+
HCPatientTelehealth: () => HCPatientTelehealth,
|
|
795
|
+
HttpError: () => HttpError,
|
|
796
|
+
VideoElement: () => VideoElement_default,
|
|
797
|
+
default: () => index_default
|
|
798
|
+
});
|
|
799
|
+
module.exports = __toCommonJS(index_exports);
|
|
800
|
+
|
|
801
|
+
// src/PatientTelehealth/VideoRoom.tsx
|
|
802
|
+
var import_react_native4 = require("react-native");
|
|
803
|
+
|
|
804
|
+
// src/VideoElement/VideoElement.tsx
|
|
805
|
+
var import_react_native3 = require("react-native");
|
|
806
|
+
var VideoElement2 = import_react_native3.Platform.OS === "web" ? (init_VideoElement_web(), __toCommonJS(VideoElement_web_exports)).default : (init_VideoElement_native(), __toCommonJS(VideoElement_native_exports)).default;
|
|
807
|
+
var VideoElement_default = VideoElement2;
|
|
808
|
+
|
|
809
|
+
// src/PatientTelehealth/VideoRoom.tsx
|
|
810
|
+
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
811
|
+
function HCPatientTelehealth(props) {
|
|
812
|
+
console.info("[hc-patient-telehealth] HCPatientTelehealth render", {
|
|
813
|
+
hasTokenClient: !!(props == null ? void 0 : props.tokenClient),
|
|
814
|
+
autoJoin: props == null ? void 0 : props.autoJoin
|
|
815
|
+
});
|
|
816
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native4.View, { style: { flex: 1, backgroundColor: "black" }, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(VideoElement_default, { ...props }) });
|
|
817
|
+
}
|
|
818
|
+
|
|
819
|
+
// src/errors.ts
|
|
820
|
+
var ConfigError = class extends Error {
|
|
821
|
+
constructor(message) {
|
|
822
|
+
super(message);
|
|
823
|
+
this.name = "ConfigError";
|
|
824
|
+
}
|
|
825
|
+
};
|
|
826
|
+
var AuthError = class extends Error {
|
|
827
|
+
constructor(message) {
|
|
828
|
+
super(message);
|
|
829
|
+
this.name = "AuthError";
|
|
830
|
+
}
|
|
831
|
+
};
|
|
832
|
+
var HttpError = class extends Error {
|
|
833
|
+
constructor(status, message) {
|
|
834
|
+
super(message);
|
|
835
|
+
this.name = "HttpError";
|
|
836
|
+
this.status = status;
|
|
837
|
+
}
|
|
838
|
+
};
|
|
839
|
+
|
|
840
|
+
// src/index.ts
|
|
841
|
+
var index_default = HCPatientTelehealth;
|
|
842
|
+
console.info("[hc-patient-telehealth] package entry loaded");
|
|
843
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
844
|
+
0 && (module.exports = {
|
|
845
|
+
AuthError,
|
|
846
|
+
ConfigError,
|
|
847
|
+
HCPatientTelehealth,
|
|
848
|
+
HttpError,
|
|
849
|
+
VideoElement
|
|
850
|
+
});
|