@ovok/core 0.4.31 → 0.4.32

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.
Files changed (123) hide show
  1. package/dist/client/ai-fhir/methods/AIFhirResources.d.ts +2 -1
  2. package/dist/client/ai-fhir/methods/AIFhirResources.js +2 -2
  3. package/dist/client/auth/methods/appleLogin.d.ts +2 -1
  4. package/dist/client/auth/methods/appleLogin.js +2 -2
  5. package/dist/client/auth/methods/changePassword.d.ts +2 -1
  6. package/dist/client/auth/methods/changePassword.js +2 -2
  7. package/dist/client/auth/methods/getSessions.d.ts +2 -1
  8. package/dist/client/auth/methods/getSessions.js +2 -2
  9. package/dist/client/auth/methods/googleLogin.d.ts +2 -1
  10. package/dist/client/auth/methods/googleLogin.js +2 -2
  11. package/dist/client/auth/methods/index.d.ts +1 -0
  12. package/dist/client/auth/methods/index.js +1 -0
  13. package/dist/client/auth/methods/login.d.ts +6 -2
  14. package/dist/client/auth/methods/login.js +60 -44
  15. package/dist/client/auth/methods/logout.d.ts +2 -1
  16. package/dist/client/auth/methods/logout.js +2 -2
  17. package/dist/client/auth/methods/refetchProfile.d.ts +2 -1
  18. package/dist/client/auth/methods/refetchProfile.js +3 -4
  19. package/dist/client/auth/methods/register.d.ts +2 -1
  20. package/dist/client/auth/methods/register.js +2 -2
  21. package/dist/client/auth/methods/registerPractitioner.d.ts +2 -1
  22. package/dist/client/auth/methods/registerPractitioner.js +2 -2
  23. package/dist/client/auth/methods/reloadSession.d.ts +7 -0
  24. package/dist/client/auth/methods/reloadSession.js +23 -0
  25. package/dist/client/auth/methods/requestDeleteUser.d.ts +2 -1
  26. package/dist/client/auth/methods/requestDeleteUser.js +5 -5
  27. package/dist/client/auth/methods/resetPassword.d.ts +2 -1
  28. package/dist/client/auth/methods/resetPassword.js +2 -2
  29. package/dist/client/auth/methods/revokeSessions.d.ts +2 -1
  30. package/dist/client/auth/methods/revokeSessions.js +2 -2
  31. package/dist/client/auth/methods/setPasswordFromReset.d.ts +2 -1
  32. package/dist/client/auth/methods/setPasswordFromReset.js +2 -2
  33. package/dist/client/auth/types/LoginBody.d.ts +10 -20
  34. package/dist/client/auth/types/LoginError.d.ts +15 -0
  35. package/dist/client/auth/types/LoginError.js +15 -0
  36. package/dist/client/bot/methods/executeBot.d.ts +2 -1
  37. package/dist/client/bot/methods/executeBot.js +2 -2
  38. package/dist/client/change-history/methods.d.ts +2 -1
  39. package/dist/client/change-history/methods.js +2 -2
  40. package/dist/client/chat/ai/methods/createAiSession.d.ts +2 -1
  41. package/dist/client/chat/ai/methods/createAiSession.js +2 -2
  42. package/dist/client/cms/methods.d.ts +6 -5
  43. package/dist/client/cms/methods.js +10 -10
  44. package/dist/client/consent/methods.d.ts +5 -4
  45. package/dist/client/consent/methods.js +8 -8
  46. package/dist/client/email/methods.d.ts +2 -1
  47. package/dist/client/email/methods.js +2 -2
  48. package/dist/client/errors/ovok-error-utils.d.ts +7 -0
  49. package/dist/client/errors/ovok-error-utils.js +49 -5
  50. package/dist/client/errors/ovok-error.d.ts +4 -0
  51. package/dist/client/errors/ovok-error.js +17 -4
  52. package/dist/client/errors/rate-limit-error.js +5 -3
  53. package/dist/client/experience/methods.d.ts +32 -31
  54. package/dist/client/experience/methods.js +62 -62
  55. package/dist/client/invites/methods.d.ts +6 -5
  56. package/dist/client/invites/methods.js +11 -11
  57. package/dist/client/notifications/methods.d.ts +6 -5
  58. package/dist/client/notifications/methods.js +10 -10
  59. package/dist/client/notifications/types.d.ts +92 -11
  60. package/dist/client/observation/methods/getLatestObservationsByCodes.d.ts +2 -1
  61. package/dist/client/observation/methods/getLatestObservationsByCodes.js +4 -4
  62. package/dist/client/offline/offline-measurement-queue.d.ts +4 -3
  63. package/dist/client/offline/offline-measurement-queue.js +6 -6
  64. package/dist/client/ovok-client.d.ts +9 -7
  65. package/dist/client/ovok-client.js +148 -22
  66. package/dist/client/patient/methods.d.ts +24 -23
  67. package/dist/client/patient/methods.js +49 -49
  68. package/dist/client/patient-sharing/methods.d.ts +7 -6
  69. package/dist/client/patient-sharing/methods.js +12 -12
  70. package/dist/client/platform/methods.d.ts +24 -23
  71. package/dist/client/platform/methods.js +46 -46
  72. package/dist/client/questionnaire-response/methods/createQuestionnaireResponseWithObservations.d.ts +2 -1
  73. package/dist/client/questionnaire-response/methods/createQuestionnaireResponseWithObservations.js +2 -2
  74. package/dist/client/questionnaire-response/methods/extractQuestionnaireObservations.d.ts +2 -1
  75. package/dist/client/questionnaire-response/methods/extractQuestionnaireObservations.js +2 -2
  76. package/dist/client/questionnaire-response/methods/populateQuestionnaire.d.ts +2 -1
  77. package/dist/client/questionnaire-response/methods/populateQuestionnaire.js +2 -2
  78. package/dist/client/questionnaire-response/methods/submitQuestionnaireResponse.d.ts +2 -1
  79. package/dist/client/questionnaire-response/methods/submitQuestionnaireResponse.js +2 -2
  80. package/dist/client/signals/methods.d.ts +22 -21
  81. package/dist/client/signals/methods.js +42 -42
  82. package/dist/client/slim/methods.d.ts +93 -57
  83. package/dist/client/slim/methods.js +295 -108
  84. package/dist/client/slim/paging.d.ts +18 -0
  85. package/dist/client/slim/paging.js +57 -0
  86. package/dist/client/slim/types.d.ts +370 -3
  87. package/dist/conformance/api-requirements.js +22 -0
  88. package/dist/conformance/capability-requirements.js +1 -1
  89. package/dist/hooks/account-hooks.js +7 -7
  90. package/dist/hooks/api-hooks.d.ts +5 -2
  91. package/dist/hooks/api-hooks.js +39 -16
  92. package/dist/hooks/cms-hooks.js +3 -3
  93. package/dist/hooks/email-hooks.js +1 -1
  94. package/dist/hooks/experience-hooks.js +5 -5
  95. package/dist/hooks/index.d.ts +2 -0
  96. package/dist/hooks/index.js +5 -3
  97. package/dist/hooks/notification-ack-hooks.d.ts +2 -1
  98. package/dist/hooks/notification-hooks.d.ts +4 -2
  99. package/dist/hooks/notification-hooks.js +11 -23
  100. package/dist/hooks/notification-invalidation.d.ts +3 -2
  101. package/dist/hooks/notification-invalidation.js +10 -1
  102. package/dist/hooks/notification-note-hooks.js +3 -3
  103. package/dist/hooks/observation-hooks.d.ts +5 -1
  104. package/dist/hooks/observation-hooks.js +6 -6
  105. package/dist/hooks/patient-hooks.js +18 -18
  106. package/dist/hooks/patient-sharing-hooks.js +2 -2
  107. package/dist/hooks/platform-hooks.js +3 -3
  108. package/dist/hooks/poll-hooks.d.ts +14 -0
  109. package/dist/hooks/poll-hooks.js +127 -0
  110. package/dist/hooks/signals-alert-hooks.d.ts +5 -20
  111. package/dist/hooks/signals-alert-hooks.js +38 -34
  112. package/dist/hooks/signals-alert-item-hooks.d.ts +19 -0
  113. package/dist/hooks/signals-alert-item-hooks.js +62 -0
  114. package/dist/hooks/signals-hooks.js +2 -2
  115. package/dist/index.d.ts +3 -0
  116. package/dist/index.js +4 -1
  117. package/dist/utils/auth/exchange-code.d.ts +2 -0
  118. package/dist/utils/auth/exchange-code.js +2 -2
  119. package/dist/utils/auth/handle-tenant-code.d.ts +1 -1
  120. package/dist/utils/auth/handle-tenant-code.js +13 -4
  121. package/dist/utils/auth/start-login.d.ts +3 -1
  122. package/dist/utils/auth/start-login.js +3 -3
  123. package/package.json +1 -1
