@hipnation-truth/sdk 0.26.4 → 0.26.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/react.d.ts CHANGED
@@ -591,23 +591,6 @@ interface UsePatientMedicalOptions {
591
591
  */
592
592
  skipRefresh?: boolean;
593
593
  }
594
- /**
595
- * Composite hook that returns a patient's medical records — medications,
596
- * problems, allergies, appointments — from the Convex cache.
597
- *
598
- * On mount (and when `elationId` changes) fires a background refresh
599
- * against Truth's `/api/patients/medical/refresh` endpoint so stale data
600
- * is pulled in without blocking render. Returns cached data immediately;
601
- * Convex subscription updates the UI when refresh completes.
602
- *
603
- * OFFLINE-READS POLICY: these medical-record queries ARE mirrored offline
604
- * via `usePersistentQuery`, so medications, problems, allergies and
605
- * appointments render from the at-rest mirror when the device is offline.
606
- * Full medical records are the most sensitive PHI we hold, so they are
607
- * only ever written to the encrypted-at-rest store (256-bit MMKV key held
608
- * in the device keychain), never to any plaintext storage. Keep them on
609
- * the encrypted mirror only — do not relax the store's encryption.
610
- */
611
594
  declare function usePatientMedical(elationId: number | undefined, options?: UsePatientMedicalOptions): {
612
595
  medications: unknown[] | undefined;
613
596
  problems: unknown[] | undefined;
@@ -1262,8 +1245,15 @@ type Environment = (typeof ENVIRONMENTS)[keyof typeof ENVIRONMENTS];
1262
1245
  * your identity provider's Clerk JWT template named "convex"
1263
1246
  * (e.g. `getToken({ template: "convex" })` from `@clerk/expo`), or
1264
1247
  * `null` when no user is signed in.
1248
+ *
1249
+ * Convex invokes this with `{ forceRefreshToken: true }` when the cached
1250
+ * token has expired — forward it to your provider (e.g. Clerk's
1251
+ * `getToken({ template: "convex", skipCache: opts?.forceRefreshToken })`)
1252
+ * so the refresh returns a fresh token rather than a stale cached one.
1265
1253
  */
1266
- type AuthTokenFetcher = () => Promise<string | null | undefined>;
1254
+ type AuthTokenFetcher = (opts?: {
1255
+ forceRefreshToken?: boolean;
1256
+ }) => Promise<string | null | undefined>;
1267
1257
  /**
1268
1258
  * Configuration for initializing a TruthClient.
1269
1259
  */
@@ -2771,6 +2761,13 @@ interface TruthSdkContextValue {
2771
2761
  apiKey: string;
2772
2762
  environment: string;
2773
2763
  client: TruthClient;
2764
+ /**
2765
+ * Clerk token fetcher (template "convex"), if wired. Hooks that make their
2766
+ * own HTTP calls (e.g. the patient `…/refresh` endpoints) use this to attach
2767
+ * `Authorization: Bearer <jwt>` so they work under a publishable `hn_pk_*`
2768
+ * key, which the API gate accepts only with a verified user JWT.
2769
+ */
2770
+ getAuthToken?: AuthTokenFetcher;
2774
2771
  /** Injected offline mirror (or the Noop default on web / flag off). */
2775
2772
  offlineStore: OfflineStore;
2776
2773
  /** Whether the offline-reads layer is active for this provider. */
package/dist/react.js CHANGED
@@ -2296,26 +2296,34 @@ function TruthProvider({
2296
2296
  getAuthTokenRef.current = getAuthToken;
2297
2297
  const hasAuthFetcher = Boolean(getAuthToken);
2298
2298
  const stableGetAuthToken = (0, import_react2.useMemo)(
2299
- () => hasAuthFetcher ? () => __async(null, null, function* () {
2299
+ () => hasAuthFetcher ? (opts) => __async(null, null, function* () {
2300
2300
  var _a2, _b2;
2301
- return (_b2 = yield (_a2 = getAuthTokenRef.current) == null ? void 0 : _a2.call(getAuthTokenRef)) != null ? _b2 : null;
2301
+ return (_b2 = yield (_a2 = getAuthTokenRef.current) == null ? void 0 : _a2.call(getAuthTokenRef, opts)) != null ? _b2 : null;
2302
2302
  }) : void 0,
2303
2303
  [hasAuthFetcher]
2304
2304
  );
2305
2305
  const [convexAuthed, setConvexAuthed] = (0, import_react2.useState)(false);
2306
2306
  (0, import_react2.useEffect)(() => {
2307
- if (stableGetAuthToken) {
2308
- convexClient.setAuth(
2309
- () => __async(null, null, function* () {
2310
- var _a2;
2311
- return (_a2 = yield stableGetAuthToken()) != null ? _a2 : null;
2312
- }),
2313
- (isAuthenticated) => setConvexAuthed(isAuthenticated)
2314
- );
2315
- } else {
2307
+ if (!stableGetAuthToken) {
2316
2308
  convexClient.clearAuth();
2317
2309
  setConvexAuthed(false);
2310
+ return;
2318
2311
  }
2312
+ const fetchToken = (opts) => __async(null, null, function* () {
2313
+ for (let attempt = 0; attempt < 6; attempt++) {
2314
+ try {
2315
+ const token = yield stableGetAuthToken(opts);
2316
+ if (token) return token;
2317
+ } catch (e) {
2318
+ }
2319
+ yield new Promise((resolve) => setTimeout(resolve, 200 + attempt * 150));
2320
+ }
2321
+ return null;
2322
+ });
2323
+ convexClient.setAuth(
2324
+ fetchToken,
2325
+ (isAuthenticated) => setConvexAuthed(isAuthenticated)
2326
+ );
2319
2327
  }, [convexClient, stableGetAuthToken]);
2320
2328
  const convexQueryClient = (0, import_react2.useMemo)(
2321
2329
  () => new import_react_query.ConvexQueryClient(convexClient),
@@ -2390,6 +2398,7 @@ function TruthProvider({
2390
2398
  client: truthClient,
2391
2399
  offlineStore,
2392
2400
  offlineEnabled,
2401
+ getAuthToken: stableGetAuthToken,
2393
2402
  authGated: hasAuthFetcher,
2394
2403
  authReady: convexAuthed
2395
2404
  }),
@@ -2400,6 +2409,7 @@ function TruthProvider({
2400
2409
  truthClient,
2401
2410
  offlineStore,
2402
2411
  offlineEnabled,
2412
+ stableGetAuthToken,
2403
2413
  hasAuthFetcher,
2404
2414
  convexAuthed
2405
2415
  ]
@@ -2739,11 +2749,33 @@ var medicationsByPatientRef = (0, import_server5.makeFunctionReference)("medical
2739
2749
  var problemsByPatientRef = (0, import_server5.makeFunctionReference)("medicalRecords:getProblemsByElationPatient");
2740
2750
  var allergiesByPatientRef = (0, import_server5.makeFunctionReference)("medicalRecords:getAllergiesByElationPatient");
2741
2751
  var appointmentsByPatientRef = (0, import_server5.makeFunctionReference)("medicalRecords:getAppointmentsByElationPatient");
2752
+ function postPatientRefresh(url, apiKey, getAuthToken, body, signal) {
2753
+ return __async(this, null, function* () {
2754
+ const headers = {
2755
+ "Content-Type": "application/json",
2756
+ "X-API-Key": apiKey
2757
+ };
2758
+ try {
2759
+ const token = yield getAuthToken == null ? void 0 : getAuthToken();
2760
+ if (token) {
2761
+ headers.Authorization = `Bearer ${token}`;
2762
+ }
2763
+ } catch (e) {
2764
+ }
2765
+ yield fetch(url, {
2766
+ method: "POST",
2767
+ headers,
2768
+ body: JSON.stringify(body),
2769
+ signal
2770
+ });
2771
+ });
2772
+ }
2742
2773
  function usePatientMedical(elationId, options) {
2743
2774
  var _a, _b;
2744
2775
  const sdkContext = useTruthSdkContext();
2745
2776
  const apiBaseUrl = (_a = options == null ? void 0 : options.apiBaseUrl) != null ? _a : sdkContext == null ? void 0 : sdkContext.apiBaseUrl;
2746
2777
  const apiKey = (_b = options == null ? void 0 : options.apiKey) != null ? _b : sdkContext == null ? void 0 : sdkContext.apiKey;
2778
+ const getAuthToken = sdkContext == null ? void 0 : sdkContext.getAuthToken;
2747
2779
  const medications = usePersistentQuery(
2748
2780
  medicationsByPatientRef,
2749
2781
  elationId !== void 0 ? { elationPatientId: elationId } : "skip"
@@ -2768,18 +2800,16 @@ function usePatientMedical(elationId, options) {
2768
2800
  return;
2769
2801
  }
2770
2802
  const controller = new AbortController();
2771
- void fetch(`${apiBaseUrl}/api/patients/medical/refresh`, {
2772
- method: "POST",
2773
- headers: {
2774
- "Content-Type": "application/json",
2775
- "X-API-Key": apiKey
2776
- },
2777
- body: JSON.stringify({ elationId }),
2778
- signal: controller.signal
2779
- }).catch(() => {
2803
+ void postPatientRefresh(
2804
+ `${apiBaseUrl}/api/patients/medical/refresh`,
2805
+ apiKey,
2806
+ getAuthToken,
2807
+ { elationId },
2808
+ controller.signal
2809
+ ).catch(() => {
2780
2810
  });
2781
2811
  return () => controller.abort();
2782
- }, [elationId, apiBaseUrl, apiKey, options == null ? void 0 : options.skipRefresh]);
2812
+ }, [elationId, apiBaseUrl, apiKey, getAuthToken, options == null ? void 0 : options.skipRefresh]);
2783
2813
  return { medications, problems, allergies, appointments };
2784
2814
  }
2785
2815
  var elationPatientByIdRef = (0, import_server5.makeFunctionReference)("elationPatients:getByElationId");
@@ -2791,6 +2821,7 @@ function usePatientBasic(input, options) {
2791
2821
  const sdkContext = useTruthSdkContext();
2792
2822
  const apiBaseUrl = (_a = options == null ? void 0 : options.apiBaseUrl) != null ? _a : sdkContext == null ? void 0 : sdkContext.apiBaseUrl;
2793
2823
  const apiKey = (_b = options == null ? void 0 : options.apiKey) != null ? _b : sdkContext == null ? void 0 : sdkContext.apiKey;
2824
+ const getAuthToken = sdkContext == null ? void 0 : sdkContext.getAuthToken;
2794
2825
  const elationRow = usePersistentQuery(
2795
2826
  elationPatientByIdRef,
2796
2827
  input.elationId !== void 0 ? { elationId: input.elationId } : "skip"
@@ -2810,21 +2841,23 @@ function usePatientBasic(input, options) {
2810
2841
  return;
2811
2842
  }
2812
2843
  const controller = new AbortController();
2813
- void fetch(`${apiBaseUrl}/api/patients/basic/refresh`, {
2814
- method: "POST",
2815
- headers: {
2816
- "Content-Type": "application/json",
2817
- "X-API-Key": apiKey
2818
- },
2819
- body: JSON.stringify({
2820
- hintId: input.hintId,
2821
- elationId: input.elationId
2822
- }),
2823
- signal: controller.signal
2824
- }).catch(() => {
2844
+ void postPatientRefresh(
2845
+ `${apiBaseUrl}/api/patients/basic/refresh`,
2846
+ apiKey,
2847
+ getAuthToken,
2848
+ { hintId: input.hintId, elationId: input.elationId },
2849
+ controller.signal
2850
+ ).catch(() => {
2825
2851
  });
2826
2852
  return () => controller.abort();
2827
- }, [input.hintId, input.elationId, apiBaseUrl, apiKey, options == null ? void 0 : options.skipRefresh]);
2853
+ }, [
2854
+ input.hintId,
2855
+ input.elationId,
2856
+ apiBaseUrl,
2857
+ apiKey,
2858
+ getAuthToken,
2859
+ options == null ? void 0 : options.skipRefresh
2860
+ ]);
2828
2861
  const elationPatient = elationRow === void 0 ? void 0 : elationRow === null ? null : (_c = elationRow.raw) != null ? _c : null;
2829
2862
  const hintPatient = hintRow === void 0 ? void 0 : hintRow === null ? null : (_d = hintRow.raw) != null ? _d : null;
2830
2863
  const elationLoading = input.elationId !== void 0 && elationRow === void 0;
@@ -2848,6 +2881,7 @@ function usePatientPhoto(elationId, options) {
2848
2881
  const sdkContext = useTruthSdkContext();
2849
2882
  const apiBaseUrl = (_a = options == null ? void 0 : options.apiBaseUrl) != null ? _a : sdkContext == null ? void 0 : sdkContext.apiBaseUrl;
2850
2883
  const apiKey = (_b = options == null ? void 0 : options.apiKey) != null ? _b : sdkContext == null ? void 0 : sdkContext.apiKey;
2884
+ const getAuthToken = sdkContext == null ? void 0 : sdkContext.getAuthToken;
2851
2885
  const photo = usePersistentQuery(
2852
2886
  patientPhotoByIdRef,
2853
2887
  elationId !== void 0 ? { elationPatientId: elationId } : "skip"
@@ -2863,18 +2897,16 @@ function usePatientPhoto(elationId, options) {
2863
2897
  return;
2864
2898
  }
2865
2899
  const controller = new AbortController();
2866
- void fetch(`${apiBaseUrl}/api/patients/photo/refresh`, {
2867
- method: "POST",
2868
- headers: {
2869
- "Content-Type": "application/json",
2870
- "X-API-Key": apiKey
2871
- },
2872
- body: JSON.stringify({ elationId }),
2873
- signal: controller.signal
2874
- }).catch(() => {
2900
+ void postPatientRefresh(
2901
+ `${apiBaseUrl}/api/patients/photo/refresh`,
2902
+ apiKey,
2903
+ getAuthToken,
2904
+ { elationId },
2905
+ controller.signal
2906
+ ).catch(() => {
2875
2907
  });
2876
2908
  return () => controller.abort();
2877
- }, [elationId, apiBaseUrl, apiKey, options == null ? void 0 : options.skipRefresh]);
2909
+ }, [elationId, apiBaseUrl, apiKey, getAuthToken, options == null ? void 0 : options.skipRefresh]);
2878
2910
  return photo;
2879
2911
  }
2880
2912
  var messagesByPhonesRef = (0, import_server5.makeFunctionReference)("conversationMessages:getByPhones");