@hipnation-truth/sdk 0.17.2 → 0.18.0
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/index.d.mts +30 -1
- package/dist/index.d.ts +30 -1
- package/dist/index.js +81 -14
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +81 -14
- package/dist/index.mjs.map +1 -1
- package/dist/react.d.ts +1296 -1123
- package/dist/react.js +2388 -397
- package/dist/react.js.map +1 -1
- package/package.json +1 -1
package/dist/react.js
CHANGED
|
@@ -57,12 +57,17 @@ var __async = (__this, __arguments, generator) => {
|
|
|
57
57
|
var react_exports = {};
|
|
58
58
|
__export(react_exports, {
|
|
59
59
|
ACTIVE_CALL_STATES: () => ACTIVE_CALL_STATES,
|
|
60
|
+
API_BASE_URLS: () => API_BASE_URLS,
|
|
60
61
|
CONNECTED_CALL_STATES: () => CONNECTED_CALL_STATES,
|
|
62
|
+
CONVEX_URLS: () => CONVEX_URLS2,
|
|
61
63
|
DialpadCallState: () => DialpadCallState,
|
|
62
64
|
RINGING_CALL_STATES: () => RINGING_CALL_STATES,
|
|
63
65
|
TERMINAL_CALL_STATES: () => TERMINAL_CALL_STATES,
|
|
64
66
|
TruthProvider: () => TruthProvider,
|
|
65
67
|
TruthTrackingProvider: () => TruthTrackingProvider,
|
|
68
|
+
getTruthClient: () => getTruthClient,
|
|
69
|
+
resolveApiBaseUrl: () => resolveApiBaseUrl,
|
|
70
|
+
resolveConvexUrl: () => resolveConvexUrl,
|
|
66
71
|
useActiveCalls: () => useActiveCalls,
|
|
67
72
|
useAppointment: () => useAppointment,
|
|
68
73
|
useAppointmentByElationId: () => useAppointmentByElationId,
|
|
@@ -82,6 +87,7 @@ __export(react_exports, {
|
|
|
82
87
|
useDialpadCallsForConversation: () => useDialpadCallsForConversation,
|
|
83
88
|
useMessages: () => useMessages,
|
|
84
89
|
useNotifications: () => useNotifications,
|
|
90
|
+
useNotificationsActions: () => useNotificationsActions,
|
|
85
91
|
usePatient: () => usePatient,
|
|
86
92
|
usePatientBasic: () => usePatientBasic,
|
|
87
93
|
usePatientByElationId: () => usePatientByElationId,
|
|
@@ -98,9 +104,12 @@ __export(react_exports, {
|
|
|
98
104
|
usePhysiciansByElationIds: () => usePhysiciansByElationIds,
|
|
99
105
|
useRemindersForConversations: () => useRemindersForConversations,
|
|
100
106
|
useTruth: () => useTruth,
|
|
107
|
+
useTruthClient: () => useTruthClient,
|
|
108
|
+
useTruthSdkContext: () => useTruthSdkContext,
|
|
101
109
|
useUnreadAggregate: () => useUnreadAggregate,
|
|
102
110
|
useUnreadCount: () => useUnreadCount,
|
|
103
111
|
useUserSettings: () => useUserSettings,
|
|
112
|
+
useUserSync: () => useUserSync,
|
|
104
113
|
useVoicemailUrl: () => useVoicemailUrl
|
|
105
114
|
});
|
|
106
115
|
module.exports = __toCommonJS(react_exports);
|
|
@@ -291,7 +300,7 @@ function useUnreadAggregate(userId, options) {
|
|
|
291
300
|
function useMemoizedPhones(phones) {
|
|
292
301
|
const key = phones ? [...phones].sort().join("|") : "";
|
|
293
302
|
return (0, import_react4.useMemo)(
|
|
294
|
-
() => phones
|
|
303
|
+
() => (phones == null ? void 0 : phones.length) ? [...phones].sort() : void 0,
|
|
295
304
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
296
305
|
[key]
|
|
297
306
|
);
|
|
@@ -338,87 +347,2172 @@ function useConversationTasksByPhonePair(phonePair) {
|
|
|
338
347
|
}
|
|
339
348
|
|
|
340
349
|
// src/react/hooks.ts
|
|
350
|
+
var import_react7 = require("convex/react");
|
|
351
|
+
var import_react8 = require("react");
|
|
352
|
+
|
|
353
|
+
// src/react/provider.ts
|
|
341
354
|
var import_react5 = require("convex/react");
|
|
342
355
|
var import_react6 = require("react");
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
var
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
var
|
|
349
|
-
|
|
350
|
-
|
|
356
|
+
|
|
357
|
+
// src/client.ts
|
|
358
|
+
var import_browser = require("convex/browser");
|
|
359
|
+
|
|
360
|
+
// src/resources/appointments.ts
|
|
361
|
+
var AppointmentResource = class {
|
|
362
|
+
constructor(convexClient) {
|
|
363
|
+
this.convex = convexClient;
|
|
364
|
+
}
|
|
365
|
+
/**
|
|
366
|
+
* Get an appointment by its Truth platform ID.
|
|
367
|
+
*/
|
|
368
|
+
get(id) {
|
|
369
|
+
return __async(this, null, function* () {
|
|
370
|
+
try {
|
|
371
|
+
const result = yield this.convex.query(
|
|
372
|
+
"appointments:getById",
|
|
373
|
+
{ id }
|
|
374
|
+
);
|
|
375
|
+
return result != null ? result : null;
|
|
376
|
+
} catch (e) {
|
|
377
|
+
return null;
|
|
378
|
+
}
|
|
379
|
+
});
|
|
380
|
+
}
|
|
381
|
+
/**
|
|
382
|
+
* List appointments with optional filters, pagination, and limit.
|
|
383
|
+
*/
|
|
384
|
+
list(options) {
|
|
385
|
+
return __async(this, null, function* () {
|
|
386
|
+
try {
|
|
387
|
+
const result = yield this.convex.query(
|
|
388
|
+
"appointments:list",
|
|
389
|
+
{
|
|
390
|
+
patientId: options == null ? void 0 : options.patientId,
|
|
391
|
+
startDate: options == null ? void 0 : options.startDate,
|
|
392
|
+
endDate: options == null ? void 0 : options.endDate,
|
|
393
|
+
status: options == null ? void 0 : options.status,
|
|
394
|
+
limit: options == null ? void 0 : options.limit,
|
|
395
|
+
cursor: options == null ? void 0 : options.cursor
|
|
396
|
+
}
|
|
397
|
+
);
|
|
398
|
+
const typed = result;
|
|
399
|
+
return typed != null ? typed : { data: [], cursor: null, hasMore: false };
|
|
400
|
+
} catch (e) {
|
|
401
|
+
return { data: [], cursor: null, hasMore: false };
|
|
402
|
+
}
|
|
403
|
+
});
|
|
404
|
+
}
|
|
405
|
+
};
|
|
406
|
+
|
|
407
|
+
// src/resources/attachments.ts
|
|
408
|
+
var AttachmentsError = class extends Error {
|
|
409
|
+
constructor(operation, status, message) {
|
|
410
|
+
super(message != null ? message : `Attachment ${operation} failed (HTTP ${status})`);
|
|
411
|
+
this.name = "AttachmentsError";
|
|
412
|
+
this.status = status;
|
|
413
|
+
}
|
|
414
|
+
};
|
|
415
|
+
var AttachmentsResource = class {
|
|
416
|
+
constructor(apiBaseUrl, apiKey, convexClient) {
|
|
417
|
+
this.baseUrl = apiBaseUrl;
|
|
418
|
+
this.apiKey = apiKey;
|
|
419
|
+
this.convex = convexClient;
|
|
420
|
+
}
|
|
421
|
+
post(path, body) {
|
|
422
|
+
return __async(this, null, function* () {
|
|
423
|
+
const res = yield fetch(`${this.baseUrl}/api${path}`, {
|
|
424
|
+
method: "POST",
|
|
425
|
+
headers: {
|
|
426
|
+
"Content-Type": "application/json",
|
|
427
|
+
Accept: "application/json",
|
|
428
|
+
"X-API-Key": this.apiKey
|
|
429
|
+
},
|
|
430
|
+
body: JSON.stringify(body)
|
|
431
|
+
});
|
|
432
|
+
if (!res.ok) {
|
|
433
|
+
const text = yield res.text().catch(() => "");
|
|
434
|
+
throw new AttachmentsError(path, res.status, text.slice(0, 200));
|
|
435
|
+
}
|
|
436
|
+
return yield res.json();
|
|
437
|
+
});
|
|
438
|
+
}
|
|
439
|
+
createUploadUrl(input) {
|
|
440
|
+
return __async(this, null, function* () {
|
|
441
|
+
return yield this.post(
|
|
442
|
+
"/attachments/upload-url",
|
|
443
|
+
input
|
|
444
|
+
);
|
|
445
|
+
});
|
|
446
|
+
}
|
|
447
|
+
getDownloadUrl(s3Key, expiresIn) {
|
|
448
|
+
return __async(this, null, function* () {
|
|
449
|
+
return yield this.post("/attachments/download-url", {
|
|
450
|
+
s3Key,
|
|
451
|
+
expiresIn
|
|
452
|
+
});
|
|
453
|
+
});
|
|
454
|
+
}
|
|
455
|
+
record(input) {
|
|
456
|
+
return __async(this, null, function* () {
|
|
457
|
+
return yield this.convex.mutation(
|
|
458
|
+
"attachments:record",
|
|
459
|
+
input
|
|
460
|
+
);
|
|
461
|
+
});
|
|
462
|
+
}
|
|
463
|
+
get(attachmentId) {
|
|
464
|
+
return __async(this, null, function* () {
|
|
465
|
+
try {
|
|
466
|
+
const row = yield this.convex.query(
|
|
467
|
+
"attachments:getById",
|
|
468
|
+
{ attachmentId }
|
|
469
|
+
);
|
|
470
|
+
return row != null ? row : null;
|
|
471
|
+
} catch (e) {
|
|
472
|
+
return null;
|
|
473
|
+
}
|
|
474
|
+
});
|
|
475
|
+
}
|
|
476
|
+
listByConversation(conversationId) {
|
|
477
|
+
return __async(this, null, function* () {
|
|
478
|
+
try {
|
|
479
|
+
const rows = yield this.convex.query(
|
|
480
|
+
"attachments:listByConversation",
|
|
481
|
+
{ conversationId }
|
|
482
|
+
);
|
|
483
|
+
return rows != null ? rows : [];
|
|
484
|
+
} catch (e) {
|
|
485
|
+
return [];
|
|
486
|
+
}
|
|
487
|
+
});
|
|
488
|
+
}
|
|
489
|
+
/**
|
|
490
|
+
* One-shot upload: presign → PUT to S3 → record in Convex → return a
|
|
491
|
+
* 7-day signed download URL ready to embed in an outbound SMS. Caller
|
|
492
|
+
* passes the resulting `downloadUrl` to `messages.dialpad.sendSms` (or
|
|
493
|
+
* the new `messages.sendAttachmentMessage`) to actually deliver it.
|
|
494
|
+
*
|
|
495
|
+
* Replaces CommHub's NestJS `/send-attachment` controller in a single
|
|
496
|
+
* SDK call — no base64 round-trip, no legacy `/attachments/:id/download`
|
|
497
|
+
* REST endpoint required.
|
|
498
|
+
*/
|
|
499
|
+
upload(input) {
|
|
500
|
+
return __async(this, null, function* () {
|
|
501
|
+
var _a;
|
|
502
|
+
const presigned = yield this.createUploadUrl({
|
|
503
|
+
fileName: input.fileName,
|
|
504
|
+
mimeType: input.mimeType,
|
|
505
|
+
size: input.size,
|
|
506
|
+
conversationId: input.conversationId
|
|
507
|
+
});
|
|
508
|
+
const body = input.file instanceof Blob ? input.file : input.file instanceof Uint8Array ? input.file : new Uint8Array(input.file);
|
|
509
|
+
const abort = new AbortController();
|
|
510
|
+
const timer = setTimeout(() => abort.abort(), 3e4);
|
|
511
|
+
let putRes;
|
|
512
|
+
try {
|
|
513
|
+
putRes = yield fetch(presigned.uploadUrl, {
|
|
514
|
+
method: "PUT",
|
|
515
|
+
headers: { "Content-Type": input.mimeType },
|
|
516
|
+
body,
|
|
517
|
+
signal: abort.signal
|
|
518
|
+
});
|
|
519
|
+
} catch (err) {
|
|
520
|
+
const isAbort = err instanceof Error && (err.name === "AbortError" || err.name === "TimeoutError");
|
|
521
|
+
if (isAbort) {
|
|
522
|
+
throw new AttachmentsError(
|
|
523
|
+
"s3-put",
|
|
524
|
+
0,
|
|
525
|
+
"S3 upload timed out after 30s"
|
|
526
|
+
);
|
|
527
|
+
}
|
|
528
|
+
throw err;
|
|
529
|
+
} finally {
|
|
530
|
+
clearTimeout(timer);
|
|
531
|
+
}
|
|
532
|
+
if (!putRes.ok) {
|
|
533
|
+
throw new AttachmentsError(
|
|
534
|
+
"s3-put",
|
|
535
|
+
putRes.status,
|
|
536
|
+
`S3 PUT ${putRes.status} for ${presigned.s3Key}`
|
|
537
|
+
);
|
|
538
|
+
}
|
|
539
|
+
const recorded = yield this.record({
|
|
540
|
+
s3Key: presigned.s3Key,
|
|
541
|
+
fileName: input.fileName,
|
|
542
|
+
mimeType: input.mimeType,
|
|
543
|
+
size: input.size,
|
|
544
|
+
conversationId: input.conversationId,
|
|
545
|
+
uploadedBy: input.uploadedBy
|
|
546
|
+
});
|
|
547
|
+
const signed = yield this.getDownloadUrl(
|
|
548
|
+
presigned.s3Key,
|
|
549
|
+
(_a = input.downloadExpiresIn) != null ? _a : 7 * 24 * 3600
|
|
550
|
+
);
|
|
551
|
+
return {
|
|
552
|
+
attachmentId: recorded.attachmentId,
|
|
553
|
+
s3Key: presigned.s3Key,
|
|
554
|
+
downloadUrl: signed.url
|
|
555
|
+
};
|
|
556
|
+
});
|
|
557
|
+
}
|
|
558
|
+
};
|
|
559
|
+
|
|
560
|
+
// src/resources/conversations.ts
|
|
561
|
+
var ConversationsError = class extends Error {
|
|
562
|
+
constructor(operation, status, message) {
|
|
563
|
+
super(message != null ? message : `Conversations ${operation} failed (HTTP ${status})`);
|
|
564
|
+
this.name = "ConversationsError";
|
|
565
|
+
this.status = status;
|
|
566
|
+
}
|
|
567
|
+
};
|
|
568
|
+
function assertConversationAddress(operation, input) {
|
|
569
|
+
if (!input.conversationId && !input.phonePair) {
|
|
570
|
+
throw new ConversationsError(
|
|
571
|
+
operation,
|
|
572
|
+
0,
|
|
573
|
+
"Either `conversationId` or `phonePair` is required"
|
|
574
|
+
);
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
var ConversationNotesSubresource = class {
|
|
578
|
+
constructor(post) {
|
|
579
|
+
this.post = post;
|
|
580
|
+
}
|
|
581
|
+
/** Create a note on a conversation (addressed by id or phonePair). */
|
|
582
|
+
create(input) {
|
|
583
|
+
return __async(this, null, function* () {
|
|
584
|
+
assertConversationAddress("notes.create", input);
|
|
585
|
+
return this.post("/conversations/notes", input);
|
|
586
|
+
});
|
|
587
|
+
}
|
|
588
|
+
};
|
|
589
|
+
var ConversationTasksSubresource = class {
|
|
590
|
+
constructor(post, patch) {
|
|
591
|
+
this.post = post;
|
|
592
|
+
this.patch = patch;
|
|
593
|
+
}
|
|
594
|
+
/** Create a task on a conversation. */
|
|
595
|
+
create(input) {
|
|
596
|
+
return __async(this, null, function* () {
|
|
597
|
+
assertConversationAddress("tasks.create", input);
|
|
598
|
+
return this.post("/conversations/tasks", input);
|
|
599
|
+
});
|
|
600
|
+
}
|
|
601
|
+
/** Mark a task pending or completed. */
|
|
602
|
+
setStatus(input) {
|
|
603
|
+
return __async(this, null, function* () {
|
|
604
|
+
return this.post(
|
|
605
|
+
`/conversations/tasks/${encodeURIComponent(input.taskId)}/status`,
|
|
606
|
+
__spreadValues({
|
|
607
|
+
id: input.taskId,
|
|
608
|
+
status: input.status
|
|
609
|
+
}, input.resolvedBy ? { resolvedBy: input.resolvedBy } : {})
|
|
610
|
+
);
|
|
611
|
+
});
|
|
612
|
+
}
|
|
613
|
+
/**
|
|
614
|
+
* Update task fields (priority, assignee, description, type). Wraps
|
|
615
|
+
* `PATCH /api/conversations/tasks/{id}` so CommHub doesn't have to
|
|
616
|
+
* direct-fetch for non-status field edits.
|
|
617
|
+
*/
|
|
618
|
+
update(input) {
|
|
619
|
+
return __async(this, null, function* () {
|
|
620
|
+
return this.patch(
|
|
621
|
+
`/conversations/tasks/${encodeURIComponent(input.taskId)}`,
|
|
622
|
+
__spreadValues(__spreadValues(__spreadValues(__spreadValues({
|
|
623
|
+
id: input.taskId,
|
|
624
|
+
conversationId: input.conversationId,
|
|
625
|
+
author: input.author,
|
|
626
|
+
description: input.description
|
|
627
|
+
}, input.priority ? { priority: input.priority } : {}), input.status ? { status: input.status } : {}), input.assignee !== void 0 ? { assignee: input.assignee } : {}), input.type !== void 0 ? { type: input.type } : {})
|
|
628
|
+
);
|
|
629
|
+
});
|
|
630
|
+
}
|
|
631
|
+
};
|
|
632
|
+
var ConversationMessagesSubresource = class {
|
|
633
|
+
constructor(post) {
|
|
634
|
+
this.post = post;
|
|
635
|
+
}
|
|
636
|
+
/**
|
|
637
|
+
* Send an outbound SMS / MMS via the typed `sendMessage` oRPC procedure.
|
|
638
|
+
*
|
|
639
|
+
* Prefer this over the generic Dialpad proxy (`messages.dialpad.sendSms`)
|
|
640
|
+
* — this hits the validated Truth route and consistently surfaces
|
|
641
|
+
* `ConversationsError` on failure.
|
|
642
|
+
*/
|
|
643
|
+
send(input) {
|
|
644
|
+
return __async(this, null, function* () {
|
|
645
|
+
if (!input.message && !input.media) {
|
|
646
|
+
throw new ConversationsError(
|
|
647
|
+
"messages.send",
|
|
648
|
+
0,
|
|
649
|
+
"send requires `message` or `media`"
|
|
650
|
+
);
|
|
651
|
+
}
|
|
652
|
+
return this.post(
|
|
653
|
+
"/conversations/messages",
|
|
654
|
+
input
|
|
655
|
+
);
|
|
656
|
+
});
|
|
657
|
+
}
|
|
658
|
+
};
|
|
659
|
+
var _ConversationsResource = class _ConversationsResource {
|
|
660
|
+
constructor(apiBaseUrl, apiKey, convex) {
|
|
661
|
+
this.baseUrl = apiBaseUrl;
|
|
662
|
+
this.apiKey = apiKey;
|
|
663
|
+
this.convex = convex != null ? convex : null;
|
|
664
|
+
const post = (path, body) => this.postRequest(path, body);
|
|
665
|
+
const patch = (path, body) => this.patchRequest(path, body);
|
|
666
|
+
this.notes = new ConversationNotesSubresource(post);
|
|
667
|
+
this.tasks = new ConversationTasksSubresource(post, patch);
|
|
668
|
+
this.messages = new ConversationMessagesSubresource(post);
|
|
669
|
+
}
|
|
670
|
+
/**
|
|
671
|
+
* Mark a conversation read for the calling user (zeroes unreadCount,
|
|
672
|
+
* stamps `lastReadAt`). Calls the public Convex `markRead` mutation
|
|
673
|
+
* which enforces self-tenancy on the auth identity.
|
|
674
|
+
*/
|
|
675
|
+
markRead(input) {
|
|
676
|
+
return __async(this, null, function* () {
|
|
677
|
+
if (!this.convex) {
|
|
678
|
+
throw new ConversationsError(
|
|
679
|
+
"/markRead",
|
|
680
|
+
0,
|
|
681
|
+
"ConversationsResource missing Convex client"
|
|
682
|
+
);
|
|
683
|
+
}
|
|
684
|
+
return yield this.convex.mutation(
|
|
685
|
+
"conversations:markRead",
|
|
686
|
+
input
|
|
687
|
+
);
|
|
688
|
+
});
|
|
689
|
+
}
|
|
690
|
+
/**
|
|
691
|
+
* Mark a conversation unread for the calling user (sets unreadCount=1).
|
|
692
|
+
*/
|
|
693
|
+
markUnread(input) {
|
|
694
|
+
return __async(this, null, function* () {
|
|
695
|
+
if (!this.convex) {
|
|
696
|
+
throw new ConversationsError(
|
|
697
|
+
"/markUnread",
|
|
698
|
+
0,
|
|
699
|
+
"ConversationsResource missing Convex client"
|
|
700
|
+
);
|
|
701
|
+
}
|
|
702
|
+
return yield this.convex.mutation(
|
|
703
|
+
"conversations:markUnread",
|
|
704
|
+
input
|
|
705
|
+
);
|
|
706
|
+
});
|
|
707
|
+
}
|
|
708
|
+
/**
|
|
709
|
+
* Zero unread on every conversation the user has reads for, except
|
|
710
|
+
* those whose `providerPhone` is in `excludedProviderPhones`.
|
|
711
|
+
*/
|
|
712
|
+
clearAllUnread(input) {
|
|
713
|
+
return __async(this, null, function* () {
|
|
714
|
+
if (!this.convex) {
|
|
715
|
+
throw new ConversationsError(
|
|
716
|
+
"/clearAllUnread",
|
|
717
|
+
0,
|
|
718
|
+
"ConversationsResource missing Convex client"
|
|
719
|
+
);
|
|
720
|
+
}
|
|
721
|
+
return yield this.convex.mutation(
|
|
722
|
+
"conversations:clearAllUnread",
|
|
723
|
+
input
|
|
724
|
+
);
|
|
725
|
+
});
|
|
726
|
+
}
|
|
727
|
+
postRequest(path, body) {
|
|
728
|
+
return __async(this, null, function* () {
|
|
729
|
+
if (!this.apiKey) {
|
|
730
|
+
throw new ConversationsError(
|
|
731
|
+
path,
|
|
732
|
+
0,
|
|
733
|
+
"Truth API key not configured \u2014 request blocked"
|
|
734
|
+
);
|
|
735
|
+
}
|
|
736
|
+
const controller = new AbortController();
|
|
737
|
+
const timeout = setTimeout(
|
|
738
|
+
() => controller.abort(),
|
|
739
|
+
_ConversationsResource.REQUEST_TIMEOUT_MS
|
|
740
|
+
);
|
|
741
|
+
let res;
|
|
742
|
+
try {
|
|
743
|
+
res = yield fetch(`${this.baseUrl}/api${path}`, {
|
|
744
|
+
method: "POST",
|
|
745
|
+
headers: {
|
|
746
|
+
"Content-Type": "application/json",
|
|
747
|
+
Accept: "application/json",
|
|
748
|
+
"X-API-Key": this.apiKey
|
|
749
|
+
},
|
|
750
|
+
body: JSON.stringify(body),
|
|
751
|
+
signal: controller.signal
|
|
752
|
+
});
|
|
753
|
+
} catch (err) {
|
|
754
|
+
const isAbort = err instanceof Error && (err.name === "AbortError" || err.name === "TimeoutError");
|
|
755
|
+
const message = isAbort ? `Conversations ${path} timed out after ${_ConversationsResource.REQUEST_TIMEOUT_MS}ms` : err instanceof Error ? err.message : "Conversations request failed before response";
|
|
756
|
+
throw new ConversationsError(path, 0, message);
|
|
757
|
+
} finally {
|
|
758
|
+
clearTimeout(timeout);
|
|
759
|
+
}
|
|
760
|
+
if (!res.ok) {
|
|
761
|
+
const text = yield res.text().catch(() => "");
|
|
762
|
+
throw new ConversationsError(path, res.status, text.slice(0, 200));
|
|
763
|
+
}
|
|
764
|
+
return yield res.json();
|
|
765
|
+
});
|
|
766
|
+
}
|
|
767
|
+
/**
|
|
768
|
+
* PATCH variant of `postRequest`. Mirrors the timeout + API-key
|
|
769
|
+
* handling so callers like `tasks.update()` don't need to roll their
|
|
770
|
+
* own fetch. The Truth task router treats unknown methods as 405, so
|
|
771
|
+
* a dedicated PATCH path is required.
|
|
772
|
+
*/
|
|
773
|
+
patchRequest(path, body) {
|
|
774
|
+
return __async(this, null, function* () {
|
|
775
|
+
if (!this.apiKey) {
|
|
776
|
+
throw new ConversationsError(
|
|
777
|
+
path,
|
|
778
|
+
0,
|
|
779
|
+
"Truth API key not configured \u2014 request blocked"
|
|
780
|
+
);
|
|
781
|
+
}
|
|
782
|
+
const controller = new AbortController();
|
|
783
|
+
const timeout = setTimeout(
|
|
784
|
+
() => controller.abort(),
|
|
785
|
+
_ConversationsResource.REQUEST_TIMEOUT_MS
|
|
786
|
+
);
|
|
787
|
+
let res;
|
|
788
|
+
try {
|
|
789
|
+
res = yield fetch(`${this.baseUrl}/api${path}`, {
|
|
790
|
+
method: "PATCH",
|
|
791
|
+
headers: {
|
|
792
|
+
"Content-Type": "application/json",
|
|
793
|
+
Accept: "application/json",
|
|
794
|
+
"X-API-Key": this.apiKey
|
|
795
|
+
},
|
|
796
|
+
body: JSON.stringify(body),
|
|
797
|
+
signal: controller.signal
|
|
798
|
+
});
|
|
799
|
+
} catch (err) {
|
|
800
|
+
const isAbort = err instanceof Error && (err.name === "AbortError" || err.name === "TimeoutError");
|
|
801
|
+
const message = isAbort ? `Conversations ${path} timed out after ${_ConversationsResource.REQUEST_TIMEOUT_MS}ms` : err instanceof Error ? err.message : String(err);
|
|
802
|
+
throw new ConversationsError(path, 0, message);
|
|
803
|
+
} finally {
|
|
804
|
+
clearTimeout(timeout);
|
|
805
|
+
}
|
|
806
|
+
if (!res.ok) {
|
|
807
|
+
const text = yield res.text().catch(() => "");
|
|
808
|
+
throw new ConversationsError(
|
|
809
|
+
path,
|
|
810
|
+
res.status,
|
|
811
|
+
`Conversations ${path} failed: ${text.slice(0, 200)}`
|
|
812
|
+
);
|
|
813
|
+
}
|
|
814
|
+
return yield res.json();
|
|
815
|
+
});
|
|
816
|
+
}
|
|
817
|
+
};
|
|
818
|
+
/** 30s upstream timeout — matches NotesResource for consistency. */
|
|
819
|
+
_ConversationsResource.REQUEST_TIMEOUT_MS = 3e4;
|
|
820
|
+
var ConversationsResource = _ConversationsResource;
|
|
821
|
+
|
|
822
|
+
// src/resources/dialpad.ts
|
|
823
|
+
var DialpadResource = class {
|
|
824
|
+
constructor(apiBaseUrl, apiKey) {
|
|
825
|
+
this.baseUrl = apiBaseUrl;
|
|
826
|
+
this.apiKey = apiKey;
|
|
827
|
+
}
|
|
828
|
+
/**
|
|
829
|
+
* Send an SMS or MMS message via Dialpad.
|
|
830
|
+
*/
|
|
831
|
+
sendSms(params) {
|
|
832
|
+
return __async(this, null, function* () {
|
|
833
|
+
const body = __spreadValues(__spreadValues({
|
|
834
|
+
to_numbers: [params.to_number],
|
|
835
|
+
from_number: params.from_number,
|
|
836
|
+
infer_country_code: false
|
|
837
|
+
}, params.message ? { text: params.message } : {}), params.media ? { media: params.media } : {});
|
|
838
|
+
return this.post("/sms", body);
|
|
839
|
+
});
|
|
840
|
+
}
|
|
841
|
+
/**
|
|
842
|
+
* Initiate an outbound call from a Dialpad user to a phone number.
|
|
843
|
+
*/
|
|
844
|
+
initiateCall(userId, phoneNumber) {
|
|
845
|
+
return __async(this, null, function* () {
|
|
846
|
+
return this.post(`/users/${userId}/initiate_call`, {
|
|
847
|
+
phone_number: phoneNumber
|
|
848
|
+
});
|
|
849
|
+
});
|
|
850
|
+
}
|
|
851
|
+
/**
|
|
852
|
+
* Hang up an active call.
|
|
853
|
+
*/
|
|
854
|
+
hangupCall(callId) {
|
|
855
|
+
return __async(this, null, function* () {
|
|
856
|
+
yield this.put(`/call/${callId}/actions/hangup`);
|
|
857
|
+
});
|
|
858
|
+
}
|
|
859
|
+
/**
|
|
860
|
+
* Alias for `hangupCall` — mirrors the CommHub `endCall` action name so
|
|
861
|
+
* the SDK swap is a direct rename.
|
|
862
|
+
*/
|
|
863
|
+
endCall(callId) {
|
|
864
|
+
return __async(this, null, function* () {
|
|
865
|
+
yield this.hangupCall(callId);
|
|
866
|
+
});
|
|
867
|
+
}
|
|
868
|
+
/**
|
|
869
|
+
* Send an MMS with a pre-uploaded attachment. Takes the S3 key returned
|
|
870
|
+
* by `client.attachments.createUploadUrl(...)` + PUT, fetches a short-
|
|
871
|
+
* lived download URL, and hands it to Dialpad as `media[]`.
|
|
872
|
+
*
|
|
873
|
+
* Replaces CommHub's `sendAttachment` Hasura Action (which stored bytes
|
|
874
|
+
* as base64 in Postgres and served them through a GET endpoint).
|
|
875
|
+
*/
|
|
876
|
+
sendAttachmentWithUrl(params) {
|
|
877
|
+
return __async(this, null, function* () {
|
|
878
|
+
return this.sendSms({
|
|
879
|
+
from_number: params.from_number,
|
|
880
|
+
to_number: params.to_number,
|
|
881
|
+
message: params.message,
|
|
882
|
+
media: [params.mediaUrl]
|
|
883
|
+
});
|
|
884
|
+
});
|
|
885
|
+
}
|
|
886
|
+
/**
|
|
887
|
+
* Get the status of a call.
|
|
888
|
+
*/
|
|
889
|
+
getCallStatus(callId) {
|
|
890
|
+
return __async(this, null, function* () {
|
|
891
|
+
try {
|
|
892
|
+
return yield this.get(`/call/${callId}`);
|
|
893
|
+
} catch (error) {
|
|
894
|
+
if (error instanceof DialpadProxyError && error.status === 404) {
|
|
895
|
+
return null;
|
|
896
|
+
}
|
|
897
|
+
throw error;
|
|
898
|
+
}
|
|
899
|
+
});
|
|
900
|
+
}
|
|
901
|
+
/**
|
|
902
|
+
* Get a Dialpad user by their user ID.
|
|
903
|
+
*/
|
|
904
|
+
getUser(userId) {
|
|
905
|
+
return __async(this, null, function* () {
|
|
906
|
+
try {
|
|
907
|
+
return yield this.get(`/users/${userId}`);
|
|
908
|
+
} catch (error) {
|
|
909
|
+
if (error instanceof DialpadProxyError && error.status === 404) {
|
|
910
|
+
return null;
|
|
911
|
+
}
|
|
912
|
+
throw error;
|
|
913
|
+
}
|
|
914
|
+
});
|
|
915
|
+
}
|
|
916
|
+
/**
|
|
917
|
+
* Find a Dialpad user by email.
|
|
918
|
+
*/
|
|
919
|
+
getUserByEmail(email) {
|
|
920
|
+
return __async(this, null, function* () {
|
|
921
|
+
var _a, _b;
|
|
922
|
+
const result = yield this.get("/users", {
|
|
923
|
+
email
|
|
924
|
+
});
|
|
925
|
+
return (_b = (_a = result.items) == null ? void 0 : _a[0]) != null ? _b : null;
|
|
926
|
+
});
|
|
927
|
+
}
|
|
928
|
+
/**
|
|
929
|
+
* Find a Dialpad user by phone number.
|
|
930
|
+
*/
|
|
931
|
+
getUserByPhoneNumber(phoneNumber) {
|
|
932
|
+
return __async(this, null, function* () {
|
|
933
|
+
var _a, _b;
|
|
934
|
+
const result = yield this.get("/users", {
|
|
935
|
+
number: phoneNumber
|
|
936
|
+
});
|
|
937
|
+
return (_b = (_a = result.items) == null ? void 0 : _a[0]) != null ? _b : null;
|
|
938
|
+
});
|
|
939
|
+
}
|
|
940
|
+
/**
|
|
941
|
+
* Get information about a Dialpad phone number.
|
|
942
|
+
*/
|
|
943
|
+
getNumberInfo(phoneNumber) {
|
|
944
|
+
return __async(this, null, function* () {
|
|
945
|
+
try {
|
|
946
|
+
const cleanNumber = phoneNumber.replace(/[^\d+]/g, "");
|
|
947
|
+
return yield this.get(
|
|
948
|
+
`/numbers/${encodeURIComponent(cleanNumber)}`
|
|
949
|
+
);
|
|
950
|
+
} catch (error) {
|
|
951
|
+
if (error instanceof DialpadProxyError && error.status === 404) {
|
|
952
|
+
return null;
|
|
953
|
+
}
|
|
954
|
+
throw error;
|
|
955
|
+
}
|
|
956
|
+
});
|
|
957
|
+
}
|
|
958
|
+
/**
|
|
959
|
+
* Authenticate a voicemail download URL. Truth appends the Dialpad API key,
|
|
960
|
+
* follows redirects, and returns the clean URL for client-side playback.
|
|
961
|
+
*/
|
|
962
|
+
authenticateVoicemail(voicemailLink) {
|
|
963
|
+
return __async(this, null, function* () {
|
|
964
|
+
const url = `${this.baseUrl}/api/messages/dialpad/voicemail/authenticate`;
|
|
965
|
+
const response = yield fetch(url, {
|
|
966
|
+
method: "POST",
|
|
967
|
+
headers: {
|
|
968
|
+
"Content-Type": "application/json",
|
|
969
|
+
"X-API-Key": this.apiKey
|
|
970
|
+
},
|
|
971
|
+
body: JSON.stringify({ voicemail_link: voicemailLink })
|
|
972
|
+
});
|
|
973
|
+
const result = yield response.json();
|
|
974
|
+
if (!response.ok || !result.success) {
|
|
975
|
+
return null;
|
|
976
|
+
}
|
|
977
|
+
return result.authenticated_url;
|
|
978
|
+
});
|
|
979
|
+
}
|
|
980
|
+
// -----------------------------------------------------------------------
|
|
981
|
+
// Internal HTTP helpers
|
|
982
|
+
// -----------------------------------------------------------------------
|
|
983
|
+
get(path, params) {
|
|
984
|
+
return __async(this, null, function* () {
|
|
985
|
+
const url = new URL(`/api/messages/dialpad${path}`, this.baseUrl);
|
|
986
|
+
if (params) {
|
|
987
|
+
for (const [key, value] of Object.entries(params)) {
|
|
988
|
+
if (value !== void 0) {
|
|
989
|
+
url.searchParams.set(key, String(value));
|
|
990
|
+
}
|
|
991
|
+
}
|
|
992
|
+
}
|
|
993
|
+
const response = yield fetch(url.toString(), {
|
|
994
|
+
method: "GET",
|
|
995
|
+
headers: {
|
|
996
|
+
Accept: "application/json",
|
|
997
|
+
"X-API-Key": this.apiKey
|
|
998
|
+
}
|
|
999
|
+
});
|
|
1000
|
+
if (!response.ok) {
|
|
1001
|
+
throw new DialpadProxyError("GET", path, response.status);
|
|
1002
|
+
}
|
|
1003
|
+
return yield response.json();
|
|
1004
|
+
});
|
|
1005
|
+
}
|
|
1006
|
+
post(path, body) {
|
|
1007
|
+
return __async(this, null, function* () {
|
|
1008
|
+
const url = `${this.baseUrl}/api/messages/dialpad${path}`;
|
|
1009
|
+
const response = yield fetch(url, {
|
|
1010
|
+
method: "POST",
|
|
1011
|
+
headers: {
|
|
1012
|
+
"Content-Type": "application/json",
|
|
1013
|
+
Accept: "application/json",
|
|
1014
|
+
"X-API-Key": this.apiKey
|
|
1015
|
+
},
|
|
1016
|
+
body: body !== void 0 ? JSON.stringify(body) : void 0
|
|
1017
|
+
});
|
|
1018
|
+
if (!response.ok) {
|
|
1019
|
+
throw new DialpadProxyError("POST", path, response.status);
|
|
1020
|
+
}
|
|
1021
|
+
return yield response.json();
|
|
1022
|
+
});
|
|
1023
|
+
}
|
|
1024
|
+
put(path, body) {
|
|
1025
|
+
return __async(this, null, function* () {
|
|
1026
|
+
var _a;
|
|
1027
|
+
const url = `${this.baseUrl}/api/messages/dialpad${path}`;
|
|
1028
|
+
const response = yield fetch(url, {
|
|
1029
|
+
method: "PUT",
|
|
1030
|
+
headers: {
|
|
1031
|
+
"Content-Type": "application/json",
|
|
1032
|
+
Accept: "application/json",
|
|
1033
|
+
"X-API-Key": this.apiKey
|
|
1034
|
+
},
|
|
1035
|
+
body: body !== void 0 ? JSON.stringify(body) : void 0
|
|
1036
|
+
});
|
|
1037
|
+
if (!response.ok) {
|
|
1038
|
+
throw new DialpadProxyError("PUT", path, response.status);
|
|
1039
|
+
}
|
|
1040
|
+
if ((_a = response.headers.get("content-type")) == null ? void 0 : _a.includes("json")) {
|
|
1041
|
+
return yield response.json();
|
|
1042
|
+
}
|
|
1043
|
+
return void 0;
|
|
1044
|
+
});
|
|
1045
|
+
}
|
|
1046
|
+
};
|
|
1047
|
+
var MessagesResource = class {
|
|
1048
|
+
constructor(apiBaseUrl, apiKey) {
|
|
1049
|
+
this.dialpad = new DialpadResource(apiBaseUrl, apiKey);
|
|
1050
|
+
this.baseUrl = apiBaseUrl;
|
|
1051
|
+
this.apiKey = apiKey;
|
|
1052
|
+
}
|
|
1053
|
+
/**
|
|
1054
|
+
* Get an authenticated URL for a Dialpad voicemail recording.
|
|
1055
|
+
*
|
|
1056
|
+
* Replaces CommHub's `getAuthenticatedVoicemailUrl` Hasura mutation
|
|
1057
|
+
* (which proxied to the legacy NestJS backend). Truth appends the
|
|
1058
|
+
* Dialpad API key, follows redirects, strips the key from the final
|
|
1059
|
+
* URL, and returns it for client-side audio playback.
|
|
1060
|
+
*
|
|
1061
|
+
* @param voicemailLink The raw Dialpad voicemail download URL (value
|
|
1062
|
+
* of the `voicemail_link` field on the call event row).
|
|
1063
|
+
* @returns An object with `url` (clean playback URL) and `expiresAt`
|
|
1064
|
+
* (ISO-8601 timestamp, ~5 min from request time, informational only).
|
|
1065
|
+
*/
|
|
1066
|
+
getVoicemailUrl(voicemailLink) {
|
|
1067
|
+
return __async(this, null, function* () {
|
|
1068
|
+
const res = yield fetch(`${this.baseUrl}/api/conversations/voicemail/url`, {
|
|
1069
|
+
method: "POST",
|
|
1070
|
+
headers: {
|
|
1071
|
+
"Content-Type": "application/json",
|
|
1072
|
+
Accept: "application/json",
|
|
1073
|
+
"X-API-Key": this.apiKey
|
|
1074
|
+
},
|
|
1075
|
+
body: JSON.stringify({ voicemailLink })
|
|
1076
|
+
});
|
|
1077
|
+
if (!res.ok) {
|
|
1078
|
+
const text = yield res.text().catch(() => "");
|
|
1079
|
+
throw new Error(
|
|
1080
|
+
`messages.getVoicemailUrl failed (HTTP ${res.status}): ${text.slice(0, 200)}`
|
|
1081
|
+
);
|
|
1082
|
+
}
|
|
1083
|
+
return yield res.json();
|
|
1084
|
+
});
|
|
1085
|
+
}
|
|
1086
|
+
/**
|
|
1087
|
+
* End a Dialpad call via the typed oRPC procedure (POST hangup, with
|
|
1088
|
+
* 404→`alreadyEnded` so the UI doesn't flash an error on a natural
|
|
1089
|
+
* race). Replaces CommHub's `useEndCallMutation` Hasura action.
|
|
1090
|
+
*
|
|
1091
|
+
* Prefer this over `messages.dialpad.endCall` which goes through the
|
|
1092
|
+
* generic proxy (PUT, no 404 handling).
|
|
1093
|
+
*/
|
|
1094
|
+
endCall(callId) {
|
|
1095
|
+
return __async(this, null, function* () {
|
|
1096
|
+
const res = yield fetch(`${this.baseUrl}/api/conversations/calls/end`, {
|
|
1097
|
+
method: "POST",
|
|
1098
|
+
headers: {
|
|
1099
|
+
"Content-Type": "application/json",
|
|
1100
|
+
Accept: "application/json",
|
|
1101
|
+
"X-API-Key": this.apiKey
|
|
1102
|
+
},
|
|
1103
|
+
body: JSON.stringify({ callId })
|
|
1104
|
+
});
|
|
1105
|
+
if (!res.ok) {
|
|
1106
|
+
const text = yield res.text().catch(() => "");
|
|
1107
|
+
throw new Error(
|
|
1108
|
+
`messages.endCall failed (HTTP ${res.status}): ${text.slice(0, 200)}`
|
|
1109
|
+
);
|
|
1110
|
+
}
|
|
1111
|
+
return yield res.json();
|
|
1112
|
+
});
|
|
1113
|
+
}
|
|
1114
|
+
};
|
|
1115
|
+
var DialpadProxyError = class extends Error {
|
|
1116
|
+
constructor(method, path, status) {
|
|
1117
|
+
super(
|
|
1118
|
+
`Dialpad proxy error: ${method} /api/messages/dialpad${path} returned ${status}`
|
|
1119
|
+
);
|
|
1120
|
+
this.name = "DialpadProxyError";
|
|
1121
|
+
this.method = method;
|
|
1122
|
+
this.path = path;
|
|
1123
|
+
this.status = status;
|
|
1124
|
+
}
|
|
1125
|
+
};
|
|
1126
|
+
|
|
1127
|
+
// src/resources/ehr.ts
|
|
1128
|
+
var EhrProviderProxy = class {
|
|
1129
|
+
constructor(apiBaseUrl, provider) {
|
|
1130
|
+
this.baseUrl = apiBaseUrl;
|
|
1131
|
+
this.provider = provider;
|
|
1132
|
+
}
|
|
1133
|
+
/**
|
|
1134
|
+
* GET request to the EHR proxy.
|
|
1135
|
+
* @param path — path relative to the provider root (e.g., "/patients/123/")
|
|
1136
|
+
* @param params — optional query parameters
|
|
1137
|
+
*/
|
|
1138
|
+
get(path, params) {
|
|
1139
|
+
return __async(this, null, function* () {
|
|
1140
|
+
const url = new URL(`/api/ehr/${this.provider}${path}`, this.baseUrl);
|
|
1141
|
+
if (params) {
|
|
1142
|
+
for (const [key, value] of Object.entries(params)) {
|
|
1143
|
+
if (value !== void 0) {
|
|
1144
|
+
url.searchParams.set(key, String(value));
|
|
1145
|
+
}
|
|
1146
|
+
}
|
|
1147
|
+
}
|
|
1148
|
+
const response = yield fetch(url.toString(), {
|
|
1149
|
+
method: "GET",
|
|
1150
|
+
headers: { Accept: "application/json" }
|
|
1151
|
+
});
|
|
1152
|
+
if (!response.ok) {
|
|
1153
|
+
throw new EhrProxyError(this.provider, "GET", path, response.status);
|
|
1154
|
+
}
|
|
1155
|
+
return yield response.json();
|
|
1156
|
+
});
|
|
1157
|
+
}
|
|
1158
|
+
/**
|
|
1159
|
+
* POST request to the EHR proxy.
|
|
1160
|
+
*/
|
|
1161
|
+
post(path, body) {
|
|
1162
|
+
return __async(this, null, function* () {
|
|
1163
|
+
const url = `${this.baseUrl}/api/ehr/${this.provider}${path}`;
|
|
1164
|
+
const response = yield fetch(url, {
|
|
1165
|
+
method: "POST",
|
|
1166
|
+
headers: {
|
|
1167
|
+
"Content-Type": "application/json",
|
|
1168
|
+
Accept: "application/json"
|
|
1169
|
+
},
|
|
1170
|
+
body: body !== void 0 ? JSON.stringify(body) : void 0
|
|
1171
|
+
});
|
|
1172
|
+
if (!response.ok) {
|
|
1173
|
+
throw new EhrProxyError(this.provider, "POST", path, response.status);
|
|
1174
|
+
}
|
|
1175
|
+
return yield response.json();
|
|
1176
|
+
});
|
|
1177
|
+
}
|
|
1178
|
+
/**
|
|
1179
|
+
* PUT request to the EHR proxy.
|
|
1180
|
+
*/
|
|
1181
|
+
put(path, body) {
|
|
1182
|
+
return __async(this, null, function* () {
|
|
1183
|
+
const url = `${this.baseUrl}/api/ehr/${this.provider}${path}`;
|
|
1184
|
+
const response = yield fetch(url, {
|
|
1185
|
+
method: "PUT",
|
|
1186
|
+
headers: {
|
|
1187
|
+
"Content-Type": "application/json",
|
|
1188
|
+
Accept: "application/json"
|
|
1189
|
+
},
|
|
1190
|
+
body: body !== void 0 ? JSON.stringify(body) : void 0
|
|
1191
|
+
});
|
|
1192
|
+
if (!response.ok) {
|
|
1193
|
+
throw new EhrProxyError(this.provider, "PUT", path, response.status);
|
|
1194
|
+
}
|
|
1195
|
+
return yield response.json();
|
|
1196
|
+
});
|
|
1197
|
+
}
|
|
1198
|
+
/**
|
|
1199
|
+
* PATCH request to the EHR proxy.
|
|
1200
|
+
*/
|
|
1201
|
+
patch(path, body) {
|
|
1202
|
+
return __async(this, null, function* () {
|
|
1203
|
+
const url = `${this.baseUrl}/api/ehr/${this.provider}${path}`;
|
|
1204
|
+
const response = yield fetch(url, {
|
|
1205
|
+
method: "PATCH",
|
|
1206
|
+
headers: {
|
|
1207
|
+
"Content-Type": "application/json",
|
|
1208
|
+
Accept: "application/json"
|
|
1209
|
+
},
|
|
1210
|
+
body: body !== void 0 ? JSON.stringify(body) : void 0
|
|
1211
|
+
});
|
|
1212
|
+
if (!response.ok) {
|
|
1213
|
+
throw new EhrProxyError(this.provider, "PATCH", path, response.status);
|
|
1214
|
+
}
|
|
1215
|
+
return yield response.json();
|
|
1216
|
+
});
|
|
1217
|
+
}
|
|
1218
|
+
/**
|
|
1219
|
+
* DELETE request to the EHR proxy.
|
|
1220
|
+
*/
|
|
1221
|
+
delete(path) {
|
|
1222
|
+
return __async(this, null, function* () {
|
|
1223
|
+
const url = `${this.baseUrl}/api/ehr/${this.provider}${path}`;
|
|
1224
|
+
const response = yield fetch(url, {
|
|
1225
|
+
method: "DELETE",
|
|
1226
|
+
headers: { Accept: "application/json" }
|
|
1227
|
+
});
|
|
1228
|
+
if (!response.ok) {
|
|
1229
|
+
throw new EhrProxyError(this.provider, "DELETE", path, response.status);
|
|
1230
|
+
}
|
|
1231
|
+
return yield response.json();
|
|
1232
|
+
});
|
|
1233
|
+
}
|
|
1234
|
+
};
|
|
1235
|
+
var EhrResource = class {
|
|
1236
|
+
constructor(apiBaseUrl) {
|
|
1237
|
+
this.elation = new EhrProviderProxy(apiBaseUrl, "elation");
|
|
1238
|
+
this.hint = new EhrProviderProxy(apiBaseUrl, "hint");
|
|
1239
|
+
}
|
|
1240
|
+
};
|
|
1241
|
+
var EhrProxyError = class extends Error {
|
|
1242
|
+
constructor(provider, method, path, status) {
|
|
1243
|
+
super(
|
|
1244
|
+
`EHR proxy error: ${method} /api/ehr/${provider}${path} returned ${status}`
|
|
1245
|
+
);
|
|
1246
|
+
this.name = "EhrProxyError";
|
|
1247
|
+
this.provider = provider;
|
|
1248
|
+
this.method = method;
|
|
1249
|
+
this.path = path;
|
|
1250
|
+
this.status = status;
|
|
1251
|
+
}
|
|
1252
|
+
};
|
|
1253
|
+
|
|
1254
|
+
// src/resources/notes.ts
|
|
1255
|
+
var NotesError = class extends Error {
|
|
1256
|
+
constructor(operation, status, message) {
|
|
1257
|
+
super(message != null ? message : `Notes ${operation} failed (HTTP ${status})`);
|
|
1258
|
+
this.name = "NotesError";
|
|
1259
|
+
this.status = status;
|
|
1260
|
+
}
|
|
1261
|
+
};
|
|
1262
|
+
var _NotesResource = class _NotesResource {
|
|
1263
|
+
constructor(apiBaseUrl, apiKey) {
|
|
1264
|
+
this.baseUrl = apiBaseUrl;
|
|
1265
|
+
this.apiKey = apiKey;
|
|
1266
|
+
}
|
|
1267
|
+
post(path, body) {
|
|
1268
|
+
return __async(this, null, function* () {
|
|
1269
|
+
const controller = new AbortController();
|
|
1270
|
+
const timeout = setTimeout(
|
|
1271
|
+
() => controller.abort(),
|
|
1272
|
+
_NotesResource.REQUEST_TIMEOUT_MS
|
|
1273
|
+
);
|
|
1274
|
+
let res;
|
|
1275
|
+
try {
|
|
1276
|
+
res = yield fetch(`${this.baseUrl}/api${path}`, {
|
|
1277
|
+
method: "POST",
|
|
1278
|
+
headers: {
|
|
1279
|
+
"Content-Type": "application/json",
|
|
1280
|
+
Accept: "application/json",
|
|
1281
|
+
"X-API-Key": this.apiKey
|
|
1282
|
+
},
|
|
1283
|
+
body: JSON.stringify(body),
|
|
1284
|
+
signal: controller.signal
|
|
1285
|
+
});
|
|
1286
|
+
} catch (err) {
|
|
1287
|
+
const isAbort = err instanceof Error && (err.name === "AbortError" || err.name === "TimeoutError");
|
|
1288
|
+
const message = isAbort ? `Notes ${path} timed out after ${_NotesResource.REQUEST_TIMEOUT_MS}ms` : err instanceof Error ? err.message : "Notes request failed before response";
|
|
1289
|
+
throw new NotesError(path, 0, message);
|
|
1290
|
+
} finally {
|
|
1291
|
+
clearTimeout(timeout);
|
|
1292
|
+
}
|
|
1293
|
+
if (!res.ok) {
|
|
1294
|
+
const text = yield res.text().catch(() => "");
|
|
1295
|
+
throw new NotesError(path, res.status, text.slice(0, 200));
|
|
1296
|
+
}
|
|
1297
|
+
return yield res.json();
|
|
1298
|
+
});
|
|
1299
|
+
}
|
|
1300
|
+
/**
|
|
1301
|
+
* Low-level — caller has already resolved Elation patient / physician
|
|
1302
|
+
* / practice. Use `pushConversationToElation` if you only have a
|
|
1303
|
+
* conversation handle.
|
|
1304
|
+
*/
|
|
1305
|
+
pushToElation(input) {
|
|
1306
|
+
return __async(this, null, function* () {
|
|
1307
|
+
return yield this.post(
|
|
1308
|
+
"/notes/push-to-elation",
|
|
1309
|
+
input
|
|
1310
|
+
);
|
|
1311
|
+
});
|
|
1312
|
+
}
|
|
1313
|
+
/**
|
|
1314
|
+
* Orchestrator — pass a conversation handle + pre-assembled note text.
|
|
1315
|
+
* Truth resolves the linked patient via Convex, looks up
|
|
1316
|
+
* physician/practice in Elation, posts the note, and writes an audit
|
|
1317
|
+
* row to `elationSyncEvents`. Replaces CommHub's `pushNotesToElation`
|
|
1318
|
+
* Hasura action.
|
|
1319
|
+
*/
|
|
1320
|
+
pushConversationToElation(input) {
|
|
1321
|
+
return __async(this, null, function* () {
|
|
1322
|
+
return yield this.post(
|
|
1323
|
+
"/notes/push-conversation-to-elation",
|
|
1324
|
+
input
|
|
1325
|
+
);
|
|
1326
|
+
});
|
|
1327
|
+
}
|
|
1328
|
+
};
|
|
1329
|
+
/** 30s upstream timeout — Elation API has occasional slow hops; we
|
|
1330
|
+
* don't want a pending mutation to hold the UI thread indefinitely. */
|
|
1331
|
+
_NotesResource.REQUEST_TIMEOUT_MS = 3e4;
|
|
1332
|
+
var NotesResource = _NotesResource;
|
|
1333
|
+
|
|
1334
|
+
// src/resources/notifications.ts
|
|
1335
|
+
var NotificationsError = class extends Error {
|
|
1336
|
+
constructor(operation, status, message) {
|
|
1337
|
+
super(message != null ? message : `Notifications ${operation} failed (HTTP ${status})`);
|
|
1338
|
+
this.name = "NotificationsError";
|
|
1339
|
+
this.status = status;
|
|
1340
|
+
}
|
|
1341
|
+
};
|
|
1342
|
+
var NotificationsResource = class {
|
|
1343
|
+
constructor(apiBaseUrl, apiKey) {
|
|
1344
|
+
this.baseUrl = apiBaseUrl;
|
|
1345
|
+
this.apiKey = apiKey;
|
|
1346
|
+
}
|
|
1347
|
+
post(path, body) {
|
|
1348
|
+
return __async(this, null, function* () {
|
|
1349
|
+
const res = yield fetch(`${this.baseUrl}/api${path}`, {
|
|
1350
|
+
method: "POST",
|
|
1351
|
+
headers: {
|
|
1352
|
+
"Content-Type": "application/json",
|
|
1353
|
+
Accept: "application/json",
|
|
1354
|
+
"X-API-Key": this.apiKey
|
|
1355
|
+
},
|
|
1356
|
+
body: JSON.stringify(body)
|
|
1357
|
+
});
|
|
1358
|
+
if (!res.ok) {
|
|
1359
|
+
const text = yield res.text().catch(() => "");
|
|
1360
|
+
throw new NotificationsError(path, res.status, text.slice(0, 200));
|
|
1361
|
+
}
|
|
1362
|
+
return yield res.json();
|
|
1363
|
+
});
|
|
1364
|
+
}
|
|
1365
|
+
get(path, params) {
|
|
1366
|
+
return __async(this, null, function* () {
|
|
1367
|
+
const url = new URL(`${this.baseUrl}/api${path}`);
|
|
1368
|
+
for (const [k, v] of Object.entries(params)) {
|
|
1369
|
+
url.searchParams.set(k, v);
|
|
1370
|
+
}
|
|
1371
|
+
const res = yield fetch(url.toString(), {
|
|
1372
|
+
method: "GET",
|
|
1373
|
+
headers: {
|
|
1374
|
+
Accept: "application/json",
|
|
1375
|
+
"X-API-Key": this.apiKey
|
|
1376
|
+
}
|
|
1377
|
+
});
|
|
1378
|
+
if (!res.ok) {
|
|
1379
|
+
const text = yield res.text().catch(() => "");
|
|
1380
|
+
throw new NotificationsError(path, res.status, text.slice(0, 200));
|
|
1381
|
+
}
|
|
1382
|
+
return yield res.json();
|
|
1383
|
+
});
|
|
1384
|
+
}
|
|
1385
|
+
delete(path) {
|
|
1386
|
+
return __async(this, null, function* () {
|
|
1387
|
+
const res = yield fetch(`${this.baseUrl}/api${path}`, {
|
|
1388
|
+
method: "DELETE",
|
|
1389
|
+
headers: {
|
|
1390
|
+
Accept: "application/json",
|
|
1391
|
+
"X-API-Key": this.apiKey
|
|
1392
|
+
}
|
|
1393
|
+
});
|
|
1394
|
+
if (!res.ok) {
|
|
1395
|
+
const text = yield res.text().catch(() => "");
|
|
1396
|
+
throw new NotificationsError(path, res.status, text.slice(0, 200));
|
|
1397
|
+
}
|
|
1398
|
+
return yield res.json();
|
|
1399
|
+
});
|
|
1400
|
+
}
|
|
1401
|
+
/**
|
|
1402
|
+
* Register a device (or refresh its metadata) for push delivery.
|
|
1403
|
+
* Safe to call repeatedly — the server dedupes by native token.
|
|
1404
|
+
*/
|
|
1405
|
+
registerDevice(input) {
|
|
1406
|
+
return __async(this, null, function* () {
|
|
1407
|
+
return this.post("/notifications/devices/register", input);
|
|
1408
|
+
});
|
|
1409
|
+
}
|
|
1410
|
+
/** Revoke a device — on sign-out or when the OS reports an invalid token. */
|
|
1411
|
+
unregisterDevice(input) {
|
|
1412
|
+
return __async(this, null, function* () {
|
|
1413
|
+
return this.post("/notifications/devices/unregister", input);
|
|
1414
|
+
});
|
|
1415
|
+
}
|
|
1416
|
+
/**
|
|
1417
|
+
* Send a push notification to every active device belonging to
|
|
1418
|
+
* `userId`. Honors the user's notificationPreferences (quiet hours,
|
|
1419
|
+
* DND, channel off) before publishing.
|
|
1420
|
+
*/
|
|
1421
|
+
send(input) {
|
|
1422
|
+
return __async(this, null, function* () {
|
|
1423
|
+
return this.post("/notifications/send", input);
|
|
1424
|
+
});
|
|
1425
|
+
}
|
|
1426
|
+
/** Read a user's notification preferences. Returns defaults when no row exists. */
|
|
1427
|
+
getPreferences(userId) {
|
|
1428
|
+
return __async(this, null, function* () {
|
|
1429
|
+
return this.get("/notifications/preferences", { userId });
|
|
1430
|
+
});
|
|
1431
|
+
}
|
|
1432
|
+
updatePreferences(input) {
|
|
1433
|
+
return __async(this, null, function* () {
|
|
1434
|
+
return this.post("/notifications/preferences", input);
|
|
1435
|
+
});
|
|
1436
|
+
}
|
|
1437
|
+
/**
|
|
1438
|
+
* Schedule a future push notification. Convex's native scheduler
|
|
1439
|
+
* fires the send at `scheduledAt` and runs the same delivery
|
|
1440
|
+
* pipeline as `send()` (preferences, devices, history audit).
|
|
1441
|
+
*
|
|
1442
|
+
* Throws `NotificationsError` with status 400 if `scheduledAt` is
|
|
1443
|
+
* not strictly in the future.
|
|
1444
|
+
*/
|
|
1445
|
+
schedule(input) {
|
|
1446
|
+
return __async(this, null, function* () {
|
|
1447
|
+
return this.post("/notifications/schedule", input);
|
|
1448
|
+
});
|
|
1449
|
+
}
|
|
1450
|
+
/**
|
|
1451
|
+
* Cancel a pending scheduled notification. Returns `cancelled: false`
|
|
1452
|
+
* (no error) if the job has already executed, was previously
|
|
1453
|
+
* cancelled, or no longer exists — `reason` describes which case.
|
|
1454
|
+
*/
|
|
1455
|
+
cancelScheduled(jobId) {
|
|
1456
|
+
return __async(this, null, function* () {
|
|
1457
|
+
return this.delete(`/notifications/schedule/${encodeURIComponent(jobId)}`);
|
|
1458
|
+
});
|
|
1459
|
+
}
|
|
1460
|
+
/**
|
|
1461
|
+
* List scheduled notifications for a user — pending, executed,
|
|
1462
|
+
* cancelled, or failed. Most-recent first. Default limit 100.
|
|
1463
|
+
*/
|
|
1464
|
+
listScheduled(userId, options) {
|
|
1465
|
+
return __async(this, null, function* () {
|
|
1466
|
+
const params = { userId };
|
|
1467
|
+
if ((options == null ? void 0 : options.limit) !== void 0) {
|
|
1468
|
+
params.limit = String(options.limit);
|
|
1469
|
+
}
|
|
1470
|
+
return this.get("/notifications/schedule", params);
|
|
1471
|
+
});
|
|
1472
|
+
}
|
|
1473
|
+
getVapidKey() {
|
|
1474
|
+
return __async(this, null, function* () {
|
|
1475
|
+
try {
|
|
1476
|
+
const result = yield this.get(
|
|
1477
|
+
"/notifications/vapid-key",
|
|
1478
|
+
{}
|
|
1479
|
+
);
|
|
1480
|
+
return result.vapidPublicKey;
|
|
1481
|
+
} catch (e) {
|
|
1482
|
+
return null;
|
|
1483
|
+
}
|
|
1484
|
+
});
|
|
1485
|
+
}
|
|
1486
|
+
onPushReceived(callback) {
|
|
1487
|
+
if (typeof navigator === "undefined" || !("serviceWorker" in navigator)) {
|
|
1488
|
+
return () => {
|
|
1489
|
+
};
|
|
1490
|
+
}
|
|
1491
|
+
const handler = (event) => {
|
|
1492
|
+
var _a;
|
|
1493
|
+
if (((_a = event.data) == null ? void 0 : _a.type) === "TRUTH_PUSH_RECEIVED") {
|
|
1494
|
+
callback(event.data.payload);
|
|
1495
|
+
}
|
|
1496
|
+
};
|
|
1497
|
+
navigator.serviceWorker.addEventListener("message", handler);
|
|
1498
|
+
return () => navigator.serviceWorker.removeEventListener("message", handler);
|
|
1499
|
+
}
|
|
1500
|
+
onPushTapped(callback) {
|
|
1501
|
+
if (typeof navigator === "undefined" || !("serviceWorker" in navigator)) {
|
|
1502
|
+
return () => {
|
|
1503
|
+
};
|
|
1504
|
+
}
|
|
1505
|
+
const handler = (event) => {
|
|
1506
|
+
var _a;
|
|
1507
|
+
if (((_a = event.data) == null ? void 0 : _a.type) === "TRUTH_PUSH_TAPPED") {
|
|
1508
|
+
callback(event.data.payload);
|
|
1509
|
+
}
|
|
1510
|
+
};
|
|
1511
|
+
navigator.serviceWorker.addEventListener("message", handler);
|
|
1512
|
+
return () => navigator.serviceWorker.removeEventListener("message", handler);
|
|
1513
|
+
}
|
|
1514
|
+
};
|
|
1515
|
+
|
|
1516
|
+
// src/resources/patient-details.ts
|
|
1517
|
+
var PatientDetailsError = class extends Error {
|
|
1518
|
+
constructor(operation, status, message) {
|
|
1519
|
+
super(message != null ? message : `Patient ${operation} failed (HTTP ${status})`);
|
|
1520
|
+
this.name = "PatientDetailsError";
|
|
1521
|
+
this.status = status;
|
|
1522
|
+
}
|
|
1523
|
+
};
|
|
1524
|
+
var PatientDetailsResource = class {
|
|
1525
|
+
constructor(apiBaseUrl, apiKey) {
|
|
1526
|
+
this.baseUrl = apiBaseUrl;
|
|
1527
|
+
this.apiKey = apiKey;
|
|
1528
|
+
}
|
|
1529
|
+
post(path, body) {
|
|
1530
|
+
return __async(this, null, function* () {
|
|
1531
|
+
const res = yield fetch(`${this.baseUrl}/api${path}`, {
|
|
1532
|
+
method: "POST",
|
|
1533
|
+
headers: {
|
|
1534
|
+
"Content-Type": "application/json",
|
|
1535
|
+
Accept: "application/json",
|
|
1536
|
+
"X-API-Key": this.apiKey
|
|
1537
|
+
},
|
|
1538
|
+
body: JSON.stringify(body)
|
|
1539
|
+
});
|
|
1540
|
+
if (!res.ok) {
|
|
1541
|
+
const text = yield res.text().catch(() => "");
|
|
1542
|
+
throw new PatientDetailsError(path, res.status, text.slice(0, 200));
|
|
1543
|
+
}
|
|
1544
|
+
return yield res.json();
|
|
1545
|
+
});
|
|
1546
|
+
}
|
|
1547
|
+
get(input) {
|
|
1548
|
+
return __async(this, null, function* () {
|
|
1549
|
+
return yield this.post("/patients/details", input);
|
|
1550
|
+
});
|
|
1551
|
+
}
|
|
1552
|
+
getBasic(input) {
|
|
1553
|
+
return __async(this, null, function* () {
|
|
1554
|
+
return yield this.post(
|
|
1555
|
+
"/patients/details/basic",
|
|
1556
|
+
input
|
|
1557
|
+
);
|
|
1558
|
+
});
|
|
1559
|
+
}
|
|
1560
|
+
getMedical(elationId) {
|
|
1561
|
+
return __async(this, null, function* () {
|
|
1562
|
+
return yield this.post(
|
|
1563
|
+
"/patients/details/medical",
|
|
1564
|
+
{ elationId }
|
|
1565
|
+
);
|
|
1566
|
+
});
|
|
1567
|
+
}
|
|
1568
|
+
/**
|
|
1569
|
+
* Trigger a server-side refresh of the patient's Elation medical
|
|
1570
|
+
* records (medications, problems, allergies, appointments) into the
|
|
1571
|
+
* Convex cache. Fire-and-forget — the UI should read via the Convex-
|
|
1572
|
+
* reactive `usePatientMedical` hook.
|
|
1573
|
+
*/
|
|
1574
|
+
refreshMedical(elationId) {
|
|
1575
|
+
return __async(this, null, function* () {
|
|
1576
|
+
return yield this.post("/patients/medical/refresh", { elationId });
|
|
1577
|
+
});
|
|
1578
|
+
}
|
|
1579
|
+
};
|
|
1580
|
+
|
|
1581
|
+
// src/resources/patients.ts
|
|
1582
|
+
var PatientResource = class {
|
|
1583
|
+
constructor(convexClient) {
|
|
1584
|
+
this.convex = convexClient;
|
|
1585
|
+
}
|
|
1586
|
+
/**
|
|
1587
|
+
* Get a patient by their Truth platform ID.
|
|
1588
|
+
*/
|
|
1589
|
+
get(id) {
|
|
1590
|
+
return __async(this, null, function* () {
|
|
1591
|
+
try {
|
|
1592
|
+
const result = yield this.convex.query(
|
|
1593
|
+
"patients:getById",
|
|
1594
|
+
{
|
|
1595
|
+
id
|
|
1596
|
+
}
|
|
1597
|
+
);
|
|
1598
|
+
return result != null ? result : null;
|
|
1599
|
+
} catch (e) {
|
|
1600
|
+
return null;
|
|
1601
|
+
}
|
|
1602
|
+
});
|
|
1603
|
+
}
|
|
1604
|
+
/**
|
|
1605
|
+
* Get a patient by their Elation EHR ID.
|
|
1606
|
+
*/
|
|
1607
|
+
getByElationId(elationId) {
|
|
1608
|
+
return __async(this, null, function* () {
|
|
1609
|
+
try {
|
|
1610
|
+
const result = yield this.convex.query(
|
|
1611
|
+
"patients:getByElationId",
|
|
1612
|
+
{ elationId }
|
|
1613
|
+
);
|
|
1614
|
+
return result != null ? result : null;
|
|
1615
|
+
} catch (e) {
|
|
1616
|
+
return null;
|
|
1617
|
+
}
|
|
1618
|
+
});
|
|
1619
|
+
}
|
|
1620
|
+
/**
|
|
1621
|
+
* Get a patient by their Hint EHR ID.
|
|
1622
|
+
*/
|
|
1623
|
+
getByHintId(hintId) {
|
|
1624
|
+
return __async(this, null, function* () {
|
|
1625
|
+
try {
|
|
1626
|
+
const result = yield this.convex.query(
|
|
1627
|
+
"patients:getByHintId",
|
|
1628
|
+
{
|
|
1629
|
+
hintId
|
|
1630
|
+
}
|
|
1631
|
+
);
|
|
1632
|
+
return result != null ? result : null;
|
|
1633
|
+
} catch (e) {
|
|
1634
|
+
return null;
|
|
1635
|
+
}
|
|
1636
|
+
});
|
|
1637
|
+
}
|
|
1638
|
+
/**
|
|
1639
|
+
* List patients with optional search, pagination, and limit.
|
|
1640
|
+
*/
|
|
1641
|
+
list(options) {
|
|
1642
|
+
return __async(this, null, function* () {
|
|
1643
|
+
try {
|
|
1644
|
+
const result = yield this.convex.query(
|
|
1645
|
+
"patients:list",
|
|
1646
|
+
{
|
|
1647
|
+
search: options == null ? void 0 : options.search,
|
|
1648
|
+
limit: options == null ? void 0 : options.limit,
|
|
1649
|
+
cursor: options == null ? void 0 : options.cursor
|
|
1650
|
+
}
|
|
1651
|
+
);
|
|
1652
|
+
const typed = result;
|
|
1653
|
+
return typed != null ? typed : { data: [], cursor: null, hasMore: false };
|
|
1654
|
+
} catch (e) {
|
|
1655
|
+
return { data: [], cursor: null, hasMore: false };
|
|
1656
|
+
}
|
|
1657
|
+
});
|
|
1658
|
+
}
|
|
1659
|
+
};
|
|
1660
|
+
|
|
1661
|
+
// src/resources/physicians.ts
|
|
1662
|
+
var PhysiciansResource = class {
|
|
1663
|
+
constructor(convex) {
|
|
1664
|
+
this.convex = convex;
|
|
1665
|
+
}
|
|
1666
|
+
/**
|
|
1667
|
+
* Resolve a batch of physicians by Elation IDs. Missing ids are dropped.
|
|
1668
|
+
*/
|
|
1669
|
+
getByElationIds(ids) {
|
|
1670
|
+
return __async(this, null, function* () {
|
|
1671
|
+
if (ids.length === 0) {
|
|
1672
|
+
return [];
|
|
1673
|
+
}
|
|
1674
|
+
try {
|
|
1675
|
+
const rows = yield this.convex.query(
|
|
1676
|
+
"physicians:getByElationIds",
|
|
1677
|
+
{ ids }
|
|
1678
|
+
);
|
|
1679
|
+
return rows != null ? rows : [];
|
|
1680
|
+
} catch (e) {
|
|
1681
|
+
return [];
|
|
1682
|
+
}
|
|
1683
|
+
});
|
|
1684
|
+
}
|
|
1685
|
+
getByElationId(id) {
|
|
1686
|
+
return __async(this, null, function* () {
|
|
1687
|
+
try {
|
|
1688
|
+
const row = yield this.convex.query(
|
|
1689
|
+
"physicians:getByElationId",
|
|
1690
|
+
{ id }
|
|
1691
|
+
);
|
|
1692
|
+
return row != null ? row : null;
|
|
1693
|
+
} catch (e) {
|
|
1694
|
+
return null;
|
|
1695
|
+
}
|
|
1696
|
+
});
|
|
1697
|
+
}
|
|
1698
|
+
listByPractice(practice, limit) {
|
|
1699
|
+
return __async(this, null, function* () {
|
|
1700
|
+
try {
|
|
1701
|
+
const rows = yield this.convex.query(
|
|
1702
|
+
"physicians:listByPractice",
|
|
1703
|
+
{ practice, limit }
|
|
1704
|
+
);
|
|
1705
|
+
return rows != null ? rows : [];
|
|
1706
|
+
} catch (e) {
|
|
1707
|
+
return [];
|
|
1708
|
+
}
|
|
1709
|
+
});
|
|
1710
|
+
}
|
|
1711
|
+
};
|
|
1712
|
+
|
|
1713
|
+
// src/resources/reminders.ts
|
|
1714
|
+
var RemindersResource = class {
|
|
1715
|
+
constructor(convexClient) {
|
|
1716
|
+
this.convex = convexClient;
|
|
1717
|
+
}
|
|
1718
|
+
/**
|
|
1719
|
+
* Schedule a reminder to fire at `remindAt`. Returns the reminder id,
|
|
1720
|
+
* which callers should store if they may want to cancel it later.
|
|
1721
|
+
*/
|
|
1722
|
+
schedule(input) {
|
|
1723
|
+
return __async(this, null, function* () {
|
|
1724
|
+
const remindAt = input.remindAt instanceof Date ? input.remindAt.toISOString() : input.remindAt;
|
|
1725
|
+
const result = yield this.convex.mutation(
|
|
1726
|
+
"reminders:schedule",
|
|
1727
|
+
{
|
|
1728
|
+
conversationId: input.conversationId,
|
|
1729
|
+
remindAt,
|
|
1730
|
+
note: input.note,
|
|
1731
|
+
createdBy: input.createdBy
|
|
1732
|
+
}
|
|
1733
|
+
);
|
|
1734
|
+
return result;
|
|
1735
|
+
});
|
|
1736
|
+
}
|
|
1737
|
+
/**
|
|
1738
|
+
* Cancel a pending reminder. No-op if the reminder has already fired or
|
|
1739
|
+
* been cancelled.
|
|
1740
|
+
*/
|
|
1741
|
+
cancel(reminderId, cancelledBy) {
|
|
1742
|
+
return __async(this, null, function* () {
|
|
1743
|
+
return yield this.convex.mutation(
|
|
1744
|
+
"reminders:cancel",
|
|
1745
|
+
{ reminderId, cancelledBy }
|
|
1746
|
+
);
|
|
1747
|
+
});
|
|
1748
|
+
}
|
|
1749
|
+
/**
|
|
1750
|
+
* List reminders for a conversation (most recent first).
|
|
1751
|
+
*/
|
|
1752
|
+
listByConversation(conversationId) {
|
|
1753
|
+
return __async(this, null, function* () {
|
|
1754
|
+
try {
|
|
1755
|
+
const rows = yield this.convex.query(
|
|
1756
|
+
"reminders:listByConversation",
|
|
1757
|
+
{ conversationId }
|
|
1758
|
+
);
|
|
1759
|
+
return rows != null ? rows : [];
|
|
1760
|
+
} catch (e) {
|
|
1761
|
+
return [];
|
|
1762
|
+
}
|
|
1763
|
+
});
|
|
1764
|
+
}
|
|
1765
|
+
};
|
|
1766
|
+
|
|
1767
|
+
// src/resources/tasks.ts
|
|
1768
|
+
var TasksResource = class {
|
|
1769
|
+
constructor(convexClient) {
|
|
1770
|
+
this.convex = convexClient;
|
|
1771
|
+
}
|
|
1772
|
+
create(input) {
|
|
1773
|
+
return __async(this, null, function* () {
|
|
1774
|
+
return yield this.convex.mutation(
|
|
1775
|
+
"tasks:create",
|
|
1776
|
+
input
|
|
1777
|
+
);
|
|
1778
|
+
});
|
|
1779
|
+
}
|
|
1780
|
+
updateStatus(input) {
|
|
1781
|
+
return __async(this, null, function* () {
|
|
1782
|
+
return yield this.convex.mutation(
|
|
1783
|
+
"tasks:updateStatus",
|
|
1784
|
+
input
|
|
1785
|
+
);
|
|
1786
|
+
});
|
|
1787
|
+
}
|
|
1788
|
+
get(taskId) {
|
|
1789
|
+
return __async(this, null, function* () {
|
|
1790
|
+
try {
|
|
1791
|
+
const row = yield this.convex.query(
|
|
1792
|
+
"tasks:get",
|
|
1793
|
+
{ taskId }
|
|
1794
|
+
);
|
|
1795
|
+
return row != null ? row : null;
|
|
1796
|
+
} catch (e) {
|
|
1797
|
+
return null;
|
|
1798
|
+
}
|
|
1799
|
+
});
|
|
1800
|
+
}
|
|
1801
|
+
listByAssignee(assignedTo, options) {
|
|
1802
|
+
return __async(this, null, function* () {
|
|
1803
|
+
try {
|
|
1804
|
+
const rows = yield this.convex.query(
|
|
1805
|
+
"tasks:listByAssignee",
|
|
1806
|
+
{
|
|
1807
|
+
assignedTo,
|
|
1808
|
+
status: options == null ? void 0 : options.status,
|
|
1809
|
+
limit: options == null ? void 0 : options.limit
|
|
1810
|
+
}
|
|
1811
|
+
);
|
|
1812
|
+
return rows != null ? rows : [];
|
|
1813
|
+
} catch (e) {
|
|
1814
|
+
return [];
|
|
1815
|
+
}
|
|
1816
|
+
});
|
|
1817
|
+
}
|
|
1818
|
+
listOpen(limit) {
|
|
1819
|
+
return __async(this, null, function* () {
|
|
1820
|
+
try {
|
|
1821
|
+
const rows = yield this.convex.query(
|
|
1822
|
+
"tasks:listOpen",
|
|
1823
|
+
{ limit }
|
|
1824
|
+
);
|
|
1825
|
+
return rows != null ? rows : [];
|
|
1826
|
+
} catch (e) {
|
|
1827
|
+
return [];
|
|
1828
|
+
}
|
|
1829
|
+
});
|
|
1830
|
+
}
|
|
1831
|
+
/**
|
|
1832
|
+
* Mark a conversation task as seen by the given user. Appends `userId`
|
|
1833
|
+
* to the `seenBy` array on the `conversationTasks` row if not already
|
|
1834
|
+
* present. Replaces CommHub's `useMark_Event_Activity_SeenMutation`.
|
|
1835
|
+
*
|
|
1836
|
+
* @returns `{ ok: true }` on success.
|
|
1837
|
+
* @throws if the task does not exist in Convex.
|
|
1838
|
+
*/
|
|
1839
|
+
markSeen(input) {
|
|
1840
|
+
return __async(this, null, function* () {
|
|
1841
|
+
return yield this.convex.mutation(
|
|
1842
|
+
"conversationTasks:markSeen",
|
|
1843
|
+
input
|
|
1844
|
+
);
|
|
1845
|
+
});
|
|
1846
|
+
}
|
|
1847
|
+
};
|
|
1848
|
+
|
|
1849
|
+
// src/resources/translation.ts
|
|
1850
|
+
var TranslationError = class extends Error {
|
|
1851
|
+
constructor(operation, status, message) {
|
|
1852
|
+
super(message != null ? message : `Translation ${operation} failed (HTTP ${status})`);
|
|
1853
|
+
this.name = "TranslationError";
|
|
1854
|
+
this.status = status;
|
|
1855
|
+
this.operation = operation;
|
|
1856
|
+
}
|
|
1857
|
+
};
|
|
1858
|
+
var TranslationResource = class {
|
|
1859
|
+
constructor(apiBaseUrl, apiKey) {
|
|
1860
|
+
this.baseUrl = apiBaseUrl;
|
|
1861
|
+
this.apiKey = apiKey;
|
|
1862
|
+
}
|
|
1863
|
+
post(path, body) {
|
|
1864
|
+
return __async(this, null, function* () {
|
|
1865
|
+
const url = `${this.baseUrl}/api${path}`;
|
|
1866
|
+
const res = yield fetch(url, {
|
|
1867
|
+
method: "POST",
|
|
1868
|
+
headers: {
|
|
1869
|
+
"Content-Type": "application/json",
|
|
1870
|
+
Accept: "application/json",
|
|
1871
|
+
"X-API-Key": this.apiKey
|
|
1872
|
+
},
|
|
1873
|
+
body: JSON.stringify(body)
|
|
1874
|
+
});
|
|
1875
|
+
if (!res.ok) {
|
|
1876
|
+
const text = yield res.text().catch(() => "");
|
|
1877
|
+
throw new TranslationError(path, res.status, text.slice(0, 200));
|
|
1878
|
+
}
|
|
1879
|
+
return yield res.json();
|
|
1880
|
+
});
|
|
1881
|
+
}
|
|
1882
|
+
translate(input) {
|
|
1883
|
+
return __async(this, null, function* () {
|
|
1884
|
+
return yield this.post("/translation/translate", input);
|
|
1885
|
+
});
|
|
1886
|
+
}
|
|
1887
|
+
translateBatch(input) {
|
|
1888
|
+
return __async(this, null, function* () {
|
|
1889
|
+
const response = yield this.post(
|
|
1890
|
+
"/translation/translate-batch",
|
|
1891
|
+
input
|
|
1892
|
+
);
|
|
1893
|
+
return response.results;
|
|
1894
|
+
});
|
|
1895
|
+
}
|
|
1896
|
+
detect(text) {
|
|
1897
|
+
return __async(this, null, function* () {
|
|
1898
|
+
return yield this.post("/translation/detect", { text });
|
|
1899
|
+
});
|
|
1900
|
+
}
|
|
1901
|
+
};
|
|
1902
|
+
|
|
1903
|
+
// src/resources/user-settings.ts
|
|
1904
|
+
var import_server4 = require("convex/server");
|
|
1905
|
+
var upsertNotificationsRef = (0, import_server4.makeFunctionReference)("userSettings:upsertNotifications");
|
|
1906
|
+
var UserSettingsResource = class {
|
|
1907
|
+
constructor(convex) {
|
|
1908
|
+
this.convex = convex;
|
|
1909
|
+
}
|
|
1910
|
+
/**
|
|
1911
|
+
* Upsert notification preferences for a user. Creates the row if it
|
|
1912
|
+
* doesn't exist; patches `notificationsEnabled` + `updatedAt` otherwise.
|
|
1913
|
+
*/
|
|
1914
|
+
updateNotifications(input) {
|
|
1915
|
+
return __async(this, null, function* () {
|
|
1916
|
+
return this.convex.mutation(upsertNotificationsRef, input);
|
|
1917
|
+
});
|
|
1918
|
+
}
|
|
1919
|
+
};
|
|
1920
|
+
|
|
1921
|
+
// src/tracking/tracker.ts
|
|
1922
|
+
function generateUuidV7() {
|
|
1923
|
+
const now = Date.now();
|
|
1924
|
+
const timeBytes = new Uint8Array(6);
|
|
1925
|
+
let ts = now;
|
|
1926
|
+
for (let i = 5; i >= 0; i--) {
|
|
1927
|
+
timeBytes[i] = ts & 255;
|
|
1928
|
+
ts = Math.floor(ts / 256);
|
|
1929
|
+
}
|
|
1930
|
+
const randomBytes = new Uint8Array(10);
|
|
1931
|
+
if (typeof globalThis.crypto !== "undefined" && globalThis.crypto.getRandomValues) {
|
|
1932
|
+
globalThis.crypto.getRandomValues(randomBytes);
|
|
1933
|
+
} else {
|
|
1934
|
+
for (let i = 0; i < 10; i++) {
|
|
1935
|
+
randomBytes[i] = Math.floor(Math.random() * 256);
|
|
1936
|
+
}
|
|
1937
|
+
}
|
|
1938
|
+
const bytes = new Uint8Array(16);
|
|
1939
|
+
bytes.set(timeBytes, 0);
|
|
1940
|
+
bytes.set(randomBytes, 6);
|
|
1941
|
+
bytes[6] = bytes[6] & 15 | 112;
|
|
1942
|
+
bytes[8] = bytes[8] & 63 | 128;
|
|
1943
|
+
const hex = Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
1944
|
+
return [
|
|
1945
|
+
hex.slice(0, 8),
|
|
1946
|
+
hex.slice(8, 12),
|
|
1947
|
+
hex.slice(12, 16),
|
|
1948
|
+
hex.slice(16, 20),
|
|
1949
|
+
hex.slice(20, 32)
|
|
1950
|
+
].join("-");
|
|
1951
|
+
}
|
|
1952
|
+
var API_URLS = {
|
|
1953
|
+
local: "http://localhost:3000",
|
|
1954
|
+
staging: "https://app.sandbox.communication-hub.com",
|
|
1955
|
+
stg: "https://app.sandbox.communication-hub.com",
|
|
1956
|
+
sandbox: "https://app.sandbox.communication-hub.com",
|
|
1957
|
+
uat: "https://app.truth.communication-hub.com",
|
|
1958
|
+
production: "https://app.truth.communication-hub.com"
|
|
1959
|
+
};
|
|
1960
|
+
var DEFAULT_BATCH_SIZE = 25;
|
|
1961
|
+
var DEFAULT_FLUSH_INTERVAL_MS = 5e3;
|
|
1962
|
+
var MAX_RETRIES = 3;
|
|
1963
|
+
var BASE_RETRY_DELAY_MS = 500;
|
|
1964
|
+
var Tracker = class {
|
|
1965
|
+
constructor(config) {
|
|
1966
|
+
this.queue = [];
|
|
1967
|
+
this.flushTimer = null;
|
|
1968
|
+
this.isFlushing = false;
|
|
1969
|
+
this.isShutdown = false;
|
|
1970
|
+
var _a, _b;
|
|
1971
|
+
this.config = config;
|
|
1972
|
+
this.apiUrl = (_b = (_a = config.apiBaseUrl) != null ? _a : API_URLS[config.environment]) != null ? _b : API_URLS.local;
|
|
1973
|
+
this.startFlushInterval();
|
|
1974
|
+
this.registerShutdownHooks();
|
|
1975
|
+
}
|
|
1976
|
+
/**
|
|
1977
|
+
* Set the default actor context for subsequent events.
|
|
1978
|
+
*/
|
|
1979
|
+
setActor(actor) {
|
|
1980
|
+
this.defaultActor = actor;
|
|
1981
|
+
}
|
|
1982
|
+
/**
|
|
1983
|
+
* Enqueue a typed event for delivery. This is fire-and-forget from
|
|
1984
|
+
* the caller's perspective -- events are buffered and flushed in batches.
|
|
1985
|
+
*/
|
|
1986
|
+
track(eventType, payload, options) {
|
|
1987
|
+
var _a, _b, _c;
|
|
1988
|
+
if (this.isShutdown) {
|
|
1989
|
+
return;
|
|
1990
|
+
}
|
|
1991
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
1992
|
+
const envelope = {
|
|
1993
|
+
event_id: generateUuidV7(),
|
|
1994
|
+
event_type: eventType,
|
|
1995
|
+
schema_version: 1,
|
|
1996
|
+
occurred_at: (_a = options == null ? void 0 : options.occurredAt) != null ? _a : now,
|
|
1997
|
+
received_at: now,
|
|
1998
|
+
source: this.config.source,
|
|
1999
|
+
source_version: this.config.sourceVersion,
|
|
2000
|
+
tenant_id: (_b = options == null ? void 0 : options.tenantId) != null ? _b : this.config.tenantId,
|
|
2001
|
+
actor: (_c = options == null ? void 0 : options.actor) != null ? _c : this.defaultActor ? {
|
|
2002
|
+
actor_id: this.defaultActor.actorId,
|
|
2003
|
+
actor_type: this.defaultActor.actorType
|
|
2004
|
+
} : void 0,
|
|
2005
|
+
subject: options == null ? void 0 : options.subject,
|
|
2006
|
+
compliance: options == null ? void 0 : options.compliance,
|
|
2007
|
+
payload
|
|
2008
|
+
};
|
|
2009
|
+
this.queue.push(envelope);
|
|
2010
|
+
if (this.queue.length >= this.config.batchSize) {
|
|
2011
|
+
void this.flush();
|
|
2012
|
+
}
|
|
2013
|
+
}
|
|
2014
|
+
/**
|
|
2015
|
+
* Force an immediate flush of all buffered events.
|
|
2016
|
+
* Returns a promise that resolves when the flush completes.
|
|
2017
|
+
*/
|
|
2018
|
+
flush() {
|
|
2019
|
+
return __async(this, null, function* () {
|
|
2020
|
+
if (this.queue.length === 0 || this.isFlushing) {
|
|
2021
|
+
return;
|
|
2022
|
+
}
|
|
2023
|
+
this.isFlushing = true;
|
|
2024
|
+
const batch = this.queue.splice(0, this.config.batchSize);
|
|
2025
|
+
try {
|
|
2026
|
+
yield this.sendBatch(batch);
|
|
2027
|
+
} catch (e) {
|
|
2028
|
+
this.queue.unshift(...batch);
|
|
2029
|
+
} finally {
|
|
2030
|
+
this.isFlushing = false;
|
|
2031
|
+
}
|
|
2032
|
+
if (this.queue.length >= this.config.batchSize) {
|
|
2033
|
+
yield this.flush();
|
|
2034
|
+
}
|
|
2035
|
+
});
|
|
2036
|
+
}
|
|
2037
|
+
/**
|
|
2038
|
+
* Gracefully shut down the tracker. Flushes remaining events and
|
|
2039
|
+
* clears the flush interval.
|
|
2040
|
+
*/
|
|
2041
|
+
shutdown() {
|
|
2042
|
+
return __async(this, null, function* () {
|
|
2043
|
+
this.isShutdown = true;
|
|
2044
|
+
this.stopFlushInterval();
|
|
2045
|
+
yield this.flush();
|
|
2046
|
+
});
|
|
2047
|
+
}
|
|
2048
|
+
/**
|
|
2049
|
+
* Send a batch of events to the Truth API with exponential backoff retry.
|
|
2050
|
+
*/
|
|
2051
|
+
sendBatch(batch) {
|
|
2052
|
+
return __async(this, null, function* () {
|
|
2053
|
+
let lastError;
|
|
2054
|
+
for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
|
|
2055
|
+
try {
|
|
2056
|
+
const response = yield fetch(`${this.apiUrl}/api/events/ingest`, {
|
|
2057
|
+
method: "POST",
|
|
2058
|
+
headers: {
|
|
2059
|
+
"Content-Type": "application/json",
|
|
2060
|
+
"X-API-Key": this.config.apiKey
|
|
2061
|
+
},
|
|
2062
|
+
body: JSON.stringify({ events: batch })
|
|
2063
|
+
});
|
|
2064
|
+
if (response.ok) {
|
|
2065
|
+
return;
|
|
2066
|
+
}
|
|
2067
|
+
if (response.status >= 400 && response.status < 500 && response.status !== 429) {
|
|
2068
|
+
return;
|
|
2069
|
+
}
|
|
2070
|
+
lastError = new Error(
|
|
2071
|
+
`HTTP ${response.status}: ${response.statusText}`
|
|
2072
|
+
);
|
|
2073
|
+
} catch (error) {
|
|
2074
|
+
lastError = error;
|
|
2075
|
+
}
|
|
2076
|
+
if (attempt < MAX_RETRIES) {
|
|
2077
|
+
const delay = BASE_RETRY_DELAY_MS * __pow(2, attempt);
|
|
2078
|
+
const jitter = Math.random() * delay * 0.5;
|
|
2079
|
+
yield sleep(delay + jitter);
|
|
2080
|
+
}
|
|
2081
|
+
}
|
|
2082
|
+
throw lastError;
|
|
2083
|
+
});
|
|
2084
|
+
}
|
|
2085
|
+
startFlushInterval() {
|
|
2086
|
+
if (this.config.flushIntervalMs > 0) {
|
|
2087
|
+
this.flushTimer = setInterval(() => {
|
|
2088
|
+
void this.flush();
|
|
2089
|
+
}, this.config.flushIntervalMs);
|
|
2090
|
+
if (typeof this.flushTimer === "object" && "unref" in this.flushTimer) {
|
|
2091
|
+
this.flushTimer.unref();
|
|
2092
|
+
}
|
|
2093
|
+
}
|
|
2094
|
+
}
|
|
2095
|
+
stopFlushInterval() {
|
|
2096
|
+
if (this.flushTimer !== null) {
|
|
2097
|
+
clearInterval(this.flushTimer);
|
|
2098
|
+
this.flushTimer = null;
|
|
2099
|
+
}
|
|
2100
|
+
}
|
|
2101
|
+
registerShutdownHooks() {
|
|
2102
|
+
if (typeof globalThis.process !== "undefined" && globalThis.process.on) {
|
|
2103
|
+
const shutdownHandler = () => {
|
|
2104
|
+
void this.shutdown();
|
|
2105
|
+
};
|
|
2106
|
+
globalThis.process.on("beforeExit", shutdownHandler);
|
|
2107
|
+
globalThis.process.on("SIGTERM", shutdownHandler);
|
|
2108
|
+
}
|
|
2109
|
+
}
|
|
2110
|
+
};
|
|
2111
|
+
function sleep(ms) {
|
|
2112
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
2113
|
+
}
|
|
2114
|
+
|
|
2115
|
+
// src/web-push.ts
|
|
2116
|
+
function isWebPushSupported() {
|
|
2117
|
+
return typeof window !== "undefined" && "serviceWorker" in navigator && "PushManager" in window;
|
|
2118
|
+
}
|
|
2119
|
+
function registerServiceWorker(path = "/truth-sw.js") {
|
|
2120
|
+
return __async(this, null, function* () {
|
|
2121
|
+
return navigator.serviceWorker.register(path);
|
|
2122
|
+
});
|
|
2123
|
+
}
|
|
2124
|
+
function subscribeToPush(registration, vapidPublicKey) {
|
|
2125
|
+
return __async(this, null, function* () {
|
|
2126
|
+
const existing = yield registration.pushManager.getSubscription();
|
|
2127
|
+
if (existing) {
|
|
2128
|
+
return existing;
|
|
2129
|
+
}
|
|
2130
|
+
return registration.pushManager.subscribe({
|
|
2131
|
+
userVisibleOnly: true,
|
|
2132
|
+
applicationServerKey: urlBase64ToUint8Array(
|
|
2133
|
+
vapidPublicKey
|
|
2134
|
+
)
|
|
2135
|
+
});
|
|
2136
|
+
});
|
|
2137
|
+
}
|
|
2138
|
+
function subscriptionToJSON(sub) {
|
|
2139
|
+
var _a, _b, _c, _d;
|
|
2140
|
+
const json = sub.toJSON();
|
|
2141
|
+
return {
|
|
2142
|
+
endpoint: sub.endpoint,
|
|
2143
|
+
keys: {
|
|
2144
|
+
p256dh: (_b = (_a = json.keys) == null ? void 0 : _a.p256dh) != null ? _b : "",
|
|
2145
|
+
auth: (_d = (_c = json.keys) == null ? void 0 : _c.auth) != null ? _d : ""
|
|
2146
|
+
}
|
|
2147
|
+
};
|
|
2148
|
+
}
|
|
2149
|
+
function urlBase64ToUint8Array(base64String) {
|
|
2150
|
+
const padding = "=".repeat((4 - base64String.length % 4) % 4);
|
|
2151
|
+
const base64 = (base64String + padding).replace(/-/g, "+").replace(/_/g, "/");
|
|
2152
|
+
const rawData = atob(base64);
|
|
2153
|
+
const outputArray = new Uint8Array(rawData.length);
|
|
2154
|
+
for (let i = 0; i < rawData.length; ++i) {
|
|
2155
|
+
outputArray[i] = rawData.charCodeAt(i);
|
|
2156
|
+
}
|
|
2157
|
+
return outputArray;
|
|
2158
|
+
}
|
|
2159
|
+
|
|
2160
|
+
// src/client.ts
|
|
2161
|
+
var CONVEX_URLS = {
|
|
2162
|
+
local: "https://courteous-duck-623.convex.cloud",
|
|
2163
|
+
staging: "https://courteous-duck-623.convex.cloud",
|
|
2164
|
+
stg: "https://courteous-duck-623.convex.cloud",
|
|
2165
|
+
sandbox: "https://courteous-duck-623.convex.cloud",
|
|
2166
|
+
uat: "https://gallant-gecko-217.convex.cloud",
|
|
2167
|
+
production: "https://gallant-gecko-217.convex.cloud"
|
|
2168
|
+
};
|
|
2169
|
+
var TruthClient = class {
|
|
2170
|
+
constructor(config) {
|
|
2171
|
+
this._vapidPublicKey = null;
|
|
2172
|
+
this._webPushReady = null;
|
|
2173
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
2174
|
+
const convexUrl = (_b = (_a = config.convexUrl) != null ? _a : CONVEX_URLS[config.environment]) != null ? _b : CONVEX_URLS.local;
|
|
2175
|
+
this.convex = new import_browser.ConvexHttpClient(convexUrl);
|
|
2176
|
+
this.tracker = new Tracker({
|
|
2177
|
+
apiKey: config.apiKey,
|
|
2178
|
+
environment: config.environment,
|
|
2179
|
+
source: (_c = config.source) != null ? _c : "unknown",
|
|
2180
|
+
sourceVersion: (_d = config.sourceVersion) != null ? _d : "unknown",
|
|
2181
|
+
tenantId: (_e = config.tenantId) != null ? _e : "",
|
|
2182
|
+
batchSize: (_f = config.batchSize) != null ? _f : DEFAULT_BATCH_SIZE,
|
|
2183
|
+
flushIntervalMs: (_g = config.flushIntervalMs) != null ? _g : DEFAULT_FLUSH_INTERVAL_MS,
|
|
2184
|
+
apiBaseUrl: config.apiBaseUrl
|
|
2185
|
+
});
|
|
2186
|
+
const apiUrl = this.tracker.apiUrl;
|
|
2187
|
+
this.patients = new PatientResource(this.convex);
|
|
2188
|
+
this.appointments = new AppointmentResource(this.convex);
|
|
2189
|
+
this.ehr = new EhrResource(apiUrl);
|
|
2190
|
+
this.messages = new MessagesResource(apiUrl, config.apiKey);
|
|
2191
|
+
this.reminders = new RemindersResource(this.convex);
|
|
2192
|
+
this.translation = new TranslationResource(apiUrl, config.apiKey);
|
|
2193
|
+
this.tasks = new TasksResource(this.convex);
|
|
2194
|
+
this.patientDetails = new PatientDetailsResource(apiUrl, config.apiKey);
|
|
2195
|
+
this.attachments = new AttachmentsResource(
|
|
2196
|
+
apiUrl,
|
|
2197
|
+
config.apiKey,
|
|
2198
|
+
this.convex
|
|
2199
|
+
);
|
|
2200
|
+
this.notes = new NotesResource(apiUrl, config.apiKey);
|
|
2201
|
+
this.physicians = new PhysiciansResource(this.convex);
|
|
2202
|
+
this.notifications = new NotificationsResource(apiUrl, config.apiKey);
|
|
2203
|
+
this.conversations = new ConversationsResource(
|
|
2204
|
+
apiUrl,
|
|
2205
|
+
config.apiKey,
|
|
2206
|
+
this.convex
|
|
2207
|
+
);
|
|
2208
|
+
this.userSettings = new UserSettingsResource(this.convex);
|
|
2209
|
+
this._serviceWorkerPath = (_h = config.serviceWorkerPath) != null ? _h : "/truth-sw.js";
|
|
2210
|
+
if (typeof window !== "undefined" && isWebPushSupported() && config.autoInitServiceWorker !== false) {
|
|
2211
|
+
this._webPushReady = this.initWebPush();
|
|
2212
|
+
}
|
|
2213
|
+
}
|
|
2214
|
+
get vapidPublicKey() {
|
|
2215
|
+
return this._vapidPublicKey;
|
|
2216
|
+
}
|
|
2217
|
+
get webPushReady() {
|
|
2218
|
+
return this._webPushReady;
|
|
2219
|
+
}
|
|
2220
|
+
initWebPush() {
|
|
2221
|
+
return __async(this, null, function* () {
|
|
2222
|
+
try {
|
|
2223
|
+
const key = yield this.notifications.getVapidKey();
|
|
2224
|
+
if (!key) {
|
|
2225
|
+
return;
|
|
2226
|
+
}
|
|
2227
|
+
this._vapidPublicKey = key;
|
|
2228
|
+
const registration = yield registerServiceWorker(this._serviceWorkerPath);
|
|
2229
|
+
yield navigator.serviceWorker.ready;
|
|
2230
|
+
const subscription = yield subscribeToPush(registration, key);
|
|
2231
|
+
const subJSON = subscriptionToJSON(subscription);
|
|
2232
|
+
yield this.notifications.registerDevice({
|
|
2233
|
+
userId: "__pending__",
|
|
2234
|
+
platform: "web",
|
|
2235
|
+
webPushSubscription: subJSON,
|
|
2236
|
+
locale: navigator.language,
|
|
2237
|
+
timezone: Intl.DateTimeFormat().resolvedOptions().timeZone
|
|
2238
|
+
});
|
|
2239
|
+
} catch (e) {
|
|
2240
|
+
}
|
|
2241
|
+
});
|
|
2242
|
+
}
|
|
2243
|
+
/**
|
|
2244
|
+
* The resolved Truth API base URL for this environment.
|
|
2245
|
+
* Use this when making HTTP calls to Truth's proxy endpoints
|
|
2246
|
+
* (e.g., EHR proxy, messages proxy).
|
|
2247
|
+
*
|
|
2248
|
+
* @example
|
|
2249
|
+
* ```ts
|
|
2250
|
+
* const url = `${truth.apiBaseUrl}/api/ehr/elation/patients/123`;
|
|
2251
|
+
* ```
|
|
2252
|
+
*/
|
|
2253
|
+
get apiBaseUrl() {
|
|
2254
|
+
return this.tracker.apiUrl;
|
|
2255
|
+
}
|
|
2256
|
+
/**
|
|
2257
|
+
* Track an event. Fire-and-forget -- the event is buffered internally
|
|
2258
|
+
* and flushed in batches to the Truth API.
|
|
2259
|
+
*
|
|
2260
|
+
* @example
|
|
2261
|
+
* ```ts
|
|
2262
|
+
* truth.track('conversation.message_sent.v1', {
|
|
2263
|
+
* channel: 'sms',
|
|
2264
|
+
* direction: 'outbound',
|
|
2265
|
+
* message_chars: 140,
|
|
2266
|
+
* has_attachment: false,
|
|
2267
|
+
* provider_system: 'dialpad',
|
|
2268
|
+
* });
|
|
2269
|
+
* ```
|
|
2270
|
+
*/
|
|
2271
|
+
track(eventType, payload, options) {
|
|
2272
|
+
this.tracker.track(eventType, payload, options);
|
|
2273
|
+
}
|
|
2274
|
+
/**
|
|
2275
|
+
* Set the default actor context for all subsequent tracked events.
|
|
2276
|
+
* Can be overridden per-event via TrackOptions.
|
|
2277
|
+
*
|
|
2278
|
+
* @example
|
|
2279
|
+
* ```ts
|
|
2280
|
+
* truth.identify('user_123', 'user');
|
|
2281
|
+
* ```
|
|
2282
|
+
*/
|
|
2283
|
+
identify(actorId, actorType) {
|
|
2284
|
+
this.tracker.setActor({ actorId, actorType });
|
|
2285
|
+
}
|
|
2286
|
+
/**
|
|
2287
|
+
* Flush all buffered events immediately. Returns a Promise that resolves
|
|
2288
|
+
* when the flush completes. Use this for graceful shutdown.
|
|
2289
|
+
*
|
|
2290
|
+
* @example
|
|
2291
|
+
* ```ts
|
|
2292
|
+
* process.on('SIGTERM', async () => {
|
|
2293
|
+
* await truth.flush();
|
|
2294
|
+
* process.exit(0);
|
|
2295
|
+
* });
|
|
2296
|
+
* ```
|
|
2297
|
+
*/
|
|
2298
|
+
flush() {
|
|
2299
|
+
return __async(this, null, function* () {
|
|
2300
|
+
yield this.tracker.flush();
|
|
2301
|
+
});
|
|
2302
|
+
}
|
|
2303
|
+
/**
|
|
2304
|
+
* Gracefully shut down the client. Flushes all pending events and
|
|
2305
|
+
* releases resources.
|
|
2306
|
+
*/
|
|
2307
|
+
destroy() {
|
|
2308
|
+
return __async(this, null, function* () {
|
|
2309
|
+
yield this.tracker.shutdown();
|
|
2310
|
+
});
|
|
2311
|
+
}
|
|
2312
|
+
};
|
|
2313
|
+
|
|
2314
|
+
// src/react/provider.ts
|
|
2315
|
+
var CONVEX_URLS2 = {
|
|
2316
|
+
local: "https://courteous-duck-623.convex.cloud",
|
|
2317
|
+
staging: "https://courteous-duck-623.convex.cloud",
|
|
2318
|
+
stg: "https://courteous-duck-623.convex.cloud",
|
|
2319
|
+
sandbox: "https://courteous-duck-623.convex.cloud",
|
|
2320
|
+
uat: "https://gallant-gecko-217.convex.cloud",
|
|
2321
|
+
production: "https://gallant-gecko-217.convex.cloud"
|
|
2322
|
+
};
|
|
2323
|
+
var API_BASE_URLS = {
|
|
2324
|
+
local: "https://app.sandbox.communication-hub.com",
|
|
2325
|
+
staging: "https://app.sandbox.communication-hub.com",
|
|
2326
|
+
stg: "https://app.sandbox.communication-hub.com",
|
|
2327
|
+
sandbox: "https://app.sandbox.communication-hub.com",
|
|
2328
|
+
uat: "https://app.truth.communication-hub.com",
|
|
2329
|
+
production: "https://app.truth.communication-hub.com"
|
|
2330
|
+
};
|
|
2331
|
+
function resolveConvexUrl(environment, override) {
|
|
2332
|
+
var _a;
|
|
2333
|
+
if (override) {
|
|
2334
|
+
return override;
|
|
2335
|
+
}
|
|
2336
|
+
const env = environment != null ? environment : "sandbox";
|
|
2337
|
+
return (_a = CONVEX_URLS2[env]) != null ? _a : CONVEX_URLS2.sandbox;
|
|
2338
|
+
}
|
|
2339
|
+
function resolveApiBaseUrl(environment, override) {
|
|
2340
|
+
var _a;
|
|
2341
|
+
if (override) {
|
|
2342
|
+
return override;
|
|
2343
|
+
}
|
|
2344
|
+
const env = environment != null ? environment : "sandbox";
|
|
2345
|
+
return (_a = API_BASE_URLS[env]) != null ? _a : API_BASE_URLS.sandbox;
|
|
2346
|
+
}
|
|
2347
|
+
function readEnv(name) {
|
|
2348
|
+
if (typeof process === "undefined" || !process.env) {
|
|
2349
|
+
return void 0;
|
|
2350
|
+
}
|
|
2351
|
+
const v = process.env[name];
|
|
2352
|
+
return typeof v === "string" && v.length > 0 ? v : void 0;
|
|
2353
|
+
}
|
|
2354
|
+
var TruthSdkContext = (0, import_react6.createContext)(null);
|
|
2355
|
+
function useTruthSdkContext() {
|
|
2356
|
+
return (0, import_react6.useContext)(TruthSdkContext);
|
|
2357
|
+
}
|
|
2358
|
+
function useTruthClient() {
|
|
2359
|
+
const ctx = (0, import_react6.useContext)(TruthSdkContext);
|
|
2360
|
+
if (!ctx) {
|
|
2361
|
+
throw new Error(
|
|
2362
|
+
"useTruthClient() called outside <TruthProvider>. Wrap your app in <TruthProvider> from @hipnation-truth/sdk/react."
|
|
2363
|
+
);
|
|
2364
|
+
}
|
|
2365
|
+
return ctx.client;
|
|
2366
|
+
}
|
|
2367
|
+
var _activeClient = null;
|
|
2368
|
+
function getTruthClient() {
|
|
2369
|
+
if (!_activeClient) {
|
|
2370
|
+
throw new Error(
|
|
2371
|
+
"getTruthClient() called before <TruthProvider> mounted. Either wrap your app in <TruthProvider> or call useTruthClient() inside a component."
|
|
2372
|
+
);
|
|
2373
|
+
}
|
|
2374
|
+
return _activeClient;
|
|
2375
|
+
}
|
|
2376
|
+
function TruthProvider({
|
|
2377
|
+
environment = "sandbox",
|
|
2378
|
+
convexUrl,
|
|
2379
|
+
apiBaseUrl,
|
|
2380
|
+
apiKey,
|
|
2381
|
+
source,
|
|
2382
|
+
sourceVersion,
|
|
2383
|
+
tenantId,
|
|
2384
|
+
children
|
|
2385
|
+
}) {
|
|
2386
|
+
var _a, _b;
|
|
2387
|
+
const url = resolveConvexUrl(environment, convexUrl);
|
|
2388
|
+
const resolvedApiBaseUrl = (_a = apiBaseUrl != null ? apiBaseUrl : readEnv("EXPO_PUBLIC_TRUTH_API_BASE_URL")) != null ? _a : resolveApiBaseUrl(environment);
|
|
2389
|
+
const resolvedApiKey = (_b = apiKey != null ? apiKey : readEnv("EXPO_PUBLIC_TRUTH_API_KEY")) != null ? _b : "";
|
|
2390
|
+
const convexClient = (0, import_react6.useMemo)(() => new import_react5.ConvexReactClient(url), [url]);
|
|
2391
|
+
const truthClient = (0, import_react6.useMemo)(
|
|
2392
|
+
() => new TruthClient({
|
|
2393
|
+
apiKey: resolvedApiKey,
|
|
2394
|
+
environment,
|
|
2395
|
+
apiBaseUrl: resolvedApiBaseUrl,
|
|
2396
|
+
source: source != null ? source : "unknown",
|
|
2397
|
+
sourceVersion: sourceVersion != null ? sourceVersion : "unknown",
|
|
2398
|
+
tenantId: tenantId != null ? tenantId : "",
|
|
2399
|
+
autoInitServiceWorker: false
|
|
2400
|
+
}),
|
|
2401
|
+
[
|
|
2402
|
+
resolvedApiKey,
|
|
2403
|
+
resolvedApiBaseUrl,
|
|
2404
|
+
environment,
|
|
2405
|
+
source,
|
|
2406
|
+
sourceVersion,
|
|
2407
|
+
tenantId
|
|
2408
|
+
]
|
|
2409
|
+
);
|
|
2410
|
+
(0, import_react6.useEffect)(() => {
|
|
2411
|
+
_activeClient = truthClient;
|
|
2412
|
+
return () => {
|
|
2413
|
+
if (_activeClient === truthClient) {
|
|
2414
|
+
_activeClient = null;
|
|
2415
|
+
}
|
|
2416
|
+
};
|
|
2417
|
+
}, [truthClient]);
|
|
2418
|
+
const sdkContext = (0, import_react6.useMemo)(
|
|
2419
|
+
() => ({
|
|
2420
|
+
apiBaseUrl: resolvedApiBaseUrl,
|
|
2421
|
+
apiKey: resolvedApiKey,
|
|
2422
|
+
environment,
|
|
2423
|
+
client: truthClient
|
|
2424
|
+
}),
|
|
2425
|
+
[resolvedApiBaseUrl, resolvedApiKey, environment, truthClient]
|
|
2426
|
+
);
|
|
2427
|
+
return (0, import_react6.createElement)(
|
|
2428
|
+
TruthSdkContext.Provider,
|
|
2429
|
+
{ value: sdkContext },
|
|
2430
|
+
(0, import_react6.createElement)(import_react5.ConvexProvider, { client: convexClient }, children)
|
|
2431
|
+
);
|
|
2432
|
+
}
|
|
2433
|
+
|
|
2434
|
+
// src/react/hooks.ts
|
|
2435
|
+
var import_server5 = require("convex/server");
|
|
2436
|
+
var patientsListRef = (0, import_server5.makeFunctionReference)("patients:list");
|
|
2437
|
+
var patientsGetRef = (0, import_server5.makeFunctionReference)("patients:get");
|
|
2438
|
+
var patientsByElationIdRef = (0, import_server5.makeFunctionReference)("patients:getByElationId");
|
|
2439
|
+
var patientsByHintIdRef = (0, import_server5.makeFunctionReference)("patients:getByHintId");
|
|
2440
|
+
var appointmentsListRef = (0, import_server5.makeFunctionReference)("appointments:list");
|
|
2441
|
+
var appointmentsGetRef = (0, import_server5.makeFunctionReference)("appointments:get");
|
|
2442
|
+
var appointmentsByElationIdRef = (0, import_server5.makeFunctionReference)("appointments:getByElationId");
|
|
351
2443
|
function usePatients(options) {
|
|
352
|
-
return (0,
|
|
2444
|
+
return (0, import_react7.useQuery)(patientsListRef, options != null ? options : {});
|
|
353
2445
|
}
|
|
354
2446
|
function usePatient(id) {
|
|
355
|
-
return (0,
|
|
2447
|
+
return (0, import_react7.useQuery)(patientsGetRef, { id });
|
|
356
2448
|
}
|
|
357
2449
|
function usePatientByElationId(elationId) {
|
|
358
|
-
return (0,
|
|
2450
|
+
return (0, import_react7.useQuery)(patientsByElationIdRef, {
|
|
359
2451
|
elationId
|
|
360
2452
|
});
|
|
361
2453
|
}
|
|
362
2454
|
function usePatientByHintId(hintId) {
|
|
363
|
-
return (0,
|
|
2455
|
+
return (0, import_react7.useQuery)(patientsByHintIdRef, {
|
|
364
2456
|
hintId
|
|
365
2457
|
});
|
|
366
2458
|
}
|
|
367
2459
|
function useAppointments(options) {
|
|
368
|
-
return (0,
|
|
2460
|
+
return (0, import_react7.useQuery)(
|
|
369
2461
|
appointmentsListRef,
|
|
370
2462
|
options != null ? options : {}
|
|
371
2463
|
);
|
|
372
2464
|
}
|
|
373
2465
|
function useAppointment(id) {
|
|
374
|
-
return (0,
|
|
2466
|
+
return (0, import_react7.useQuery)(appointmentsGetRef, { id });
|
|
375
2467
|
}
|
|
376
2468
|
function useAppointmentByElationId(elationId) {
|
|
377
|
-
return (0,
|
|
2469
|
+
return (0, import_react7.useQuery)(appointmentsByElationIdRef, {
|
|
378
2470
|
elationId
|
|
379
2471
|
});
|
|
380
2472
|
}
|
|
381
|
-
var physiciansGetByElationIdsRef = (0,
|
|
382
|
-
var physiciansGetByElationIdRef = (0,
|
|
2473
|
+
var physiciansGetByElationIdsRef = (0, import_server5.makeFunctionReference)("physicians:getByElationIds");
|
|
2474
|
+
var physiciansGetByElationIdRef = (0, import_server5.makeFunctionReference)("physicians:getByElationId");
|
|
383
2475
|
function usePhysiciansByElationIds(ids) {
|
|
384
|
-
return (0,
|
|
2476
|
+
return (0, import_react7.useQuery)(
|
|
385
2477
|
physiciansGetByElationIdsRef,
|
|
386
2478
|
ids && ids.length > 0 ? { ids } : "skip"
|
|
387
2479
|
);
|
|
388
2480
|
}
|
|
389
2481
|
function usePhysicianByElationId(id) {
|
|
390
|
-
return (0,
|
|
2482
|
+
return (0, import_react7.useQuery)(
|
|
391
2483
|
physiciansGetByElationIdRef,
|
|
392
2484
|
id !== void 0 ? { id } : "skip"
|
|
393
2485
|
);
|
|
394
2486
|
}
|
|
395
|
-
var medicationsByPatientRef = (0,
|
|
396
|
-
var problemsByPatientRef = (0,
|
|
397
|
-
var allergiesByPatientRef = (0,
|
|
398
|
-
var appointmentsByPatientRef = (0,
|
|
2487
|
+
var medicationsByPatientRef = (0, import_server5.makeFunctionReference)("medicalRecords:getMedicationsByElationPatient");
|
|
2488
|
+
var problemsByPatientRef = (0, import_server5.makeFunctionReference)("medicalRecords:getProblemsByElationPatient");
|
|
2489
|
+
var allergiesByPatientRef = (0, import_server5.makeFunctionReference)("medicalRecords:getAllergiesByElationPatient");
|
|
2490
|
+
var appointmentsByPatientRef = (0, import_server5.makeFunctionReference)("medicalRecords:getAppointmentsByElationPatient");
|
|
399
2491
|
function usePatientMedical(elationId, options) {
|
|
400
|
-
|
|
2492
|
+
var _a, _b;
|
|
2493
|
+
const sdkContext = useTruthSdkContext();
|
|
2494
|
+
const apiBaseUrl = (_a = options == null ? void 0 : options.apiBaseUrl) != null ? _a : sdkContext == null ? void 0 : sdkContext.apiBaseUrl;
|
|
2495
|
+
const apiKey = (_b = options == null ? void 0 : options.apiKey) != null ? _b : sdkContext == null ? void 0 : sdkContext.apiKey;
|
|
2496
|
+
const medications = (0, import_react7.useQuery)(
|
|
401
2497
|
medicationsByPatientRef,
|
|
402
2498
|
elationId !== void 0 ? { elationPatientId: elationId } : "skip"
|
|
403
2499
|
);
|
|
404
|
-
const problems = (0,
|
|
2500
|
+
const problems = (0, import_react7.useQuery)(
|
|
405
2501
|
problemsByPatientRef,
|
|
406
2502
|
elationId !== void 0 ? { elationPatientId: elationId } : "skip"
|
|
407
2503
|
);
|
|
408
|
-
const allergies = (0,
|
|
2504
|
+
const allergies = (0, import_react7.useQuery)(
|
|
409
2505
|
allergiesByPatientRef,
|
|
410
2506
|
elationId !== void 0 ? { elationPatientId: elationId } : "skip"
|
|
411
2507
|
);
|
|
412
|
-
const appointments = (0,
|
|
2508
|
+
const appointments = (0, import_react7.useQuery)(
|
|
413
2509
|
appointmentsByPatientRef,
|
|
414
2510
|
elationId !== void 0 ? { elationPatientId: elationId } : "skip"
|
|
415
2511
|
);
|
|
416
|
-
(0,
|
|
2512
|
+
(0, import_react8.useEffect)(() => {
|
|
417
2513
|
if (elationId === void 0 || (options == null ? void 0 : options.skipRefresh)) {
|
|
418
2514
|
return;
|
|
419
2515
|
}
|
|
420
|
-
const apiBaseUrl = options == null ? void 0 : options.apiBaseUrl;
|
|
421
|
-
const apiKey = options == null ? void 0 : options.apiKey;
|
|
422
2516
|
if (!apiBaseUrl || !apiKey) {
|
|
423
2517
|
return;
|
|
424
2518
|
}
|
|
@@ -434,32 +2528,33 @@ function usePatientMedical(elationId, options) {
|
|
|
434
2528
|
}).catch(() => {
|
|
435
2529
|
});
|
|
436
2530
|
return () => controller.abort();
|
|
437
|
-
}, [elationId,
|
|
2531
|
+
}, [elationId, apiBaseUrl, apiKey, options == null ? void 0 : options.skipRefresh]);
|
|
438
2532
|
return { medications, problems, allergies, appointments };
|
|
439
2533
|
}
|
|
440
|
-
var elationPatientByIdRef = (0,
|
|
441
|
-
var hintPatientByIdRef = (0,
|
|
442
|
-
var pharmacyByNcpdpRef = (0,
|
|
443
|
-
var patientPhotoByIdRef = (0,
|
|
2534
|
+
var elationPatientByIdRef = (0, import_server5.makeFunctionReference)("elationPatients:getByElationId");
|
|
2535
|
+
var hintPatientByIdRef = (0, import_server5.makeFunctionReference)("hintPatients:getByHintId");
|
|
2536
|
+
var pharmacyByNcpdpRef = (0, import_server5.makeFunctionReference)("elationPharmacies:getByNcpdpId");
|
|
2537
|
+
var patientPhotoByIdRef = (0, import_server5.makeFunctionReference)("elationPatientPhotos:getByElationPatientId");
|
|
444
2538
|
function usePatientBasic(input, options) {
|
|
445
|
-
var _a, _b;
|
|
446
|
-
const
|
|
2539
|
+
var _a, _b, _c, _d;
|
|
2540
|
+
const sdkContext = useTruthSdkContext();
|
|
2541
|
+
const apiBaseUrl = (_a = options == null ? void 0 : options.apiBaseUrl) != null ? _a : sdkContext == null ? void 0 : sdkContext.apiBaseUrl;
|
|
2542
|
+
const apiKey = (_b = options == null ? void 0 : options.apiKey) != null ? _b : sdkContext == null ? void 0 : sdkContext.apiKey;
|
|
2543
|
+
const elationRow = (0, import_react7.useQuery)(
|
|
447
2544
|
elationPatientByIdRef,
|
|
448
2545
|
input.elationId !== void 0 ? { elationId: input.elationId } : "skip"
|
|
449
2546
|
);
|
|
450
|
-
const hintRow = (0,
|
|
2547
|
+
const hintRow = (0, import_react7.useQuery)(
|
|
451
2548
|
hintPatientByIdRef,
|
|
452
2549
|
input.hintId !== void 0 ? { hintId: input.hintId } : "skip"
|
|
453
2550
|
);
|
|
454
|
-
(0,
|
|
2551
|
+
(0, import_react8.useEffect)(() => {
|
|
455
2552
|
if (options == null ? void 0 : options.skipRefresh) {
|
|
456
2553
|
return;
|
|
457
2554
|
}
|
|
458
2555
|
if (!input.hintId && input.elationId === void 0) {
|
|
459
2556
|
return;
|
|
460
2557
|
}
|
|
461
|
-
const apiBaseUrl = options == null ? void 0 : options.apiBaseUrl;
|
|
462
|
-
const apiKey = options == null ? void 0 : options.apiKey;
|
|
463
2558
|
if (!apiBaseUrl || !apiKey) {
|
|
464
2559
|
return;
|
|
465
2560
|
}
|
|
@@ -478,15 +2573,9 @@ function usePatientBasic(input, options) {
|
|
|
478
2573
|
}).catch(() => {
|
|
479
2574
|
});
|
|
480
2575
|
return () => controller.abort();
|
|
481
|
-
}, [
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
options == null ? void 0 : options.apiBaseUrl,
|
|
485
|
-
options == null ? void 0 : options.apiKey,
|
|
486
|
-
options == null ? void 0 : options.skipRefresh
|
|
487
|
-
]);
|
|
488
|
-
const elationPatient = elationRow === void 0 ? void 0 : elationRow === null ? null : (_a = elationRow.raw) != null ? _a : null;
|
|
489
|
-
const hintPatient = hintRow === void 0 ? void 0 : hintRow === null ? null : (_b = hintRow.raw) != null ? _b : null;
|
|
2576
|
+
}, [input.hintId, input.elationId, apiBaseUrl, apiKey, options == null ? void 0 : options.skipRefresh]);
|
|
2577
|
+
const elationPatient = elationRow === void 0 ? void 0 : elationRow === null ? null : (_c = elationRow.raw) != null ? _c : null;
|
|
2578
|
+
const hintPatient = hintRow === void 0 ? void 0 : hintRow === null ? null : (_d = hintRow.raw) != null ? _d : null;
|
|
490
2579
|
const elationLoading = input.elationId !== void 0 && elationRow === void 0;
|
|
491
2580
|
const hintLoading = input.hintId !== void 0 && hintRow === void 0;
|
|
492
2581
|
return {
|
|
@@ -498,25 +2587,27 @@ function usePatientBasic(input, options) {
|
|
|
498
2587
|
};
|
|
499
2588
|
}
|
|
500
2589
|
function usePharmacyByNcpdpId(ncpdpId) {
|
|
501
|
-
return (0,
|
|
2590
|
+
return (0, import_react7.useQuery)(
|
|
502
2591
|
pharmacyByNcpdpRef,
|
|
503
2592
|
ncpdpId ? { ncpdpId } : "skip"
|
|
504
2593
|
);
|
|
505
2594
|
}
|
|
506
2595
|
function usePatientPhoto(elationId, options) {
|
|
507
|
-
|
|
2596
|
+
var _a, _b;
|
|
2597
|
+
const sdkContext = useTruthSdkContext();
|
|
2598
|
+
const apiBaseUrl = (_a = options == null ? void 0 : options.apiBaseUrl) != null ? _a : sdkContext == null ? void 0 : sdkContext.apiBaseUrl;
|
|
2599
|
+
const apiKey = (_b = options == null ? void 0 : options.apiKey) != null ? _b : sdkContext == null ? void 0 : sdkContext.apiKey;
|
|
2600
|
+
const photo = (0, import_react7.useQuery)(
|
|
508
2601
|
patientPhotoByIdRef,
|
|
509
2602
|
elationId !== void 0 ? { elationPatientId: elationId } : "skip"
|
|
510
2603
|
);
|
|
511
|
-
(0,
|
|
2604
|
+
(0, import_react8.useEffect)(() => {
|
|
512
2605
|
if (options == null ? void 0 : options.skipRefresh) {
|
|
513
2606
|
return;
|
|
514
2607
|
}
|
|
515
2608
|
if (elationId === void 0) {
|
|
516
2609
|
return;
|
|
517
2610
|
}
|
|
518
|
-
const apiBaseUrl = options == null ? void 0 : options.apiBaseUrl;
|
|
519
|
-
const apiKey = options == null ? void 0 : options.apiKey;
|
|
520
2611
|
if (!apiBaseUrl || !apiKey) {
|
|
521
2612
|
return;
|
|
522
2613
|
}
|
|
@@ -532,14 +2623,14 @@ function usePatientPhoto(elationId, options) {
|
|
|
532
2623
|
}).catch(() => {
|
|
533
2624
|
});
|
|
534
2625
|
return () => controller.abort();
|
|
535
|
-
}, [elationId,
|
|
2626
|
+
}, [elationId, apiBaseUrl, apiKey, options == null ? void 0 : options.skipRefresh]);
|
|
536
2627
|
return photo;
|
|
537
2628
|
}
|
|
538
|
-
var messagesByPhonesRef = (0,
|
|
539
|
-
var messagesByConversationIdRef = (0,
|
|
2629
|
+
var messagesByPhonesRef = (0, import_server5.makeFunctionReference)("conversationMessages:getByPhones");
|
|
2630
|
+
var messagesByConversationIdRef = (0, import_server5.makeFunctionReference)("conversationMessages:getByConversationId");
|
|
540
2631
|
function useConversationMessages(input, options) {
|
|
541
2632
|
const hasPair = !!input.phoneA && !!input.phoneB;
|
|
542
|
-
const byPair = (0,
|
|
2633
|
+
const byPair = (0, import_react7.useQuery)(
|
|
543
2634
|
messagesByPhonesRef,
|
|
544
2635
|
hasPair ? {
|
|
545
2636
|
phoneA: input.phoneA,
|
|
@@ -547,7 +2638,7 @@ function useConversationMessages(input, options) {
|
|
|
547
2638
|
limit: options == null ? void 0 : options.limit
|
|
548
2639
|
} : "skip"
|
|
549
2640
|
);
|
|
550
|
-
const byConvo = (0,
|
|
2641
|
+
const byConvo = (0, import_react7.useQuery)(
|
|
551
2642
|
messagesByConversationIdRef,
|
|
552
2643
|
!hasPair && input.conversationId ? { conversationId: input.conversationId, limit: options == null ? void 0 : options.limit } : "skip"
|
|
553
2644
|
);
|
|
@@ -555,54 +2646,7 @@ function useConversationMessages(input, options) {
|
|
|
555
2646
|
}
|
|
556
2647
|
|
|
557
2648
|
// src/react/notifications.ts
|
|
558
|
-
var
|
|
559
|
-
|
|
560
|
-
// src/web-push.ts
|
|
561
|
-
function isWebPushSupported() {
|
|
562
|
-
return typeof window !== "undefined" && "serviceWorker" in navigator && "PushManager" in window;
|
|
563
|
-
}
|
|
564
|
-
function registerServiceWorker(path = "/truth-sw.js") {
|
|
565
|
-
return __async(this, null, function* () {
|
|
566
|
-
return navigator.serviceWorker.register(path);
|
|
567
|
-
});
|
|
568
|
-
}
|
|
569
|
-
function subscribeToPush(registration, vapidPublicKey) {
|
|
570
|
-
return __async(this, null, function* () {
|
|
571
|
-
const existing = yield registration.pushManager.getSubscription();
|
|
572
|
-
if (existing) {
|
|
573
|
-
return existing;
|
|
574
|
-
}
|
|
575
|
-
return registration.pushManager.subscribe({
|
|
576
|
-
userVisibleOnly: true,
|
|
577
|
-
applicationServerKey: urlBase64ToUint8Array(
|
|
578
|
-
vapidPublicKey
|
|
579
|
-
)
|
|
580
|
-
});
|
|
581
|
-
});
|
|
582
|
-
}
|
|
583
|
-
function subscriptionToJSON(sub) {
|
|
584
|
-
var _a, _b, _c, _d;
|
|
585
|
-
const json = sub.toJSON();
|
|
586
|
-
return {
|
|
587
|
-
endpoint: sub.endpoint,
|
|
588
|
-
keys: {
|
|
589
|
-
p256dh: (_b = (_a = json.keys) == null ? void 0 : _a.p256dh) != null ? _b : "",
|
|
590
|
-
auth: (_d = (_c = json.keys) == null ? void 0 : _c.auth) != null ? _d : ""
|
|
591
|
-
}
|
|
592
|
-
};
|
|
593
|
-
}
|
|
594
|
-
function urlBase64ToUint8Array(base64String) {
|
|
595
|
-
const padding = "=".repeat((4 - base64String.length % 4) % 4);
|
|
596
|
-
const base64 = (base64String + padding).replace(/-/g, "+").replace(/_/g, "/");
|
|
597
|
-
const rawData = atob(base64);
|
|
598
|
-
const outputArray = new Uint8Array(rawData.length);
|
|
599
|
-
for (let i = 0; i < rawData.length; ++i) {
|
|
600
|
-
outputArray[i] = rawData.charCodeAt(i);
|
|
601
|
-
}
|
|
602
|
-
return outputArray;
|
|
603
|
-
}
|
|
604
|
-
|
|
605
|
-
// src/react/notifications.ts
|
|
2649
|
+
var import_react9 = require("react");
|
|
606
2650
|
function loadExpo() {
|
|
607
2651
|
return __async(this, null, function* () {
|
|
608
2652
|
try {
|
|
@@ -613,13 +2657,16 @@ function loadExpo() {
|
|
|
613
2657
|
});
|
|
614
2658
|
}
|
|
615
2659
|
function useNotifications(options) {
|
|
616
|
-
var _a;
|
|
617
|
-
const
|
|
618
|
-
const
|
|
619
|
-
const
|
|
620
|
-
const
|
|
621
|
-
const
|
|
622
|
-
(0,
|
|
2660
|
+
var _a, _b, _c, _d, _e;
|
|
2661
|
+
const sdkContext = useTruthSdkContext();
|
|
2662
|
+
const apiBaseUrl = (_b = (_a = options.apiBaseUrl) != null ? _a : sdkContext == null ? void 0 : sdkContext.apiBaseUrl) != null ? _b : "";
|
|
2663
|
+
const apiKey = (_d = (_c = options.apiKey) != null ? _c : sdkContext == null ? void 0 : sdkContext.apiKey) != null ? _d : "";
|
|
2664
|
+
const [permissionStatus, setPermissionStatus] = (0, import_react9.useState)("unknown");
|
|
2665
|
+
const [devicePushToken, setDevicePushToken] = (0, import_react9.useState)(null);
|
|
2666
|
+
const expoRef = (0, import_react9.useRef)(null);
|
|
2667
|
+
const isWebRef = (0, import_react9.useRef)(false);
|
|
2668
|
+
const vapidKeyRef = (0, import_react9.useRef)((_e = options.vapidPublicKey) != null ? _e : null);
|
|
2669
|
+
(0, import_react9.useEffect)(() => {
|
|
623
2670
|
let mounted = true;
|
|
624
2671
|
void (() => __async(null, null, function* () {
|
|
625
2672
|
var _a2;
|
|
@@ -645,11 +2692,11 @@ function useNotifications(options) {
|
|
|
645
2692
|
if (!vapidKeyRef.current) {
|
|
646
2693
|
try {
|
|
647
2694
|
const res = yield fetch(
|
|
648
|
-
`${
|
|
2695
|
+
`${apiBaseUrl}/api/notifications/vapid-key`,
|
|
649
2696
|
{
|
|
650
2697
|
headers: {
|
|
651
2698
|
Accept: "application/json",
|
|
652
|
-
"X-API-Key":
|
|
2699
|
+
"X-API-Key": apiKey
|
|
653
2700
|
}
|
|
654
2701
|
}
|
|
655
2702
|
);
|
|
@@ -674,9 +2721,9 @@ function useNotifications(options) {
|
|
|
674
2721
|
return () => {
|
|
675
2722
|
mounted = false;
|
|
676
2723
|
};
|
|
677
|
-
}, [
|
|
678
|
-
const register = (0,
|
|
679
|
-
var _a2,
|
|
2724
|
+
}, [apiBaseUrl, apiKey]);
|
|
2725
|
+
const register = (0, import_react9.useCallback)(() => __async(null, null, function* () {
|
|
2726
|
+
var _a2, _b2;
|
|
680
2727
|
if (!options.userId) {
|
|
681
2728
|
return { ok: false, reason: "missing_userId" };
|
|
682
2729
|
}
|
|
@@ -700,12 +2747,12 @@ function useNotifications(options) {
|
|
|
700
2747
|
const subJSON = subscriptionToJSON(subscription);
|
|
701
2748
|
setDevicePushToken(subscription.endpoint);
|
|
702
2749
|
const res2 = yield fetch(
|
|
703
|
-
`${
|
|
2750
|
+
`${apiBaseUrl}/api/notifications/devices/register`,
|
|
704
2751
|
{
|
|
705
2752
|
method: "POST",
|
|
706
2753
|
headers: {
|
|
707
2754
|
"Content-Type": "application/json",
|
|
708
|
-
"X-API-Key":
|
|
2755
|
+
"X-API-Key": apiKey
|
|
709
2756
|
},
|
|
710
2757
|
body: JSON.stringify({
|
|
711
2758
|
userId: options.userId,
|
|
@@ -732,7 +2779,7 @@ function useNotifications(options) {
|
|
|
732
2779
|
};
|
|
733
2780
|
}
|
|
734
2781
|
}
|
|
735
|
-
const expo = (
|
|
2782
|
+
const expo = (_b2 = expoRef.current) != null ? _b2 : yield loadExpo();
|
|
736
2783
|
expoRef.current = expo;
|
|
737
2784
|
if (!expo) {
|
|
738
2785
|
return { ok: false, reason: "expo_notifications_missing" };
|
|
@@ -753,12 +2800,12 @@ function useNotifications(options) {
|
|
|
753
2800
|
}
|
|
754
2801
|
setDevicePushToken(nativeToken);
|
|
755
2802
|
const res = yield fetch(
|
|
756
|
-
`${
|
|
2803
|
+
`${apiBaseUrl}/api/notifications/devices/register`,
|
|
757
2804
|
{
|
|
758
2805
|
method: "POST",
|
|
759
2806
|
headers: {
|
|
760
2807
|
"Content-Type": "application/json",
|
|
761
|
-
"X-API-Key":
|
|
2808
|
+
"X-API-Key": apiKey
|
|
762
2809
|
},
|
|
763
2810
|
body: JSON.stringify(__spreadValues({
|
|
764
2811
|
userId: options.userId,
|
|
@@ -779,28 +2826,28 @@ function useNotifications(options) {
|
|
|
779
2826
|
}
|
|
780
2827
|
return { ok: true };
|
|
781
2828
|
}), [
|
|
782
|
-
|
|
783
|
-
|
|
2829
|
+
apiBaseUrl,
|
|
2830
|
+
apiKey,
|
|
784
2831
|
options.userId,
|
|
785
2832
|
options.appVersion,
|
|
786
2833
|
options.serviceWorkerPath
|
|
787
2834
|
]);
|
|
788
|
-
const unregister = (0,
|
|
2835
|
+
const unregister = (0, import_react9.useCallback)(() => __async(null, null, function* () {
|
|
789
2836
|
if (!devicePushToken) {
|
|
790
2837
|
return;
|
|
791
2838
|
}
|
|
792
|
-
yield fetch(`${
|
|
2839
|
+
yield fetch(`${apiBaseUrl}/api/notifications/devices/unregister`, {
|
|
793
2840
|
method: "POST",
|
|
794
2841
|
headers: {
|
|
795
2842
|
"Content-Type": "application/json",
|
|
796
|
-
"X-API-Key":
|
|
2843
|
+
"X-API-Key": apiKey
|
|
797
2844
|
},
|
|
798
2845
|
body: JSON.stringify({ nativeToken: devicePushToken })
|
|
799
2846
|
}).catch(() => {
|
|
800
2847
|
});
|
|
801
2848
|
setDevicePushToken(null);
|
|
802
|
-
}), [
|
|
803
|
-
const addReceivedListener = (0,
|
|
2849
|
+
}), [apiBaseUrl, apiKey, devicePushToken]);
|
|
2850
|
+
const addReceivedListener = (0, import_react9.useCallback)(
|
|
804
2851
|
(listener) => {
|
|
805
2852
|
if (isWebRef.current) {
|
|
806
2853
|
if (typeof navigator === "undefined" || !("serviceWorker" in navigator)) {
|
|
@@ -829,7 +2876,7 @@ function useNotifications(options) {
|
|
|
829
2876
|
},
|
|
830
2877
|
[]
|
|
831
2878
|
);
|
|
832
|
-
const addResponseListener = (0,
|
|
2879
|
+
const addResponseListener = (0, import_react9.useCallback)(
|
|
833
2880
|
(listener) => {
|
|
834
2881
|
if (isWebRef.current) {
|
|
835
2882
|
if (typeof navigator === "undefined" || !("serviceWorker" in navigator)) {
|
|
@@ -858,7 +2905,7 @@ function useNotifications(options) {
|
|
|
858
2905
|
},
|
|
859
2906
|
[]
|
|
860
2907
|
);
|
|
861
|
-
const getBadgeCount = (0,
|
|
2908
|
+
const getBadgeCount = (0, import_react9.useCallback)(() => __async(null, null, function* () {
|
|
862
2909
|
var _a2;
|
|
863
2910
|
const expo = expoRef.current;
|
|
864
2911
|
if (!(expo == null ? void 0 : expo.getBadgeCountAsync)) {
|
|
@@ -866,7 +2913,7 @@ function useNotifications(options) {
|
|
|
866
2913
|
}
|
|
867
2914
|
return (_a2 = yield expo.getBadgeCountAsync()) != null ? _a2 : 0;
|
|
868
2915
|
}), []);
|
|
869
|
-
const setBadgeCount = (0,
|
|
2916
|
+
const setBadgeCount = (0, import_react9.useCallback)((count) => __async(null, null, function* () {
|
|
870
2917
|
const expo = expoRef.current;
|
|
871
2918
|
if (!(expo == null ? void 0 : expo.setBadgeCountAsync)) {
|
|
872
2919
|
return;
|
|
@@ -874,7 +2921,7 @@ function useNotifications(options) {
|
|
|
874
2921
|
yield expo.setBadgeCountAsync(count);
|
|
875
2922
|
}), []);
|
|
876
2923
|
const autoRegister = options.autoRegister !== false;
|
|
877
|
-
(0,
|
|
2924
|
+
(0, import_react9.useEffect)(() => {
|
|
878
2925
|
if (!autoRegister) {
|
|
879
2926
|
return;
|
|
880
2927
|
}
|
|
@@ -906,6 +2953,71 @@ function useNotifications(options) {
|
|
|
906
2953
|
setBadgeCount
|
|
907
2954
|
};
|
|
908
2955
|
}
|
|
2956
|
+
function useNotificationsActions() {
|
|
2957
|
+
var _a, _b;
|
|
2958
|
+
const sdkContext = useTruthSdkContext();
|
|
2959
|
+
const apiBaseUrl = (_a = sdkContext == null ? void 0 : sdkContext.apiBaseUrl) != null ? _a : "";
|
|
2960
|
+
const apiKey = (_b = sdkContext == null ? void 0 : sdkContext.apiKey) != null ? _b : "";
|
|
2961
|
+
const post = (0, import_react9.useCallback)(
|
|
2962
|
+
(path, body) => __async(null, null, function* () {
|
|
2963
|
+
const res = yield fetch(`${apiBaseUrl}/api${path}`, {
|
|
2964
|
+
method: "POST",
|
|
2965
|
+
headers: {
|
|
2966
|
+
"Content-Type": "application/json",
|
|
2967
|
+
Accept: "application/json",
|
|
2968
|
+
"X-API-Key": apiKey
|
|
2969
|
+
},
|
|
2970
|
+
body: JSON.stringify(body)
|
|
2971
|
+
});
|
|
2972
|
+
if (!res.ok) {
|
|
2973
|
+
const text = yield res.text().catch(() => "");
|
|
2974
|
+
throw new Error(
|
|
2975
|
+
`Truth API ${path} failed (${res.status}): ${text.slice(0, 200)}`
|
|
2976
|
+
);
|
|
2977
|
+
}
|
|
2978
|
+
return yield res.json();
|
|
2979
|
+
}),
|
|
2980
|
+
[apiBaseUrl, apiKey]
|
|
2981
|
+
);
|
|
2982
|
+
const get = (0, import_react9.useCallback)(
|
|
2983
|
+
(path) => __async(null, null, function* () {
|
|
2984
|
+
const res = yield fetch(`${apiBaseUrl}/api${path}`, {
|
|
2985
|
+
method: "GET",
|
|
2986
|
+
headers: { Accept: "application/json", "X-API-Key": apiKey }
|
|
2987
|
+
});
|
|
2988
|
+
if (!res.ok) {
|
|
2989
|
+
const text = yield res.text().catch(() => "");
|
|
2990
|
+
throw new Error(
|
|
2991
|
+
`Truth API ${path} failed (${res.status}): ${text.slice(0, 200)}`
|
|
2992
|
+
);
|
|
2993
|
+
}
|
|
2994
|
+
return yield res.json();
|
|
2995
|
+
}),
|
|
2996
|
+
[apiBaseUrl, apiKey]
|
|
2997
|
+
);
|
|
2998
|
+
const send = (0, import_react9.useCallback)(
|
|
2999
|
+
(input) => post("/notifications/send", input),
|
|
3000
|
+
[post]
|
|
3001
|
+
);
|
|
3002
|
+
const schedule = (0, import_react9.useCallback)(
|
|
3003
|
+
(input) => post("/notifications/schedule", input),
|
|
3004
|
+
[post]
|
|
3005
|
+
);
|
|
3006
|
+
const getPreferences = (0, import_react9.useCallback)(
|
|
3007
|
+
(userId) => get(
|
|
3008
|
+
`/notifications/preferences/${encodeURIComponent(userId)}`
|
|
3009
|
+
),
|
|
3010
|
+
[get]
|
|
3011
|
+
);
|
|
3012
|
+
const updatePreferences = (0, import_react9.useCallback)(
|
|
3013
|
+
(userId, prefs) => post(
|
|
3014
|
+
`/notifications/preferences/${encodeURIComponent(userId)}`,
|
|
3015
|
+
prefs
|
|
3016
|
+
),
|
|
3017
|
+
[post]
|
|
3018
|
+
);
|
|
3019
|
+
return { send, schedule, getPreferences, updatePreferences };
|
|
3020
|
+
}
|
|
909
3021
|
function mapStatus(status) {
|
|
910
3022
|
if (status === "granted") {
|
|
911
3023
|
return "granted";
|
|
@@ -932,16 +3044,16 @@ function detectPlatform(tokenType) {
|
|
|
932
3044
|
}
|
|
933
3045
|
|
|
934
3046
|
// src/react/patient-family.ts
|
|
935
|
-
var
|
|
936
|
-
var
|
|
937
|
-
var patientsFamilyMembersRef = (0,
|
|
3047
|
+
var import_react10 = require("convex/react");
|
|
3048
|
+
var import_server6 = require("convex/server");
|
|
3049
|
+
var patientsFamilyMembersRef = (0, import_server6.makeFunctionReference)("patients:listFamilyMembers");
|
|
938
3050
|
var SKIP3 = "skip";
|
|
939
3051
|
function usePatientFamilyMembers(input) {
|
|
940
3052
|
const hasFamilyId = !!(input == null ? void 0 : input.familyId);
|
|
941
3053
|
const hasPhoneNumbers = !!((input == null ? void 0 : input.phoneNumbers) && input.phoneNumbers.length > 0);
|
|
942
3054
|
const shouldQuery = hasFamilyId || hasPhoneNumbers;
|
|
943
3055
|
const args = shouldQuery ? __spreadValues(__spreadValues(__spreadValues({}, (input == null ? void 0 : input.familyId) ? { familyId: input.familyId } : {}), (input == null ? void 0 : input.phoneNumbers) && input.phoneNumbers.length > 0 ? { phoneNumbers: input.phoneNumbers } : {}), (input == null ? void 0 : input.excludeHintId) ? { excludeHintId: input.excludeHintId } : {}) : SKIP3;
|
|
944
|
-
const result = (0,
|
|
3056
|
+
const result = (0, import_react10.useQuery)(
|
|
945
3057
|
patientsFamilyMembersRef,
|
|
946
3058
|
args
|
|
947
3059
|
);
|
|
@@ -956,15 +3068,15 @@ function usePatientFamilyMembers(input) {
|
|
|
956
3068
|
}
|
|
957
3069
|
|
|
958
3070
|
// src/react/patient-search.ts
|
|
959
|
-
var
|
|
960
|
-
var
|
|
961
|
-
var patientsSearchRef = (0,
|
|
3071
|
+
var import_react11 = require("convex/react");
|
|
3072
|
+
var import_server7 = require("convex/server");
|
|
3073
|
+
var patientsSearchRef = (0, import_server7.makeFunctionReference)("patients:search");
|
|
962
3074
|
var SKIP4 = "skip";
|
|
963
3075
|
function usePatientSearch(options) {
|
|
964
3076
|
var _a;
|
|
965
3077
|
const trimmedQuery = ((_a = options.query) != null ? _a : "").trim();
|
|
966
3078
|
const skipped = trimmedQuery.length === 0;
|
|
967
|
-
const result = (0,
|
|
3079
|
+
const result = (0, import_react11.useQuery)(
|
|
968
3080
|
patientsSearchRef,
|
|
969
3081
|
skipped ? SKIP4 : __spreadValues(__spreadValues(__spreadValues({
|
|
970
3082
|
query: trimmedQuery
|
|
@@ -981,24 +3093,26 @@ function usePatientSearch(options) {
|
|
|
981
3093
|
}
|
|
982
3094
|
|
|
983
3095
|
// src/react/patients-bulk.ts
|
|
984
|
-
var
|
|
985
|
-
var
|
|
986
|
-
var
|
|
987
|
-
var patientsGetByIdsRef = (0,
|
|
988
|
-
var patientsGetByPhonesRef = (0,
|
|
3096
|
+
var import_react12 = require("convex/react");
|
|
3097
|
+
var import_server8 = require("convex/server");
|
|
3098
|
+
var import_react13 = require("react");
|
|
3099
|
+
var patientsGetByIdsRef = (0, import_server8.makeFunctionReference)("patients:getByIds");
|
|
3100
|
+
var patientsGetByPhonesRef = (0, import_server8.makeFunctionReference)("patients:getByPhones");
|
|
989
3101
|
var SKIP5 = "skip";
|
|
990
3102
|
function usePatientsByIds(ids) {
|
|
991
|
-
const stableIds = (0,
|
|
3103
|
+
const stableIds = (0, import_react13.useMemo)(() => {
|
|
992
3104
|
const arr = ids != null ? ids : [];
|
|
993
3105
|
return [...new Set(arr)].sort();
|
|
994
3106
|
}, [ids]);
|
|
995
3107
|
const skipped = stableIds.length === 0;
|
|
996
|
-
const result = (0,
|
|
3108
|
+
const result = (0, import_react12.useQuery)(
|
|
997
3109
|
patientsGetByIdsRef,
|
|
998
3110
|
skipped ? SKIP5 : { ids: stableIds }
|
|
999
3111
|
);
|
|
1000
|
-
const mapped = (0,
|
|
1001
|
-
if (result === void 0)
|
|
3112
|
+
const mapped = (0, import_react13.useMemo)(() => {
|
|
3113
|
+
if (result === void 0) {
|
|
3114
|
+
return void 0;
|
|
3115
|
+
}
|
|
1002
3116
|
return Object.fromEntries(
|
|
1003
3117
|
result.map((p) => {
|
|
1004
3118
|
var _a, _b;
|
|
@@ -1017,18 +3131,20 @@ function usePatientsByIds(ids) {
|
|
|
1017
3131
|
};
|
|
1018
3132
|
}
|
|
1019
3133
|
function usePatientsByPhones(phones) {
|
|
1020
|
-
const stableDigits = (0,
|
|
3134
|
+
const stableDigits = (0, import_react13.useMemo)(() => {
|
|
1021
3135
|
const arr = phones != null ? phones : [];
|
|
1022
3136
|
const digits = arr.map((p) => p.replace(/\D+/g, "")).filter((s) => s.length > 0);
|
|
1023
3137
|
return [...new Set(digits)].sort();
|
|
1024
3138
|
}, [phones]);
|
|
1025
3139
|
const skipped = stableDigits.length === 0;
|
|
1026
|
-
const result = (0,
|
|
3140
|
+
const result = (0, import_react12.useQuery)(
|
|
1027
3141
|
patientsGetByPhonesRef,
|
|
1028
3142
|
skipped ? SKIP5 : { phoneDigits: stableDigits }
|
|
1029
3143
|
);
|
|
1030
|
-
const mapped = (0,
|
|
1031
|
-
if (result === void 0)
|
|
3144
|
+
const mapped = (0, import_react13.useMemo)(() => {
|
|
3145
|
+
if (result === void 0) {
|
|
3146
|
+
return void 0;
|
|
3147
|
+
}
|
|
1032
3148
|
return Object.fromEntries(result.map((r) => [r.phoneDigits, r.patient]));
|
|
1033
3149
|
}, [result]);
|
|
1034
3150
|
if (skipped) {
|
|
@@ -1041,39 +3157,10 @@ function usePatientsByPhones(phones) {
|
|
|
1041
3157
|
};
|
|
1042
3158
|
}
|
|
1043
3159
|
|
|
1044
|
-
// src/react/provider.ts
|
|
1045
|
-
var import_react12 = require("convex/react");
|
|
1046
|
-
var import_react13 = require("react");
|
|
1047
|
-
var CONVEX_URLS = {
|
|
1048
|
-
local: "https://courteous-duck-623.convex.cloud",
|
|
1049
|
-
staging: "https://courteous-duck-623.convex.cloud",
|
|
1050
|
-
stg: "https://courteous-duck-623.convex.cloud",
|
|
1051
|
-
sandbox: "https://courteous-duck-623.convex.cloud",
|
|
1052
|
-
uat: "https://gallant-gecko-217.convex.cloud",
|
|
1053
|
-
production: "https://gallant-gecko-217.convex.cloud"
|
|
1054
|
-
};
|
|
1055
|
-
function resolveConvexUrl(environment, override) {
|
|
1056
|
-
var _a;
|
|
1057
|
-
if (override) {
|
|
1058
|
-
return override;
|
|
1059
|
-
}
|
|
1060
|
-
const env = environment != null ? environment : "sandbox";
|
|
1061
|
-
return (_a = CONVEX_URLS[env]) != null ? _a : CONVEX_URLS.sandbox;
|
|
1062
|
-
}
|
|
1063
|
-
function TruthProvider({
|
|
1064
|
-
environment = "sandbox",
|
|
1065
|
-
convexUrl,
|
|
1066
|
-
children
|
|
1067
|
-
}) {
|
|
1068
|
-
const url = resolveConvexUrl(environment, convexUrl);
|
|
1069
|
-
const client = (0, import_react13.useMemo)(() => new import_react12.ConvexReactClient(url), [url]);
|
|
1070
|
-
return (0, import_react13.createElement)(import_react12.ConvexProvider, { client }, children);
|
|
1071
|
-
}
|
|
1072
|
-
|
|
1073
3160
|
// src/react/reminders.ts
|
|
1074
3161
|
var import_react14 = require("convex/react");
|
|
1075
|
-
var
|
|
1076
|
-
var remindersListPendingByConversationIdsRef = (0,
|
|
3162
|
+
var import_server9 = require("convex/server");
|
|
3163
|
+
var remindersListPendingByConversationIdsRef = (0, import_server9.makeFunctionReference)("reminders:listPendingByConversationIds");
|
|
1077
3164
|
var SKIP6 = "skip";
|
|
1078
3165
|
function useRemindersForConversations(conversationIds) {
|
|
1079
3166
|
const ids = conversationIds != null ? conversationIds : [];
|
|
@@ -1095,9 +3182,9 @@ function useRemindersForConversations(conversationIds) {
|
|
|
1095
3182
|
|
|
1096
3183
|
// src/react/tasks.ts
|
|
1097
3184
|
var import_react15 = require("convex/react");
|
|
1098
|
-
var
|
|
3185
|
+
var import_server10 = require("convex/server");
|
|
1099
3186
|
var import_react16 = require("react");
|
|
1100
|
-
var conversationTasksMarkSeenRef = (0,
|
|
3187
|
+
var conversationTasksMarkSeenRef = (0, import_server10.makeFunctionReference)("conversationTasks:markSeen");
|
|
1101
3188
|
function useConversationTaskMarkSeen() {
|
|
1102
3189
|
const mutate = (0, import_react15.useMutation)(
|
|
1103
3190
|
conversationTasksMarkSeenRef
|
|
@@ -1110,200 +3197,6 @@ function useConversationTaskMarkSeen() {
|
|
|
1110
3197
|
|
|
1111
3198
|
// src/react/tracking.ts
|
|
1112
3199
|
var import_react17 = require("react");
|
|
1113
|
-
|
|
1114
|
-
// src/tracking/tracker.ts
|
|
1115
|
-
function generateUuidV7() {
|
|
1116
|
-
const now = Date.now();
|
|
1117
|
-
const timeBytes = new Uint8Array(6);
|
|
1118
|
-
let ts = now;
|
|
1119
|
-
for (let i = 5; i >= 0; i--) {
|
|
1120
|
-
timeBytes[i] = ts & 255;
|
|
1121
|
-
ts = Math.floor(ts / 256);
|
|
1122
|
-
}
|
|
1123
|
-
const randomBytes = new Uint8Array(10);
|
|
1124
|
-
if (typeof globalThis.crypto !== "undefined" && globalThis.crypto.getRandomValues) {
|
|
1125
|
-
globalThis.crypto.getRandomValues(randomBytes);
|
|
1126
|
-
} else {
|
|
1127
|
-
for (let i = 0; i < 10; i++) {
|
|
1128
|
-
randomBytes[i] = Math.floor(Math.random() * 256);
|
|
1129
|
-
}
|
|
1130
|
-
}
|
|
1131
|
-
const bytes = new Uint8Array(16);
|
|
1132
|
-
bytes.set(timeBytes, 0);
|
|
1133
|
-
bytes.set(randomBytes, 6);
|
|
1134
|
-
bytes[6] = bytes[6] & 15 | 112;
|
|
1135
|
-
bytes[8] = bytes[8] & 63 | 128;
|
|
1136
|
-
const hex = Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
1137
|
-
return [
|
|
1138
|
-
hex.slice(0, 8),
|
|
1139
|
-
hex.slice(8, 12),
|
|
1140
|
-
hex.slice(12, 16),
|
|
1141
|
-
hex.slice(16, 20),
|
|
1142
|
-
hex.slice(20, 32)
|
|
1143
|
-
].join("-");
|
|
1144
|
-
}
|
|
1145
|
-
var API_URLS = {
|
|
1146
|
-
local: "http://localhost:3000",
|
|
1147
|
-
staging: "https://app.sandbox.communication-hub.com",
|
|
1148
|
-
stg: "https://app.sandbox.communication-hub.com",
|
|
1149
|
-
sandbox: "https://app.sandbox.communication-hub.com",
|
|
1150
|
-
uat: "https://app.truth.communication-hub.com",
|
|
1151
|
-
production: "https://app.truth.communication-hub.com"
|
|
1152
|
-
};
|
|
1153
|
-
var MAX_RETRIES = 3;
|
|
1154
|
-
var BASE_RETRY_DELAY_MS = 500;
|
|
1155
|
-
var Tracker = class {
|
|
1156
|
-
constructor(config) {
|
|
1157
|
-
this.queue = [];
|
|
1158
|
-
this.flushTimer = null;
|
|
1159
|
-
this.isFlushing = false;
|
|
1160
|
-
this.isShutdown = false;
|
|
1161
|
-
var _a, _b;
|
|
1162
|
-
this.config = config;
|
|
1163
|
-
this.apiUrl = (_b = (_a = config.apiBaseUrl) != null ? _a : API_URLS[config.environment]) != null ? _b : API_URLS.local;
|
|
1164
|
-
this.startFlushInterval();
|
|
1165
|
-
this.registerShutdownHooks();
|
|
1166
|
-
}
|
|
1167
|
-
/**
|
|
1168
|
-
* Set the default actor context for subsequent events.
|
|
1169
|
-
*/
|
|
1170
|
-
setActor(actor) {
|
|
1171
|
-
this.defaultActor = actor;
|
|
1172
|
-
}
|
|
1173
|
-
/**
|
|
1174
|
-
* Enqueue a typed event for delivery. This is fire-and-forget from
|
|
1175
|
-
* the caller's perspective -- events are buffered and flushed in batches.
|
|
1176
|
-
*/
|
|
1177
|
-
track(eventType, payload, options) {
|
|
1178
|
-
var _a, _b, _c;
|
|
1179
|
-
if (this.isShutdown) {
|
|
1180
|
-
return;
|
|
1181
|
-
}
|
|
1182
|
-
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
1183
|
-
const envelope = {
|
|
1184
|
-
event_id: generateUuidV7(),
|
|
1185
|
-
event_type: eventType,
|
|
1186
|
-
schema_version: 1,
|
|
1187
|
-
occurred_at: (_a = options == null ? void 0 : options.occurredAt) != null ? _a : now,
|
|
1188
|
-
received_at: now,
|
|
1189
|
-
source: this.config.source,
|
|
1190
|
-
source_version: this.config.sourceVersion,
|
|
1191
|
-
tenant_id: (_b = options == null ? void 0 : options.tenantId) != null ? _b : this.config.tenantId,
|
|
1192
|
-
actor: (_c = options == null ? void 0 : options.actor) != null ? _c : this.defaultActor ? {
|
|
1193
|
-
actor_id: this.defaultActor.actorId,
|
|
1194
|
-
actor_type: this.defaultActor.actorType
|
|
1195
|
-
} : void 0,
|
|
1196
|
-
subject: options == null ? void 0 : options.subject,
|
|
1197
|
-
compliance: options == null ? void 0 : options.compliance,
|
|
1198
|
-
payload
|
|
1199
|
-
};
|
|
1200
|
-
this.queue.push(envelope);
|
|
1201
|
-
if (this.queue.length >= this.config.batchSize) {
|
|
1202
|
-
void this.flush();
|
|
1203
|
-
}
|
|
1204
|
-
}
|
|
1205
|
-
/**
|
|
1206
|
-
* Force an immediate flush of all buffered events.
|
|
1207
|
-
* Returns a promise that resolves when the flush completes.
|
|
1208
|
-
*/
|
|
1209
|
-
flush() {
|
|
1210
|
-
return __async(this, null, function* () {
|
|
1211
|
-
if (this.queue.length === 0 || this.isFlushing) {
|
|
1212
|
-
return;
|
|
1213
|
-
}
|
|
1214
|
-
this.isFlushing = true;
|
|
1215
|
-
const batch = this.queue.splice(0, this.config.batchSize);
|
|
1216
|
-
try {
|
|
1217
|
-
yield this.sendBatch(batch);
|
|
1218
|
-
} catch (e) {
|
|
1219
|
-
this.queue.unshift(...batch);
|
|
1220
|
-
} finally {
|
|
1221
|
-
this.isFlushing = false;
|
|
1222
|
-
}
|
|
1223
|
-
if (this.queue.length >= this.config.batchSize) {
|
|
1224
|
-
yield this.flush();
|
|
1225
|
-
}
|
|
1226
|
-
});
|
|
1227
|
-
}
|
|
1228
|
-
/**
|
|
1229
|
-
* Gracefully shut down the tracker. Flushes remaining events and
|
|
1230
|
-
* clears the flush interval.
|
|
1231
|
-
*/
|
|
1232
|
-
shutdown() {
|
|
1233
|
-
return __async(this, null, function* () {
|
|
1234
|
-
this.isShutdown = true;
|
|
1235
|
-
this.stopFlushInterval();
|
|
1236
|
-
yield this.flush();
|
|
1237
|
-
});
|
|
1238
|
-
}
|
|
1239
|
-
/**
|
|
1240
|
-
* Send a batch of events to the Truth API with exponential backoff retry.
|
|
1241
|
-
*/
|
|
1242
|
-
sendBatch(batch) {
|
|
1243
|
-
return __async(this, null, function* () {
|
|
1244
|
-
let lastError;
|
|
1245
|
-
for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
|
|
1246
|
-
try {
|
|
1247
|
-
const response = yield fetch(`${this.apiUrl}/api/events/ingest`, {
|
|
1248
|
-
method: "POST",
|
|
1249
|
-
headers: {
|
|
1250
|
-
"Content-Type": "application/json",
|
|
1251
|
-
"X-API-Key": this.config.apiKey
|
|
1252
|
-
},
|
|
1253
|
-
body: JSON.stringify({ events: batch })
|
|
1254
|
-
});
|
|
1255
|
-
if (response.ok) {
|
|
1256
|
-
return;
|
|
1257
|
-
}
|
|
1258
|
-
if (response.status >= 400 && response.status < 500 && response.status !== 429) {
|
|
1259
|
-
return;
|
|
1260
|
-
}
|
|
1261
|
-
lastError = new Error(
|
|
1262
|
-
`HTTP ${response.status}: ${response.statusText}`
|
|
1263
|
-
);
|
|
1264
|
-
} catch (error) {
|
|
1265
|
-
lastError = error;
|
|
1266
|
-
}
|
|
1267
|
-
if (attempt < MAX_RETRIES) {
|
|
1268
|
-
const delay = BASE_RETRY_DELAY_MS * __pow(2, attempt);
|
|
1269
|
-
const jitter = Math.random() * delay * 0.5;
|
|
1270
|
-
yield sleep(delay + jitter);
|
|
1271
|
-
}
|
|
1272
|
-
}
|
|
1273
|
-
throw lastError;
|
|
1274
|
-
});
|
|
1275
|
-
}
|
|
1276
|
-
startFlushInterval() {
|
|
1277
|
-
if (this.config.flushIntervalMs > 0) {
|
|
1278
|
-
this.flushTimer = setInterval(() => {
|
|
1279
|
-
void this.flush();
|
|
1280
|
-
}, this.config.flushIntervalMs);
|
|
1281
|
-
if (typeof this.flushTimer === "object" && "unref" in this.flushTimer) {
|
|
1282
|
-
this.flushTimer.unref();
|
|
1283
|
-
}
|
|
1284
|
-
}
|
|
1285
|
-
}
|
|
1286
|
-
stopFlushInterval() {
|
|
1287
|
-
if (this.flushTimer !== null) {
|
|
1288
|
-
clearInterval(this.flushTimer);
|
|
1289
|
-
this.flushTimer = null;
|
|
1290
|
-
}
|
|
1291
|
-
}
|
|
1292
|
-
registerShutdownHooks() {
|
|
1293
|
-
if (typeof globalThis.process !== "undefined" && globalThis.process.on) {
|
|
1294
|
-
const shutdownHandler = () => {
|
|
1295
|
-
void this.shutdown();
|
|
1296
|
-
};
|
|
1297
|
-
globalThis.process.on("beforeExit", shutdownHandler);
|
|
1298
|
-
globalThis.process.on("SIGTERM", shutdownHandler);
|
|
1299
|
-
}
|
|
1300
|
-
}
|
|
1301
|
-
};
|
|
1302
|
-
function sleep(ms) {
|
|
1303
|
-
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
1304
|
-
}
|
|
1305
|
-
|
|
1306
|
-
// src/react/tracking.ts
|
|
1307
3200
|
var TruthTrackingContext = (0, import_react17.createContext)(
|
|
1308
3201
|
null
|
|
1309
3202
|
);
|
|
@@ -1312,12 +3205,14 @@ function TruthTrackingProvider({
|
|
|
1312
3205
|
source = "communication-hub.frontend",
|
|
1313
3206
|
sourceVersion = "unknown",
|
|
1314
3207
|
tenantId = "hipnation",
|
|
1315
|
-
apiKey
|
|
3208
|
+
apiKey,
|
|
1316
3209
|
children
|
|
1317
3210
|
}) {
|
|
3211
|
+
var _a, _b;
|
|
3212
|
+
const resolvedApiKey = (_b = apiKey != null ? apiKey : typeof process !== "undefined" ? (_a = process.env) == null ? void 0 : _a.EXPO_PUBLIC_TRUTH_API_KEY : void 0) != null ? _b : "";
|
|
1318
3213
|
const value = (0, import_react17.useMemo)(() => {
|
|
1319
3214
|
const tracker = new Tracker({
|
|
1320
|
-
apiKey,
|
|
3215
|
+
apiKey: resolvedApiKey,
|
|
1321
3216
|
environment,
|
|
1322
3217
|
source,
|
|
1323
3218
|
sourceVersion,
|
|
@@ -1333,7 +3228,7 @@ function TruthTrackingProvider({
|
|
|
1333
3228
|
tracker.setActor({ actorId, actorType });
|
|
1334
3229
|
}
|
|
1335
3230
|
};
|
|
1336
|
-
}, [
|
|
3231
|
+
}, [resolvedApiKey, environment, source, sourceVersion, tenantId]);
|
|
1337
3232
|
return (0, import_react17.createElement)(TruthTrackingContext.Provider, { value }, children);
|
|
1338
3233
|
}
|
|
1339
3234
|
function useTruth() {
|
|
@@ -1346,8 +3241,8 @@ function useTruth() {
|
|
|
1346
3241
|
|
|
1347
3242
|
// src/react/user-settings.ts
|
|
1348
3243
|
var import_react18 = require("convex/react");
|
|
1349
|
-
var
|
|
1350
|
-
var userSettingsGetByUserIdRef = (0,
|
|
3244
|
+
var import_server11 = require("convex/server");
|
|
3245
|
+
var userSettingsGetByUserIdRef = (0, import_server11.makeFunctionReference)("userSettings:getByUserId");
|
|
1351
3246
|
var SKIP7 = "skip";
|
|
1352
3247
|
function useUserSettings(userId) {
|
|
1353
3248
|
const skip = !userId;
|
|
@@ -1365,16 +3260,103 @@ function useUserSettings(userId) {
|
|
|
1365
3260
|
};
|
|
1366
3261
|
}
|
|
1367
3262
|
|
|
1368
|
-
// src/react/
|
|
3263
|
+
// src/react/users.ts
|
|
1369
3264
|
var import_react19 = require("react");
|
|
1370
|
-
function
|
|
1371
|
-
|
|
1372
|
-
const
|
|
3265
|
+
function useUserSync(input) {
|
|
3266
|
+
var _a, _b, _c, _d;
|
|
3267
|
+
const sdkContext = useTruthSdkContext();
|
|
3268
|
+
const apiBaseUrl = (_b = (_a = input.apiBaseUrl) != null ? _a : sdkContext == null ? void 0 : sdkContext.apiBaseUrl) != null ? _b : "";
|
|
3269
|
+
const apiKey = (_d = (_c = input.apiKey) != null ? _c : sdkContext == null ? void 0 : sdkContext.apiKey) != null ? _d : "";
|
|
3270
|
+
const [status, setStatus] = (0, import_react19.useState)("idle");
|
|
1373
3271
|
const [error, setError] = (0, import_react19.useState)(null);
|
|
1374
|
-
const
|
|
1375
|
-
const
|
|
3272
|
+
const lastKeyRef = (0, import_react19.useRef)(null);
|
|
3273
|
+
const sync = () => __async(null, null, function* () {
|
|
3274
|
+
if (!input.userId) {
|
|
3275
|
+
return { ok: false, reason: "missing_userId" };
|
|
3276
|
+
}
|
|
3277
|
+
if (!apiBaseUrl || !apiKey) {
|
|
3278
|
+
return { ok: false, reason: "missing_truth_config" };
|
|
3279
|
+
}
|
|
3280
|
+
setStatus("syncing");
|
|
3281
|
+
setError(null);
|
|
3282
|
+
try {
|
|
3283
|
+
const res = yield fetch(`${apiBaseUrl}/api/users/sync`, {
|
|
3284
|
+
method: "POST",
|
|
3285
|
+
headers: {
|
|
3286
|
+
"Content-Type": "application/json",
|
|
3287
|
+
"X-API-Key": apiKey
|
|
3288
|
+
},
|
|
3289
|
+
body: JSON.stringify({
|
|
3290
|
+
userId: input.userId,
|
|
3291
|
+
email: input.email,
|
|
3292
|
+
name: input.name,
|
|
3293
|
+
firstName: input.firstName,
|
|
3294
|
+
lastName: input.lastName,
|
|
3295
|
+
imageUrl: input.imageUrl,
|
|
3296
|
+
notificationsEnabled: input.notificationsEnabled
|
|
3297
|
+
})
|
|
3298
|
+
});
|
|
3299
|
+
if (!res.ok) {
|
|
3300
|
+
const text = yield res.text().catch(() => "");
|
|
3301
|
+
const reason = `sync_failed_${res.status}: ${text.slice(0, 120)}`;
|
|
3302
|
+
setStatus("error");
|
|
3303
|
+
setError(reason);
|
|
3304
|
+
return { ok: false, reason };
|
|
3305
|
+
}
|
|
3306
|
+
setStatus("synced");
|
|
3307
|
+
return { ok: true };
|
|
3308
|
+
} catch (err) {
|
|
3309
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
3310
|
+
setStatus("error");
|
|
3311
|
+
setError(message);
|
|
3312
|
+
return { ok: false, reason: message };
|
|
3313
|
+
}
|
|
3314
|
+
});
|
|
3315
|
+
(0, import_react19.useEffect)(() => {
|
|
3316
|
+
var _a2, _b2, _c2, _d2, _e;
|
|
3317
|
+
if (!input.userId) {
|
|
3318
|
+
return;
|
|
3319
|
+
}
|
|
3320
|
+
const key = [
|
|
3321
|
+
input.userId,
|
|
3322
|
+
(_a2 = input.email) != null ? _a2 : "",
|
|
3323
|
+
(_b2 = input.name) != null ? _b2 : "",
|
|
3324
|
+
(_c2 = input.firstName) != null ? _c2 : "",
|
|
3325
|
+
(_d2 = input.lastName) != null ? _d2 : "",
|
|
3326
|
+
(_e = input.imageUrl) != null ? _e : "",
|
|
3327
|
+
input.notificationsEnabled === void 0 ? "" : String(input.notificationsEnabled)
|
|
3328
|
+
].join("|");
|
|
3329
|
+
if (key === lastKeyRef.current) {
|
|
3330
|
+
return;
|
|
3331
|
+
}
|
|
3332
|
+
lastKeyRef.current = key;
|
|
3333
|
+
void sync();
|
|
3334
|
+
}, [
|
|
3335
|
+
apiBaseUrl,
|
|
3336
|
+
apiKey,
|
|
3337
|
+
input.userId,
|
|
3338
|
+
input.email,
|
|
3339
|
+
input.name,
|
|
3340
|
+
input.firstName,
|
|
3341
|
+
input.lastName,
|
|
3342
|
+
input.imageUrl,
|
|
3343
|
+
input.notificationsEnabled
|
|
3344
|
+
]);
|
|
3345
|
+
return { status, error, sync };
|
|
3346
|
+
}
|
|
3347
|
+
|
|
3348
|
+
// src/react/voicemail.ts
|
|
3349
|
+
var import_react20 = require("react");
|
|
3350
|
+
function useVoicemailUrl(client) {
|
|
3351
|
+
const [url, setUrl] = (0, import_react20.useState)(null);
|
|
3352
|
+
const [isLoading, setIsLoading] = (0, import_react20.useState)(false);
|
|
3353
|
+
const [error, setError] = (0, import_react20.useState)(null);
|
|
3354
|
+
const inFlightRef = (0, import_react20.useRef)(false);
|
|
3355
|
+
const fetchUrl = (0, import_react20.useCallback)(
|
|
1376
3356
|
(voicemailLink) => __async(null, null, function* () {
|
|
1377
|
-
if (inFlightRef.current)
|
|
3357
|
+
if (inFlightRef.current) {
|
|
3358
|
+
return null;
|
|
3359
|
+
}
|
|
1378
3360
|
inFlightRef.current = true;
|
|
1379
3361
|
setIsLoading(true);
|
|
1380
3362
|
setError(null);
|
|
@@ -1398,12 +3380,17 @@ function useVoicemailUrl(client) {
|
|
|
1398
3380
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1399
3381
|
0 && (module.exports = {
|
|
1400
3382
|
ACTIVE_CALL_STATES,
|
|
3383
|
+
API_BASE_URLS,
|
|
1401
3384
|
CONNECTED_CALL_STATES,
|
|
3385
|
+
CONVEX_URLS,
|
|
1402
3386
|
DialpadCallState,
|
|
1403
3387
|
RINGING_CALL_STATES,
|
|
1404
3388
|
TERMINAL_CALL_STATES,
|
|
1405
3389
|
TruthProvider,
|
|
1406
3390
|
TruthTrackingProvider,
|
|
3391
|
+
getTruthClient,
|
|
3392
|
+
resolveApiBaseUrl,
|
|
3393
|
+
resolveConvexUrl,
|
|
1407
3394
|
useActiveCalls,
|
|
1408
3395
|
useAppointment,
|
|
1409
3396
|
useAppointmentByElationId,
|
|
@@ -1423,6 +3410,7 @@ function useVoicemailUrl(client) {
|
|
|
1423
3410
|
useDialpadCallsForConversation,
|
|
1424
3411
|
useMessages,
|
|
1425
3412
|
useNotifications,
|
|
3413
|
+
useNotificationsActions,
|
|
1426
3414
|
usePatient,
|
|
1427
3415
|
usePatientBasic,
|
|
1428
3416
|
usePatientByElationId,
|
|
@@ -1439,9 +3427,12 @@ function useVoicemailUrl(client) {
|
|
|
1439
3427
|
usePhysiciansByElationIds,
|
|
1440
3428
|
useRemindersForConversations,
|
|
1441
3429
|
useTruth,
|
|
3430
|
+
useTruthClient,
|
|
3431
|
+
useTruthSdkContext,
|
|
1442
3432
|
useUnreadAggregate,
|
|
1443
3433
|
useUnreadCount,
|
|
1444
3434
|
useUserSettings,
|
|
3435
|
+
useUserSync,
|
|
1445
3436
|
useVoicemailUrl
|
|
1446
3437
|
});
|
|
1447
3438
|
//# sourceMappingURL=react.js.map
|