@@ -271,10 +271,19 @@ export type SlimTrendPoint = {
271
271
  deviceModel?: string;
272
272
  deviceId?: string;
273
273
  };
274
- export type SlimTrends = {
275
- heartRate?: Record<string, SlimTrendPoint[]>;
276
- respiratoryRate?: Record<string, SlimTrendPoint[]>;
274
+ export type SlimGraphType = "heartRate" | "respiratoryRate" | "oxygenSaturation" | "pulseRate" | "perfusionIndex" | "bodyTemperature" | "systolicBloodPressure" | "diastolicBloodPressure" | "heartRateVariability";
275
+ export type SlimHistoricalGraphType = "heartRate" | "respiratoryRate";
276
+ export type SlimTrendStats = {
277
+ average: number | null;
278
+ max: number | null;
279
+ min: number | null;
280
+ total: number;
281
+ };
282
+ export type SlimTrendDeviceData = {
283
+ dataPoints: SlimTrendPoint[];
284
+ stats: SlimTrendStats;
277
285
  };
286
+ export type SlimTrends = Partial<Record<SlimGraphType, Record<string, SlimTrendDeviceData>>>;
278
287
  export type SlimSleepMetric = {
279
288
  current: number | string | null;
280
289
  average: number | string | null;
@@ -360,3 +369,361 @@ export type SlimExportPdfRequest = {
360
369
  end: string;
361
370
  };
362
371
  };
372
+ export type SlimProjectAddress = {
373
+ use?: "work" | "temp" | "old" | "billing";
374
+ type?: "postal" | "physical" | "both";
375
+ text?: string;
376
+ line?: string[];
377
+ city?: string;
378
+ district?: string;
379
+ state?: string;
380
+ postalCode?: string;
381
+ country?: string;
382
+ };
383
+ export type SlimProjectContact = {
384
+ telecom?: Array<{
385
+ system?: "email" | "phone" | "fax" | "pager" | "url" | "sms" | "other";
386
+ use?: "work" | "temp" | "old" | "mobile";
387
+ value?: string;
388
+ }>;
389
+ name?: {
390
+ use?: "temp" | "old" | "official" | "usual" | "nickname" | "anonymous" | "maiden";
391
+ prefix?: string[];
392
+ given?: string[];
393
+ family?: string;
394
+ suffix?: string[];
395
+ };
396
+ address?: SlimProjectAddress;
397
+ };
398
+ export type SlimProject = {
399
+ resourceType: "Project";
400
+ id: string;
401
+ name: string;
402
+ address?: SlimProjectAddress[];
403
+ contact?: SlimProjectContact[];
404
+ settings?: {
405
+ timeZone?: string;
406
+ trendsPeriod?: {
407
+ start: string;
408
+ durationSeconds: number;
409
+ };
410
+ };
411
+ };
412
+ export type SlimProjectRelationships = {
413
+ currentProject: SlimProject | null;
414
+ parentProject: SlimProject | null;
415
+ childProjects: SlimProject[];
416
+ };
417
+ export type SlimProjectRelationshipsV2 = {
418
+ currentProject: (SlimProject & {
419
+ deviceCount: number;
420
+ }) | null;
421
+ parentProject: (SlimProject & {
422
+ deviceCount: number;
423
+ }) | null;
424
+ childProjects: Array<SlimProject & {
425
+ deviceCount: number;
426
+ }>;
427
+ };
428
+ export type SlimChildProjectInput = {
429
+ id?: string;
430
+ name: string;
431
+ address?: SlimProjectAddress[];
432
+ contact?: SlimProjectContact[];
433
+ extension?: unknown;
434
+ settings?: SlimProject["settings"];
435
+ };
436
+ export type SlimProjectUsersQuery = {
437
+ profileType?: "Practitioner";
438
+ sortBy?: "profileName" | "userName" | "accessPolicyName";
439
+ orderBy?: "ASC" | "DESC";
440
+ search?: string;
441
+ accessPolicyId?: string;
442
+ profileId?: string;
443
+ userId?: string;
444
+ page?: number;
445
+ count?: number;
446
+ };
447
+ export type SlimProjectUser = {
448
+ user: {
449
+ resourceType: "User";
450
+ id: string;
451
+ firstName?: string;
452
+ lastName?: string;
453
+ email?: string;
454
+ project?: {
455
+ reference?: string;
456
+ display?: string;
457
+ };
458
+ meta?: {
459
+ project?: string;
460
+ lastUpdated?: string;
461
+ };
462
+ };
463
+ profile: {
464
+ resourceType: "Practitioner";
465
+ id: string;
466
+ name?: Array<{
467
+ use?: string;
468
+ text?: string;
469
+ family?: string;
470
+ given?: string[];
471
+ prefix?: string[];
472
+ suffix?: string[];
473
+ }>;
474
+ meta?: {
475
+ project?: string;
476
+ lastUpdated?: string;
477
+ };
478
+ };
479
+ membership: {
480
+ resourceType: "ProjectMembership";
481
+ id: string;
482
+ project?: {
483
+ reference?: string;
484
+ display?: string;
485
+ };
486
+ user?: {
487
+ reference?: string;
488
+ display?: string;
489
+ };
490
+ profile?: {
491
+ reference?: string;
492
+ display?: string;
493
+ };
494
+ accessPolicy?: {
495
+ reference?: string;
496
+ display?: string;
497
+ };
498
+ meta?: {
499
+ project?: string;
500
+ lastUpdated?: string;
501
+ };
502
+ };
503
+ status: "Active" | "Pending";
504
+ accessPolicy?: {
505
+ resourceType: "AccessPolicy";
506
+ id: string;
507
+ name?: string;
508
+ };
509
+ };
510
+ export type SlimProjectUsersPage = SlimPage<SlimProjectUser>;
511
+ export type SlimProjectDeviceCounts = {
512
+ projectId: string;
513
+ totalDeviceCount: number;
514
+ assignedResidentDeviceCount: number;
515
+ unassignedDeviceCount: number;
516
+ activeDeviceCount: number;
517
+ inactiveDeviceCount: number;
518
+ radarDeviceCount: number;
519
+ withingsDeviceCount: number;
520
+ };
521
+ export type SlimProjectPatientCounts = {
522
+ projectId: string;
523
+ totalPatientCount: number;
524
+ activePatientCount: number;
525
+ dischargedRecentPatientCount: number;
526
+ dischargedPatientCount: number;
527
+ archivedPatientCount: number;
528
+ };
529
+ export type SlimPolicyResource = {
530
+ resourceType: string;
531
+ interaction?: string[];
532
+ criteria?: string;
533
+ readonly?: boolean;
534
+ [key: string]: unknown;
535
+ };
536
+ export type SlimPolicy = {
537
+ resourceType: "AccessPolicy";
538
+ id: string;
539
+ name: string;
540
+ resource?: SlimPolicyResource[];
541
+ meta?: {
542
+ project?: string;
543
+ author?: {
544
+ reference: string;
545
+ };
546
+ lastUpdated?: string;
547
+ };
548
+ };
549
+ export type SlimPolicyMember = {
550
+ reference: string;
551
+ display?: string;
552
+ };
553
+ export type SlimPolicyResponse = {
554
+ policy: SlimPolicy;
555
+ members: SlimPolicyMember[];
556
+ };
557
+ export type SlimPolicyListQuery = {
558
+ page?: number;
559
+ count?: number;
560
+ sortBy?: "_id" | "_lastUpdated" | "name";
561
+ orderBy?: "ASC" | "DESC";
562
+ projectId?: string;
563
+ profile?: string;
564
+ search?: string;
565
+ };
566
+ export type SlimPolicyList = {
567
+ total: number;
568
+ resources: SlimPolicyResponse[];
569
+ };
570
+ export type SlimCreatePolicy = {
571
+ policy: {
572
+ resourceType: "AccessPolicy";
573
+ name: string;
574
+ resource: Array<{
575
+ resourceType: string;
576
+ interaction: string[];
577
+ }>;
578
+ };
579
+ members: SlimPolicyMember[];
580
+ };
581
+ export type SlimUpdatePolicy = Omit<SlimCreatePolicy, "policy"> & {
582
+ policy: SlimCreatePolicy["policy"] & {
583
+ id: string;
584
+ };
585
+ };
586
+ export type SlimOrganization = {
587
+ id: string;
588
+ name: string;
589
+ parentOrganizationId?: string;
590
+ description?: string;
591
+ };
592
+ export type SlimOrganizationInput = {
593
+ name: string;
594
+ parentOrganizationId?: string;
595
+ description?: string | null;
596
+ };
597
+ export type SlimPractitionerInviteInput = {
598
+ email: string;
599
+ name: string;
600
+ surname: string;
601
+ accessPolicyId: string;
602
+ admin?: boolean;
603
+ projectId?: string;
604
+ };
605
+ export type SlimPractitionerInviteResponse = {
606
+ membership: {
607
+ resourceType: "ProjectMembership";
608
+ id: string;
609
+ project?: {
610
+ reference: string;
611
+ display?: string;
612
+ };
613
+ user?: {
614
+ reference: string;
615
+ };
616
+ profile?: {
617
+ reference: string;
618
+ };
619
+ accessPolicy?: {
620
+ reference: string;
621
+ display: string;
622
+ };
623
+ meta?: {
624
+ project?: string;
625
+ author?: {
626
+ reference: string;
627
+ };
628
+ lastUpdated?: string;
629
+ };
630
+ };
631
+ profile: {
632
+ resourceType: "Practitioner";
633
+ id: string;
634
+ name?: unknown[];
635
+ meta?: {
636
+ project?: string;
637
+ lastUpdated?: string;
638
+ };
639
+ };
640
+ status: "Pending";
641
+ };
642
+ export type SlimUserProfileType = "Patient" | "Practitioner";
643
+ export type SlimHealthDependency = {
644
+ status: "up" | "down";
645
+ version?: string;
646
+ postgres?: boolean;
647
+ redis?: boolean;
648
+ platform?: string;
649
+ runtime?: string;
650
+ responseTimeMs?: number;
651
+ serverMetrics?: {
652
+ db: {
653
+ idleConnections?: number;
654
+ queriesAwaitingClient?: number;
655
+ healthcheckRttSeconds?: number;
656
+ };
657
+ memory: {
658
+ usedHeapBytes?: number;
659
+ oldSpaceBytes?: number;
660
+ newSpaceBytes?: number;
661
+ };
662
+ queues: {
663
+ batchWaiting?: number;
664
+ batchDelayed?: number;
665
+ cronWaiting?: number;
666
+ cronDelayed?: number;
667
+ subscriptionWaiting?: number;
668
+ subscriptionDelayed?: number;
669
+ };
670
+ fhirOps?: {
671
+ readCount?: number;
672
+ searchCount?: number;
673
+ createCount?: number;
674
+ updateCount?: number;
675
+ deleteCount?: number;
676
+ patchCount?: number;
677
+ };
678
+ server?: {
679
+ indexingDurationMsMax?: number;
680
+ validationDurationMsMax?: number;
681
+ };
682
+ };
683
+ uptimeSeconds?: number;
684
+ connectedClients?: number;
685
+ usedMemoryBytes?: number;
686
+ usedMemoryHuman?: string;
687
+ peakMemoryBytes?: number;
688
+ peakMemoryHuman?: string;
689
+ opsPerSecond?: number;
690
+ hitRate?: number;
691
+ evictedKeys?: number;
692
+ blockedClients?: number;
693
+ };
694
+ export type SlimHealth = {
695
+ status: "healthy" | "degraded" | "unhealthy";
696
+ environment: string;
697
+ version: string | null;
698
+ uptimeSeconds: number;
699
+ timestamp: string;
700
+ endpoints: {
701
+ api: string;
702
+ fhir: string;
703
+ };
704
+ externalSystems: {
705
+ fhirStore: SlimHealthDependency;
706
+ redis: SlimHealthDependency;
707
+ };
708
+ cache?: {
709
+ hits: number;
710
+ misses: number;
711
+ errors: number;
712
+ hitRate?: number;
713
+ };
714
+ ovok?: {
715
+ cpuUsage?: number;
716
+ memoryUsageBytes?: number;
717
+ eventLoopLagMs?: number;
718
+ };
719
+ system?: {
720
+ cpuUtilization?: number;
721
+ loadAverage1m?: number;
722
+ loadAverage5m?: number;
723
+ loadAverage15m?: number;
724
+ memoryUsageBytes?: number;
725
+ };
726
+ observability: {
727
+ signoz: string | null;
728
+ };
729
+ };
@@ -180,5 +180,27 @@ exports.OVOK_CORE_API_REQUIREMENTS = {
180
180
  { method: "GET", path: "/v1/slim/zones/:zoneId", group: "Slim/Zones" },
181
181
  { method: "GET", path: "/v1/slim/zones/device-counts", group: "Slim/Zones" },
182
182
  { method: "POST", path: "/v1/slim/export/pdf", group: "Slim/Export" },
183
+ { method: "GET", path: "/v1/slim/project/users", group: "Slim/Project" },
184
+ { method: "POST", path: "/v1/slim/project/child", group: "Slim/Project" },
185
+ { method: "GET", path: "/v1/slim/project/child", group: "Slim/Project" },
186
+ { method: "GET", path: "/v2/slim/project/child", group: "Slim/Project" },
187
+ { method: "DELETE", path: "/v1/slim/project/child/:subProjectId", group: "Slim/Project" },
188
+ { method: "GET", path: "/v1/slim/project/:id/users", group: "Slim/Project" },
189
+ { method: "GET", path: "/v1/slim/project/:id/device-counts", group: "Slim/Project" },
190
+ { method: "GET", path: "/v1/slim/project/:id/patient-counts", group: "Slim/Project" },
191
+ { method: "PUT", path: "/v1/slim/project/:id", group: "Slim/Project" },
192
+ { method: "GET", path: "/v1/slim/project/:id", group: "Slim/Project" },
193
+ { method: "GET", path: "/v1/slim/policy", group: "Slim/Policy" },
194
+ { method: "GET", path: "/v1/slim/policy/:id", group: "Slim/Policy" },
195
+ { method: "POST", path: "/v1/slim/policy", group: "Slim/Policy" },
196
+ { method: "PUT", path: "/v1/slim/policy/:id", group: "Slim/Policy" },
197
+ { method: "DELETE", path: "/v1/slim/policy/:id", group: "Slim/Policy" },
198
+ { method: "GET", path: "/v1/slim/organization/:id", group: "Slim/Organization" },
199
+ { method: "POST", path: "/v1/slim/organization", group: "Slim/Organization" },
200
+ { method: "PUT", path: "/v1/slim/organization/:id", group: "Slim/Organization" },
201
+ { method: "DELETE", path: "/v1/slim/organization/:id", group: "Slim/Organization" },
202
+ { method: "POST", path: "/v1/slim/invite/practitioner", group: "Slim/Invite" },
203
+ { method: "DELETE", path: "/v1/slim/user/:profileType/:profileId", group: "Slim/User" },
204
+ { method: "GET", path: "/v1/slim/health", group: "Slim/Health" },
183
205
  ],
184
206
  };
