@hipnation-truth/sdk 0.7.3 → 0.7.5

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/react.mjs DELETED
@@ -1,969 +0,0 @@
1
- "use client";
2
- var __pow = Math.pow;
3
- var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
4
- get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
5
- }) : x)(function(x) {
6
- if (typeof require !== "undefined") return require.apply(this, arguments);
7
- throw Error('Dynamic require of "' + x + '" is not supported');
8
- });
9
- var __async = (__this, __arguments, generator) => {
10
- return new Promise((resolve, reject) => {
11
- var fulfilled = (value) => {
12
- try {
13
- step(generator.next(value));
14
- } catch (e) {
15
- reject(e);
16
- }
17
- };
18
- var rejected = (value) => {
19
- try {
20
- step(generator.throw(value));
21
- } catch (e) {
22
- reject(e);
23
- }
24
- };
25
- var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
26
- step((generator = generator.apply(__this, __arguments)).next());
27
- });
28
- };
29
-
30
- // src/react/conversations.ts
31
- import { useQuery } from "convex/react";
32
- import { makeFunctionReference } from "convex/server";
33
- var conversationsListForUserRef = makeFunctionReference("conversations:listForUser");
34
- var conversationsGetUnreadTotalForUserRef = makeFunctionReference("conversations:getUnreadTotalForUser");
35
- var conversationsGetByPhonePairRef = makeFunctionReference("conversations:getByPhonePair");
36
- var conversationMessagesGetByConversationIdRef = makeFunctionReference("conversationMessages:getByConversationId");
37
- var SKIP = "skip";
38
- function toResult(value, skipped) {
39
- if (skipped) {
40
- return { data: void 0, loading: false, error: void 0 };
41
- }
42
- return {
43
- data: value,
44
- loading: value === void 0,
45
- error: void 0
46
- };
47
- }
48
- function useConversations(filters) {
49
- const skipped = !filters.userId;
50
- const result = useQuery(
51
- conversationsListForUserRef,
52
- skipped ? SKIP : {
53
- userId: filters.userId,
54
- limit: filters.limit
55
- }
56
- );
57
- return toResult(result, skipped);
58
- }
59
- function useConversationByPhonePair(phonePair) {
60
- const skipped = !phonePair;
61
- const result = useQuery(
62
- conversationsGetByPhonePairRef,
63
- skipped ? SKIP : { phonePair }
64
- );
65
- return toResult(result, skipped);
66
- }
67
- function useMessages(conversationId, options) {
68
- const skipped = !conversationId;
69
- const result = useQuery(
70
- conversationMessagesGetByConversationIdRef,
71
- skipped ? SKIP : {
72
- conversationId,
73
- limit: options == null ? void 0 : options.limit
74
- }
75
- );
76
- return toResult(result, skipped);
77
- }
78
- function useUnreadCount(userId) {
79
- const skipped = !userId;
80
- const result = useQuery(
81
- conversationsGetUnreadTotalForUserRef,
82
- skipped ? SKIP : { userId }
83
- );
84
- return toResult(result, skipped);
85
- }
86
-
87
- // src/react/hooks.ts
88
- import { useQuery as useQuery2 } from "convex/react";
89
- import { useEffect } from "react";
90
- import { makeFunctionReference as makeFunctionReference2 } from "convex/server";
91
- var patientsListRef = makeFunctionReference2("patients:list");
92
- var patientsGetRef = makeFunctionReference2("patients:get");
93
- var patientsByElationIdRef = makeFunctionReference2("patients:getByElationId");
94
- var patientsByHintIdRef = makeFunctionReference2("patients:getByHintId");
95
- var appointmentsListRef = makeFunctionReference2("appointments:list");
96
- var appointmentsGetRef = makeFunctionReference2("appointments:get");
97
- var appointmentsByElationIdRef = makeFunctionReference2("appointments:getByElationId");
98
- function usePatients(options) {
99
- return useQuery2(patientsListRef, options != null ? options : {});
100
- }
101
- function usePatient(id) {
102
- return useQuery2(patientsGetRef, { id });
103
- }
104
- function usePatientByElationId(elationId) {
105
- return useQuery2(patientsByElationIdRef, {
106
- elationId
107
- });
108
- }
109
- function usePatientByHintId(hintId) {
110
- return useQuery2(patientsByHintIdRef, {
111
- hintId
112
- });
113
- }
114
- function useAppointments(options) {
115
- return useQuery2(
116
- appointmentsListRef,
117
- options != null ? options : {}
118
- );
119
- }
120
- function useAppointment(id) {
121
- return useQuery2(appointmentsGetRef, { id });
122
- }
123
- function useAppointmentByElationId(elationId) {
124
- return useQuery2(appointmentsByElationIdRef, {
125
- elationId
126
- });
127
- }
128
- var physiciansGetByElationIdsRef = makeFunctionReference2("physicians:getByElationIds");
129
- var physiciansGetByElationIdRef = makeFunctionReference2("physicians:getByElationId");
130
- function usePhysiciansByElationIds(ids) {
131
- return useQuery2(
132
- physiciansGetByElationIdsRef,
133
- ids && ids.length > 0 ? { ids } : "skip"
134
- );
135
- }
136
- function usePhysicianByElationId(id) {
137
- return useQuery2(
138
- physiciansGetByElationIdRef,
139
- id !== void 0 ? { id } : "skip"
140
- );
141
- }
142
- var medicationsByPatientRef = makeFunctionReference2("medicalRecords:getMedicationsByElationPatient");
143
- var problemsByPatientRef = makeFunctionReference2("medicalRecords:getProblemsByElationPatient");
144
- var allergiesByPatientRef = makeFunctionReference2("medicalRecords:getAllergiesByElationPatient");
145
- var appointmentsByPatientRef = makeFunctionReference2("medicalRecords:getAppointmentsByElationPatient");
146
- function usePatientMedical(elationId, options) {
147
- const medications = useQuery2(
148
- medicationsByPatientRef,
149
- elationId !== void 0 ? { elationPatientId: elationId } : "skip"
150
- );
151
- const problems = useQuery2(
152
- problemsByPatientRef,
153
- elationId !== void 0 ? { elationPatientId: elationId } : "skip"
154
- );
155
- const allergies = useQuery2(
156
- allergiesByPatientRef,
157
- elationId !== void 0 ? { elationPatientId: elationId } : "skip"
158
- );
159
- const appointments = useQuery2(
160
- appointmentsByPatientRef,
161
- elationId !== void 0 ? { elationPatientId: elationId } : "skip"
162
- );
163
- useEffect(() => {
164
- if (elationId === void 0 || (options == null ? void 0 : options.skipRefresh)) {
165
- return;
166
- }
167
- const apiBaseUrl = options == null ? void 0 : options.apiBaseUrl;
168
- const apiKey = options == null ? void 0 : options.apiKey;
169
- if (!apiBaseUrl || !apiKey) {
170
- return;
171
- }
172
- const controller = new AbortController();
173
- void fetch(`${apiBaseUrl}/api/patients/medical/refresh`, {
174
- method: "POST",
175
- headers: {
176
- "Content-Type": "application/json",
177
- "X-API-Key": apiKey
178
- },
179
- body: JSON.stringify({ elationId }),
180
- signal: controller.signal
181
- }).catch(() => {
182
- });
183
- return () => controller.abort();
184
- }, [elationId, options == null ? void 0 : options.apiBaseUrl, options == null ? void 0 : options.apiKey, options == null ? void 0 : options.skipRefresh]);
185
- return { medications, problems, allergies, appointments };
186
- }
187
- var elationPatientByIdRef = makeFunctionReference2("elationPatients:getByElationId");
188
- var hintPatientByIdRef = makeFunctionReference2("hintPatients:getByHintId");
189
- var pharmacyByNcpdpRef = makeFunctionReference2("elationPharmacies:getByNcpdpId");
190
- var patientPhotoByIdRef = makeFunctionReference2("elationPatientPhotos:getByElationPatientId");
191
- function usePatientBasic(input, options) {
192
- var _a, _b;
193
- const elationRow = useQuery2(
194
- elationPatientByIdRef,
195
- input.elationId !== void 0 ? { elationId: input.elationId } : "skip"
196
- );
197
- const hintRow = useQuery2(
198
- hintPatientByIdRef,
199
- input.hintId !== void 0 ? { hintId: input.hintId } : "skip"
200
- );
201
- useEffect(() => {
202
- if (options == null ? void 0 : options.skipRefresh) {
203
- return;
204
- }
205
- if (!input.hintId && input.elationId === void 0) {
206
- return;
207
- }
208
- const apiBaseUrl = options == null ? void 0 : options.apiBaseUrl;
209
- const apiKey = options == null ? void 0 : options.apiKey;
210
- if (!apiBaseUrl || !apiKey) {
211
- return;
212
- }
213
- const controller = new AbortController();
214
- void fetch(`${apiBaseUrl}/api/patients/basic/refresh`, {
215
- method: "POST",
216
- headers: {
217
- "Content-Type": "application/json",
218
- "X-API-Key": apiKey
219
- },
220
- body: JSON.stringify({
221
- hintId: input.hintId,
222
- elationId: input.elationId
223
- }),
224
- signal: controller.signal
225
- }).catch(() => {
226
- });
227
- return () => controller.abort();
228
- }, [
229
- input.hintId,
230
- input.elationId,
231
- options == null ? void 0 : options.apiBaseUrl,
232
- options == null ? void 0 : options.apiKey,
233
- options == null ? void 0 : options.skipRefresh
234
- ]);
235
- const elationPatient = elationRow === void 0 ? void 0 : elationRow === null ? null : (_a = elationRow.raw) != null ? _a : null;
236
- const hintPatient = hintRow === void 0 ? void 0 : hintRow === null ? null : (_b = hintRow.raw) != null ? _b : null;
237
- const elationLoading = input.elationId !== void 0 && elationRow === void 0;
238
- const hintLoading = input.hintId !== void 0 && hintRow === void 0;
239
- return {
240
- elationPatient,
241
- hintPatient,
242
- elationRow,
243
- hintRow,
244
- loading: elationLoading || hintLoading
245
- };
246
- }
247
- function usePharmacyByNcpdpId(ncpdpId) {
248
- return useQuery2(
249
- pharmacyByNcpdpRef,
250
- ncpdpId ? { ncpdpId } : "skip"
251
- );
252
- }
253
- function usePatientPhoto(elationId, options) {
254
- const photo = useQuery2(
255
- patientPhotoByIdRef,
256
- elationId !== void 0 ? { elationPatientId: elationId } : "skip"
257
- );
258
- useEffect(() => {
259
- if (options == null ? void 0 : options.skipRefresh) {
260
- return;
261
- }
262
- if (elationId === void 0) {
263
- return;
264
- }
265
- const apiBaseUrl = options == null ? void 0 : options.apiBaseUrl;
266
- const apiKey = options == null ? void 0 : options.apiKey;
267
- if (!apiBaseUrl || !apiKey) {
268
- return;
269
- }
270
- const controller = new AbortController();
271
- void fetch(`${apiBaseUrl}/api/patients/photo/refresh`, {
272
- method: "POST",
273
- headers: {
274
- "Content-Type": "application/json",
275
- "X-API-Key": apiKey
276
- },
277
- body: JSON.stringify({ elationId }),
278
- signal: controller.signal
279
- }).catch(() => {
280
- });
281
- return () => controller.abort();
282
- }, [elationId, options == null ? void 0 : options.apiBaseUrl, options == null ? void 0 : options.apiKey, options == null ? void 0 : options.skipRefresh]);
283
- return photo;
284
- }
285
- var messagesByPhonesRef = makeFunctionReference2("conversationMessages:getByPhones");
286
- var messagesByConversationIdRef = makeFunctionReference2("conversationMessages:getByConversationId");
287
- function useConversationMessages(input, options) {
288
- const hasPair = !!input.phoneA && !!input.phoneB;
289
- const byPair = useQuery2(
290
- messagesByPhonesRef,
291
- hasPair ? {
292
- phoneA: input.phoneA,
293
- phoneB: input.phoneB,
294
- limit: options == null ? void 0 : options.limit
295
- } : "skip"
296
- );
297
- const byConvo = useQuery2(
298
- messagesByConversationIdRef,
299
- !hasPair && input.conversationId ? { conversationId: input.conversationId, limit: options == null ? void 0 : options.limit } : "skip"
300
- );
301
- return hasPair ? byPair : byConvo;
302
- }
303
-
304
- // src/react/notifications.ts
305
- import { useCallback, useEffect as useEffect2, useRef, useState } from "react";
306
-
307
- // src/web-push.ts
308
- function isWebPushSupported() {
309
- return typeof window !== "undefined" && "serviceWorker" in navigator && "PushManager" in window;
310
- }
311
- function registerServiceWorker(path = "/truth-sw.js") {
312
- return __async(this, null, function* () {
313
- return navigator.serviceWorker.register(path);
314
- });
315
- }
316
- function subscribeToPush(registration, vapidPublicKey) {
317
- return __async(this, null, function* () {
318
- const existing = yield registration.pushManager.getSubscription();
319
- if (existing) {
320
- return existing;
321
- }
322
- return registration.pushManager.subscribe({
323
- userVisibleOnly: true,
324
- applicationServerKey: urlBase64ToUint8Array(
325
- vapidPublicKey
326
- )
327
- });
328
- });
329
- }
330
- function subscriptionToJSON(sub) {
331
- var _a, _b, _c, _d;
332
- const json = sub.toJSON();
333
- return {
334
- endpoint: sub.endpoint,
335
- keys: {
336
- p256dh: (_b = (_a = json.keys) == null ? void 0 : _a.p256dh) != null ? _b : "",
337
- auth: (_d = (_c = json.keys) == null ? void 0 : _c.auth) != null ? _d : ""
338
- }
339
- };
340
- }
341
- function urlBase64ToUint8Array(base64String) {
342
- const padding = "=".repeat((4 - base64String.length % 4) % 4);
343
- const base64 = (base64String + padding).replace(/-/g, "+").replace(/_/g, "/");
344
- const rawData = atob(base64);
345
- const outputArray = new Uint8Array(rawData.length);
346
- for (let i = 0; i < rawData.length; ++i) {
347
- outputArray[i] = rawData.charCodeAt(i);
348
- }
349
- return outputArray;
350
- }
351
-
352
- // src/react/notifications.ts
353
- function loadExpo() {
354
- return __async(this, null, function* () {
355
- try {
356
- return __require("expo-notifications");
357
- } catch (e) {
358
- return null;
359
- }
360
- });
361
- }
362
- function useNotifications(options) {
363
- var _a;
364
- const [permissionStatus, setPermissionStatus] = useState("unknown");
365
- const [devicePushToken, setDevicePushToken] = useState(null);
366
- const expoRef = useRef(null);
367
- const isWebRef = useRef(false);
368
- const vapidKeyRef = useRef((_a = options.vapidPublicKey) != null ? _a : null);
369
- useEffect2(() => {
370
- let mounted = true;
371
- void (() => __async(null, null, function* () {
372
- var _a2;
373
- const expo = yield loadExpo();
374
- if (!mounted) {
375
- return;
376
- }
377
- expoRef.current = expo;
378
- if (expo) {
379
- try {
380
- const perm = yield expo.getPermissionsAsync();
381
- if (!mounted) {
382
- return;
383
- }
384
- setPermissionStatus(mapStatus(perm == null ? void 0 : perm.status));
385
- } catch (e) {
386
- setPermissionStatus("unknown");
387
- }
388
- return;
389
- }
390
- if (isWebPushSupported()) {
391
- isWebRef.current = true;
392
- if (!vapidKeyRef.current) {
393
- try {
394
- const res = yield fetch(
395
- `${options.apiBaseUrl}/api/notifications/vapid-key`,
396
- {
397
- headers: {
398
- Accept: "application/json",
399
- "X-API-Key": options.apiKey
400
- }
401
- }
402
- );
403
- if (res.ok) {
404
- const data = yield res.json();
405
- vapidKeyRef.current = (_a2 = data.vapidPublicKey) != null ? _a2 : null;
406
- }
407
- } catch (e) {
408
- }
409
- }
410
- if (!mounted) {
411
- return;
412
- }
413
- const webPerm = typeof Notification !== "undefined" ? Notification.permission : "default";
414
- setPermissionStatus(
415
- webPerm === "granted" ? "granted" : webPerm === "denied" ? "denied" : "undetermined"
416
- );
417
- } else {
418
- setPermissionStatus("unknown");
419
- }
420
- }))();
421
- return () => {
422
- mounted = false;
423
- };
424
- }, [options.apiBaseUrl, options.apiKey]);
425
- const register = useCallback(() => __async(null, null, function* () {
426
- var _a2, _b;
427
- if (!options.userId) {
428
- return { ok: false, reason: "missing_userId" };
429
- }
430
- if (isWebRef.current) {
431
- const vapidKey = vapidKeyRef.current;
432
- if (!vapidKey) {
433
- return { ok: false, reason: "no_vapid_key" };
434
- }
435
- const webPerm = yield Notification.requestPermission();
436
- setPermissionStatus(
437
- webPerm === "granted" ? "granted" : webPerm === "denied" ? "denied" : "undetermined"
438
- );
439
- if (webPerm !== "granted") {
440
- return { ok: false, reason: "permission_denied" };
441
- }
442
- try {
443
- const swPath = (_a2 = options.serviceWorkerPath) != null ? _a2 : "/truth-sw.js";
444
- const registration = yield registerServiceWorker(swPath);
445
- yield navigator.serviceWorker.ready;
446
- const subscription = yield subscribeToPush(registration, vapidKey);
447
- const subJSON = subscriptionToJSON(subscription);
448
- setDevicePushToken(subscription.endpoint);
449
- const res2 = yield fetch(
450
- `${options.apiBaseUrl}/api/notifications/devices/register`,
451
- {
452
- method: "POST",
453
- headers: {
454
- "Content-Type": "application/json",
455
- "X-API-Key": options.apiKey
456
- },
457
- body: JSON.stringify({
458
- userId: options.userId,
459
- platform: "web",
460
- webPushSubscription: subJSON,
461
- appVersion: options.appVersion,
462
- locale: navigator.language,
463
- timezone: Intl.DateTimeFormat().resolvedOptions().timeZone
464
- })
465
- }
466
- );
467
- if (!res2.ok) {
468
- const text = yield res2.text().catch(() => "");
469
- return {
470
- ok: false,
471
- reason: `register_failed_${res2.status}: ${text.slice(0, 120)}`
472
- };
473
- }
474
- return { ok: true };
475
- } catch (err) {
476
- return {
477
- ok: false,
478
- reason: `web_push_error: ${err instanceof Error ? err.message : String(err)}`
479
- };
480
- }
481
- }
482
- const expo = (_b = expoRef.current) != null ? _b : yield loadExpo();
483
- expoRef.current = expo;
484
- if (!expo) {
485
- return { ok: false, reason: "expo_notifications_missing" };
486
- }
487
- let perm = yield expo.getPermissionsAsync();
488
- if ((perm == null ? void 0 : perm.status) !== "granted") {
489
- perm = yield expo.requestPermissionsAsync();
490
- }
491
- setPermissionStatus(mapStatus(perm == null ? void 0 : perm.status));
492
- if ((perm == null ? void 0 : perm.status) !== "granted") {
493
- return { ok: false, reason: "permission_denied" };
494
- }
495
- const tokenResp = yield expo.getDevicePushTokenAsync();
496
- const nativeToken = tokenResp == null ? void 0 : tokenResp.data;
497
- const platform = detectPlatform(tokenResp == null ? void 0 : tokenResp.type);
498
- if (!nativeToken || platform !== "ios" && platform !== "android") {
499
- return { ok: false, reason: "no_native_token" };
500
- }
501
- setDevicePushToken(nativeToken);
502
- const res = yield fetch(
503
- `${options.apiBaseUrl}/api/notifications/devices/register`,
504
- {
505
- method: "POST",
506
- headers: {
507
- "Content-Type": "application/json",
508
- "X-API-Key": options.apiKey
509
- },
510
- body: JSON.stringify({
511
- userId: options.userId,
512
- platform,
513
- nativeToken,
514
- appVersion: options.appVersion,
515
- locale: typeof navigator !== "undefined" ? navigator.language : void 0,
516
- timezone: Intl.DateTimeFormat().resolvedOptions().timeZone
517
- })
518
- }
519
- );
520
- if (!res.ok) {
521
- const text = yield res.text().catch(() => "");
522
- return {
523
- ok: false,
524
- reason: `register_failed_${res.status}: ${text.slice(0, 120)}`
525
- };
526
- }
527
- return { ok: true };
528
- }), [
529
- options.apiBaseUrl,
530
- options.apiKey,
531
- options.userId,
532
- options.appVersion,
533
- options.serviceWorkerPath
534
- ]);
535
- const unregister = useCallback(() => __async(null, null, function* () {
536
- if (!devicePushToken) {
537
- return;
538
- }
539
- yield fetch(`${options.apiBaseUrl}/api/notifications/devices/unregister`, {
540
- method: "POST",
541
- headers: {
542
- "Content-Type": "application/json",
543
- "X-API-Key": options.apiKey
544
- },
545
- body: JSON.stringify({ nativeToken: devicePushToken })
546
- }).catch(() => {
547
- });
548
- setDevicePushToken(null);
549
- }), [options.apiBaseUrl, options.apiKey, devicePushToken]);
550
- const addReceivedListener = useCallback(
551
- (listener) => {
552
- if (isWebRef.current) {
553
- if (typeof navigator === "undefined" || !("serviceWorker" in navigator)) {
554
- return () => {
555
- };
556
- }
557
- const handler = (event) => {
558
- var _a2;
559
- if (((_a2 = event.data) == null ? void 0 : _a2.type) === "TRUTH_PUSH_RECEIVED") {
560
- listener(event.data.payload);
561
- }
562
- };
563
- navigator.serviceWorker.addEventListener("message", handler);
564
- return () => navigator.serviceWorker.removeEventListener("message", handler);
565
- }
566
- const expo = expoRef.current;
567
- if (!(expo == null ? void 0 : expo.addNotificationReceivedListener)) {
568
- return () => {
569
- };
570
- }
571
- const sub = expo.addNotificationReceivedListener(listener);
572
- return () => {
573
- var _a2;
574
- return (_a2 = sub.remove) == null ? void 0 : _a2.call(sub);
575
- };
576
- },
577
- []
578
- );
579
- const addResponseListener = useCallback(
580
- (listener) => {
581
- if (isWebRef.current) {
582
- if (typeof navigator === "undefined" || !("serviceWorker" in navigator)) {
583
- return () => {
584
- };
585
- }
586
- const handler = (event) => {
587
- var _a2;
588
- if (((_a2 = event.data) == null ? void 0 : _a2.type) === "TRUTH_PUSH_TAPPED") {
589
- listener(event.data.payload);
590
- }
591
- };
592
- navigator.serviceWorker.addEventListener("message", handler);
593
- return () => navigator.serviceWorker.removeEventListener("message", handler);
594
- }
595
- const expo = expoRef.current;
596
- if (!(expo == null ? void 0 : expo.addNotificationResponseReceivedListener)) {
597
- return () => {
598
- };
599
- }
600
- const sub = expo.addNotificationResponseReceivedListener(listener);
601
- return () => {
602
- var _a2;
603
- return (_a2 = sub.remove) == null ? void 0 : _a2.call(sub);
604
- };
605
- },
606
- []
607
- );
608
- const getBadgeCount = useCallback(() => __async(null, null, function* () {
609
- var _a2;
610
- const expo = expoRef.current;
611
- if (!(expo == null ? void 0 : expo.getBadgeCountAsync)) {
612
- return 0;
613
- }
614
- return (_a2 = yield expo.getBadgeCountAsync()) != null ? _a2 : 0;
615
- }), []);
616
- const setBadgeCount = useCallback((count) => __async(null, null, function* () {
617
- const expo = expoRef.current;
618
- if (!(expo == null ? void 0 : expo.setBadgeCountAsync)) {
619
- return;
620
- }
621
- yield expo.setBadgeCountAsync(count);
622
- }), []);
623
- const autoRegister = options.autoRegister !== false;
624
- useEffect2(() => {
625
- if (!autoRegister) {
626
- return;
627
- }
628
- if (permissionStatus !== "granted") {
629
- return;
630
- }
631
- if (devicePushToken) {
632
- return;
633
- }
634
- if (!options.userId) {
635
- return;
636
- }
637
- void register();
638
- }, [
639
- autoRegister,
640
- permissionStatus,
641
- devicePushToken,
642
- options.userId,
643
- register
644
- ]);
645
- return {
646
- permissionStatus,
647
- devicePushToken,
648
- register,
649
- unregister,
650
- addReceivedListener,
651
- addResponseListener,
652
- getBadgeCount,
653
- setBadgeCount
654
- };
655
- }
656
- function mapStatus(status) {
657
- if (status === "granted") {
658
- return "granted";
659
- }
660
- if (status === "denied") {
661
- return "denied";
662
- }
663
- if (status === "undetermined") {
664
- return "undetermined";
665
- }
666
- return "unknown";
667
- }
668
- function detectPlatform(tokenType) {
669
- if (tokenType === "apns") {
670
- return "ios";
671
- }
672
- if (tokenType === "fcm") {
673
- return "android";
674
- }
675
- if (tokenType === "web") {
676
- return "web";
677
- }
678
- return "unknown";
679
- }
680
-
681
- // src/react/provider.ts
682
- import { ConvexProvider, ConvexReactClient } from "convex/react";
683
- import { createElement, useMemo } from "react";
684
- var CONVEX_URLS = {
685
- local: "https://courteous-duck-623.convex.cloud",
686
- staging: "https://courteous-duck-623.convex.cloud",
687
- stg: "https://courteous-duck-623.convex.cloud",
688
- sandbox: "https://courteous-duck-623.convex.cloud",
689
- uat: "https://gallant-gecko-217.convex.cloud",
690
- production: "https://gallant-gecko-217.convex.cloud"
691
- };
692
- function resolveConvexUrl(environment, override) {
693
- var _a;
694
- if (override) {
695
- return override;
696
- }
697
- const env = environment != null ? environment : "sandbox";
698
- return (_a = CONVEX_URLS[env]) != null ? _a : CONVEX_URLS.sandbox;
699
- }
700
- function TruthProvider({
701
- environment = "sandbox",
702
- convexUrl,
703
- children
704
- }) {
705
- const url = resolveConvexUrl(environment, convexUrl);
706
- const client = useMemo(() => new ConvexReactClient(url), [url]);
707
- return createElement(ConvexProvider, { client }, children);
708
- }
709
-
710
- // src/react/tracking.ts
711
- import { createContext, createElement as createElement2, useContext, useMemo as useMemo2 } from "react";
712
-
713
- // src/tracking/tracker.ts
714
- function generateUuidV7() {
715
- const now = Date.now();
716
- const timeBytes = new Uint8Array(6);
717
- let ts = now;
718
- for (let i = 5; i >= 0; i--) {
719
- timeBytes[i] = ts & 255;
720
- ts = Math.floor(ts / 256);
721
- }
722
- const randomBytes = new Uint8Array(10);
723
- if (typeof globalThis.crypto !== "undefined" && globalThis.crypto.getRandomValues) {
724
- globalThis.crypto.getRandomValues(randomBytes);
725
- } else {
726
- for (let i = 0; i < 10; i++) {
727
- randomBytes[i] = Math.floor(Math.random() * 256);
728
- }
729
- }
730
- const bytes = new Uint8Array(16);
731
- bytes.set(timeBytes, 0);
732
- bytes.set(randomBytes, 6);
733
- bytes[6] = bytes[6] & 15 | 112;
734
- bytes[8] = bytes[8] & 63 | 128;
735
- const hex = Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join("");
736
- return [
737
- hex.slice(0, 8),
738
- hex.slice(8, 12),
739
- hex.slice(12, 16),
740
- hex.slice(16, 20),
741
- hex.slice(20, 32)
742
- ].join("-");
743
- }
744
- var API_URLS = {
745
- local: "http://localhost:3000",
746
- staging: "https://app.sandbox.communication-hub.com",
747
- stg: "https://app.sandbox.communication-hub.com",
748
- sandbox: "https://app.sandbox.communication-hub.com",
749
- uat: "https://app.truth.communication-hub.com",
750
- production: "https://app.truth.communication-hub.com"
751
- };
752
- var MAX_RETRIES = 3;
753
- var BASE_RETRY_DELAY_MS = 500;
754
- var Tracker = class {
755
- constructor(config) {
756
- this.queue = [];
757
- this.flushTimer = null;
758
- this.isFlushing = false;
759
- this.isShutdown = false;
760
- var _a, _b;
761
- this.config = config;
762
- this.apiUrl = (_b = (_a = config.apiBaseUrl) != null ? _a : API_URLS[config.environment]) != null ? _b : API_URLS.local;
763
- this.startFlushInterval();
764
- this.registerShutdownHooks();
765
- }
766
- /**
767
- * Set the default actor context for subsequent events.
768
- */
769
- setActor(actor) {
770
- this.defaultActor = actor;
771
- }
772
- /**
773
- * Enqueue a typed event for delivery. This is fire-and-forget from
774
- * the caller's perspective -- events are buffered and flushed in batches.
775
- */
776
- track(eventType, payload, options) {
777
- var _a, _b, _c;
778
- if (this.isShutdown) {
779
- return;
780
- }
781
- const now = (/* @__PURE__ */ new Date()).toISOString();
782
- const envelope = {
783
- event_id: generateUuidV7(),
784
- event_type: eventType,
785
- schema_version: 1,
786
- occurred_at: (_a = options == null ? void 0 : options.occurredAt) != null ? _a : now,
787
- received_at: now,
788
- source: this.config.source,
789
- source_version: this.config.sourceVersion,
790
- tenant_id: (_b = options == null ? void 0 : options.tenantId) != null ? _b : this.config.tenantId,
791
- actor: (_c = options == null ? void 0 : options.actor) != null ? _c : this.defaultActor ? {
792
- actor_id: this.defaultActor.actorId,
793
- actor_type: this.defaultActor.actorType
794
- } : void 0,
795
- subject: options == null ? void 0 : options.subject,
796
- compliance: options == null ? void 0 : options.compliance,
797
- payload
798
- };
799
- this.queue.push(envelope);
800
- if (this.queue.length >= this.config.batchSize) {
801
- void this.flush();
802
- }
803
- }
804
- /**
805
- * Force an immediate flush of all buffered events.
806
- * Returns a promise that resolves when the flush completes.
807
- */
808
- flush() {
809
- return __async(this, null, function* () {
810
- if (this.queue.length === 0 || this.isFlushing) {
811
- return;
812
- }
813
- this.isFlushing = true;
814
- const batch = this.queue.splice(0, this.config.batchSize);
815
- try {
816
- yield this.sendBatch(batch);
817
- } catch (e) {
818
- this.queue.unshift(...batch);
819
- } finally {
820
- this.isFlushing = false;
821
- }
822
- if (this.queue.length >= this.config.batchSize) {
823
- yield this.flush();
824
- }
825
- });
826
- }
827
- /**
828
- * Gracefully shut down the tracker. Flushes remaining events and
829
- * clears the flush interval.
830
- */
831
- shutdown() {
832
- return __async(this, null, function* () {
833
- this.isShutdown = true;
834
- this.stopFlushInterval();
835
- yield this.flush();
836
- });
837
- }
838
- /**
839
- * Send a batch of events to the Truth API with exponential backoff retry.
840
- */
841
- sendBatch(batch) {
842
- return __async(this, null, function* () {
843
- let lastError;
844
- for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
845
- try {
846
- const response = yield fetch(`${this.apiUrl}/api/events/ingest`, {
847
- method: "POST",
848
- headers: {
849
- "Content-Type": "application/json",
850
- "X-API-Key": this.config.apiKey
851
- },
852
- body: JSON.stringify({ events: batch })
853
- });
854
- if (response.ok) {
855
- return;
856
- }
857
- if (response.status >= 400 && response.status < 500 && response.status !== 429) {
858
- return;
859
- }
860
- lastError = new Error(
861
- `HTTP ${response.status}: ${response.statusText}`
862
- );
863
- } catch (error) {
864
- lastError = error;
865
- }
866
- if (attempt < MAX_RETRIES) {
867
- const delay = BASE_RETRY_DELAY_MS * __pow(2, attempt);
868
- const jitter = Math.random() * delay * 0.5;
869
- yield sleep(delay + jitter);
870
- }
871
- }
872
- throw lastError;
873
- });
874
- }
875
- startFlushInterval() {
876
- if (this.config.flushIntervalMs > 0) {
877
- this.flushTimer = setInterval(() => {
878
- void this.flush();
879
- }, this.config.flushIntervalMs);
880
- if (typeof this.flushTimer === "object" && "unref" in this.flushTimer) {
881
- this.flushTimer.unref();
882
- }
883
- }
884
- }
885
- stopFlushInterval() {
886
- if (this.flushTimer !== null) {
887
- clearInterval(this.flushTimer);
888
- this.flushTimer = null;
889
- }
890
- }
891
- registerShutdownHooks() {
892
- if (typeof globalThis.process !== "undefined" && globalThis.process.on) {
893
- const shutdownHandler = () => {
894
- void this.shutdown();
895
- };
896
- globalThis.process.on("beforeExit", shutdownHandler);
897
- globalThis.process.on("SIGTERM", shutdownHandler);
898
- }
899
- }
900
- };
901
- function sleep(ms) {
902
- return new Promise((resolve) => setTimeout(resolve, ms));
903
- }
904
-
905
- // src/react/tracking.ts
906
- var TruthTrackingContext = createContext(
907
- null
908
- );
909
- function TruthTrackingProvider({
910
- environment = "sandbox",
911
- source = "communication-hub.frontend",
912
- sourceVersion = "unknown",
913
- tenantId = "hipnation",
914
- apiKey = "",
915
- children
916
- }) {
917
- const value = useMemo2(() => {
918
- const tracker = new Tracker({
919
- apiKey,
920
- environment,
921
- source,
922
- sourceVersion,
923
- tenantId,
924
- batchSize: 10,
925
- flushIntervalMs: 5e3
926
- });
927
- return {
928
- track: (eventType, payload, options) => {
929
- tracker.track(eventType, payload, options);
930
- },
931
- identify: (actorId, actorType) => {
932
- tracker.setActor({ actorId, actorType });
933
- }
934
- };
935
- }, [apiKey, environment, source, sourceVersion, tenantId]);
936
- return createElement2(TruthTrackingContext.Provider, { value }, children);
937
- }
938
- function useTruth() {
939
- const ctx = useContext(TruthTrackingContext);
940
- if (!ctx) {
941
- throw new Error("useTruth must be used within a TruthTrackingProvider");
942
- }
943
- return ctx;
944
- }
945
- export {
946
- TruthProvider,
947
- TruthTrackingProvider,
948
- useAppointment,
949
- useAppointmentByElationId,
950
- useAppointments,
951
- useConversationByPhonePair,
952
- useConversationMessages,
953
- useConversations,
954
- useMessages,
955
- useNotifications,
956
- usePatient,
957
- usePatientBasic,
958
- usePatientByElationId,
959
- usePatientByHintId,
960
- usePatientMedical,
961
- usePatientPhoto,
962
- usePatients,
963
- usePharmacyByNcpdpId,
964
- usePhysicianByElationId,
965
- usePhysiciansByElationIds,
966
- useTruth,
967
- useUnreadCount
968
- };
969
- //# sourceMappingURL=react.mjs.map