@everfur/sdk 0.1.1 → 0.4.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.
Files changed (219) hide show
  1. package/CHANGELOG.md +703 -4
  2. package/README.md +63 -23
  3. package/consent/package.json +8 -0
  4. package/dist/Chat-BZZ-Py5l.d.ts +128 -0
  5. package/dist/Chat-Dq4fffIO.d.cts +128 -0
  6. package/dist/DepthViews-BG3E25MD.d.ts +16 -0
  7. package/dist/DepthViews-B_hIypI6.d.cts +19 -0
  8. package/dist/DepthViews-CL75jyRA.d.cts +16 -0
  9. package/dist/DepthViews-CkYri51q.d.ts +19 -0
  10. package/dist/ErrorPolicyPort-CNf4uQZP.d.cts +22 -0
  11. package/dist/ErrorPolicyPort-CwbfmxzJ.d.ts +22 -0
  12. package/dist/{EverfurResult-D92-uL82.d.cts → EverfurResult-DN9pL2Ab.d.cts} +11 -10
  13. package/dist/{EverfurResult-D92-uL82.d.ts → EverfurResult-DN9pL2Ab.d.ts} +11 -10
  14. package/dist/{PhotoController-BItt5M7u.d.cts → PhotoController-3l7MT9jA.d.cts} +1 -1
  15. package/dist/{PhotoController-D8zMTdcW.d.ts → PhotoController-vzY5bfY_.d.ts} +1 -1
  16. package/dist/animations/index.cjs +1 -1997
  17. package/dist/animations/index.d.cts +35 -35
  18. package/dist/animations/index.d.ts +35 -35
  19. package/dist/animations/index.js +1 -1972
  20. package/dist/attachments-BorG422I.d.cts +146 -0
  21. package/dist/attachments-BrUWQYNK.d.ts +257 -0
  22. package/dist/attachments-D_SECjr1.d.cts +257 -0
  23. package/dist/attachments-DpldrvIW.d.ts +146 -0
  24. package/dist/bookingCopy-CqtDYvCR.d.ts +732 -0
  25. package/dist/bookingCopy-SREvkG19.d.cts +732 -0
  26. package/dist/branding-CsRdeNwK.d.cts +566 -0
  27. package/dist/branding-CsRdeNwK.d.ts +566 -0
  28. package/dist/callCopy-DoQKG3-L.d.cts +40 -0
  29. package/dist/callCopy-DoQKG3-L.d.ts +40 -0
  30. package/dist/casesRepository-DwtZVsbj.d.cts +51 -0
  31. package/dist/casesRepository-v6QczS9N.d.ts +51 -0
  32. package/dist/chat/index.cjs +1 -1170
  33. package/dist/chat/index.d.cts +32 -53
  34. package/dist/chat/index.d.ts +32 -53
  35. package/dist/chat/index.js +1 -1167
  36. package/dist/client/index.cjs +9 -2315
  37. package/dist/client/index.d.cts +80 -16
  38. package/dist/client/index.d.ts +80 -16
  39. package/dist/client/index.js +9 -2215
  40. package/dist/{config-CiJ0PVBB.d.ts → config--Wu1Umhd.d.cts} +64 -26
  41. package/dist/{config-BSjBdxrZ.d.cts → config-C7eb_IMD.d.ts} +64 -26
  42. package/dist/consent/index.cjs +1 -0
  43. package/dist/consent/index.d.cts +33 -0
  44. package/dist/consent/index.d.ts +33 -0
  45. package/dist/consent/index.js +1 -0
  46. package/dist/context-CL3lyuy1.d.cts +159 -0
  47. package/dist/context-CahAEha8.d.ts +159 -0
  48. package/dist/copy-DdVFDL01.d.ts +198 -0
  49. package/dist/copy-UeUJVk8X.d.cts +198 -0
  50. package/dist/core/index.cjs +13 -3178
  51. package/dist/core/index.d.cts +164 -29
  52. package/dist/core/index.d.ts +164 -29
  53. package/dist/core/index.js +13 -3166
  54. package/dist/depth-D5HwcvKC.d.cts +533 -0
  55. package/dist/depth-DvPwPuT_.d.ts +533 -0
  56. package/dist/entitlementRepository-B7egEdW6.d.ts +43 -0
  57. package/dist/entitlementRepository-BpJ7tiwl.d.cts +43 -0
  58. package/dist/{identity-Brl-lDd6.d.cts → identity-C2-08BZW.d.cts} +20 -7
  59. package/dist/{identity-DK9zORrG.d.ts → identity-CEi9GRFZ.d.ts} +20 -7
  60. package/dist/{ids-CJ1S6adf.d.cts → ids-B2GAAifq.d.cts} +1 -1
  61. package/dist/{ids-CJ1S6adf.d.ts → ids-B2GAAifq.d.ts} +1 -1
  62. package/dist/index.cjs +12 -4494
  63. package/dist/index.d.cts +30 -121
  64. package/dist/index.d.ts +30 -121
  65. package/dist/index.js +12 -4470
  66. package/dist/models-B-Uh2LTf.d.ts +214 -0
  67. package/dist/models-D2EUxPZY.d.cts +214 -0
  68. package/dist/notifications/index.cjs +2 -0
  69. package/dist/notifications/index.d.cts +17 -0
  70. package/dist/notifications/index.d.ts +17 -0
  71. package/dist/notifications/index.js +2 -0
  72. package/dist/optionalModule-DbJmsq5f.d.cts +21 -0
  73. package/dist/optionalModule-DbJmsq5f.d.ts +21 -0
  74. package/dist/pets-DJv2sj2H.d.ts +92 -0
  75. package/dist/pets-JVCXgRgR.d.cts +92 -0
  76. package/dist/petsRepository-B_gKbAzJ.d.cts +142 -0
  77. package/dist/petsRepository-Bk6GDwLs.d.ts +142 -0
  78. package/dist/photo/index.cjs +1 -2189
  79. package/dist/photo/index.d.cts +6 -6
  80. package/dist/photo/index.d.ts +6 -6
  81. package/dist/photo/index.js +1 -2186
  82. package/dist/ports-BN6RHF9W.d.cts +48 -0
  83. package/dist/ports-BN6RHF9W.d.ts +48 -0
  84. package/dist/ports-BY2ph0_y.d.cts +376 -0
  85. package/dist/ports-D7YW8qz9.d.ts +376 -0
  86. package/dist/profile-CSs1wlXT.d.cts +93 -0
  87. package/dist/profile-CSs1wlXT.d.ts +93 -0
  88. package/dist/records/depth/index.cjs +2 -0
  89. package/dist/records/depth/index.d.cts +13 -0
  90. package/dist/records/depth/index.d.ts +13 -0
  91. package/dist/records/depth/index.js +2 -0
  92. package/dist/records/index.cjs +3 -2839
  93. package/dist/records/index.d.cts +137 -203
  94. package/dist/records/index.d.ts +137 -203
  95. package/dist/records/index.js +3 -2833
  96. package/dist/requestFunnel-BjDpqqvm.d.cts +110 -0
  97. package/dist/requestFunnel-DFMGcluw.d.ts +110 -0
  98. package/dist/{resolve-Dq_4_agU.d.ts → resolve-D4Ywz5OS.d.cts} +10 -4
  99. package/dist/{resolve-Dq_4_agU.d.cts → resolve-D4Ywz5OS.d.ts} +10 -4
  100. package/dist/{runtime-Bvr8yqXm.d.cts → runtimeTypes-gZEJu-da.d.cts} +104 -132
  101. package/dist/{runtime-BIYzf9cK.d.ts → runtimeTypes-w5KqBMcs.d.ts} +104 -132
  102. package/dist/server/events/index.cjs +2 -0
  103. package/dist/server/events/index.d.cts +550 -0
  104. package/dist/server/events/index.d.ts +550 -0
  105. package/dist/server/events/index.js +2 -0
  106. package/dist/server/index.cjs +2 -533
  107. package/dist/server/index.d.cts +73 -18
  108. package/dist/server/index.d.ts +73 -18
  109. package/dist/server/index.js +2 -530
  110. package/dist/species-BXAIMh7I.d.cts +9 -0
  111. package/dist/species-BXAIMh7I.d.ts +9 -0
  112. package/dist/televet/booking/index.cjs +1 -0
  113. package/dist/televet/booking/index.d.cts +294 -0
  114. package/dist/televet/booking/index.d.ts +294 -0
  115. package/dist/televet/booking/index.js +1 -0
  116. package/dist/televet/call/index.cjs +1 -0
  117. package/dist/televet/call/index.d.cts +141 -0
  118. package/dist/televet/call/index.d.ts +141 -0
  119. package/dist/televet/call/index.js +1 -0
  120. package/dist/televet/index.cjs +1 -0
  121. package/dist/televet/index.d.cts +142 -0
  122. package/dist/televet/index.d.ts +142 -0
  123. package/dist/televet/index.js +1 -0
  124. package/dist/testing/index.cjs +5 -823
  125. package/dist/testing/index.d.cts +18 -4
  126. package/dist/testing/index.d.ts +18 -4
  127. package/dist/testing/index.js +5 -820
  128. package/dist/testing/rn/index.cjs +1 -449
  129. package/dist/testing/rn/index.d.cts +18 -29
  130. package/dist/testing/rn/index.d.ts +18 -29
  131. package/dist/testing/rn/index.js +1 -444
  132. package/dist/testing/web/index.cjs +1 -0
  133. package/dist/testing/web/index.d.cts +132 -0
  134. package/dist/testing/web/index.d.ts +132 -0
  135. package/dist/testing/web/index.js +1 -0
  136. package/dist/timelineRows-C15jxFFH.d.ts +19 -0
  137. package/dist/timelineRows-odO8g9r2.d.cts +19 -0
  138. package/dist/typeStyle-CKqVYD6L.d.cts +111 -0
  139. package/dist/typeStyle-DmoyacDG.d.ts +111 -0
  140. package/dist/uploadTransport-D0M0T4hN.d.ts +38 -0
  141. package/dist/uploadTransport-DKJHs3Yj.d.cts +38 -0
  142. package/dist/useRecordsDepth-C6rjEaLn.d.cts +237 -0
  143. package/dist/useRecordsDepth-crhBllQK.d.ts +237 -0
  144. package/dist/useVetVisit-Bc84hWUU.d.cts +187 -0
  145. package/dist/useVetVisit-CjmMa896.d.ts +187 -0
  146. package/dist/video/index.cjs +1 -1941
  147. package/dist/video/index.d.cts +4 -4
  148. package/dist/video/index.d.ts +4 -4
  149. package/dist/video/index.js +1 -1938
  150. package/dist/view-Bxwxp4xD.d.ts +310 -0
  151. package/dist/view-DyitEO0m.d.cts +310 -0
  152. package/dist/visitIntent-D7_yVp1I.d.cts +8 -0
  153. package/dist/visitIntent-D7_yVp1I.d.ts +8 -0
  154. package/dist/web/consent/index.cjs +1 -0
  155. package/dist/web/consent/index.d.cts +34 -0
  156. package/dist/web/consent/index.d.ts +34 -0
  157. package/dist/web/consent/index.js +1 -0
  158. package/dist/web/index.cjs +14 -0
  159. package/dist/web/index.d.cts +218 -0
  160. package/dist/web/index.d.ts +218 -0
  161. package/dist/web/index.js +14 -0
  162. package/dist/web/notifications/index.cjs +2 -0
  163. package/dist/web/notifications/index.d.cts +213 -0
  164. package/dist/web/notifications/index.d.ts +213 -0
  165. package/dist/web/notifications/index.js +2 -0
  166. package/dist/web/records/depth/index.cjs +2 -0
  167. package/dist/web/records/depth/index.d.cts +12 -0
  168. package/dist/web/records/depth/index.d.ts +12 -0
  169. package/dist/web/records/depth/index.js +2 -0
  170. package/dist/web/records/index.cjs +4 -0
  171. package/dist/web/records/index.d.cts +285 -0
  172. package/dist/web/records/index.d.ts +285 -0
  173. package/dist/web/records/index.js +4 -0
  174. package/dist/web/televet/booking/index.cjs +1 -0
  175. package/dist/web/televet/booking/index.d.cts +349 -0
  176. package/dist/web/televet/booking/index.d.ts +349 -0
  177. package/dist/web/televet/booking/index.js +1 -0
  178. package/dist/web/televet/call/index.cjs +1 -0
  179. package/dist/web/televet/call/index.d.cts +142 -0
  180. package/dist/web/televet/call/index.d.ts +142 -0
  181. package/dist/web/televet/call/index.js +1 -0
  182. package/dist/web/televet/index.cjs +1 -0
  183. package/dist/web/televet/index.d.cts +136 -0
  184. package/dist/web/televet/index.d.ts +136 -0
  185. package/dist/web/televet/index.js +1 -0
  186. package/notifications/package.json +8 -0
  187. package/package.json +266 -10
  188. package/records/depth/package.json +8 -0
  189. package/server/events/device-blocked.cjs +15 -0
  190. package/server/events/package.json +9 -0
  191. package/televet/booking/package.json +8 -0
  192. package/televet/call/package.json +8 -0
  193. package/televet/package.json +8 -0
  194. package/testing/web/native-blocked.cjs +12 -0
  195. package/testing/web/package.json +8 -0
  196. package/web/consent/native-blocked.cjs +12 -0
  197. package/web/consent/package.json +8 -0
  198. package/web/native-blocked.cjs +12 -0
  199. package/web/notifications/native-blocked.cjs +12 -0
  200. package/web/notifications/package.json +8 -0
  201. package/web/package.json +8 -0
  202. package/web/records/depth/native-blocked.cjs +12 -0
  203. package/web/records/depth/package.json +8 -0
  204. package/web/records/native-blocked.cjs +12 -0
  205. package/web/records/package.json +8 -0
  206. package/web/televet/booking/native-blocked.cjs +12 -0
  207. package/web/televet/booking/package.json +8 -0
  208. package/web/televet/call/native-blocked.cjs +12 -0
  209. package/web/televet/call/package.json +8 -0
  210. package/web/televet/native-blocked.cjs +12 -0
  211. package/web/televet/package.json +8 -0
  212. package/dist/ChatController-CKdBvPj2.d.ts +0 -146
  213. package/dist/ChatController-CpUMvvZf.d.cts +0 -146
  214. package/dist/FilePort-BabWrv7I.d.cts +0 -22
  215. package/dist/FilePort-BabWrv7I.d.ts +0 -22
  216. package/dist/petsRepository-BEGb97M9.d.cts +0 -326
  217. package/dist/petsRepository-Bu18r2kK.d.ts +0 -326
  218. package/dist/requestFunnel-DuUH-kAe.d.cts +0 -28
  219. package/dist/requestFunnel-dio5OmR9.d.ts +0 -28
