@hipnation-truth/sdk 0.5.0 → 0.7.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 +201 -1
- package/dist/index.d.ts +201 -1
- package/dist/index.js +294 -3
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +286 -2
- package/dist/index.mjs.map +1 -1
- package/dist/react.d.mts +281 -1
- package/dist/react.d.ts +281 -1
- package/dist/react.js +546 -58
- package/dist/react.js.map +1 -1
- package/dist/react.mjs +527 -45
- package/dist/react.mjs.map +1 -1
- package/package.json +6 -3
package/dist/react.d.mts
CHANGED
|
@@ -2,6 +2,194 @@ import * as react from 'react';
|
|
|
2
2
|
import { ReactNode } from 'react';
|
|
3
3
|
import { ConvexReactClient } from 'convex/react';
|
|
4
4
|
|
|
5
|
+
/**
|
|
6
|
+
* React hooks for Truth SDK — reactive conversation + message data.
|
|
7
|
+
*
|
|
8
|
+
* Wraps Convex queries owned by the Truth backend so consumers (CommHub
|
|
9
|
+
* Expo frontend) get live-updating conversation lists, message threads,
|
|
10
|
+
* and unread totals without managing subscriptions themselves.
|
|
11
|
+
*
|
|
12
|
+
* **Hook contract:** every hook in this file returns
|
|
13
|
+
* `{ data, loading, error }`. `data` is `undefined` while loading and
|
|
14
|
+
* also when the underlying query is `"skip"`'d (caller didn't pass the
|
|
15
|
+
* required arg yet). `loading` is `true` only while a real subscription
|
|
16
|
+
* is in-flight; once `data` resolves (even to `null`) `loading` flips
|
|
17
|
+
* to `false`. `error` is reserved for SDK-side validation — Convex
|
|
18
|
+
* itself throws on subscribe rather than returning an error value, so
|
|
19
|
+
* unhandled query errors propagate as React errors and should be caught
|
|
20
|
+
* with an error boundary.
|
|
21
|
+
*
|
|
22
|
+
* **Backed by PR #110 schema (commit `41dbb59` on
|
|
23
|
+
* `feat/migrate-dialpad-webhook-and-messages-to-truth`):**
|
|
24
|
+
* - `conversations:listForUser` → `useConversations`
|
|
25
|
+
* - `conversations:getUnreadTotalForUser` → `useUnreadCount`
|
|
26
|
+
* - `conversations:getByPhonePair` → `useConversationByPhonePair`
|
|
27
|
+
* - `conversationMessages:getByConversationId` → `useMessages`
|
|
28
|
+
*
|
|
29
|
+
* **Deliberately NOT shipped here (no backend query yet — flagged in
|
|
30
|
+
* PR #111 body for follow-up):**
|
|
31
|
+
* - Single-conversation-by-id lookup. Convex `conversations` has no
|
|
32
|
+
* `get(id)` query — only `getByPhonePair`. CommHub uses phonePair as
|
|
33
|
+
* the primary handle, so the byPair flavor is what consumers need;
|
|
34
|
+
* if id-based lookup is needed later we can add a `conversations:get`
|
|
35
|
+
* in Truth.
|
|
36
|
+
* - Participants / "seen by" hook. The migrated schema has no
|
|
37
|
+
* `conversationParticipants` table — read state is per-user via
|
|
38
|
+
* `conversationReads` and there's no public list query for it yet.
|
|
39
|
+
* - `markRead` mutation. PR #110 declares `markRead` as
|
|
40
|
+
* `internalMutation`, so the frontend can't invoke it directly — it
|
|
41
|
+
* has to go through a Truth HTTP endpoint, or webhook-migrator needs
|
|
42
|
+
* to flip it to a public `mutation`. Flagged for a follow-up.
|
|
43
|
+
*
|
|
44
|
+
* Must be used within `<TruthProvider />` (see `./provider`).
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* ```tsx
|
|
48
|
+
* import {
|
|
49
|
+
* useConversations,
|
|
50
|
+
* useConversationByPhonePair,
|
|
51
|
+
* useMessages,
|
|
52
|
+
* useUnreadCount,
|
|
53
|
+
* } from '@hipnation-truth/sdk/react';
|
|
54
|
+
*
|
|
55
|
+
* function Inbox({ userId }: { userId: string }) {
|
|
56
|
+
* const { data: convos, loading } = useConversations({ userId });
|
|
57
|
+
* const { data: unread } = useUnreadCount(userId);
|
|
58
|
+
* if (loading) return <Spinner />;
|
|
59
|
+
* return (
|
|
60
|
+
* <div>
|
|
61
|
+
* <Badge count={unread ?? 0} />
|
|
62
|
+
* {convos?.map((c) => <ConvoRow key={c.id} convo={c} />)}
|
|
63
|
+
* </div>
|
|
64
|
+
* );
|
|
65
|
+
* }
|
|
66
|
+
* ```
|
|
67
|
+
*/
|
|
68
|
+
/**
|
|
69
|
+
* Row shape returned by `conversations:listForUser` — joins the base
|
|
70
|
+
* `conversations` row with the caller's per-user `conversationReads`
|
|
71
|
+
* entry so unread state lives on each item.
|
|
72
|
+
*/
|
|
73
|
+
interface ConversationListItem {
|
|
74
|
+
/** Convex id of the conversation row. */
|
|
75
|
+
id: string;
|
|
76
|
+
patientPhone: string;
|
|
77
|
+
providerPhone: string;
|
|
78
|
+
/** Sorted-digit-pair key (commutative — same regardless of direction). */
|
|
79
|
+
phonePair: string;
|
|
80
|
+
/** Truth-side patient id, when the kinesis pipeline could resolve it. */
|
|
81
|
+
patientId: string | null;
|
|
82
|
+
/** ISO timestamp of the most recent message in the conversation. */
|
|
83
|
+
lastMessageAt: string;
|
|
84
|
+
/** Caller's unread count for this conversation. */
|
|
85
|
+
unreadCount: number;
|
|
86
|
+
/** ISO timestamp of when the caller last marked the conversation read. */
|
|
87
|
+
lastReadAt: string | null;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Raw `conversations` table row — what `getByPhonePair` returns. No
|
|
91
|
+
* unread / read joining; for that, prefer `useConversations`.
|
|
92
|
+
*/
|
|
93
|
+
interface ConversationRow {
|
|
94
|
+
_id: string;
|
|
95
|
+
_creationTime: number;
|
|
96
|
+
patientPhone: string;
|
|
97
|
+
providerPhone: string;
|
|
98
|
+
phonePair: string;
|
|
99
|
+
patientId: string | null;
|
|
100
|
+
lastEventId: string | null;
|
|
101
|
+
lastMessageAt: string;
|
|
102
|
+
createdAt: string;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Message row returned by `conversationMessages:getByConversationId` —
|
|
106
|
+
* calls + SMS merged chronologically. Mirrors `ConversationMessage`
|
|
107
|
+
* already exported from the SDK; re-exported here under a clearer name
|
|
108
|
+
* for the new hook surface.
|
|
109
|
+
*/
|
|
110
|
+
interface ConversationMessageRow {
|
|
111
|
+
kind: "call" | "sms";
|
|
112
|
+
id: string;
|
|
113
|
+
providerId: string;
|
|
114
|
+
state: string | null;
|
|
115
|
+
direction: string | null;
|
|
116
|
+
fromNumber: string | null;
|
|
117
|
+
toNumber: string | null;
|
|
118
|
+
voicemailLink: string | null;
|
|
119
|
+
duration: number | null;
|
|
120
|
+
text: string | null;
|
|
121
|
+
mms: boolean;
|
|
122
|
+
mmsUrl: string | null;
|
|
123
|
+
messageStatus: string | null;
|
|
124
|
+
occurredAt: string;
|
|
125
|
+
conversationId: string | null;
|
|
126
|
+
patientId: string | null;
|
|
127
|
+
}
|
|
128
|
+
interface UseQueryResult<T> {
|
|
129
|
+
/**
|
|
130
|
+
* Query data. `undefined` while loading or while the query is
|
|
131
|
+
* intentionally skipped (e.g. caller hasn't supplied `userId` yet).
|
|
132
|
+
*/
|
|
133
|
+
data: T | undefined;
|
|
134
|
+
/** True only while a real subscription is in-flight. */
|
|
135
|
+
loading: boolean;
|
|
136
|
+
/**
|
|
137
|
+
* Reserved for client-side validation errors surfaced by the SDK
|
|
138
|
+
* itself. Convex query errors propagate as React errors and should
|
|
139
|
+
* be caught with an error boundary.
|
|
140
|
+
*/
|
|
141
|
+
error: Error | undefined;
|
|
142
|
+
}
|
|
143
|
+
interface UseConversationsFilters {
|
|
144
|
+
/**
|
|
145
|
+
* Truth user id (the Better Auth subject). Pass `undefined` to skip
|
|
146
|
+
* the query — useful when the auth session is still loading.
|
|
147
|
+
*/
|
|
148
|
+
userId: string | null | undefined;
|
|
149
|
+
/** Page size. Server caps at 100 by default. */
|
|
150
|
+
limit?: number;
|
|
151
|
+
}
|
|
152
|
+
interface UseMessagesOptions {
|
|
153
|
+
/** Page size. Server caps at 200 by default. */
|
|
154
|
+
limit?: number;
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Subscribe to a user's conversations — joined with their per-conversation
|
|
158
|
+
* unread count, sorted by most recent message. Updates live as new
|
|
159
|
+
* SMS / calls land in Convex and the webhook bumps `unreadCount`.
|
|
160
|
+
*
|
|
161
|
+
* Returns `{ data: undefined, loading: false }` while the auth session
|
|
162
|
+
* resolves (`userId === undefined`); not an error, just a skip.
|
|
163
|
+
*/
|
|
164
|
+
declare function useConversations(filters: UseConversationsFilters): UseQueryResult<ConversationListItem[]>;
|
|
165
|
+
/**
|
|
166
|
+
* Look up a single conversation by its normalized phonePair (sorted
|
|
167
|
+
* digit-pair, e.g. `"5125550123|6505551234"`). Returns `null` if no
|
|
168
|
+
* conversation exists yet for that pair.
|
|
169
|
+
*
|
|
170
|
+
* Use the `phonePairKey(patientPhone, providerPhone)` helper exposed by
|
|
171
|
+
* the Truth Convex module to derive the key from raw phone strings.
|
|
172
|
+
*/
|
|
173
|
+
declare function useConversationByPhonePair(phonePair: string | null | undefined): UseQueryResult<ConversationRow | null>;
|
|
174
|
+
/**
|
|
175
|
+
* Subscribe to a paginated message stream for a single conversation.
|
|
176
|
+
* Calls + SMS merged chronologically, newest-first. Live as the
|
|
177
|
+
* kinesis consumer writes to `messageCalls` / `messageSms`.
|
|
178
|
+
*
|
|
179
|
+
* Pass the Convex `_id` of the conversation row (from
|
|
180
|
+
* `useConversations` / `useConversationByPhonePair`) as
|
|
181
|
+
* `conversationId`.
|
|
182
|
+
*/
|
|
183
|
+
declare function useMessages(conversationId: string | null | undefined, options?: UseMessagesOptions): UseQueryResult<ConversationMessageRow[]>;
|
|
184
|
+
/**
|
|
185
|
+
* Subscribe to the user's total unread message count across all
|
|
186
|
+
* conversations. Backs the inbox tab badge in CommHub.
|
|
187
|
+
*
|
|
188
|
+
* Returns `0` when the underlying query resolves with no unread
|
|
189
|
+
* messages, `undefined` while loading or when `userId` is missing.
|
|
190
|
+
*/
|
|
191
|
+
declare function useUnreadCount(userId: string | null | undefined): UseQueryResult<number>;
|
|
192
|
+
|
|
5
193
|
/**
|
|
6
194
|
* React hooks for Truth SDK — real-time Convex-backed data access.
|
|
7
195
|
*
|
|
@@ -184,6 +372,98 @@ interface UsePatientPhotoOptions {
|
|
|
184
372
|
* binary from Elation + upload to S3.
|
|
185
373
|
*/
|
|
186
374
|
declare function usePatientPhoto(elationId: number | undefined, options?: UsePatientPhotoOptions): any;
|
|
375
|
+
interface ConversationMessage {
|
|
376
|
+
kind: "call" | "sms";
|
|
377
|
+
id: string;
|
|
378
|
+
providerId: string;
|
|
379
|
+
state: string | null;
|
|
380
|
+
direction: string | null;
|
|
381
|
+
fromNumber: string | null;
|
|
382
|
+
toNumber: string | null;
|
|
383
|
+
voicemailLink: string | null;
|
|
384
|
+
duration: number | null;
|
|
385
|
+
text: string | null;
|
|
386
|
+
mms: boolean;
|
|
387
|
+
mmsUrl: string | null;
|
|
388
|
+
messageStatus: string | null;
|
|
389
|
+
occurredAt: string;
|
|
390
|
+
conversationId: string | null;
|
|
391
|
+
patientId: string | null;
|
|
392
|
+
}
|
|
393
|
+
interface UseConversationMessagesOptions {
|
|
394
|
+
/** Max items to return (default 200). */
|
|
395
|
+
limit?: number;
|
|
396
|
+
}
|
|
397
|
+
/**
|
|
398
|
+
* Subscribe to a conversation's calls + SMS merged chronologically.
|
|
399
|
+
* Pass the patient phone + the provider phone — Truth computes a
|
|
400
|
+
* normalized pair key server-side so formatting differences don't
|
|
401
|
+
* matter.
|
|
402
|
+
*
|
|
403
|
+
* Returns `undefined` while loading, then `ConversationMessage[]`
|
|
404
|
+
* sorted newest-first. Updates live as new webhook events land in
|
|
405
|
+
* Convex via the kinesis consumer.
|
|
406
|
+
*/
|
|
407
|
+
declare function useConversationMessages(input: {
|
|
408
|
+
phoneA?: string;
|
|
409
|
+
phoneB?: string;
|
|
410
|
+
conversationId?: string;
|
|
411
|
+
}, options?: UseConversationMessagesOptions): ConversationMessage[] | undefined;
|
|
412
|
+
|
|
413
|
+
/**
|
|
414
|
+
* useNotifications — Truth SDK React hook for push notifications.
|
|
415
|
+
*
|
|
416
|
+
* Shape-compatible with `expo-notifications` where practical so
|
|
417
|
+
* consumers port with minimal change. The hook dynamically imports
|
|
418
|
+
* `expo-notifications` so the SDK doesn't hard-depend on Expo —
|
|
419
|
+
* consumers running on a non-Expo runtime (e.g. a server test harness)
|
|
420
|
+
* can still import the SDK without Metro blowing up.
|
|
421
|
+
*
|
|
422
|
+
* Exposes:
|
|
423
|
+
* - permissionStatus — "granted" / "denied" / "undetermined"
|
|
424
|
+
* - devicePushToken — native APNs/FCM token (undefined until register)
|
|
425
|
+
* - register() — request permission, fetch token, register with Truth
|
|
426
|
+
* - unregister() — revoke the device
|
|
427
|
+
* - addReceivedListener / addResponseListener — re-exports of expo's
|
|
428
|
+
* - getBadgeCount / setBadgeCount — re-exports of expo's
|
|
429
|
+
*
|
|
430
|
+
* Web push (VAPID subscription) lands in Phase 3.
|
|
431
|
+
*/
|
|
432
|
+
type PermissionStatus = "granted" | "denied" | "undetermined" | "unknown";
|
|
433
|
+
interface UseNotificationsOptions {
|
|
434
|
+
/** Truth API base URL, e.g. https://app.truth.communication-hub.com */
|
|
435
|
+
apiBaseUrl: string;
|
|
436
|
+
/** `hn_live_*` API key for the caller's application. */
|
|
437
|
+
apiKey: string;
|
|
438
|
+
/** Current user id — used when registering the device. */
|
|
439
|
+
userId: string | null | undefined;
|
|
440
|
+
/** Optional app version string stored on the device row. */
|
|
441
|
+
appVersion?: string;
|
|
442
|
+
/**
|
|
443
|
+
* Auto-register on mount when permission is already granted.
|
|
444
|
+
* Default: true. Set false if you want to control the registration
|
|
445
|
+
* lifecycle yourself.
|
|
446
|
+
*/
|
|
447
|
+
autoRegister?: boolean;
|
|
448
|
+
/** VAPID public key for web push. Fetched automatically if omitted. */
|
|
449
|
+
vapidPublicKey?: string;
|
|
450
|
+
/** Path to the service worker file. Default: "/truth-sw.js" */
|
|
451
|
+
serviceWorkerPath?: string;
|
|
452
|
+
}
|
|
453
|
+
interface UseNotificationsResult {
|
|
454
|
+
permissionStatus: PermissionStatus;
|
|
455
|
+
devicePushToken: string | null;
|
|
456
|
+
register: () => Promise<{
|
|
457
|
+
ok: boolean;
|
|
458
|
+
reason?: string;
|
|
459
|
+
}>;
|
|
460
|
+
unregister: () => Promise<void>;
|
|
461
|
+
addReceivedListener: (listener: (n: unknown) => void) => () => void;
|
|
462
|
+
addResponseListener: (listener: (r: unknown) => void) => () => void;
|
|
463
|
+
getBadgeCount: () => Promise<number>;
|
|
464
|
+
setBadgeCount: (count: number) => Promise<void>;
|
|
465
|
+
}
|
|
466
|
+
declare function useNotifications(options: UseNotificationsOptions): UseNotificationsResult;
|
|
187
467
|
|
|
188
468
|
interface TruthProviderProps {
|
|
189
469
|
/** Truth environment — determines which Convex deployment to connect to */
|
|
@@ -615,4 +895,4 @@ interface PatientListOptions {
|
|
|
615
895
|
cursor?: string;
|
|
616
896
|
}
|
|
617
897
|
|
|
618
|
-
export { type Appointment, type AppointmentListOptions, type EventPayloadMap, type EventType, type Patient, type PatientListOptions, type Physician, type TrackOptions, TruthProvider, type TruthProviderProps, type TruthTrackingContextValue, TruthTrackingProvider, type TruthTrackingProviderProps, type UseAppointmentListOptions, type UsePatientBasicOptions, type UsePatientBasicResult, type UsePatientListOptions, type UsePatientMedicalOptions, type UsePatientPhotoOptions, useAppointment, useAppointmentByElationId, useAppointments, usePatient, usePatientBasic, usePatientByElationId, usePatientByHintId, usePatientMedical, usePatientPhoto, usePatients, usePharmacyByNcpdpId, usePhysicianByElationId, usePhysiciansByElationIds, useTruth };
|
|
898
|
+
export { type Appointment, type AppointmentListOptions, type ConversationListItem, type ConversationMessage, type ConversationMessageRow, type ConversationRow, type EventPayloadMap, type EventType, type Patient, type PatientListOptions, type PermissionStatus, type Physician, type TrackOptions, TruthProvider, type TruthProviderProps, type TruthTrackingContextValue, TruthTrackingProvider, type TruthTrackingProviderProps, type UseAppointmentListOptions, type UseConversationMessagesOptions, type UseConversationsFilters, type UseMessagesOptions, type UseNotificationsOptions, type UseNotificationsResult, type UsePatientBasicOptions, type UsePatientBasicResult, type UsePatientListOptions, type UsePatientMedicalOptions, type UsePatientPhotoOptions, type UseQueryResult, useAppointment, useAppointmentByElationId, useAppointments, useConversationByPhonePair, useConversationMessages, useConversations, useMessages, useNotifications, usePatient, usePatientBasic, usePatientByElationId, usePatientByHintId, usePatientMedical, usePatientPhoto, usePatients, usePharmacyByNcpdpId, usePhysicianByElationId, usePhysiciansByElationIds, useTruth, useUnreadCount };
|
package/dist/react.d.ts
CHANGED
|
@@ -2,6 +2,194 @@ import * as react from 'react';
|
|
|
2
2
|
import { ReactNode } from 'react';
|
|
3
3
|
import { ConvexReactClient } from 'convex/react';
|
|
4
4
|
|
|
5
|
+
/**
|
|
6
|
+
* React hooks for Truth SDK — reactive conversation + message data.
|
|
7
|
+
*
|
|
8
|
+
* Wraps Convex queries owned by the Truth backend so consumers (CommHub
|
|
9
|
+
* Expo frontend) get live-updating conversation lists, message threads,
|
|
10
|
+
* and unread totals without managing subscriptions themselves.
|
|
11
|
+
*
|
|
12
|
+
* **Hook contract:** every hook in this file returns
|
|
13
|
+
* `{ data, loading, error }`. `data` is `undefined` while loading and
|
|
14
|
+
* also when the underlying query is `"skip"`'d (caller didn't pass the
|
|
15
|
+
* required arg yet). `loading` is `true` only while a real subscription
|
|
16
|
+
* is in-flight; once `data` resolves (even to `null`) `loading` flips
|
|
17
|
+
* to `false`. `error` is reserved for SDK-side validation — Convex
|
|
18
|
+
* itself throws on subscribe rather than returning an error value, so
|
|
19
|
+
* unhandled query errors propagate as React errors and should be caught
|
|
20
|
+
* with an error boundary.
|
|
21
|
+
*
|
|
22
|
+
* **Backed by PR #110 schema (commit `41dbb59` on
|
|
23
|
+
* `feat/migrate-dialpad-webhook-and-messages-to-truth`):**
|
|
24
|
+
* - `conversations:listForUser` → `useConversations`
|
|
25
|
+
* - `conversations:getUnreadTotalForUser` → `useUnreadCount`
|
|
26
|
+
* - `conversations:getByPhonePair` → `useConversationByPhonePair`
|
|
27
|
+
* - `conversationMessages:getByConversationId` → `useMessages`
|
|
28
|
+
*
|
|
29
|
+
* **Deliberately NOT shipped here (no backend query yet — flagged in
|
|
30
|
+
* PR #111 body for follow-up):**
|
|
31
|
+
* - Single-conversation-by-id lookup. Convex `conversations` has no
|
|
32
|
+
* `get(id)` query — only `getByPhonePair`. CommHub uses phonePair as
|
|
33
|
+
* the primary handle, so the byPair flavor is what consumers need;
|
|
34
|
+
* if id-based lookup is needed later we can add a `conversations:get`
|
|
35
|
+
* in Truth.
|
|
36
|
+
* - Participants / "seen by" hook. The migrated schema has no
|
|
37
|
+
* `conversationParticipants` table — read state is per-user via
|
|
38
|
+
* `conversationReads` and there's no public list query for it yet.
|
|
39
|
+
* - `markRead` mutation. PR #110 declares `markRead` as
|
|
40
|
+
* `internalMutation`, so the frontend can't invoke it directly — it
|
|
41
|
+
* has to go through a Truth HTTP endpoint, or webhook-migrator needs
|
|
42
|
+
* to flip it to a public `mutation`. Flagged for a follow-up.
|
|
43
|
+
*
|
|
44
|
+
* Must be used within `<TruthProvider />` (see `./provider`).
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* ```tsx
|
|
48
|
+
* import {
|
|
49
|
+
* useConversations,
|
|
50
|
+
* useConversationByPhonePair,
|
|
51
|
+
* useMessages,
|
|
52
|
+
* useUnreadCount,
|
|
53
|
+
* } from '@hipnation-truth/sdk/react';
|
|
54
|
+
*
|
|
55
|
+
* function Inbox({ userId }: { userId: string }) {
|
|
56
|
+
* const { data: convos, loading } = useConversations({ userId });
|
|
57
|
+
* const { data: unread } = useUnreadCount(userId);
|
|
58
|
+
* if (loading) return <Spinner />;
|
|
59
|
+
* return (
|
|
60
|
+
* <div>
|
|
61
|
+
* <Badge count={unread ?? 0} />
|
|
62
|
+
* {convos?.map((c) => <ConvoRow key={c.id} convo={c} />)}
|
|
63
|
+
* </div>
|
|
64
|
+
* );
|
|
65
|
+
* }
|
|
66
|
+
* ```
|
|
67
|
+
*/
|
|
68
|
+
/**
|
|
69
|
+
* Row shape returned by `conversations:listForUser` — joins the base
|
|
70
|
+
* `conversations` row with the caller's per-user `conversationReads`
|
|
71
|
+
* entry so unread state lives on each item.
|
|
72
|
+
*/
|
|
73
|
+
interface ConversationListItem {
|
|
74
|
+
/** Convex id of the conversation row. */
|
|
75
|
+
id: string;
|
|
76
|
+
patientPhone: string;
|
|
77
|
+
providerPhone: string;
|
|
78
|
+
/** Sorted-digit-pair key (commutative — same regardless of direction). */
|
|
79
|
+
phonePair: string;
|
|
80
|
+
/** Truth-side patient id, when the kinesis pipeline could resolve it. */
|
|
81
|
+
patientId: string | null;
|
|
82
|
+
/** ISO timestamp of the most recent message in the conversation. */
|
|
83
|
+
lastMessageAt: string;
|
|
84
|
+
/** Caller's unread count for this conversation. */
|
|
85
|
+
unreadCount: number;
|
|
86
|
+
/** ISO timestamp of when the caller last marked the conversation read. */
|
|
87
|
+
lastReadAt: string | null;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Raw `conversations` table row — what `getByPhonePair` returns. No
|
|
91
|
+
* unread / read joining; for that, prefer `useConversations`.
|
|
92
|
+
*/
|
|
93
|
+
interface ConversationRow {
|
|
94
|
+
_id: string;
|
|
95
|
+
_creationTime: number;
|
|
96
|
+
patientPhone: string;
|
|
97
|
+
providerPhone: string;
|
|
98
|
+
phonePair: string;
|
|
99
|
+
patientId: string | null;
|
|
100
|
+
lastEventId: string | null;
|
|
101
|
+
lastMessageAt: string;
|
|
102
|
+
createdAt: string;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Message row returned by `conversationMessages:getByConversationId` —
|
|
106
|
+
* calls + SMS merged chronologically. Mirrors `ConversationMessage`
|
|
107
|
+
* already exported from the SDK; re-exported here under a clearer name
|
|
108
|
+
* for the new hook surface.
|
|
109
|
+
*/
|
|
110
|
+
interface ConversationMessageRow {
|
|
111
|
+
kind: "call" | "sms";
|
|
112
|
+
id: string;
|
|
113
|
+
providerId: string;
|
|
114
|
+
state: string | null;
|
|
115
|
+
direction: string | null;
|
|
116
|
+
fromNumber: string | null;
|
|
117
|
+
toNumber: string | null;
|
|
118
|
+
voicemailLink: string | null;
|
|
119
|
+
duration: number | null;
|
|
120
|
+
text: string | null;
|
|
121
|
+
mms: boolean;
|
|
122
|
+
mmsUrl: string | null;
|
|
123
|
+
messageStatus: string | null;
|
|
124
|
+
occurredAt: string;
|
|
125
|
+
conversationId: string | null;
|
|
126
|
+
patientId: string | null;
|
|
127
|
+
}
|
|
128
|
+
interface UseQueryResult<T> {
|
|
129
|
+
/**
|
|
130
|
+
* Query data. `undefined` while loading or while the query is
|
|
131
|
+
* intentionally skipped (e.g. caller hasn't supplied `userId` yet).
|
|
132
|
+
*/
|
|
133
|
+
data: T | undefined;
|
|
134
|
+
/** True only while a real subscription is in-flight. */
|
|
135
|
+
loading: boolean;
|
|
136
|
+
/**
|
|
137
|
+
* Reserved for client-side validation errors surfaced by the SDK
|
|
138
|
+
* itself. Convex query errors propagate as React errors and should
|
|
139
|
+
* be caught with an error boundary.
|
|
140
|
+
*/
|
|
141
|
+
error: Error | undefined;
|
|
142
|
+
}
|
|
143
|
+
interface UseConversationsFilters {
|
|
144
|
+
/**
|
|
145
|
+
* Truth user id (the Better Auth subject). Pass `undefined` to skip
|
|
146
|
+
* the query — useful when the auth session is still loading.
|
|
147
|
+
*/
|
|
148
|
+
userId: string | null | undefined;
|
|
149
|
+
/** Page size. Server caps at 100 by default. */
|
|
150
|
+
limit?: number;
|
|
151
|
+
}
|
|
152
|
+
interface UseMessagesOptions {
|
|
153
|
+
/** Page size. Server caps at 200 by default. */
|
|
154
|
+
limit?: number;
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Subscribe to a user's conversations — joined with their per-conversation
|
|
158
|
+
* unread count, sorted by most recent message. Updates live as new
|
|
159
|
+
* SMS / calls land in Convex and the webhook bumps `unreadCount`.
|
|
160
|
+
*
|
|
161
|
+
* Returns `{ data: undefined, loading: false }` while the auth session
|
|
162
|
+
* resolves (`userId === undefined`); not an error, just a skip.
|
|
163
|
+
*/
|
|
164
|
+
declare function useConversations(filters: UseConversationsFilters): UseQueryResult<ConversationListItem[]>;
|
|
165
|
+
/**
|
|
166
|
+
* Look up a single conversation by its normalized phonePair (sorted
|
|
167
|
+
* digit-pair, e.g. `"5125550123|6505551234"`). Returns `null` if no
|
|
168
|
+
* conversation exists yet for that pair.
|
|
169
|
+
*
|
|
170
|
+
* Use the `phonePairKey(patientPhone, providerPhone)` helper exposed by
|
|
171
|
+
* the Truth Convex module to derive the key from raw phone strings.
|
|
172
|
+
*/
|
|
173
|
+
declare function useConversationByPhonePair(phonePair: string | null | undefined): UseQueryResult<ConversationRow | null>;
|
|
174
|
+
/**
|
|
175
|
+
* Subscribe to a paginated message stream for a single conversation.
|
|
176
|
+
* Calls + SMS merged chronologically, newest-first. Live as the
|
|
177
|
+
* kinesis consumer writes to `messageCalls` / `messageSms`.
|
|
178
|
+
*
|
|
179
|
+
* Pass the Convex `_id` of the conversation row (from
|
|
180
|
+
* `useConversations` / `useConversationByPhonePair`) as
|
|
181
|
+
* `conversationId`.
|
|
182
|
+
*/
|
|
183
|
+
declare function useMessages(conversationId: string | null | undefined, options?: UseMessagesOptions): UseQueryResult<ConversationMessageRow[]>;
|
|
184
|
+
/**
|
|
185
|
+
* Subscribe to the user's total unread message count across all
|
|
186
|
+
* conversations. Backs the inbox tab badge in CommHub.
|
|
187
|
+
*
|
|
188
|
+
* Returns `0` when the underlying query resolves with no unread
|
|
189
|
+
* messages, `undefined` while loading or when `userId` is missing.
|
|
190
|
+
*/
|
|
191
|
+
declare function useUnreadCount(userId: string | null | undefined): UseQueryResult<number>;
|
|
192
|
+
|
|
5
193
|
/**
|
|
6
194
|
* React hooks for Truth SDK — real-time Convex-backed data access.
|
|
7
195
|
*
|
|
@@ -184,6 +372,98 @@ interface UsePatientPhotoOptions {
|
|
|
184
372
|
* binary from Elation + upload to S3.
|
|
185
373
|
*/
|
|
186
374
|
declare function usePatientPhoto(elationId: number | undefined, options?: UsePatientPhotoOptions): any;
|
|
375
|
+
interface ConversationMessage {
|
|
376
|
+
kind: "call" | "sms";
|
|
377
|
+
id: string;
|
|
378
|
+
providerId: string;
|
|
379
|
+
state: string | null;
|
|
380
|
+
direction: string | null;
|
|
381
|
+
fromNumber: string | null;
|
|
382
|
+
toNumber: string | null;
|
|
383
|
+
voicemailLink: string | null;
|
|
384
|
+
duration: number | null;
|
|
385
|
+
text: string | null;
|
|
386
|
+
mms: boolean;
|
|
387
|
+
mmsUrl: string | null;
|
|
388
|
+
messageStatus: string | null;
|
|
389
|
+
occurredAt: string;
|
|
390
|
+
conversationId: string | null;
|
|
391
|
+
patientId: string | null;
|
|
392
|
+
}
|
|
393
|
+
interface UseConversationMessagesOptions {
|
|
394
|
+
/** Max items to return (default 200). */
|
|
395
|
+
limit?: number;
|
|
396
|
+
}
|
|
397
|
+
/**
|
|
398
|
+
* Subscribe to a conversation's calls + SMS merged chronologically.
|
|
399
|
+
* Pass the patient phone + the provider phone — Truth computes a
|
|
400
|
+
* normalized pair key server-side so formatting differences don't
|
|
401
|
+
* matter.
|
|
402
|
+
*
|
|
403
|
+
* Returns `undefined` while loading, then `ConversationMessage[]`
|
|
404
|
+
* sorted newest-first. Updates live as new webhook events land in
|
|
405
|
+
* Convex via the kinesis consumer.
|
|
406
|
+
*/
|
|
407
|
+
declare function useConversationMessages(input: {
|
|
408
|
+
phoneA?: string;
|
|
409
|
+
phoneB?: string;
|
|
410
|
+
conversationId?: string;
|
|
411
|
+
}, options?: UseConversationMessagesOptions): ConversationMessage[] | undefined;
|
|
412
|
+
|
|
413
|
+
/**
|
|
414
|
+
* useNotifications — Truth SDK React hook for push notifications.
|
|
415
|
+
*
|
|
416
|
+
* Shape-compatible with `expo-notifications` where practical so
|
|
417
|
+
* consumers port with minimal change. The hook dynamically imports
|
|
418
|
+
* `expo-notifications` so the SDK doesn't hard-depend on Expo —
|
|
419
|
+
* consumers running on a non-Expo runtime (e.g. a server test harness)
|
|
420
|
+
* can still import the SDK without Metro blowing up.
|
|
421
|
+
*
|
|
422
|
+
* Exposes:
|
|
423
|
+
* - permissionStatus — "granted" / "denied" / "undetermined"
|
|
424
|
+
* - devicePushToken — native APNs/FCM token (undefined until register)
|
|
425
|
+
* - register() — request permission, fetch token, register with Truth
|
|
426
|
+
* - unregister() — revoke the device
|
|
427
|
+
* - addReceivedListener / addResponseListener — re-exports of expo's
|
|
428
|
+
* - getBadgeCount / setBadgeCount — re-exports of expo's
|
|
429
|
+
*
|
|
430
|
+
* Web push (VAPID subscription) lands in Phase 3.
|
|
431
|
+
*/
|
|
432
|
+
type PermissionStatus = "granted" | "denied" | "undetermined" | "unknown";
|
|
433
|
+
interface UseNotificationsOptions {
|
|
434
|
+
/** Truth API base URL, e.g. https://app.truth.communication-hub.com */
|
|
435
|
+
apiBaseUrl: string;
|
|
436
|
+
/** `hn_live_*` API key for the caller's application. */
|
|
437
|
+
apiKey: string;
|
|
438
|
+
/** Current user id — used when registering the device. */
|
|
439
|
+
userId: string | null | undefined;
|
|
440
|
+
/** Optional app version string stored on the device row. */
|
|
441
|
+
appVersion?: string;
|
|
442
|
+
/**
|
|
443
|
+
* Auto-register on mount when permission is already granted.
|
|
444
|
+
* Default: true. Set false if you want to control the registration
|
|
445
|
+
* lifecycle yourself.
|
|
446
|
+
*/
|
|
447
|
+
autoRegister?: boolean;
|
|
448
|
+
/** VAPID public key for web push. Fetched automatically if omitted. */
|
|
449
|
+
vapidPublicKey?: string;
|
|
450
|
+
/** Path to the service worker file. Default: "/truth-sw.js" */
|
|
451
|
+
serviceWorkerPath?: string;
|
|
452
|
+
}
|
|
453
|
+
interface UseNotificationsResult {
|
|
454
|
+
permissionStatus: PermissionStatus;
|
|
455
|
+
devicePushToken: string | null;
|
|
456
|
+
register: () => Promise<{
|
|
457
|
+
ok: boolean;
|
|
458
|
+
reason?: string;
|
|
459
|
+
}>;
|
|
460
|
+
unregister: () => Promise<void>;
|
|
461
|
+
addReceivedListener: (listener: (n: unknown) => void) => () => void;
|
|
462
|
+
addResponseListener: (listener: (r: unknown) => void) => () => void;
|
|
463
|
+
getBadgeCount: () => Promise<number>;
|
|
464
|
+
setBadgeCount: (count: number) => Promise<void>;
|
|
465
|
+
}
|
|
466
|
+
declare function useNotifications(options: UseNotificationsOptions): UseNotificationsResult;
|
|
187
467
|
|
|
188
468
|
interface TruthProviderProps {
|
|
189
469
|
/** Truth environment — determines which Convex deployment to connect to */
|
|
@@ -615,4 +895,4 @@ interface PatientListOptions {
|
|
|
615
895
|
cursor?: string;
|
|
616
896
|
}
|
|
617
897
|
|
|
618
|
-
export { type Appointment, type AppointmentListOptions, type EventPayloadMap, type EventType, type Patient, type PatientListOptions, type Physician, type TrackOptions, TruthProvider, type TruthProviderProps, type TruthTrackingContextValue, TruthTrackingProvider, type TruthTrackingProviderProps, type UseAppointmentListOptions, type UsePatientBasicOptions, type UsePatientBasicResult, type UsePatientListOptions, type UsePatientMedicalOptions, type UsePatientPhotoOptions, useAppointment, useAppointmentByElationId, useAppointments, usePatient, usePatientBasic, usePatientByElationId, usePatientByHintId, usePatientMedical, usePatientPhoto, usePatients, usePharmacyByNcpdpId, usePhysicianByElationId, usePhysiciansByElationIds, useTruth };
|
|
898
|
+
export { type Appointment, type AppointmentListOptions, type ConversationListItem, type ConversationMessage, type ConversationMessageRow, type ConversationRow, type EventPayloadMap, type EventType, type Patient, type PatientListOptions, type PermissionStatus, type Physician, type TrackOptions, TruthProvider, type TruthProviderProps, type TruthTrackingContextValue, TruthTrackingProvider, type TruthTrackingProviderProps, type UseAppointmentListOptions, type UseConversationMessagesOptions, type UseConversationsFilters, type UseMessagesOptions, type UseNotificationsOptions, type UseNotificationsResult, type UsePatientBasicOptions, type UsePatientBasicResult, type UsePatientListOptions, type UsePatientMedicalOptions, type UsePatientPhotoOptions, type UseQueryResult, useAppointment, useAppointmentByElationId, useAppointments, useConversationByPhonePair, useConversationMessages, useConversations, useMessages, useNotifications, usePatient, usePatientBasic, usePatientByElationId, usePatientByHintId, usePatientMedical, usePatientPhoto, usePatients, usePharmacyByNcpdpId, usePhysicianByElationId, usePhysiciansByElationIds, useTruth, useUnreadCount };
|