@@ -48,7 +48,7 @@ exports.OVOK_CORE_REQUIREMENTS = {
48
48
  description: "The FHIR surface a server must provide for the @ovok/core client library's own methods to function.",
49
49
  software: {
50
50
  name: "@ovok/core",
51
- version: "0.4.31",
51
+ version: "0.4.32",
52
52
  },
53
53
  fhirVersion: "4.0.1",
54
54
  format: ["json"],
@@ -41,13 +41,13 @@ const index_1 = require("./index");
41
41
  const useChangeHistory = (params = {}) => {
42
42
  const client = (0, index_1.useClient)();
43
43
  const serialized = JSON.stringify(params);
44
- const load = React.useCallback(() => client.listChangeHistory(params), [client, serialized]);
44
+ const load = React.useCallback((signal) => client.listChangeHistory(params, { signal }), [client, serialized]);
45
45
  return (0, api_hooks_1.useOvokRequest)(load);
46
46
  };
47
47
  exports.useChangeHistory = useChangeHistory;
48
48
  const useLegalConsent = () => {
49
49
  const client = (0, index_1.useClient)();
50
- const load = React.useCallback(() => client.getLegalConsent(), [client]);
50
+ const load = React.useCallback((signal) => client.getLegalConsent({ signal }), [client]);
51
51
  return (0, api_hooks_1.useOvokRequest)(load);
52
52
  };
53
53
  exports.useLegalConsent = useLegalConsent;
@@ -55,7 +55,7 @@ const useSetLegalConsent = () => (0, api_hooks_1.useOvokMutation)((client, accep
55
55
  exports.useSetLegalConsent = useSetLegalConsent;
56
56
  const useMedicalConsent = () => {
57
57
  const client = (0, index_1.useClient)();
58
- const load = React.useCallback(() => client.getMedicalConsent(), [client]);
58
+ const load = React.useCallback((signal) => client.getMedicalConsent({ signal }), [client]);
59
59
  return (0, api_hooks_1.useOvokRequest)(load);
60
60
  };
61
61
  exports.useMedicalConsent = useMedicalConsent;
@@ -63,14 +63,14 @@ const useSetMedicalConsent = () => (0, api_hooks_1.useOvokMutation)((client, acc
63
63
  exports.useSetMedicalConsent = useSetMedicalConsent;
64
64
  const useSlimThresholdV2 = () => {
65
65
  const client = (0, index_1.useClient)();
66
- const load = React.useCallback(() => client.getSlimThresholdV2(), [client]);
66
+ const load = React.useCallback((signal) => client.getSlimThresholdV2({ signal }), [client]);
67
67
  return (0, api_hooks_1.useOvokRequest)(load);
68
68
  };
69
69
  exports.useSlimThresholdV2 = useSlimThresholdV2;
70
70
  const useSlimPatientThresholdV2 = (patientId) => {
71
71
  const client = (0, index_1.useClient)();
72
- const load = React.useCallback(() => patientId
73
- ? client.getSlimPatientThresholdV2(patientId)
72
+ const load = React.useCallback((signal) => patientId
73
+ ? client.getSlimPatientThresholdV2(patientId, { signal })
74
74
  : Promise.reject(new Error("patientId is required")), [client, patientId]);
75
75
  return (0, api_hooks_1.useOvokRequest)(load, patientId !== undefined);
76
76
  };
@@ -84,7 +84,7 @@ const useUpdateSlimPatientThresholdV2 = () => (0, api_hooks_1.useOvokMutation)(a
84
84
  exports.useUpdateSlimPatientThresholdV2 = useUpdateSlimPatientThresholdV2;
85
85
  const useUnconfirmedLimits = () => {
86
86
  const client = (0, index_1.useClient)();
87
- const load = React.useCallback(() => client.listUnconfirmedLimits(), [client]);
87
+ const load = React.useCallback((signal) => client.listUnconfirmedLimits({ signal }), [client]);
88
88
  return (0, api_hooks_1.useOvokRequest)(load);
89
89
  };
90
90
  exports.useUnconfirmedLimits = useUnconfirmedLimits;
@@ -5,7 +5,10 @@ import { SlimDeviceListItem, SlimDeviceListQuery, SlimDeviceTelemetry, SlimNotif
5
5
  import { OvokPublicApiEndpoint } from "../conformance/capability";
6
6
  export type OvokRequestState<T> = {
7
7
  data: T | undefined;
8
+ dataUpdatedAt: number | undefined;
8
9
  loading: boolean;
10
+ isRefreshing: boolean;
11
+ isStale: boolean;
9
12
  error: Error | undefined;
10
13
  reload: () => void;
11
14
  };
@@ -21,9 +24,9 @@ export type OvokMutationState<TParams, TData> = {
21
24
  * add a cache or retry policy: MedplumClient already owns request caching and
22
25
  * the host app owns the retry policy appropriate to its screen.
23
26
  */
24
- export declare function useOvokRequest<T>(load: () => Promise<T>, enabled?: boolean): OvokRequestState<T>;
27
+ export declare function useOvokRequest<T>(load: (signal?: AbortSignal) => Promise<T>, enabled?: boolean): OvokRequestState<T>;
25
28
  /** Internal variant for list hooks that reconcile server-confirmed changes in mounted data. */
26
- export declare function useOvokRequestWithUpdater<T>(load: () => Promise<T>, enabled?: boolean): OvokRequestState<T> & {
29
+ export declare function useOvokRequestWithUpdater<T>(load: (signal?: AbortSignal) => Promise<T>, enabled?: boolean): OvokRequestState<T> & {
27
30
  updateData(update: (current: T | undefined) => T | undefined): void;
28
31
  };
29
32
  /** Generic mutation hook for any typed OvokClient method. */
@@ -48,17 +48,26 @@ const toError = (error) => error instanceof Error ? error : new Error(String(err
48
48
  * the host app owns the retry policy appropriate to its screen.
49
49
  */
50
50
  function useOvokRequest(load, enabled = true) {
51
- const { data, loading, error, reload } = useOvokRequestWithUpdater(load, enabled);
52
- return { data, loading, error, reload };
51
+ const { data, dataUpdatedAt, loading, isRefreshing, isStale, error, reload, } = useOvokRequestWithUpdater(load, enabled);
52
+ return { data, dataUpdatedAt, loading, isRefreshing, isStale, error, reload };
53
53
  }
54
54
  /** Internal variant for list hooks that reconcile server-confirmed changes in mounted data. */
55
55
  function useOvokRequestWithUpdater(load, enabled = true) {
56
56
  const [data, setData] = React.useState();
57
+ const [dataUpdatedAt, setDataUpdatedAt] = React.useState();
57
58
  const [error, setError] = React.useState();
58
59
  const [loading, setLoading] = React.useState(enabled);
59
60
  const [revision, setRevision] = React.useState(0);
61
+ const previousLoad = React.useRef(load);
60
62
  React.useEffect(() => {
61
63
  let disposed = false;
64
+ const controller = new AbortController();
65
+ const queryChanged = previousLoad.current !== load;
66
+ if (queryChanged) {
67
+ previousLoad.current = load;
68
+ setData(undefined);
69
+ setDataUpdatedAt(undefined);
70
+ }
62
71
  if (!enabled) {
63
72
  setLoading(false);
64
73
  setError(undefined);
@@ -68,10 +77,11 @@ function useOvokRequestWithUpdater(load, enabled = true) {
68
77
  }
69
78
  setLoading(true);
70
79
  setError(undefined);
71
- load()
80
+ load(controller.signal)
72
81
  .then((value) => {
73
82
  if (!disposed) {
74
83
  setData(value);
84
+ setDataUpdatedAt(Date.now());
75
85
  setLoading(false);
76
86
  }
77
87
  })
@@ -83,11 +93,24 @@ function useOvokRequestWithUpdater(load, enabled = true) {
83
93
  });
84
94
  return () => {
85
95
  disposed = true;
96
+ controller.abort();
86
97
  };
87
98
  }, [enabled, load, revision]);
88
99
  const reload = React.useCallback(() => setRevision((value) => value + 1), []);
89
- const updateData = React.useCallback((update) => setData(update), []);
90
- return { data, loading, error, reload, updateData };
100
+ const updateData = React.useCallback((update) => {
101
+ setData(update);
102
+ setDataUpdatedAt(Date.now());
103
+ }, []);
104
+ return {
105
+ data,
106
+ dataUpdatedAt,
107
+ loading,
108
+ isRefreshing: data !== undefined && loading,
109
+ isStale: data !== undefined && (loading || error !== undefined),
110
+ error,
111
+ reload,
112
+ updateData,
113
+ };
91
114
  }
92
115
  /** Generic mutation hook for any typed OvokClient method. */
93
116
  function useOvokMutation(mutateRequest) {
@@ -121,53 +144,53 @@ function useOvokMutation(mutateRequest) {
121
144
  }
122
145
  const useCapabilityStatement = (version = "R4") => {
123
146
  const client = (0, index_1.useClient)();
124
- const load = React.useCallback(() => client.getCapabilityStatement(version), [client, version]);
147
+ const load = React.useCallback((signal) => client.getCapabilityStatement(version, { signal }), [client, version]);
125
148
  return useOvokRequest(load);
126
149
  };
127
150
  exports.useCapabilityStatement = useCapabilityStatement;
128
151
  const usePublicApiEndpoints = (version = "R4") => {
129
152
  const client = (0, index_1.useClient)();
130
- const load = React.useCallback(() => client.getPublicApiEndpoints(version), [client, version]);
153
+ const load = React.useCallback((signal) => client.getPublicApiEndpoints(version, { signal }), [client, version]);
131
154
  return useOvokRequest(load);
132
155
  };
133
156
  exports.usePublicApiEndpoints = usePublicApiEndpoints;
134
157
  const useAdministeredProjects = (params = {}) => {
135
158
  const client = (0, index_1.useClient)();
136
159
  const serialized = JSON.stringify(params);
137
- const load = React.useCallback(() => client.listAdministeredProjects(params), [client, serialized]);
160
+ const load = React.useCallback((signal) => client.listAdministeredProjects(params, { signal }), [client, serialized]);
138
161
  return useOvokRequest(load);
139
162
  };
140
163
  exports.useAdministeredProjects = useAdministeredProjects;
141
164
  const useProjectSettings = () => {
142
165
  const client = (0, index_1.useClient)();
143
- const load = React.useCallback(() => client.getProjectSettings(), [client]);
166
+ const load = React.useCallback((signal) => client.getProjectSettings({ signal }), [client]);
144
167
  return useOvokRequest(load);
145
168
  };
146
169
  exports.useProjectSettings = useProjectSettings;
147
170
  const useProjectFeatures = () => {
148
171
  const client = (0, index_1.useClient)();
149
- const load = React.useCallback(() => client.getProjectFeatures(), [client]);
172
+ const load = React.useCallback((signal) => client.getProjectFeatures({ signal }), [client]);
150
173
  return useOvokRequest(load);
151
174
  };
152
175
  exports.useProjectFeatures = useProjectFeatures;
153
176
  const useSlimPatients = (params = {}) => {
154
177
  const client = (0, index_1.useClient)();
155
178
  const serialized = JSON.stringify(params);
156
- const load = React.useCallback(() => client.listSlimPatients(params), [client, serialized]);
179
+ const load = React.useCallback((signal) => client.listSlimPatients(params, { signal }), [client, serialized]);
157
180
  return useOvokRequest(load);
158
181
  };
159
182
  exports.useSlimPatients = useSlimPatients;
160
183
  const useSlimDevices = (params = {}) => {
161
184
  const client = (0, index_1.useClient)();
162
185
  const serialized = JSON.stringify(params);
163
- const load = React.useCallback(() => client.listSlimDevices(params), [client, serialized]);
186
+ const load = React.useCallback((signal) => client.listSlimDevices(params, { signal }), [client, serialized]);
164
187
  return useOvokRequest(load);
165
188
  };
166
189
  exports.useSlimDevices = useSlimDevices;
167
190
  const useSlimDeviceTelemetry = (deviceId) => {
168
191
  const client = (0, index_1.useClient)();
169
- const load = React.useCallback(() => deviceId
170
- ? client.getSlimDeviceTelemetry(deviceId)
192
+ const load = React.useCallback((signal) => deviceId
193
+ ? client.getSlimDeviceTelemetry(deviceId, { signal })
171
194
  : Promise.reject(new Error("deviceId is required")), [client, deviceId]);
172
195
  return useOvokRequest(load, deviceId !== undefined);
173
196
  };
@@ -176,7 +199,7 @@ exports.useSlimDeviceTelemetry = useSlimDeviceTelemetry;
176
199
  const useSlimNotifications = (params = {}) => {
177
200
  const client = (0, index_1.useClient)();
178
201
  const serialized = JSON.stringify(params);
179
- const load = React.useCallback(() => client.listSlimNotifications(params), [client, serialized]);
202
+ const load = React.useCallback((signal) => client.listSlimNotifications(params, { signal }), [client, serialized]);
180
203
  const { updateData, ...state } = useOvokRequestWithUpdater(load);
181
204
  React.useEffect(() => (0, notification_invalidation_1.subscribeToNotificationChanges)(client, (change) => {
182
205
  if (!change) {
@@ -194,7 +217,7 @@ const useSlimNotifications = (params = {}) => {
194
217
  exports.useSlimNotifications = useSlimNotifications;
195
218
  const useRecentSlimNotifications = (count) => {
196
219
  const client = (0, index_1.useClient)();
197
- const load = React.useCallback(() => client.getRecentSlimNotifications(count), [client, count]);
220
+ const load = React.useCallback((signal) => client.getRecentSlimNotifications(count, { signal }), [client, count]);
198
221
  const { updateData, ...state } = useOvokRequestWithUpdater(load);
199
222
  React.useEffect(() => (0, notification_invalidation_1.subscribeToNotificationChanges)(client, (change) => {
200
223
  if (!change) {
@@ -47,7 +47,7 @@ const useCmsDocument = (collection, slug, options = {}) => {
47
47
  const client = (0, index_1.useClient)();
48
48
  const { tenantCode, environment, allowSignedOut } = options;
49
49
  const locale = React.useMemo(() => (0, cms_1.toCmsLocale)(options.locale || (0, cms_1.defaultCmsLocale)()), [options.locale]);
50
- const load = React.useCallback(() => client.getCmsDocument(collection, slug, { locale, tenantCode, environment, allowSignedOut }), [client, collection, slug, locale, tenantCode, environment, allowSignedOut]);
50
+ const load = React.useCallback((signal) => client.getCmsDocument(collection, slug, { locale, tenantCode, environment, allowSignedOut }, { signal }), [client, collection, slug, locale, tenantCode, environment, allowSignedOut]);
51
51
  return (0, api_hooks_1.useOvokRequest)(load, Boolean(slug));
52
52
  };
53
53
  exports.useCmsDocument = useCmsDocument;
@@ -56,7 +56,7 @@ const useCmsDocuments = (collection, options = {}) => {
56
56
  const client = (0, index_1.useClient)();
57
57
  const { tenantCode, environment, allowSignedOut, page, limit, sort } = options;
58
58
  const locale = React.useMemo(() => (0, cms_1.toCmsLocale)(options.locale || (0, cms_1.defaultCmsLocale)()), [options.locale]);
59
- const load = React.useCallback(() => client.listCmsDocuments(collection, { locale, tenantCode, environment, allowSignedOut, page, limit, sort }), [client, collection, locale, tenantCode, environment, allowSignedOut, page, limit, sort]);
59
+ const load = React.useCallback((signal) => client.listCmsDocuments(collection, { locale, tenantCode, environment, allowSignedOut, page, limit, sort }, { signal }), [client, collection, locale, tenantCode, environment, allowSignedOut, page, limit, sort]);
60
60
  return (0, api_hooks_1.useOvokRequest)(load);
61
61
  };
62
62
  exports.useCmsDocuments = useCmsDocuments;
@@ -74,7 +74,7 @@ const useTranslations = (options = {}) => {
74
74
  const client = (0, index_1.useClient)();
75
75
  const { tenantCode, environment, allowSignedOut } = options;
76
76
  const locale = React.useMemo(() => (0, cms_1.toCmsLocale)(options.locale || (0, cms_1.defaultCmsLocale)()), [options.locale]);
77
- const load = React.useCallback(() => client.getTranslations({ locale, tenantCode, environment, allowSignedOut }), [client, locale, tenantCode, environment, allowSignedOut]);
77
+ const load = React.useCallback((signal) => client.getTranslations({ locale, tenantCode, environment, allowSignedOut }, { signal }), [client, locale, tenantCode, environment, allowSignedOut]);
78
78
  return (0, api_hooks_1.useOvokRequest)(load);
79
79
  };
80
80
  exports.useTranslations = useTranslations;
@@ -40,7 +40,7 @@ const api_hooks_1 = require("./api-hooks");
40
40
  const index_1 = require("./index");
41
41
  const useEmailTemplates = () => {
42
42
  const client = (0, index_1.useClient)();
43
- const load = React.useCallback(() => client.getEmailTemplates(), [client]);
43
+ const load = React.useCallback((signal) => client.getEmailTemplates({ signal }), [client]);
44
44
  return (0, api_hooks_1.useOvokRequest)(load);
45
45
  };
46
46
  exports.useEmailTemplates = useEmailTemplates;