@@ -0,0 +1,310 @@
1
+ import { c as EverfurResult, E as EverfurError } from './EverfurResult-DN9pL2Ab.js';
2
+ import { R as RecordsRequestId, P as PetRef } from './ids-B2GAAifq.js';
3
+ import { F as FileHandle, U as UploadTransport } from './ports-BN6RHF9W.js';
4
+ import { C as CreateUploadRequestInput, d as RecordsRequestView, U as UploadedDocument, g as RecordsView, h as ConsentState, G as GrantConsentInput, i as RecordsDenialReason, a as RecordEntity } from './models-B-Uh2LTf.js';
5
+ import { K as RecordMarkersView, L as RecordPdfLink, N as RecordShareLink, Q as RecordsClinicBatchClient } from './depth-DvPwPuT_.js';
6
+ import { c as RecordsDepthStatus, i as RecordsClinicController } from './useRecordsDepth-crhBllQK.js';
7
+
8
+ interface UploadDocumentInput {
9
+ readonly requestId: RecordsRequestId;
10
+ readonly file: FileHandle;
11
+ readonly onProgress?: (fraction: number) => void;
12
+ readonly signal?: AbortSignal;
13
+ }
14
+ interface RecordsController {
15
+ /** Create the self-upload request. Idempotent on `idempotencyKey`. Lands `awaiting_upload`. */
16
+ createUploadRequest(input: CreateUploadRequestInput): Promise<EverfurResult<RecordsRequestView>>;
17
+ /** Two-phase presigned upload of ONE document (§3.2). Bytes go DIRECT to S3. Resolves at `received`. */
18
+ uploadDocument(input: UploadDocumentInput): Promise<EverfurResult<UploadedDocument>>;
19
+ /** Poll one request's parse lifecycle. */
20
+ getRequest(id: RecordsRequestId): Promise<EverfurResult<RecordsRequestView>>;
21
+ /** All of this user's requests, newest-first (server-ordered). */
22
+ listRequests(): Promise<EverfurResult<readonly RecordsRequestView[]>>;
23
+ /** The parsed, partner-redacted record. Consent-gated + redaction-fail-closed. */
24
+ getRecord(pet: PetRef): Promise<EverfurResult<RecordsView>>;
25
+ /** Consent read-back. Never a hard failure for an absent row -> `granted:false`. */
26
+ getConsent(pet: PetRef): Promise<EverfurResult<ConsentState>>;
27
+ /** Grant content-exposure consent. Fail-closed audited server-side. Idempotent. */
28
+ grantConsent(input: GrantConsentInput): Promise<EverfurResult<ConsentState>>;
29
+ /** Revoke consent (prospective). Drops any cached record for the pet from memory. Idempotent. */
30
+ revokeConsent(pet: PetRef): Promise<EverfurResult<ConsentState>>;
31
+ /** The last record read for a pet, held in memory only; cleared on revoke. Null when none. */
32
+ peekCachedRecord(pet: PetRef): RecordsView | null;
33
+ /** Emit `records.capability.denied` (the rn CapabilityGate disabled surface calls this once, R12). */
34
+ reportCapabilityDenied(pet: PetRef | null): void;
35
+ }
36
+
37
+ type RecordsStatus = 'loading' | 'empty' | 'error' | 'populated';
38
+ /** Why a picked file was not uploaded (the consumer picker's `PickSkipReason`): decided BEFORE any request is made. */
39
+ type UploadSkipReason = 'too_large' | 'unsupported';
40
+ /** One file of an upload batch, with its own lifecycle and progress (the consumer `UploadItem`). */
41
+ interface UploadQueueItem {
42
+ /** Stable row key within the batch. */
43
+ readonly key: string;
44
+ /** The host's file name when it gave one; rendered locally, never sent. */
45
+ readonly name: string | null;
46
+ readonly status: 'queued' | 'uploading' | 'done' | 'failed' | 'skipped';
47
+ /** 0..1, monotonic while uploading; 1 once done. */
48
+ readonly progress: number;
49
+ readonly skipReason: UploadSkipReason | null;
50
+ readonly error: EverfurError | null;
51
+ }
52
+ interface UseEverfurRecordsState {
53
+ readonly status: RecordsStatus;
54
+ readonly record: RecordsView | null;
55
+ readonly requests: readonly RecordsRequestView[];
56
+ /** the most-recent request, whose timeline the populated state renders. */
57
+ readonly activeRequest: RecordsRequestView | null;
58
+ readonly consent: ConsentState | null;
59
+ readonly error: EverfurError | null;
60
+ /** drives the recovery affordance: consent CTA / establish-session CTA / disabled. */
61
+ readonly denialReason: RecordsDenialReason | null;
62
+ /** §5.1 fail-closed suppression: render the withheld notice, never empty, never raw. */
63
+ readonly withheld: boolean;
64
+ readonly isUploading: boolean;
65
+ readonly uploadProgress: number | null;
66
+ /** The files of the last pick, one row each, with per-file status and progress. Empty until a pick. */
67
+ readonly uploadQueue: readonly UploadQueueItem[];
68
+ /** Create a self-upload request the user attaches documents to. */
69
+ createRequest(idempotencyKey: string): Promise<EverfurResult<RecordsRequestView>>;
70
+ /** Two-phase presigned upload of one document to the active request. */
71
+ uploadDocument(requestId: RecordsRequestView['id'], file: FileHandle): Promise<EverfurResult<UploadedDocument>>;
72
+ /**
73
+ * Several documents in one pick: uploaded ONE AT A TIME (kinder to slow links), a live row per file, one failed
74
+ * file never aborts the rest (continue-on-error), and a non-PDF or oversize file is skipped with a reason before
75
+ * any request is created, so no quota is charged for it. Resolves with the settled rows.
76
+ */
77
+ uploadDocuments(requestId: RecordsRequestView['id'], files: readonly FileHandle[]): Promise<readonly UploadQueueItem[]>;
78
+ /** Grant content-exposure consent, then fetch the record. */
79
+ grantConsent(consentVersion: string, idempotencyKey: string): Promise<EverfurResult<ConsentState>>;
80
+ /** Revoke consent (prospective); drops the record from view. */
81
+ revokeConsent(): Promise<EverfurResult<ConsentState>>;
82
+ /** Re-run the surface fetch (error retry). */
83
+ refresh(): void;
84
+ }
85
+ declare function useEverfurRecords(opts: {
86
+ readonly petRef: PetRef;
87
+ /** Host/test seam: inject a controller directly instead of acquiring one from the runtime. */
88
+ readonly controller?: RecordsController;
89
+ /**
90
+ * The upload transport for this surface, overriding `EverfurConfig.uploadTransport`. The latest value is used
91
+ * at upload time, so a transport created inline on each render does not rebuild the controller.
92
+ */
93
+ readonly uploadTransport?: UploadTransport;
94
+ }): UseEverfurRecordsState;
95
+
96
+ interface UseRecordsMarkersState {
97
+ readonly status: RecordsDepthStatus;
98
+ readonly markers: RecordMarkersView | null;
99
+ /** False while the markers route is dark for the tenant: the markers surface is hidden, never an error. */
100
+ readonly available: boolean;
101
+ readonly error: EverfurError | null;
102
+ readonly refresh: () => void;
103
+ }
104
+ declare function useRecordsMarkers(petRef: PetRef): UseRecordsMarkersState;
105
+
106
+ interface ShareRowView {
107
+ readonly shareId: string;
108
+ /** The link, when it was minted in this session (the list read never repeats a URL). */
109
+ readonly shareUrl: string | null;
110
+ readonly active: boolean;
111
+ /** `Active` or `Expired`: status as text, never colour alone. */
112
+ readonly statusLabel: string;
113
+ readonly expiryLabel: string;
114
+ readonly createdLabel: string | null;
115
+ readonly a11yLabel: string;
116
+ /** Disambiguating suffix for the row's spoken action labels. */
117
+ readonly actionContext: string;
118
+ }
119
+
120
+ type RecordSharesStatus = 'loading' | 'empty' | 'error' | 'populated';
121
+ interface UseRecordSharesState {
122
+ readonly status: RecordSharesStatus;
123
+ readonly rows: readonly ShareRowView[];
124
+ /** True once a list read got an answer from behind the depth gate; false before that, after a read that never
125
+ * reached the server, and while the routes are dark. */
126
+ readonly available: boolean;
127
+ /**
128
+ * True once records consent for this pet is known to be withdrawn: a mint or an export answered the typed
129
+ * 409, or a withdrawal was made elsewhere in the app. The two consent-gated controls (create link, download
130
+ * PDF) go away while it holds; the LIST and the per-link revoke do not, because the server gates those on
131
+ * ownership alone so a member can still kill a link they no longer want live. `refresh()` clears it, which
132
+ * is the way back after the member allows records again.
133
+ */
134
+ readonly consentRequired: boolean;
135
+ readonly error: EverfurError | null;
136
+ readonly creating: boolean;
137
+ readonly revokingId: string | null;
138
+ readonly preparingPdf: boolean;
139
+ /** Mint a link; on success the list is re-read and the URL is remembered for its row. */
140
+ createLink(): Promise<EverfurResult<RecordShareLink>>;
141
+ revoke(shareId: string): Promise<EverfurResult<void>>;
142
+ /** The presigned PDF link the host opens itself. */
143
+ pdfLink(): Promise<EverfurResult<RecordPdfLink>>;
144
+ refresh(): void;
145
+ }
146
+ declare function useRecordShares(petRef: PetRef, opts?: {
147
+ readonly now?: () => number;
148
+ }): UseRecordSharesState;
149
+ interface UseRecordPdfLinkState {
150
+ readonly preparing: boolean;
151
+ /**
152
+ * True once the mount probe found the depth ROUTES lit; false before that, on the probe's dark 404, and when
153
+ * the probe never reached the server. It says nothing about whether the pet has a published record to export,
154
+ * which the same route's 404 also means: a surface that can see the record (the document screen does) must
155
+ * require that too before it draws a Download control.
156
+ */
157
+ readonly available: boolean;
158
+ readonly error: EverfurError | null;
159
+ pdfLink(): Promise<EverfurResult<RecordPdfLink>>;
160
+ }
161
+ /**
162
+ * The PDF link alone (the document screen's download control), without the share list read.
163
+ *
164
+ * `getPdfLink` answers ONE untyped 404 for two different states, and the guide says so
165
+ * (docs/partner-integration/09-GUIDE-RECORDS-AND-CONSENT.md): the tenant's depth switch is off, or the pet has
166
+ * no published record yet. The mount probe above already settled the first from a read behind the same
167
+ * router-level gate, so a 404 arriving HERE is the second, and folding it to `available:false` made the tap
168
+ * remove its own control and say nothing. It is a local, recoverable failure of one action: it sets `error`
169
+ * (every surface that draws the control has a line for it) and leaves `available` alone, so the control the
170
+ * member just pressed is still there. The honest answer to "is there a record to export" is the record read
171
+ * itself, which is why the document screen gates the control on the body it is already rendering.
172
+ */
173
+ declare function useRecordPdfLink(petRef: PetRef): UseRecordPdfLinkState;
174
+
175
+ /** Corrections and removals keyed by the row's `canonicalKey`. */
176
+ interface FactOverlay {
177
+ readonly edits: Readonly<Record<string, string>>;
178
+ readonly removed: readonly string[];
179
+ }
180
+ /** The rows as the owner now sees them: a corrected value shows, a removed row is gone. Pure. */
181
+ declare function applyFactOverlay(entities: readonly RecordEntity[], overlay: FactOverlay): readonly RecordEntity[];
182
+ /** True when the row can be corrected: the wire gave it a stable key. */
183
+ declare function isFactEditable(entity: Pick<RecordEntity, 'canonicalKey'>): boolean;
184
+ interface UseRecordFactEditState {
185
+ readonly overlay: FactOverlay;
186
+ readonly busy: boolean;
187
+ /** The curated user-facing line of the last failure; null once a new write starts. */
188
+ readonly error: string | null;
189
+ /**
190
+ * Whether to offer the editor. The fact routes are their own feature flag and it defaults ON, so this is true
191
+ * from the first render and turns false only once a write has answered the dark 404 for this scope. There is
192
+ * no cheap read on these POST-only routes to probe with, and reading another feature's route instead is what
193
+ * made a tenant's share-links setting silently disable its fact editor.
194
+ */
195
+ readonly available: boolean;
196
+ /**
197
+ * Correct the row's displayed value. The wire key is the original value's typed slot (`value_num` for a number,
198
+ * `value_date`, `value_bool`, else `value_text`). Resolves the settled result; the overlay is already patched
199
+ * or rolled back.
200
+ */
201
+ edit(entity: RecordEntity, value: string): Promise<EverfurResult<void>>;
202
+ remove(entity: RecordEntity): Promise<EverfurResult<void>>;
203
+ clearError(): void;
204
+ }
205
+ declare function useRecordFactEdit(petRef: PetRef, opts?: {
206
+ readonly newIdempotencyKey?: () => string;
207
+ }): UseRecordFactEditState;
208
+
209
+ type RecordsEmptyVariant = 'idle' | 'error' | 'rate_limited' | 'service_unavailable' | 'no_requests' | 'no_records';
210
+
211
+ /**
212
+ * - `published`: STATE C, parsed lab markers are published (the donut and the trend cards render);
213
+ * - `in_progress`: STATE B, a real request is mid-flight, driven solely by an actual request row;
214
+ * - `none`: STATE A, no published markers and no live request: the actionable chooser.
215
+ */
216
+ type RecordsDashboardState = 'published' | 'in_progress' | 'none';
217
+ /**
218
+ * The request that drives a pet's dashboard state: a `published` one first (the owner keeps their data), else
219
+ * the most recently updated in-flight one, else null (only off-rail terminal requests, or none).
220
+ */
221
+ declare function pickPetRecordsRequest(requests: readonly RecordsRequestView[], petRef: PetRef | null): RecordsRequestView | null;
222
+ /**
223
+ * Derive the dashboard state from whether published markers exist and the pet's requests. A `published`
224
+ * request whose markers have not landed yet (eventual consistency) reads as in-progress, never a bare empty;
225
+ * a prior terminal request (revoked / failed) lands on STATE A so the owner can act again.
226
+ */
227
+ declare function deriveRecordsDashboardState(args: {
228
+ readonly hasMarkers: boolean;
229
+ readonly requests: readonly RecordsRequestView[];
230
+ readonly petRef: PetRef | null;
231
+ }): RecordsDashboardState;
232
+ /** The six surfaces the dashboard body picks between, in the app's own branch order. */
233
+ type RecordsDashboardView = 'loading' | 'record' | 'error' | 'in_progress' | 'none' | 'labs_only';
234
+ interface RecordsDashboardInput {
235
+ /** The base records read (consent, requests, record) is still loading. */
236
+ readonly recordLoading: boolean;
237
+ /** The pet has a published, non-empty record. */
238
+ readonly hasFullRecord: boolean;
239
+ /** The base records read failed (any member of the error family). */
240
+ readonly recordError: boolean;
241
+ readonly markersLoading: boolean;
242
+ /** The markers read failed with a real error (a dark 404 is NOT an error: it is "no markers surface"). */
243
+ readonly markersError: boolean;
244
+ readonly hasMarkers: boolean;
245
+ readonly requestsLoading: boolean;
246
+ readonly dashboardState: RecordsDashboardState;
247
+ readonly drivingRequest: RecordsRequestView | null;
248
+ }
249
+ /** The branch order of RecordsDashboardScreen.tsx:238-419, as data. */
250
+ declare function selectDashboardView(input: RecordsDashboardInput): RecordsDashboardView;
251
+
252
+ /**
253
+ * The signed user's clinic request API. No prefetch, signature, consent, or outbound
254
+ * contact occurs on mount. The host presents backend-authored authorization copy
255
+ * and obtains the owner's explicit signature before calling createClinicRequest.
256
+ */
257
+ declare function useEverfurRecordsClinic(): RecordsClinicController;
258
+ /** The signed user's multi-clinic batch client, over the same auth and scope rules as `useEverfurRecordsClinic`. */
259
+ declare function useEverfurRecordsClinicBatch(): RecordsClinicBatchClient;
260
+
261
+ type RequestTimelineEventKey = 'requested' | 'sent_to_clinic' | 'awaiting_clinic' | 'awaiting_upload' | 'records_received' | 'processing' | 'parsing_failed' | 'manual_review' | 'ready' | 'delivery_failed' | 'processing_failed' | 'clinic_declined' | 'clinic_no_records' | 'no_response' | 'revoked';
262
+ type RequestTimelineEventState = 'done' | 'current' | 'upcoming' | 'failed';
263
+ interface RequestTimelineEvent {
264
+ readonly key: RequestTimelineEventKey;
265
+ /** Structural step title (not clinical/legal copy). */
266
+ readonly title: string;
267
+ /** Structural sub-detail (counts, dispatch substate) or null. */
268
+ readonly detail: string | null;
269
+ /** ISO timestamp when the request genuinely carries it, else null. */
270
+ readonly at: string | null;
271
+ readonly state: RequestTimelineEventState;
272
+ }
273
+ /** The step titles, verbatim: everfur-mobile-2026-7 src/features/records/lib/requestTimeline.ts `STAGE_TITLES`. */
274
+ declare const REQUEST_TIMELINE_TITLES: Readonly<Record<RequestTimelineEventKey, string>>;
275
+ /**
276
+ * Build the ordered step-wise timeline for a request. Pure + deterministic: states derive from the status,
277
+ * timestamps from the request's own fields. The terminal event (if any) is always last and carries state `failed`.
278
+ */
279
+ declare function buildRequestTimeline(request: RecordsRequestView): readonly RequestTimelineEvent[];
280
+
281
+ /**
282
+ * The card title: the clinic the request went to, else the consumer's own fallback by source
283
+ * (everfur-mobile-2026-7 src/features/records/ui/RecordsRequestScreen.tsx:97-100).
284
+ */
285
+ declare function selectRequestTitle(request: RecordsRequestView): string;
286
+ /**
287
+ * ALL of the member's requests for the pet, newest first (updatedAt, then createdAt), so the surface shows one
288
+ * step rail per request rather than only the newest. Frozen; the input is never reordered in place.
289
+ */
290
+ declare function selectRequestList(requests: readonly RecordsRequestView[]): readonly RecordsRequestView[];
291
+ /**
292
+ * The one BE-authored line a request card leads with: the consumer action-first sentence when the request needs
293
+ * the member (`actionNeededLabel`), else the status label. Never the raw status; empty when the server sent
294
+ * neither (the caller then renders no line).
295
+ */
296
+ declare function selectPrimaryLabel(request: RecordsRequestView): string;
297
+ interface ClinicCall {
298
+ /** The verified clinic number, trimmed, for display. */
299
+ readonly phone: string;
300
+ /** The `tel:` target: digits and a leading `+` only (the consumer app's own normalisation). */
301
+ readonly dial: string;
302
+ readonly clinicName: string | null;
303
+ }
304
+ /**
305
+ * The tap-to-call affordance, ONLY when the server gates it (`showClinicPhone`) AND supplies a number: the
306
+ * consumer app's `callPhone` rule (everfur-mobile-2026-7 src/features/records/ui/RecordsRequestScreen.tsx:205).
307
+ */
308
+ declare function selectClinicCall(request: RecordsRequestView): ClinicCall | null;
309
+
310
+ export { useEverfurRecords as A, useEverfurRecordsClinic as B, type ClinicCall as C, useEverfurRecordsClinicBatch as D, useRecordFactEdit as E, type FactOverlay as F, useRecordPdfLink as G, useRecordShares as H, useRecordsMarkers as I, type RecordsController as R, type ShareRowView as S, type UploadDocumentInput as U, REQUEST_TIMELINE_TITLES as a, type RecordSharesStatus as b, type RecordsDashboardState as c, type RecordsDashboardView as d, type RecordsEmptyVariant as e, type RecordsStatus as f, type RequestTimelineEvent as g, type RequestTimelineEventKey as h, type RequestTimelineEventState as i, type UploadQueueItem as j, type UploadSkipReason as k, type UseEverfurRecordsState as l, type UseRecordFactEditState as m, type UseRecordPdfLinkState as n, type UseRecordSharesState as o, type UseRecordsMarkersState as p, applyFactOverlay as q, buildRequestTimeline as r, deriveRecordsDashboardState as s, isFactEditable as t, pickPetRecordsRequest as u, selectClinicCall as v, selectDashboardView as w, selectPrimaryLabel as x, selectRequestList as y, selectRequestTitle as z };
@@ -0,0 +1,310 @@
1
+ import { c as EverfurResult, E as EverfurError } from './EverfurResult-DN9pL2Ab.cjs';
2
+ import { R as RecordsRequestId, P as PetRef } from './ids-B2GAAifq.cjs';
3
+ import { F as FileHandle, U as UploadTransport } from './ports-BN6RHF9W.cjs';
4
+ import { C as CreateUploadRequestInput, d as RecordsRequestView, U as UploadedDocument, g as RecordsView, h as ConsentState, G as GrantConsentInput, i as RecordsDenialReason, a as RecordEntity } from './models-D2EUxPZY.cjs';
5
+ import { K as RecordMarkersView, L as RecordPdfLink, N as RecordShareLink, Q as RecordsClinicBatchClient } from './depth-D5HwcvKC.cjs';
6
+ import { c as RecordsDepthStatus, i as RecordsClinicController } from './useRecordsDepth-C6rjEaLn.cjs';
7
+
8
+ interface UploadDocumentInput {
9
+ readonly requestId: RecordsRequestId;
10
+ readonly file: FileHandle;
11
+ readonly onProgress?: (fraction: number) => void;
12
+ readonly signal?: AbortSignal;
13
+ }
14
+ interface RecordsController {
15
+ /** Create the self-upload request. Idempotent on `idempotencyKey`. Lands `awaiting_upload`. */
16
+ createUploadRequest(input: CreateUploadRequestInput): Promise<EverfurResult<RecordsRequestView>>;
17
+ /** Two-phase presigned upload of ONE document (§3.2). Bytes go DIRECT to S3. Resolves at `received`. */
18
+ uploadDocument(input: UploadDocumentInput): Promise<EverfurResult<UploadedDocument>>;
19
+ /** Poll one request's parse lifecycle. */
20
+ getRequest(id: RecordsRequestId): Promise<EverfurResult<RecordsRequestView>>;
21
+ /** All of this user's requests, newest-first (server-ordered). */
22
+ listRequests(): Promise<EverfurResult<readonly RecordsRequestView[]>>;
23
+ /** The parsed, partner-redacted record. Consent-gated + redaction-fail-closed. */
24
+ getRecord(pet: PetRef): Promise<EverfurResult<RecordsView>>;
25
+ /** Consent read-back. Never a hard failure for an absent row -> `granted:false`. */
26
+ getConsent(pet: PetRef): Promise<EverfurResult<ConsentState>>;
27
+ /** Grant content-exposure consent. Fail-closed audited server-side. Idempotent. */
28
+ grantConsent(input: GrantConsentInput): Promise<EverfurResult<ConsentState>>;
29
+ /** Revoke consent (prospective). Drops any cached record for the pet from memory. Idempotent. */
30
+ revokeConsent(pet: PetRef): Promise<EverfurResult<ConsentState>>;
31
+ /** The last record read for a pet, held in memory only; cleared on revoke. Null when none. */
32
+ peekCachedRecord(pet: PetRef): RecordsView | null;
33
+ /** Emit `records.capability.denied` (the rn CapabilityGate disabled surface calls this once, R12). */
34
+ reportCapabilityDenied(pet: PetRef | null): void;
35
+ }
36
+
37
+ type RecordsStatus = 'loading' | 'empty' | 'error' | 'populated';
38
+ /** Why a picked file was not uploaded (the consumer picker's `PickSkipReason`): decided BEFORE any request is made. */
39
+ type UploadSkipReason = 'too_large' | 'unsupported';
40
+ /** One file of an upload batch, with its own lifecycle and progress (the consumer `UploadItem`). */
41
+ interface UploadQueueItem {
42
+ /** Stable row key within the batch. */
43
+ readonly key: string;
44
+ /** The host's file name when it gave one; rendered locally, never sent. */
45
+ readonly name: string | null;
46
+ readonly status: 'queued' | 'uploading' | 'done' | 'failed' | 'skipped';
47
+ /** 0..1, monotonic while uploading; 1 once done. */
48
+ readonly progress: number;
49
+ readonly skipReason: UploadSkipReason | null;
50
+ readonly error: EverfurError | null;
51
+ }
52
+ interface UseEverfurRecordsState {
53
+ readonly status: RecordsStatus;
54
+ readonly record: RecordsView | null;
55
+ readonly requests: readonly RecordsRequestView[];
56
+ /** the most-recent request, whose timeline the populated state renders. */
57
+ readonly activeRequest: RecordsRequestView | null;
58
+ readonly consent: ConsentState | null;
59
+ readonly error: EverfurError | null;
60
+ /** drives the recovery affordance: consent CTA / establish-session CTA / disabled. */
61
+ readonly denialReason: RecordsDenialReason | null;
62
+ /** §5.1 fail-closed suppression: render the withheld notice, never empty, never raw. */
63
+ readonly withheld: boolean;
64
+ readonly isUploading: boolean;
65
+ readonly uploadProgress: number | null;
66
+ /** The files of the last pick, one row each, with per-file status and progress. Empty until a pick. */
67
+ readonly uploadQueue: readonly UploadQueueItem[];
68
+ /** Create a self-upload request the user attaches documents to. */
69
+ createRequest(idempotencyKey: string): Promise<EverfurResult<RecordsRequestView>>;
70
+ /** Two-phase presigned upload of one document to the active request. */
71
+ uploadDocument(requestId: RecordsRequestView['id'], file: FileHandle): Promise<EverfurResult<UploadedDocument>>;
72
+ /**
73
+ * Several documents in one pick: uploaded ONE AT A TIME (kinder to slow links), a live row per file, one failed
74
+ * file never aborts the rest (continue-on-error), and a non-PDF or oversize file is skipped with a reason before
75
+ * any request is created, so no quota is charged for it. Resolves with the settled rows.
76
+ */
77
+ uploadDocuments(requestId: RecordsRequestView['id'], files: readonly FileHandle[]): Promise<readonly UploadQueueItem[]>;
78
+ /** Grant content-exposure consent, then fetch the record. */
79
+ grantConsent(consentVersion: string, idempotencyKey: string): Promise<EverfurResult<ConsentState>>;
80
+ /** Revoke consent (prospective); drops the record from view. */
81
+ revokeConsent(): Promise<EverfurResult<ConsentState>>;
82
+ /** Re-run the surface fetch (error retry). */
83
+ refresh(): void;
84
+ }
85
+ declare function useEverfurRecords(opts: {
86
+ readonly petRef: PetRef;
87
+ /** Host/test seam: inject a controller directly instead of acquiring one from the runtime. */
88
+ readonly controller?: RecordsController;
89
+ /**
90
+ * The upload transport for this surface, overriding `EverfurConfig.uploadTransport`. The latest value is used
91
+ * at upload time, so a transport created inline on each render does not rebuild the controller.
92
+ */
93
+ readonly uploadTransport?: UploadTransport;
94
+ }): UseEverfurRecordsState;
95
+
96
+ interface UseRecordsMarkersState {
97
+ readonly status: RecordsDepthStatus;
98
+ readonly markers: RecordMarkersView | null;
99
+ /** False while the markers route is dark for the tenant: the markers surface is hidden, never an error. */
100
+ readonly available: boolean;
101
+ readonly error: EverfurError | null;
102
+ readonly refresh: () => void;
103
+ }
104
+ declare function useRecordsMarkers(petRef: PetRef): UseRecordsMarkersState;
105
+
106
+ interface ShareRowView {
107
+ readonly shareId: string;
108
+ /** The link, when it was minted in this session (the list read never repeats a URL). */
109
+ readonly shareUrl: string | null;
110
+ readonly active: boolean;
111
+ /** `Active` or `Expired`: status as text, never colour alone. */
112
+ readonly statusLabel: string;
113
+ readonly expiryLabel: string;
114
+ readonly createdLabel: string | null;
115
+ readonly a11yLabel: string;
116
+ /** Disambiguating suffix for the row's spoken action labels. */
117
+ readonly actionContext: string;
118
+ }
119
+
120
+ type RecordSharesStatus = 'loading' | 'empty' | 'error' | 'populated';
121
+ interface UseRecordSharesState {
122
+ readonly status: RecordSharesStatus;
123
+ readonly rows: readonly ShareRowView[];
124
+ /** True once a list read got an answer from behind the depth gate; false before that, after a read that never
125
+ * reached the server, and while the routes are dark. */
126
+ readonly available: boolean;
127
+ /**
128
+ * True once records consent for this pet is known to be withdrawn: a mint or an export answered the typed
129
+ * 409, or a withdrawal was made elsewhere in the app. The two consent-gated controls (create link, download
130
+ * PDF) go away while it holds; the LIST and the per-link revoke do not, because the server gates those on
131
+ * ownership alone so a member can still kill a link they no longer want live. `refresh()` clears it, which
132
+ * is the way back after the member allows records again.
133
+ */
134
+ readonly consentRequired: boolean;
135
+ readonly error: EverfurError | null;
136
+ readonly creating: boolean;
137
+ readonly revokingId: string | null;
138
+ readonly preparingPdf: boolean;
139
+ /** Mint a link; on success the list is re-read and the URL is remembered for its row. */
140
+ createLink(): Promise<EverfurResult<RecordShareLink>>;
141
+ revoke(shareId: string): Promise<EverfurResult<void>>;
142
+ /** The presigned PDF link the host opens itself. */
143
+ pdfLink(): Promise<EverfurResult<RecordPdfLink>>;
144
+ refresh(): void;
145
+ }
146
+ declare function useRecordShares(petRef: PetRef, opts?: {
147
+ readonly now?: () => number;
148
+ }): UseRecordSharesState;
149
+ interface UseRecordPdfLinkState {
150
+ readonly preparing: boolean;
151
+ /**
152
+ * True once the mount probe found the depth ROUTES lit; false before that, on the probe's dark 404, and when
153
+ * the probe never reached the server. It says nothing about whether the pet has a published record to export,
154
+ * which the same route's 404 also means: a surface that can see the record (the document screen does) must
155
+ * require that too before it draws a Download control.
156
+ */
157
+ readonly available: boolean;
158
+ readonly error: EverfurError | null;
159
+ pdfLink(): Promise<EverfurResult<RecordPdfLink>>;
160
+ }
161
+ /**
162
+ * The PDF link alone (the document screen's download control), without the share list read.
163
+ *
164
+ * `getPdfLink` answers ONE untyped 404 for two different states, and the guide says so
165
+ * (docs/partner-integration/09-GUIDE-RECORDS-AND-CONSENT.md): the tenant's depth switch is off, or the pet has
166
+ * no published record yet. The mount probe above already settled the first from a read behind the same
167
+ * router-level gate, so a 404 arriving HERE is the second, and folding it to `available:false` made the tap
168
+ * remove its own control and say nothing. It is a local, recoverable failure of one action: it sets `error`
169
+ * (every surface that draws the control has a line for it) and leaves `available` alone, so the control the
170
+ * member just pressed is still there. The honest answer to "is there a record to export" is the record read
171
+ * itself, which is why the document screen gates the control on the body it is already rendering.
172
+ */
173
+ declare function useRecordPdfLink(petRef: PetRef): UseRecordPdfLinkState;
174
+
175
+ /** Corrections and removals keyed by the row's `canonicalKey`. */
176
+ interface FactOverlay {
177
+ readonly edits: Readonly<Record<string, string>>;
178
+ readonly removed: readonly string[];
179
+ }
180
+ /** The rows as the owner now sees them: a corrected value shows, a removed row is gone. Pure. */
181
+ declare function applyFactOverlay(entities: readonly RecordEntity[], overlay: FactOverlay): readonly RecordEntity[];
182
+ /** True when the row can be corrected: the wire gave it a stable key. */
183
+ declare function isFactEditable(entity: Pick<RecordEntity, 'canonicalKey'>): boolean;
184
+ interface UseRecordFactEditState {
185
+ readonly overlay: FactOverlay;
186
+ readonly busy: boolean;
187
+ /** The curated user-facing line of the last failure; null once a new write starts. */
188
+ readonly error: string | null;
189
+ /**
190
+ * Whether to offer the editor. The fact routes are their own feature flag and it defaults ON, so this is true
191
+ * from the first render and turns false only once a write has answered the dark 404 for this scope. There is
192
+ * no cheap read on these POST-only routes to probe with, and reading another feature's route instead is what
193
+ * made a tenant's share-links setting silently disable its fact editor.
194
+ */
195
+ readonly available: boolean;
196
+ /**
197
+ * Correct the row's displayed value. The wire key is the original value's typed slot (`value_num` for a number,
198
+ * `value_date`, `value_bool`, else `value_text`). Resolves the settled result; the overlay is already patched
199
+ * or rolled back.
200
+ */
201
+ edit(entity: RecordEntity, value: string): Promise<EverfurResult<void>>;
202
+ remove(entity: RecordEntity): Promise<EverfurResult<void>>;
203
+ clearError(): void;
204
+ }
205
+ declare function useRecordFactEdit(petRef: PetRef, opts?: {
206
+ readonly newIdempotencyKey?: () => string;
207
+ }): UseRecordFactEditState;
208
+
209
+ type RecordsEmptyVariant = 'idle' | 'error' | 'rate_limited' | 'service_unavailable' | 'no_requests' | 'no_records';
210
+
211
+ /**
212
+ * - `published`: STATE C, parsed lab markers are published (the donut and the trend cards render);
213
+ * - `in_progress`: STATE B, a real request is mid-flight, driven solely by an actual request row;
214
+ * - `none`: STATE A, no published markers and no live request: the actionable chooser.
215
+ */
216
+ type RecordsDashboardState = 'published' | 'in_progress' | 'none';
217
+ /**
218
+ * The request that drives a pet's dashboard state: a `published` one first (the owner keeps their data), else
219
+ * the most recently updated in-flight one, else null (only off-rail terminal requests, or none).
220
+ */
221
+ declare function pickPetRecordsRequest(requests: readonly RecordsRequestView[], petRef: PetRef | null): RecordsRequestView | null;
222
+ /**
223
+ * Derive the dashboard state from whether published markers exist and the pet's requests. A `published`
224
+ * request whose markers have not landed yet (eventual consistency) reads as in-progress, never a bare empty;
225
+ * a prior terminal request (revoked / failed) lands on STATE A so the owner can act again.
226
+ */
227
+ declare function deriveRecordsDashboardState(args: {
228
+ readonly hasMarkers: boolean;
229
+ readonly requests: readonly RecordsRequestView[];
230
+ readonly petRef: PetRef | null;
231
+ }): RecordsDashboardState;
232
+ /** The six surfaces the dashboard body picks between, in the app's own branch order. */
233
+ type RecordsDashboardView = 'loading' | 'record' | 'error' | 'in_progress' | 'none' | 'labs_only';
234
+ interface RecordsDashboardInput {
235
+ /** The base records read (consent, requests, record) is still loading. */
236
+ readonly recordLoading: boolean;
237
+ /** The pet has a published, non-empty record. */
238
+ readonly hasFullRecord: boolean;
239
+ /** The base records read failed (any member of the error family). */
240
+ readonly recordError: boolean;
241
+ readonly markersLoading: boolean;
242
+ /** The markers read failed with a real error (a dark 404 is NOT an error: it is "no markers surface"). */
243
+ readonly markersError: boolean;
244
+ readonly hasMarkers: boolean;
245
+ readonly requestsLoading: boolean;
246
+ readonly dashboardState: RecordsDashboardState;
247
+ readonly drivingRequest: RecordsRequestView | null;
248
+ }
249
+ /** The branch order of RecordsDashboardScreen.tsx:238-419, as data. */
250
+ declare function selectDashboardView(input: RecordsDashboardInput): RecordsDashboardView;
251
+
252
+ /**
253
+ * The signed user's clinic request API. No prefetch, signature, consent, or outbound
254
+ * contact occurs on mount. The host presents backend-authored authorization copy
255
+ * and obtains the owner's explicit signature before calling createClinicRequest.
256
+ */
257
+ declare function useEverfurRecordsClinic(): RecordsClinicController;
258
+ /** The signed user's multi-clinic batch client, over the same auth and scope rules as `useEverfurRecordsClinic`. */
259
+ declare function useEverfurRecordsClinicBatch(): RecordsClinicBatchClient;
260
+
261
+ type RequestTimelineEventKey = 'requested' | 'sent_to_clinic' | 'awaiting_clinic' | 'awaiting_upload' | 'records_received' | 'processing' | 'parsing_failed' | 'manual_review' | 'ready' | 'delivery_failed' | 'processing_failed' | 'clinic_declined' | 'clinic_no_records' | 'no_response' | 'revoked';
262
+ type RequestTimelineEventState = 'done' | 'current' | 'upcoming' | 'failed';
263
+ interface RequestTimelineEvent {
264
+ readonly key: RequestTimelineEventKey;
265
+ /** Structural step title (not clinical/legal copy). */
266
+ readonly title: string;
267
+ /** Structural sub-detail (counts, dispatch substate) or null. */
268
+ readonly detail: string | null;
269
+ /** ISO timestamp when the request genuinely carries it, else null. */
270
+ readonly at: string | null;
271
+ readonly state: RequestTimelineEventState;
272
+ }
273
+ /** The step titles, verbatim: everfur-mobile-2026-7 src/features/records/lib/requestTimeline.ts `STAGE_TITLES`. */
274
+ declare const REQUEST_TIMELINE_TITLES: Readonly<Record<RequestTimelineEventKey, string>>;
275
+ /**
276
+ * Build the ordered step-wise timeline for a request. Pure + deterministic: states derive from the status,
277
+ * timestamps from the request's own fields. The terminal event (if any) is always last and carries state `failed`.
278
+ */
279
+ declare function buildRequestTimeline(request: RecordsRequestView): readonly RequestTimelineEvent[];
280
+
281
+ /**
282
+ * The card title: the clinic the request went to, else the consumer's own fallback by source
283
+ * (everfur-mobile-2026-7 src/features/records/ui/RecordsRequestScreen.tsx:97-100).
284
+ */
285
+ declare function selectRequestTitle(request: RecordsRequestView): string;
286
+ /**
287
+ * ALL of the member's requests for the pet, newest first (updatedAt, then createdAt), so the surface shows one
288
+ * step rail per request rather than only the newest. Frozen; the input is never reordered in place.
289
+ */
290
+ declare function selectRequestList(requests: readonly RecordsRequestView[]): readonly RecordsRequestView[];
291
+ /**
292
+ * The one BE-authored line a request card leads with: the consumer action-first sentence when the request needs
293
+ * the member (`actionNeededLabel`), else the status label. Never the raw status; empty when the server sent
294
+ * neither (the caller then renders no line).
295
+ */
296
+ declare function selectPrimaryLabel(request: RecordsRequestView): string;
297
+ interface ClinicCall {
298
+ /** The verified clinic number, trimmed, for display. */
299
+ readonly phone: string;
300
+ /** The `tel:` target: digits and a leading `+` only (the consumer app's own normalisation). */
301
+ readonly dial: string;
302
+ readonly clinicName: string | null;
303
+ }
304
+ /**
305
+ * The tap-to-call affordance, ONLY when the server gates it (`showClinicPhone`) AND supplies a number: the
306
+ * consumer app's `callPhone` rule (everfur-mobile-2026-7 src/features/records/ui/RecordsRequestScreen.tsx:205).
307
+ */
308
+ declare function selectClinicCall(request: RecordsRequestView): ClinicCall | null;
309
+
310
+ export { useEverfurRecords as A, useEverfurRecordsClinic as B, type ClinicCall as C, useEverfurRecordsClinicBatch as D, useRecordFactEdit as E, type FactOverlay as F, useRecordPdfLink as G, useRecordShares as H, useRecordsMarkers as I, type RecordsController as R, type ShareRowView as S, type UploadDocumentInput as U, REQUEST_TIMELINE_TITLES as a, type RecordSharesStatus as b, type RecordsDashboardState as c, type RecordsDashboardView as d, type RecordsEmptyVariant as e, type RecordsStatus as f, type RequestTimelineEvent as g, type RequestTimelineEventKey as h, type RequestTimelineEventState as i, type UploadQueueItem as j, type UploadSkipReason as k, type UseEverfurRecordsState as l, type UseRecordFactEditState as m, type UseRecordPdfLinkState as n, type UseRecordSharesState as o, type UseRecordsMarkersState as p, applyFactOverlay as q, buildRequestTimeline as r, deriveRecordsDashboardState as s, isFactEditable as t, pickPetRecordsRequest as u, selectClinicCall as v, selectDashboardView as w, selectPrimaryLabel as x, selectRequestList as y, selectRequestTitle as z };
@@ -0,0 +1,8 @@
1
+ /** What the hosted page opens for an existing visit, in EFBackend's order. `visit` is the default. */
2
+ declare const VET_VISIT_INTENTS: readonly ["visit", "join", "summary", "messages"];
3
+ /** One intent: the visit itself, its call, its summary, or its messages. */
4
+ type VetVisitIntent = (typeof VET_VISIT_INTENTS)[number];
5
+ /** True when `value` is one of the four intents. */
6
+ declare function isVetVisitIntent(value: unknown): value is VetVisitIntent;
7
+
8
+ export { type VetVisitIntent as V, VET_VISIT_INTENTS as a, isVetVisitIntent as i };
@@ -0,0 +1,8 @@
1
+ /** What the hosted page opens for an existing visit, in EFBackend's order. `visit` is the default. */
2
+ declare const VET_VISIT_INTENTS: readonly ["visit", "join", "summary", "messages"];
3
+ /** One intent: the visit itself, its call, its summary, or its messages. */
4
+ type VetVisitIntent = (typeof VET_VISIT_INTENTS)[number];
5
+ /** True when `value` is one of the four intents. */
6
+ declare function isVetVisitIntent(value: unknown): value is VetVisitIntent;
7
+
8
+ export { type VetVisitIntent as V, VET_VISIT_INTENTS as a, isVetVisitIntent as i };