@hipnation-truth/sdk 0.6.0 → 0.7.1

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.js CHANGED
@@ -1,8 +1,10 @@
1
1
  "use client";
2
2
  "use strict";
3
+ var __create = Object.create;
3
4
  var __defProp = Object.defineProperty;
4
5
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
6
  var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __getProtoOf = Object.getPrototypeOf;
6
8
  var __hasOwnProp = Object.prototype.hasOwnProperty;
7
9
  var __pow = Math.pow;
8
10
  var __export = (target, all) => {
@@ -17,6 +19,14 @@ var __copyProps = (to, from, except, desc) => {
17
19
  }
18
20
  return to;
19
21
  };
22
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
23
+ // If the importer is in node compatibility mode or this is not an ESM
24
+ // file that has been converted to a CommonJS file using a Babel-
25
+ // compatible transform (i.e. "__esModule" has not been set), then set
26
+ // "default" to the CommonJS "module.exports" for node compatibility.
27
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
28
+ mod
29
+ ));
20
30
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
21
31
  var __async = (__this, __arguments, generator) => {
22
32
  return new Promise((resolve, reject) => {
@@ -47,7 +57,11 @@ __export(react_exports, {
47
57
  useAppointment: () => useAppointment,
48
58
  useAppointmentByElationId: () => useAppointmentByElationId,
49
59
  useAppointments: () => useAppointments,
60
+ useConversationByPhonePair: () => useConversationByPhonePair,
50
61
  useConversationMessages: () => useConversationMessages,
62
+ useConversations: () => useConversations,
63
+ useMessages: () => useMessages,
64
+ useNotifications: () => useNotifications,
51
65
  usePatient: () => usePatient,
52
66
  usePatientBasic: () => usePatientBasic,
53
67
  usePatientByElationId: () => usePatientByElationId,
@@ -58,87 +72,145 @@ __export(react_exports, {
58
72
  usePharmacyByNcpdpId: () => usePharmacyByNcpdpId,
59
73
  usePhysicianByElationId: () => usePhysicianByElationId,
60
74
  usePhysiciansByElationIds: () => usePhysiciansByElationIds,
61
- useTruth: () => useTruth
75
+ useTruth: () => useTruth,
76
+ useUnreadCount: () => useUnreadCount
62
77
  });
63
78
  module.exports = __toCommonJS(react_exports);
64
79
 
65
- // src/react/hooks.ts
80
+ // src/react/conversations.ts
66
81
  var import_react = require("convex/react");
67
- var import_react2 = require("react");
68
82
  var import_server = require("convex/server");
69
- var patientsListRef = (0, import_server.makeFunctionReference)("patients:list");
70
- var patientsGetRef = (0, import_server.makeFunctionReference)("patients:get");
71
- var patientsByElationIdRef = (0, import_server.makeFunctionReference)("patients:getByElationId");
72
- var patientsByHintIdRef = (0, import_server.makeFunctionReference)("patients:getByHintId");
73
- var appointmentsListRef = (0, import_server.makeFunctionReference)("appointments:list");
74
- var appointmentsGetRef = (0, import_server.makeFunctionReference)("appointments:get");
75
- var appointmentsByElationIdRef = (0, import_server.makeFunctionReference)("appointments:getByElationId");
83
+ var conversationsListForUserRef = (0, import_server.makeFunctionReference)("conversations:listForUser");
84
+ var conversationsGetUnreadTotalForUserRef = (0, import_server.makeFunctionReference)("conversations:getUnreadTotalForUser");
85
+ var conversationsGetByPhonePairRef = (0, import_server.makeFunctionReference)("conversations:getByPhonePair");
86
+ var conversationMessagesGetByConversationIdRef = (0, import_server.makeFunctionReference)("conversationMessages:getByConversationId");
87
+ var SKIP = "skip";
88
+ function toResult(value, skipped) {
89
+ if (skipped) {
90
+ return { data: void 0, loading: false, error: void 0 };
91
+ }
92
+ return {
93
+ data: value,
94
+ loading: value === void 0,
95
+ error: void 0
96
+ };
97
+ }
98
+ function useConversations(filters) {
99
+ const skipped = !filters.userId;
100
+ const result = (0, import_react.useQuery)(
101
+ conversationsListForUserRef,
102
+ skipped ? SKIP : {
103
+ userId: filters.userId,
104
+ limit: filters.limit
105
+ }
106
+ );
107
+ return toResult(result, skipped);
108
+ }
109
+ function useConversationByPhonePair(phonePair) {
110
+ const skipped = !phonePair;
111
+ const result = (0, import_react.useQuery)(
112
+ conversationsGetByPhonePairRef,
113
+ skipped ? SKIP : { phonePair }
114
+ );
115
+ return toResult(result, skipped);
116
+ }
117
+ function useMessages(conversationId, options) {
118
+ const skipped = !conversationId;
119
+ const result = (0, import_react.useQuery)(
120
+ conversationMessagesGetByConversationIdRef,
121
+ skipped ? SKIP : {
122
+ conversationId,
123
+ limit: options == null ? void 0 : options.limit
124
+ }
125
+ );
126
+ return toResult(result, skipped);
127
+ }
128
+ function useUnreadCount(userId) {
129
+ const skipped = !userId;
130
+ const result = (0, import_react.useQuery)(
131
+ conversationsGetUnreadTotalForUserRef,
132
+ skipped ? SKIP : { userId }
133
+ );
134
+ return toResult(result, skipped);
135
+ }
136
+
137
+ // src/react/hooks.ts
138
+ var import_react2 = require("convex/react");
139
+ var import_react3 = require("react");
140
+ var import_server2 = require("convex/server");
141
+ var patientsListRef = (0, import_server2.makeFunctionReference)("patients:list");
142
+ var patientsGetRef = (0, import_server2.makeFunctionReference)("patients:get");
143
+ var patientsByElationIdRef = (0, import_server2.makeFunctionReference)("patients:getByElationId");
144
+ var patientsByHintIdRef = (0, import_server2.makeFunctionReference)("patients:getByHintId");
145
+ var appointmentsListRef = (0, import_server2.makeFunctionReference)("appointments:list");
146
+ var appointmentsGetRef = (0, import_server2.makeFunctionReference)("appointments:get");
147
+ var appointmentsByElationIdRef = (0, import_server2.makeFunctionReference)("appointments:getByElationId");
76
148
  function usePatients(options) {
77
- return (0, import_react.useQuery)(patientsListRef, options != null ? options : {});
149
+ return (0, import_react2.useQuery)(patientsListRef, options != null ? options : {});
78
150
  }
79
151
  function usePatient(id) {
80
- return (0, import_react.useQuery)(patientsGetRef, { id });
152
+ return (0, import_react2.useQuery)(patientsGetRef, { id });
81
153
  }
82
154
  function usePatientByElationId(elationId) {
83
- return (0, import_react.useQuery)(patientsByElationIdRef, {
155
+ return (0, import_react2.useQuery)(patientsByElationIdRef, {
84
156
  elationId
85
157
  });
86
158
  }
87
159
  function usePatientByHintId(hintId) {
88
- return (0, import_react.useQuery)(patientsByHintIdRef, {
160
+ return (0, import_react2.useQuery)(patientsByHintIdRef, {
89
161
  hintId
90
162
  });
91
163
  }
92
164
  function useAppointments(options) {
93
- return (0, import_react.useQuery)(
165
+ return (0, import_react2.useQuery)(
94
166
  appointmentsListRef,
95
167
  options != null ? options : {}
96
168
  );
97
169
  }
98
170
  function useAppointment(id) {
99
- return (0, import_react.useQuery)(appointmentsGetRef, { id });
171
+ return (0, import_react2.useQuery)(appointmentsGetRef, { id });
100
172
  }
101
173
  function useAppointmentByElationId(elationId) {
102
- return (0, import_react.useQuery)(appointmentsByElationIdRef, {
174
+ return (0, import_react2.useQuery)(appointmentsByElationIdRef, {
103
175
  elationId
104
176
  });
105
177
  }
106
- var physiciansGetByElationIdsRef = (0, import_server.makeFunctionReference)("physicians:getByElationIds");
107
- var physiciansGetByElationIdRef = (0, import_server.makeFunctionReference)("physicians:getByElationId");
178
+ var physiciansGetByElationIdsRef = (0, import_server2.makeFunctionReference)("physicians:getByElationIds");
179
+ var physiciansGetByElationIdRef = (0, import_server2.makeFunctionReference)("physicians:getByElationId");
108
180
  function usePhysiciansByElationIds(ids) {
109
- return (0, import_react.useQuery)(
181
+ return (0, import_react2.useQuery)(
110
182
  physiciansGetByElationIdsRef,
111
183
  ids && ids.length > 0 ? { ids } : "skip"
112
184
  );
113
185
  }
114
186
  function usePhysicianByElationId(id) {
115
- return (0, import_react.useQuery)(
187
+ return (0, import_react2.useQuery)(
116
188
  physiciansGetByElationIdRef,
117
189
  id !== void 0 ? { id } : "skip"
118
190
  );
119
191
  }
120
- var medicationsByPatientRef = (0, import_server.makeFunctionReference)("medicalRecords:getMedicationsByElationPatient");
121
- var problemsByPatientRef = (0, import_server.makeFunctionReference)("medicalRecords:getProblemsByElationPatient");
122
- var allergiesByPatientRef = (0, import_server.makeFunctionReference)("medicalRecords:getAllergiesByElationPatient");
123
- var appointmentsByPatientRef = (0, import_server.makeFunctionReference)("medicalRecords:getAppointmentsByElationPatient");
192
+ var medicationsByPatientRef = (0, import_server2.makeFunctionReference)("medicalRecords:getMedicationsByElationPatient");
193
+ var problemsByPatientRef = (0, import_server2.makeFunctionReference)("medicalRecords:getProblemsByElationPatient");
194
+ var allergiesByPatientRef = (0, import_server2.makeFunctionReference)("medicalRecords:getAllergiesByElationPatient");
195
+ var appointmentsByPatientRef = (0, import_server2.makeFunctionReference)("medicalRecords:getAppointmentsByElationPatient");
124
196
  function usePatientMedical(elationId, options) {
125
- const medications = (0, import_react.useQuery)(
197
+ const medications = (0, import_react2.useQuery)(
126
198
  medicationsByPatientRef,
127
199
  elationId !== void 0 ? { elationPatientId: elationId } : "skip"
128
200
  );
129
- const problems = (0, import_react.useQuery)(
201
+ const problems = (0, import_react2.useQuery)(
130
202
  problemsByPatientRef,
131
203
  elationId !== void 0 ? { elationPatientId: elationId } : "skip"
132
204
  );
133
- const allergies = (0, import_react.useQuery)(
205
+ const allergies = (0, import_react2.useQuery)(
134
206
  allergiesByPatientRef,
135
207
  elationId !== void 0 ? { elationPatientId: elationId } : "skip"
136
208
  );
137
- const appointments = (0, import_react.useQuery)(
209
+ const appointments = (0, import_react2.useQuery)(
138
210
  appointmentsByPatientRef,
139
211
  elationId !== void 0 ? { elationPatientId: elationId } : "skip"
140
212
  );
141
- (0, import_react2.useEffect)(() => {
213
+ (0, import_react3.useEffect)(() => {
142
214
  if (elationId === void 0 || (options == null ? void 0 : options.skipRefresh)) {
143
215
  return;
144
216
  }
@@ -162,26 +234,32 @@ function usePatientMedical(elationId, options) {
162
234
  }, [elationId, options == null ? void 0 : options.apiBaseUrl, options == null ? void 0 : options.apiKey, options == null ? void 0 : options.skipRefresh]);
163
235
  return { medications, problems, allergies, appointments };
164
236
  }
165
- var elationPatientByIdRef = (0, import_server.makeFunctionReference)("elationPatients:getByElationId");
166
- var hintPatientByIdRef = (0, import_server.makeFunctionReference)("hintPatients:getByHintId");
167
- var pharmacyByNcpdpRef = (0, import_server.makeFunctionReference)("elationPharmacies:getByNcpdpId");
168
- var patientPhotoByIdRef = (0, import_server.makeFunctionReference)("elationPatientPhotos:getByElationPatientId");
237
+ var elationPatientByIdRef = (0, import_server2.makeFunctionReference)("elationPatients:getByElationId");
238
+ var hintPatientByIdRef = (0, import_server2.makeFunctionReference)("hintPatients:getByHintId");
239
+ var pharmacyByNcpdpRef = (0, import_server2.makeFunctionReference)("elationPharmacies:getByNcpdpId");
240
+ var patientPhotoByIdRef = (0, import_server2.makeFunctionReference)("elationPatientPhotos:getByElationPatientId");
169
241
  function usePatientBasic(input, options) {
170
242
  var _a, _b;
171
- const elationRow = (0, import_react.useQuery)(
243
+ const elationRow = (0, import_react2.useQuery)(
172
244
  elationPatientByIdRef,
173
245
  input.elationId !== void 0 ? { elationId: input.elationId } : "skip"
174
246
  );
175
- const hintRow = (0, import_react.useQuery)(
247
+ const hintRow = (0, import_react2.useQuery)(
176
248
  hintPatientByIdRef,
177
249
  input.hintId !== void 0 ? { hintId: input.hintId } : "skip"
178
250
  );
179
- (0, import_react2.useEffect)(() => {
180
- if (options == null ? void 0 : options.skipRefresh) return;
181
- if (!input.hintId && input.elationId === void 0) return;
251
+ (0, import_react3.useEffect)(() => {
252
+ if (options == null ? void 0 : options.skipRefresh) {
253
+ return;
254
+ }
255
+ if (!input.hintId && input.elationId === void 0) {
256
+ return;
257
+ }
182
258
  const apiBaseUrl = options == null ? void 0 : options.apiBaseUrl;
183
259
  const apiKey = options == null ? void 0 : options.apiKey;
184
- if (!apiBaseUrl || !apiKey) return;
260
+ if (!apiBaseUrl || !apiKey) {
261
+ return;
262
+ }
185
263
  const controller = new AbortController();
186
264
  void fetch(`${apiBaseUrl}/api/patients/basic/refresh`, {
187
265
  method: "POST",
@@ -217,22 +295,28 @@ function usePatientBasic(input, options) {
217
295
  };
218
296
  }
219
297
  function usePharmacyByNcpdpId(ncpdpId) {
220
- return (0, import_react.useQuery)(
298
+ return (0, import_react2.useQuery)(
221
299
  pharmacyByNcpdpRef,
222
300
  ncpdpId ? { ncpdpId } : "skip"
223
301
  );
224
302
  }
225
303
  function usePatientPhoto(elationId, options) {
226
- const photo = (0, import_react.useQuery)(
304
+ const photo = (0, import_react2.useQuery)(
227
305
  patientPhotoByIdRef,
228
306
  elationId !== void 0 ? { elationPatientId: elationId } : "skip"
229
307
  );
230
- (0, import_react2.useEffect)(() => {
231
- if (options == null ? void 0 : options.skipRefresh) return;
232
- if (elationId === void 0) return;
308
+ (0, import_react3.useEffect)(() => {
309
+ if (options == null ? void 0 : options.skipRefresh) {
310
+ return;
311
+ }
312
+ if (elationId === void 0) {
313
+ return;
314
+ }
233
315
  const apiBaseUrl = options == null ? void 0 : options.apiBaseUrl;
234
316
  const apiKey = options == null ? void 0 : options.apiKey;
235
- if (!apiBaseUrl || !apiKey) return;
317
+ if (!apiBaseUrl || !apiKey) {
318
+ return;
319
+ }
236
320
  const controller = new AbortController();
237
321
  void fetch(`${apiBaseUrl}/api/patients/photo/refresh`, {
238
322
  method: "POST",
@@ -248,11 +332,11 @@ function usePatientPhoto(elationId, options) {
248
332
  }, [elationId, options == null ? void 0 : options.apiBaseUrl, options == null ? void 0 : options.apiKey, options == null ? void 0 : options.skipRefresh]);
249
333
  return photo;
250
334
  }
251
- var messagesByPhonesRef = (0, import_server.makeFunctionReference)("conversationMessages:getByPhones");
252
- var messagesByConversationIdRef = (0, import_server.makeFunctionReference)("conversationMessages:getByConversationId");
335
+ var messagesByPhonesRef = (0, import_server2.makeFunctionReference)("conversationMessages:getByPhones");
336
+ var messagesByConversationIdRef = (0, import_server2.makeFunctionReference)("conversationMessages:getByConversationId");
253
337
  function useConversationMessages(input, options) {
254
338
  const hasPair = !!input.phoneA && !!input.phoneB;
255
- const byPair = (0, import_react.useQuery)(
339
+ const byPair = (0, import_react2.useQuery)(
256
340
  messagesByPhonesRef,
257
341
  hasPair ? {
258
342
  phoneA: input.phoneA,
@@ -260,16 +344,397 @@ function useConversationMessages(input, options) {
260
344
  limit: options == null ? void 0 : options.limit
261
345
  } : "skip"
262
346
  );
263
- const byConvo = (0, import_react.useQuery)(
347
+ const byConvo = (0, import_react2.useQuery)(
264
348
  messagesByConversationIdRef,
265
349
  !hasPair && input.conversationId ? { conversationId: input.conversationId, limit: options == null ? void 0 : options.limit } : "skip"
266
350
  );
267
351
  return hasPair ? byPair : byConvo;
268
352
  }
269
353
 
270
- // src/react/provider.ts
271
- var import_react3 = require("convex/react");
354
+ // src/react/notifications.ts
272
355
  var import_react4 = require("react");
356
+
357
+ // src/web-push.ts
358
+ function isWebPushSupported() {
359
+ return typeof window !== "undefined" && "serviceWorker" in navigator && "PushManager" in window;
360
+ }
361
+ function registerServiceWorker(path = "/truth-sw.js") {
362
+ return __async(this, null, function* () {
363
+ return navigator.serviceWorker.register(path);
364
+ });
365
+ }
366
+ function subscribeToPush(registration, vapidPublicKey) {
367
+ return __async(this, null, function* () {
368
+ const existing = yield registration.pushManager.getSubscription();
369
+ if (existing) {
370
+ return existing;
371
+ }
372
+ return registration.pushManager.subscribe({
373
+ userVisibleOnly: true,
374
+ applicationServerKey: urlBase64ToUint8Array(
375
+ vapidPublicKey
376
+ )
377
+ });
378
+ });
379
+ }
380
+ function subscriptionToJSON(sub) {
381
+ var _a, _b, _c, _d;
382
+ const json = sub.toJSON();
383
+ return {
384
+ endpoint: sub.endpoint,
385
+ keys: {
386
+ p256dh: (_b = (_a = json.keys) == null ? void 0 : _a.p256dh) != null ? _b : "",
387
+ auth: (_d = (_c = json.keys) == null ? void 0 : _c.auth) != null ? _d : ""
388
+ }
389
+ };
390
+ }
391
+ function urlBase64ToUint8Array(base64String) {
392
+ const padding = "=".repeat((4 - base64String.length % 4) % 4);
393
+ const base64 = (base64String + padding).replace(/-/g, "+").replace(/_/g, "/");
394
+ const rawData = atob(base64);
395
+ const outputArray = new Uint8Array(rawData.length);
396
+ for (let i = 0; i < rawData.length; ++i) {
397
+ outputArray[i] = rawData.charCodeAt(i);
398
+ }
399
+ return outputArray;
400
+ }
401
+
402
+ // src/react/notifications.ts
403
+ function loadExpo() {
404
+ return __async(this, null, function* () {
405
+ try {
406
+ return yield import(
407
+ /* @vite-ignore */
408
+ /* webpackIgnore: true */
409
+ "expo-notifications"
410
+ );
411
+ } catch (e) {
412
+ return null;
413
+ }
414
+ });
415
+ }
416
+ function useNotifications(options) {
417
+ var _a;
418
+ const [permissionStatus, setPermissionStatus] = (0, import_react4.useState)("unknown");
419
+ const [devicePushToken, setDevicePushToken] = (0, import_react4.useState)(null);
420
+ const expoRef = (0, import_react4.useRef)(null);
421
+ const isWebRef = (0, import_react4.useRef)(false);
422
+ const vapidKeyRef = (0, import_react4.useRef)((_a = options.vapidPublicKey) != null ? _a : null);
423
+ (0, import_react4.useEffect)(() => {
424
+ let mounted = true;
425
+ void (() => __async(null, null, function* () {
426
+ var _a2;
427
+ const expo = yield loadExpo();
428
+ if (!mounted) {
429
+ return;
430
+ }
431
+ expoRef.current = expo;
432
+ if (expo) {
433
+ try {
434
+ const perm = yield expo.getPermissionsAsync();
435
+ if (!mounted) {
436
+ return;
437
+ }
438
+ setPermissionStatus(mapStatus(perm == null ? void 0 : perm.status));
439
+ } catch (e) {
440
+ setPermissionStatus("unknown");
441
+ }
442
+ return;
443
+ }
444
+ if (isWebPushSupported()) {
445
+ isWebRef.current = true;
446
+ if (!vapidKeyRef.current) {
447
+ try {
448
+ const res = yield fetch(
449
+ `${options.apiBaseUrl}/api/notifications/vapid-key`,
450
+ {
451
+ headers: {
452
+ Accept: "application/json",
453
+ "X-API-Key": options.apiKey
454
+ }
455
+ }
456
+ );
457
+ if (res.ok) {
458
+ const data = yield res.json();
459
+ vapidKeyRef.current = (_a2 = data.vapidPublicKey) != null ? _a2 : null;
460
+ }
461
+ } catch (e) {
462
+ }
463
+ }
464
+ if (!mounted) {
465
+ return;
466
+ }
467
+ const webPerm = typeof Notification !== "undefined" ? Notification.permission : "default";
468
+ setPermissionStatus(
469
+ webPerm === "granted" ? "granted" : webPerm === "denied" ? "denied" : "undetermined"
470
+ );
471
+ } else {
472
+ setPermissionStatus("unknown");
473
+ }
474
+ }))();
475
+ return () => {
476
+ mounted = false;
477
+ };
478
+ }, [options.apiBaseUrl, options.apiKey]);
479
+ const register = (0, import_react4.useCallback)(() => __async(null, null, function* () {
480
+ var _a2, _b;
481
+ if (!options.userId) {
482
+ return { ok: false, reason: "missing_userId" };
483
+ }
484
+ if (isWebRef.current) {
485
+ const vapidKey = vapidKeyRef.current;
486
+ if (!vapidKey) {
487
+ return { ok: false, reason: "no_vapid_key" };
488
+ }
489
+ const webPerm = yield Notification.requestPermission();
490
+ setPermissionStatus(
491
+ webPerm === "granted" ? "granted" : webPerm === "denied" ? "denied" : "undetermined"
492
+ );
493
+ if (webPerm !== "granted") {
494
+ return { ok: false, reason: "permission_denied" };
495
+ }
496
+ try {
497
+ const swPath = (_a2 = options.serviceWorkerPath) != null ? _a2 : "/truth-sw.js";
498
+ const registration = yield registerServiceWorker(swPath);
499
+ yield navigator.serviceWorker.ready;
500
+ const subscription = yield subscribeToPush(registration, vapidKey);
501
+ const subJSON = subscriptionToJSON(subscription);
502
+ setDevicePushToken(subscription.endpoint);
503
+ const res2 = yield fetch(
504
+ `${options.apiBaseUrl}/api/notifications/devices/register`,
505
+ {
506
+ method: "POST",
507
+ headers: {
508
+ "Content-Type": "application/json",
509
+ "X-API-Key": options.apiKey
510
+ },
511
+ body: JSON.stringify({
512
+ userId: options.userId,
513
+ platform: "web",
514
+ webPushSubscription: subJSON,
515
+ appVersion: options.appVersion,
516
+ locale: navigator.language,
517
+ timezone: Intl.DateTimeFormat().resolvedOptions().timeZone
518
+ })
519
+ }
520
+ );
521
+ if (!res2.ok) {
522
+ const text = yield res2.text().catch(() => "");
523
+ return {
524
+ ok: false,
525
+ reason: `register_failed_${res2.status}: ${text.slice(0, 120)}`
526
+ };
527
+ }
528
+ return { ok: true };
529
+ } catch (err) {
530
+ return {
531
+ ok: false,
532
+ reason: `web_push_error: ${err instanceof Error ? err.message : String(err)}`
533
+ };
534
+ }
535
+ }
536
+ const expo = (_b = expoRef.current) != null ? _b : yield loadExpo();
537
+ expoRef.current = expo;
538
+ if (!expo) {
539
+ return { ok: false, reason: "expo_notifications_missing" };
540
+ }
541
+ let perm = yield expo.getPermissionsAsync();
542
+ if ((perm == null ? void 0 : perm.status) !== "granted") {
543
+ perm = yield expo.requestPermissionsAsync();
544
+ }
545
+ setPermissionStatus(mapStatus(perm == null ? void 0 : perm.status));
546
+ if ((perm == null ? void 0 : perm.status) !== "granted") {
547
+ return { ok: false, reason: "permission_denied" };
548
+ }
549
+ const tokenResp = yield expo.getDevicePushTokenAsync();
550
+ const nativeToken = tokenResp == null ? void 0 : tokenResp.data;
551
+ const platform = detectPlatform(tokenResp == null ? void 0 : tokenResp.type);
552
+ if (!nativeToken || platform !== "ios" && platform !== "android") {
553
+ return { ok: false, reason: "no_native_token" };
554
+ }
555
+ setDevicePushToken(nativeToken);
556
+ const res = yield fetch(
557
+ `${options.apiBaseUrl}/api/notifications/devices/register`,
558
+ {
559
+ method: "POST",
560
+ headers: {
561
+ "Content-Type": "application/json",
562
+ "X-API-Key": options.apiKey
563
+ },
564
+ body: JSON.stringify({
565
+ userId: options.userId,
566
+ platform,
567
+ nativeToken,
568
+ appVersion: options.appVersion,
569
+ locale: typeof navigator !== "undefined" ? navigator.language : void 0,
570
+ timezone: Intl.DateTimeFormat().resolvedOptions().timeZone
571
+ })
572
+ }
573
+ );
574
+ if (!res.ok) {
575
+ const text = yield res.text().catch(() => "");
576
+ return {
577
+ ok: false,
578
+ reason: `register_failed_${res.status}: ${text.slice(0, 120)}`
579
+ };
580
+ }
581
+ return { ok: true };
582
+ }), [
583
+ options.apiBaseUrl,
584
+ options.apiKey,
585
+ options.userId,
586
+ options.appVersion,
587
+ options.serviceWorkerPath
588
+ ]);
589
+ const unregister = (0, import_react4.useCallback)(() => __async(null, null, function* () {
590
+ if (!devicePushToken) {
591
+ return;
592
+ }
593
+ yield fetch(`${options.apiBaseUrl}/api/notifications/devices/unregister`, {
594
+ method: "POST",
595
+ headers: {
596
+ "Content-Type": "application/json",
597
+ "X-API-Key": options.apiKey
598
+ },
599
+ body: JSON.stringify({ nativeToken: devicePushToken })
600
+ }).catch(() => {
601
+ });
602
+ setDevicePushToken(null);
603
+ }), [options.apiBaseUrl, options.apiKey, devicePushToken]);
604
+ const addReceivedListener = (0, import_react4.useCallback)(
605
+ (listener) => {
606
+ if (isWebRef.current) {
607
+ if (typeof navigator === "undefined" || !("serviceWorker" in navigator)) {
608
+ return () => {
609
+ };
610
+ }
611
+ const handler = (event) => {
612
+ var _a2;
613
+ if (((_a2 = event.data) == null ? void 0 : _a2.type) === "TRUTH_PUSH_RECEIVED") {
614
+ listener(event.data.payload);
615
+ }
616
+ };
617
+ navigator.serviceWorker.addEventListener("message", handler);
618
+ return () => navigator.serviceWorker.removeEventListener("message", handler);
619
+ }
620
+ const expo = expoRef.current;
621
+ if (!(expo == null ? void 0 : expo.addNotificationReceivedListener)) {
622
+ return () => {
623
+ };
624
+ }
625
+ const sub = expo.addNotificationReceivedListener(listener);
626
+ return () => {
627
+ var _a2;
628
+ return (_a2 = sub.remove) == null ? void 0 : _a2.call(sub);
629
+ };
630
+ },
631
+ []
632
+ );
633
+ const addResponseListener = (0, import_react4.useCallback)(
634
+ (listener) => {
635
+ if (isWebRef.current) {
636
+ if (typeof navigator === "undefined" || !("serviceWorker" in navigator)) {
637
+ return () => {
638
+ };
639
+ }
640
+ const handler = (event) => {
641
+ var _a2;
642
+ if (((_a2 = event.data) == null ? void 0 : _a2.type) === "TRUTH_PUSH_TAPPED") {
643
+ listener(event.data.payload);
644
+ }
645
+ };
646
+ navigator.serviceWorker.addEventListener("message", handler);
647
+ return () => navigator.serviceWorker.removeEventListener("message", handler);
648
+ }
649
+ const expo = expoRef.current;
650
+ if (!(expo == null ? void 0 : expo.addNotificationResponseReceivedListener)) {
651
+ return () => {
652
+ };
653
+ }
654
+ const sub = expo.addNotificationResponseReceivedListener(listener);
655
+ return () => {
656
+ var _a2;
657
+ return (_a2 = sub.remove) == null ? void 0 : _a2.call(sub);
658
+ };
659
+ },
660
+ []
661
+ );
662
+ const getBadgeCount = (0, import_react4.useCallback)(() => __async(null, null, function* () {
663
+ var _a2;
664
+ const expo = expoRef.current;
665
+ if (!(expo == null ? void 0 : expo.getBadgeCountAsync)) {
666
+ return 0;
667
+ }
668
+ return (_a2 = yield expo.getBadgeCountAsync()) != null ? _a2 : 0;
669
+ }), []);
670
+ const setBadgeCount = (0, import_react4.useCallback)((count) => __async(null, null, function* () {
671
+ const expo = expoRef.current;
672
+ if (!(expo == null ? void 0 : expo.setBadgeCountAsync)) {
673
+ return;
674
+ }
675
+ yield expo.setBadgeCountAsync(count);
676
+ }), []);
677
+ const autoRegister = options.autoRegister !== false;
678
+ (0, import_react4.useEffect)(() => {
679
+ if (!autoRegister) {
680
+ return;
681
+ }
682
+ if (permissionStatus !== "granted") {
683
+ return;
684
+ }
685
+ if (devicePushToken) {
686
+ return;
687
+ }
688
+ if (!options.userId) {
689
+ return;
690
+ }
691
+ void register();
692
+ }, [
693
+ autoRegister,
694
+ permissionStatus,
695
+ devicePushToken,
696
+ options.userId,
697
+ register
698
+ ]);
699
+ return {
700
+ permissionStatus,
701
+ devicePushToken,
702
+ register,
703
+ unregister,
704
+ addReceivedListener,
705
+ addResponseListener,
706
+ getBadgeCount,
707
+ setBadgeCount
708
+ };
709
+ }
710
+ function mapStatus(status) {
711
+ if (status === "granted") {
712
+ return "granted";
713
+ }
714
+ if (status === "denied") {
715
+ return "denied";
716
+ }
717
+ if (status === "undetermined") {
718
+ return "undetermined";
719
+ }
720
+ return "unknown";
721
+ }
722
+ function detectPlatform(tokenType) {
723
+ if (tokenType === "apns") {
724
+ return "ios";
725
+ }
726
+ if (tokenType === "fcm") {
727
+ return "android";
728
+ }
729
+ if (tokenType === "web") {
730
+ return "web";
731
+ }
732
+ return "unknown";
733
+ }
734
+
735
+ // src/react/provider.ts
736
+ var import_react5 = require("convex/react");
737
+ var import_react6 = require("react");
273
738
  var CONVEX_URLS = {
274
739
  local: "https://courteous-duck-623.convex.cloud",
275
740
  staging: "https://courteous-duck-623.convex.cloud",
@@ -278,19 +743,26 @@ var CONVEX_URLS = {
278
743
  uat: "https://gallant-gecko-217.convex.cloud",
279
744
  production: "https://gallant-gecko-217.convex.cloud"
280
745
  };
746
+ function resolveConvexUrl(environment, override) {
747
+ var _a;
748
+ if (override) {
749
+ return override;
750
+ }
751
+ const env = environment != null ? environment : "sandbox";
752
+ return (_a = CONVEX_URLS[env]) != null ? _a : CONVEX_URLS.sandbox;
753
+ }
281
754
  function TruthProvider({
282
755
  environment = "sandbox",
283
756
  convexUrl,
284
757
  children
285
758
  }) {
286
- var _a;
287
- const url = (_a = convexUrl != null ? convexUrl : CONVEX_URLS[environment]) != null ? _a : CONVEX_URLS.sandbox;
288
- const client = (0, import_react4.useMemo)(() => new import_react3.ConvexReactClient(url), [url]);
289
- return (0, import_react4.createElement)(import_react3.ConvexProvider, { client }, children);
759
+ const url = resolveConvexUrl(environment, convexUrl);
760
+ const client = (0, import_react6.useMemo)(() => new import_react5.ConvexReactClient(url), [url]);
761
+ return (0, import_react6.createElement)(import_react5.ConvexProvider, { client }, children);
290
762
  }
291
763
 
292
764
  // src/react/tracking.ts
293
- var import_react5 = require("react");
765
+ var import_react7 = require("react");
294
766
 
295
767
  // src/tracking/tracker.ts
296
768
  function generateUuidV7() {
@@ -485,7 +957,7 @@ function sleep(ms) {
485
957
  }
486
958
 
487
959
  // src/react/tracking.ts
488
- var TruthTrackingContext = (0, import_react5.createContext)(
960
+ var TruthTrackingContext = (0, import_react7.createContext)(
489
961
  null
490
962
  );
491
963
  function TruthTrackingProvider({
@@ -496,7 +968,7 @@ function TruthTrackingProvider({
496
968
  apiKey = "",
497
969
  children
498
970
  }) {
499
- const value = (0, import_react5.useMemo)(() => {
971
+ const value = (0, import_react7.useMemo)(() => {
500
972
  const tracker = new Tracker({
501
973
  apiKey,
502
974
  environment,
@@ -515,10 +987,10 @@ function TruthTrackingProvider({
515
987
  }
516
988
  };
517
989
  }, [apiKey, environment, source, sourceVersion, tenantId]);
518
- return (0, import_react5.createElement)(TruthTrackingContext.Provider, { value }, children);
990
+ return (0, import_react7.createElement)(TruthTrackingContext.Provider, { value }, children);
519
991
  }
520
992
  function useTruth() {
521
- const ctx = (0, import_react5.useContext)(TruthTrackingContext);
993
+ const ctx = (0, import_react7.useContext)(TruthTrackingContext);
522
994
  if (!ctx) {
523
995
  throw new Error("useTruth must be used within a TruthTrackingProvider");
524
996
  }
@@ -531,7 +1003,11 @@ function useTruth() {
531
1003
  useAppointment,
532
1004
  useAppointmentByElationId,
533
1005
  useAppointments,
1006
+ useConversationByPhonePair,
534
1007
  useConversationMessages,
1008
+ useConversations,
1009
+ useMessages,
1010
+ useNotifications,
535
1011
  usePatient,
536
1012
  usePatientBasic,
537
1013
  usePatientByElationId,
@@ -542,6 +1018,7 @@ function useTruth() {
542
1018
  usePharmacyByNcpdpId,
543
1019
  usePhysicianByElationId,
544
1020
  usePhysiciansByElationIds,
545
- useTruth
1021
+ useTruth,
1022
+ useUnreadCount
546
1023
  });
547
1024
  //# sourceMappingURL=react.js.map