@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
package/README.md CHANGED
@@ -1,17 +1,17 @@
1
- # @everfur/sdk (React Native)
1
+ # @everfur/sdk (React Native and the web)
2
2
 
3
3
  Drop Everfur's AI vet assistant and pet-health features (records, gait/video, photo checkup, pet-state
4
- media) into a React Native app. What each of your customers and users can see is decided **server-side** by
5
- Everfur's entitlement control plane and rendered by the SDK, so you gate features without shipping an app
6
- update.
4
+ media) into a React Native app, and the assistant into a website. What each of your customers and users can
5
+ see is decided **server-side** by Everfur's entitlement control plane and rendered by the SDK, so you gate
6
+ features without shipping an app update.
7
7
 
8
8
  - Hexagonal, framework-free core with a thin RN layer; every surface settles (no thrown domain errors).
9
9
  - Server-authoritative entitlements: a feature you are not entitled to renders a deliberate off-state, never
10
10
  a blank screen, and cannot be force-enabled client-side.
11
11
  - The app never holds a secret. See [The security model](#the-security-model).
12
12
 
13
- > `0.1.0`, MIT licensed, public on npm. Requires React Native `>=0.74`, and Node `>=18` on the backend
14
- > that mints sessions.
13
+ > `0.3.0`, MIT licensed, public on npm. Requires React Native `>=0.74` (or React `>=18` with `react-dom`
14
+ > for the web entry), and Node `>=18` on the backend that mints sessions.
15
15
 
16
16
  **Getting keys:** Everfur keys are provisioned by the Everfur team during partner onboarding; there is
17
17
  no self-serve signup yet. Contact [support@everfur.com](mailto:support@everfur.com) to get set up. The
@@ -21,7 +21,8 @@ publishable key is designed to ship inside your app; the secret key is not.
21
21
 
22
22
  ```bash
23
23
  npm i @everfur/sdk
24
- # Always-required peers:
24
+ # A React Native app installs these itself (react-native and react-native-safe-area-context are declared
25
+ # optional peers, so a web project is not handed them):
25
26
  npm i react react-native react-native-safe-area-context
26
27
  ```
27
28
 
@@ -30,17 +31,18 @@ Peer dependencies by capability (install only what you use):
30
31
  | Capability | Extra peer deps | Notes |
31
32
  | --- | --- | --- |
32
33
  | chat, entitlements | none | works with react + react-native alone |
33
- | records | `expo-file-system`, `expo-image-manipulator` | document upload + client-side image prep |
34
+ | records | Host-supplied document picker and upload transport | The SDK does not import Expo file-system or image-manipulator modules. |
34
35
  | video (gait), photo (checkup) | `react-native-vision-camera` | **use `4.x` on RN 0.74**; `5.x` requires the new architecture |
35
36
 
36
- The camera and file-system peers are optional: if you never mount `./video`, `./photo`, or `./records`,
37
- you do not need them. `react-native-vision-camera` also needs its config plugin in `app.json` and a camera
38
- usage description.
37
+ The camera peer is optional: if you never mount `./video` or `./photo`, you do not need it.
38
+ `EverfurRecords` accepts the host's picker and upload transport, so use the native modules that fit your
39
+ app (including Expo SDK 57) without an SDK peer-dependency constraint. `react-native-vision-camera` also
40
+ needs its config plugin in `app.json` and a camera usage description.
39
41
 
40
42
  ### Bundler resolution
41
43
 
42
- No Metro configuration is required. Every subpath (`@everfur/sdk/chat`, `/records`, `/video`, `/photo`,
43
- `/animations`, `/client`, `/core`, `/testing`, `/testing/rn`) resolves on a stock install. Modern bundlers
44
+ No Metro configuration is required. Every subpath (`@everfur/sdk/chat`, `/records`, `/televet`, `/video`, `/photo`,
45
+ `/animations`, `/client`, `/core`, `/testing`, `/testing/rn`, `/testing/web`) resolves on a stock install. Modern bundlers
44
46
  read the package `exports` map; Metro 0.80.x, which ships with Expo 51, defaults to
45
47
  `unstable_enablePackageExports: false` and never reads it, so the package also ships classic root-level
46
48
  resolution shims for the same subpaths. You do not need to turn package exports on, and turning them on does
@@ -50,10 +52,38 @@ not change what you get.
50
52
  `sk_partner_` session minter. If it is ever pulled into an app bundle it throws on import rather than
51
53
  shipping the minter to a device. Import it from your server only.
52
54
 
55
+ ### On the web
56
+
57
+ Two ways, one wire contract, documented in
58
+ [docs/partner-integration/13-WEB-INTEGRATION.md](docs/partner-integration/13-WEB-INTEGRATION.md):
59
+
60
+ - **In-page**, for a page whose React tree you own: `import { EverfurProvider, EverfurChat } from
61
+ '@everfur/sdk/web'` (peers: `react`, `react-dom`). The copy-paste shape is
62
+ [`examples/minimal-web.tsx`](examples/minimal-web.tsx). Take the `/web` entry, not the package root: the
63
+ root is the React Native entry and imports `react-native` and `react-native-safe-area-context`, so in a
64
+ browser project it fails to resolve them rather than rendering. The `/web` entries need `react`,
65
+ `react/jsx-runtime` and `zod` and nothing native, which `npm run verify:pack` proves on every CI run by
66
+ importing all seven of them in a React web project.
67
+ - **Frame mode**, for a page you do not fully control (a storefront theme, a CMS page): one `<script
68
+ src="https://sdk.everfur.com/v1/everfur.js">` puts the surface in an iframe on `sdk.everfur.com`, and
69
+ the frame refuses to initialise on any page origin your tenant has not registered. The copy-paste shape
70
+ is [`examples/frame-embed.html`](examples/frame-embed.html).
71
+
72
+ Chat and records are the web surfaces (records on its own subpath and its own frame document, available
73
+ when Everfur enables records for your account); photo and video remain React Native for now. Vet visits (not yet enabled)
74
+ have their own entry on both hosts, `@everfur/sdk/web/televet` and `@everfur/sdk/televet`, and the video call
75
+ rendered inside your own app has an entry again beneath each, `@everfur/sdk/web/televet/call` and
76
+ `@everfur/sdk/televet/call`, so a partner mounting only the visit button takes no WebRTC dependency. Booking
77
+ the visit inside your own React Native app, rather than handing off to the hosted one, is a third entry,
78
+ `@everfur/sdk/televet/booking`, split out for the same reason: a partner that mounts only the button never
79
+ downloads a scheduler it does not render.
80
+ [docs/partner-integration/16-TELEVET-VISITS.md](docs/partner-integration/16-TELEVET-VISITS.md).
81
+
53
82
  ## Quickstart
54
83
 
55
84
  Wrap your tree once, high, then drop features in behind a gate. This is the exact shape the reference app
56
- uses:
85
+ uses, for a **React Native** host; a browser host imports the same names from `@everfur/sdk/web` (see [On
86
+ the web](#on-the-web)):
57
87
 
58
88
  ```tsx
59
89
  import { EverfurProvider, EverfurChat, petRef, userRef } from '@everfur/sdk';
@@ -80,7 +110,9 @@ export default function App() {
80
110
  }
81
111
  ```
82
112
 
83
- `getToken` calls **your** backend for a short-lived session token (never a secret in the app):
113
+ `getToken` calls **your** backend for a short-lived session token (never a secret in the app). Your route
114
+ answers with the token as a plain-text body, which is the shape the MCP planner generates and every example
115
+ in the docs uses:
84
116
 
85
117
  ```ts
86
118
  async function getToken(): Promise<string> {
@@ -88,13 +120,14 @@ async function getToken(): Promise<string> {
88
120
  method: 'POST',
89
121
  headers: { authorization: `Bearer ${yourAppsUserToken}` },
90
122
  });
91
- const { sessionToken } = await res.json();
92
- return sessionToken;
123
+ if (!res.ok) throw new Error('session mint failed: ' + res.status);
124
+ return res.text();
93
125
  }
94
126
  ```
95
127
 
96
128
  The SDK calls `getToken` lazily and re-calls it once after a `401`, so a fresh token is always used without
97
- you managing expiry. Records lives on its own subpath:
129
+ you managing expiry. Everfur never sees how you signed the person in (OAuth, a JWT, Firebase, Cognito, a
130
+ session, a magic link all work); it needs one stable, opaque, non-guessable id per person as `userRef`. Records lives on its own subpath:
98
131
 
99
132
  ```tsx
100
133
  import { EverfurRecords } from '@everfur/sdk/records';
@@ -105,13 +138,16 @@ import { petRef } from '@everfur/sdk';
105
138
 
106
139
  ## The security model
107
140
 
108
- The one rule: **the app never holds a secret.** Two credentials, kept apart.
141
+ The one rule: **the app never holds a secret.** Two provisioning credentials, kept apart, plus a read-only
142
+ docs key for tooling. Test mode is a sandbox tenant on the staging API with an ordinary `pk_live_` key
143
+ (`livemode: false` in its entitlements); no deployed environment accepts a `pk_test_` key.
109
144
 
110
145
  | Credential | Where it lives | What it does |
111
146
  | --- | --- | --- |
112
147
  | Publishable key `pk_live_...` | In the app (`EXPO_PUBLIC_...`). Safe to ship. | Names your tenant. Cannot mint a session or grant a feature by itself. |
113
148
  | Partner secret key `sk_partner_...` | **Only** on your server. Never in the app, its bundle, env, git, or logs. | Mints session tokens. Revocable and rotatable without an app release. |
114
- | Session token (bearer) | App memory, short-lived. | Authenticates one end user; re-minted via your backend on a 401. |
149
+ | Session token (bearer) | App memory, short-lived. | Authenticates one end user; re-minted via your backend on a 401. Signed, holds no secret, 15 minutes by default (1 minute to 1 hour). |
150
+ | Docs key `dk_partner_...` | Only in the MCP server or CLI configuration on a developer machine. | Read-only: fetches the Everfur contract from `GET /partners/contract` and opens no other route. |
115
151
 
116
152
  Your backend exchanges the two provisioning credentials for a short-lived session by calling
117
153
  `POST /widget/v1/sessions` with `x-everfur-partner-key: pk_live_...` + `x-everfur-partner-secret-key:
@@ -141,12 +177,16 @@ off-state, never a blank region.
141
177
  | Import | Contents |
142
178
  | --- | --- |
143
179
  | `@everfur/sdk` | `EverfurProvider`, `CapabilityGate`, `EverfurChat`, `useEverfurChat`, `CapabilityName`, error/result types, branded id helpers (`petRef`, `userRef`, `conversationId`) |
144
- | `@everfur/sdk/records` | `EverfurRecords`, records hooks + types |
180
+ | `@everfur/sdk/records` | `EverfurRecords`, `EverfurClinicRequest`, `EverfurClinicRequestBatch`, `SignaturePad`, records hooks + types |
181
+ | `@everfur/sdk/records/depth`, `@everfur/sdk/web/records/depth` | record depth (the timeline, the withheld record sections, per-document contributions) on their own entries, dark until Everfur enables it per deployment; see [chapter 9](docs/partner-integration/09-GUIDE-RECORDS-AND-CONSENT.md#record-depth-behind-a-separate-switch) |
145
182
  | `@everfur/sdk/video` | gait / live-scan surface |
146
183
  | `@everfur/sdk/photo` | photo checkup surface |
147
184
  | `@everfur/sdk/animations` | server-driven pet-state media surface |
185
+ | `@everfur/sdk/web` | the browser entry: `EverfurProvider`, `CapabilityGate`, `EverfurChat`, `useEverfurChat`, the theme hook, rendered with `react-dom`; withheld from React Native bundles the way `./server` is |
186
+ | `@everfur/sdk/web/records` | records for a browser host: `EverfurRecords`, `useEverfurRecords`, `createWebRecordsUploadTransport`, `fileToHandle`; its own entry, withheld from React Native like `./web`; available when Everfur enables records for the account. Frame mode serves it with `surface: 'records'` (see [chapter 13](docs/partner-integration/13-WEB-INTEGRATION.md)) |
148
187
  | `@everfur/sdk/server` | **server-only** `mintPartnerSession` (no React Native resolution; never bundled on-device) |
149
- | `@everfur/sdk/testing`, `@everfur/sdk/testing/rn` | test seams (`MockTransport`, ...) for your own tests |
188
+ | `@everfur/sdk/server/events` | **server-only, Node only** partner events (preview): `constructEvent` to verify webhooks, `sendPartnerEvent`; see [chapter 15](docs/partner-integration/15-EVENTS-AND-WEBHOOKS.md) |
189
+ | `@everfur/sdk/testing`, `@everfur/sdk/testing/rn`, `@everfur/sdk/testing/web` | test seams (`MockTransport`, `useEverfurTestEntitlements`, ...) for your own tests |
150
190
 
151
191
  `@everfur/sdk/client` and `@everfur/sdk/core` expose the framework-free layers for advanced integrators;
152
192
  most apps only need the root entry plus the capability subpaths.
@@ -154,7 +194,7 @@ most apps only need the root entry plus the capability subpaths.
154
194
  ## Reference app
155
195
 
156
196
  A full, runnable integration (a fictional "Pawtrail" app plus a minimal mint backend that holds the secret)
157
- lives at [`examples/minimal-integration.tsx`](examples/minimal-integration.tsx) in this repository — it is
197
+ lives at [`examples/minimal-integration.tsx`](examples/minimal-integration.tsx) in this repository; it is
158
198
  type-checked by `npm run docs:check`, so it cannot rot. It shows anonymous mode, the two-credential session
159
199
  mint, pet registration and sign-out. (A separate `everfur-integration-example-rn` app exists internally but
160
200
  is not published anywhere a partner can reach, so do not rely on references to it.) It gates every
@@ -0,0 +1,8 @@
1
+ {
2
+ "//": "GENERATED by scripts/subpath-shims.mjs from the package.json \"exports\" map. Do not edit by hand; run `npm run build`.",
3
+ "react-native": "../dist/consent/index.js",
4
+ "module": "../dist/consent/index.js",
5
+ "main": "../dist/consent/index.cjs",
6
+ "types": "../dist/consent/index.d.ts",
7
+ "sideEffects": false
8
+ }
@@ -0,0 +1,128 @@
1
+ import { ReactNode } from 'react';
2
+ import { StyleProp, ViewStyle } from 'react-native';
3
+ import { P as PetRef, C as ConversationId } from './ids-B2GAAifq.js';
4
+ import { F as FileHandle } from './ports-BN6RHF9W.js';
5
+ import { a as ChatCheckinTarget } from './ports-D7YW8qz9.js';
6
+ import { W as WidgetPet, P as PetProfileInput } from './petsRepository-Bk6GDwLs.js';
7
+ import { U as UrgencyDisplayLevel, L as LifecyclePort, E as EverfurChatDraftStore } from './attachments-BrUWQYNK.js';
8
+
9
+ /** Where a picked image comes from: the host's photo library, or its camera. */
10
+ type AttachmentSource = 'photo' | 'camera';
11
+
12
+ /** The host's own action for the two vet-care tiers, in place of Everfur's pill. */
13
+ type RenderVetAction = (level: UrgencyDisplayLevel) => ReactNode;
14
+
15
+ /**
16
+ * The host's image picker for chat attachments. The SDK depends on no picker or camera module: open your own
17
+ * (for example `expo-image-picker`'s `launchImageLibraryAsync({ mediaTypes: ['images'] })`, or your camera
18
+ * screen) and resolve `null` when the user cancels, else one `FileHandle` or several (a multi-select pick),
19
+ * each with the local `uri`, the image `mimeType` (`image/jpeg`, `image/png`, `image/webp`, `image/heic`,
20
+ * `image/heif`) and `sizeBytes`. The queue validates type and size (10 MiB) before any request.
21
+ *
22
+ * RESIZING AND EXIF ARE YOURS. The consumer app resizes to 1920 px, re-encodes as JPEG 0.85 and strips EXIF
23
+ * (location, device) before an upload; the SDK uploads the bytes at the `uri` as they are, so do the same in
24
+ * `pick` (for example with `expo-image-manipulator`) before resolving.
25
+ */
26
+ interface EverfurChatAttachments {
27
+ readonly pick: (source: AttachmentSource) => Promise<FileHandle | readonly FileHandle[] | null>;
28
+ /** The sources to offer, one popover tile each; default `['photo']`. */
29
+ readonly sources?: readonly AttachmentSource[];
30
+ /** Images per message; default 1 (the app's composer), at most 5 (the server's cap). */
31
+ readonly maxPerMessage?: number;
32
+ }
33
+ interface EverfurChatProps {
34
+ readonly petRef?: PetRef;
35
+ readonly conversationId?: ConversationId;
36
+ readonly style?: StyleProp<ViewStyle>;
37
+ /**
38
+ * Your own placeholder for the two moments Everfur would otherwise draw a waiting view of its own: the
39
+ * entitlement verdict still pending, and the chat still bootstrapping on a cold mount. Return null to draw
40
+ * nothing. A mount `prepare()` warmed up never reaches either. Absent, Everfur's skeleton and delayed spinner.
41
+ */
42
+ readonly renderPending?: () => ReactNode;
43
+ /**
44
+ * Your clipboard (for example `expo-clipboard`'s `setStringAsync`). Given, every message gets the app's
45
+ * copy control; absent, no copy control renders (the SDK depends on no clipboard module).
46
+ */
47
+ readonly onCopy?: (text: string) => Promise<void> | void;
48
+ /** Called after the user picked another pet in the header switcher and the provider re-scoped to it. */
49
+ readonly onPetChange?: (petRef: PetRef) => void;
50
+ /**
51
+ * Your vet-visit preparation screen. Given, the empty thread's `Help me prep for {pet}'s vet visit.` chip
52
+ * routes to it with the pet; absent, that chip is the Everfur vet visit entry inside Chat, shown only
53
+ * while Everfur has it switched on for your tenant, else not shown at all.
54
+ */
55
+ readonly onVetPrep?: (pet: WidgetPet | null) => void;
56
+ /**
57
+ * Your vet finder. On an `emergency` or `schedule_soon` reply the banner's `Find a vet` pill opens the
58
+ * Everfur vet visit entry when it is on for your tenant, else calls this, else does not render.
59
+ */
60
+ readonly onFindVet?: (level: UrgencyDisplayLevel) => void;
61
+ /** Your own control in the banner's action slot for those two tiers, in place of the pill. */
62
+ readonly renderVetAction?: RenderVetAction;
63
+ /** Your image picker: given, the composer gets the app's attachment control, previews and lightbox. */
64
+ readonly attachments?: EverfurChatAttachments;
65
+ /**
66
+ * The pet this chat is about, as YOUR system holds it: the whole partner pet body (name, species, breed,
67
+ * age, weight, and every health field, allergies, medications, supplements and conditions included). Given
68
+ * with `petRef`, the surface registers it with Everfur once, before the first conversation, and then names
69
+ * it in the header and the switcher. Nothing is trimmed: what you pass is what is sent.
70
+ */
71
+ readonly pet?: PetProfileInput;
72
+ /**
73
+ * Your own add-a-pet screen. Given, the switcher gets an `Add another pet` row, and a chat that cannot start
74
+ * because the `petRef` is not registered offers `Add a pet` in place of a retry that could only fail again.
75
+ * Absent, neither control is drawn: the partner plane never shows a route Everfur cannot honour.
76
+ */
77
+ readonly onAddPet?: () => void;
78
+ /**
79
+ * The check-in a tapped Everfur push is about: the `case` target `parseEverfurNotification` returned. Chat
80
+ * opens that thread on mount, once per target, so a due follow-up question is the first thing the member
81
+ * sees instead of something they would have to find in the history drawer. Absent, chat opens as usual.
82
+ */
83
+ readonly checkinTarget?: ChatCheckinTarget;
84
+ /**
85
+ * A question to ask on arrival, in a conversation of its own: the prompt one of your own screens built
86
+ * (an Everfur records "Ask Everfur" pill hands you one). It is asked once, after chat has finished
87
+ * opening, and the thread that was on screen is left behind so the answer is not buried in an unrelated
88
+ * conversation. Pass `composerSeed` instead when the user should decide whether to send it.
89
+ */
90
+ readonly initialAsk?: string;
91
+ /**
92
+ * Text to put in the composer on arrival. It is never sent for the user: they edit it, send it or clear
93
+ * it. Only an empty composer is seeded, so nothing they typed is ever replaced.
94
+ */
95
+ readonly composerSeed?: string;
96
+ /**
97
+ * Your app's lifecycle signals. Everfur has no socket and no polling here, so a message the platform
98
+ * writes into the thread (a follow-up check-in, a reminder) is not visible until something re-reads it.
99
+ * Tell Everfur when your app comes back to the foreground, when connectivity returns and when a push
100
+ * announced a change, and the thread and the unread dot catch up on that signal alone. Without this, chat
101
+ * refreshes only when the user does something.
102
+ */
103
+ readonly lifecycle?: LifecyclePort;
104
+ /**
105
+ * Your own storage for an unsent draft. Given, what the user typed and did not send survives leaving this
106
+ * screen; absent, the draft lives in memory for as long as the surface is mounted and nowhere else.
107
+ * Everfur writes a draft down only through this.
108
+ */
109
+ readonly draftStore?: EverfurChatDraftStore;
110
+ /**
111
+ * The KEY of a return destination your tenant registered with Everfur. Every vet entry inside chat (the
112
+ * header, the urgency banner's pill and the empty thread's vet-prep chip) then sends the user back to your
113
+ * app when the visit ends.
114
+ */
115
+ readonly vetReturnTo?: string;
116
+ /**
117
+ * The user's US state (for example `'CA'`). Set it and no vet entry is drawn until Everfur confirms a visit
118
+ * is available there, so it is never offered to someone who could not book.
119
+ */
120
+ readonly vetUsState?: string;
121
+ }
122
+ /**
123
+ * Entitlement-gated, four-state chat surface. Entitlement-OFF renders the CapabilityGate OffState;
124
+ * otherwise the body maps the controller snapshot to exactly one deliberate state.
125
+ */
126
+ declare function EverfurChat(props: EverfurChatProps): ReactNode;
127
+
128
+ export { type AttachmentSource as A, EverfurChat as E, type RenderVetAction as R, type EverfurChatAttachments as a, type EverfurChatProps as b };
@@ -0,0 +1,128 @@
1
+ import { ReactNode } from 'react';
2
+ import { StyleProp, ViewStyle } from 'react-native';
3
+ import { P as PetRef, C as ConversationId } from './ids-B2GAAifq.cjs';
4
+ import { F as FileHandle } from './ports-BN6RHF9W.cjs';
5
+ import { a as ChatCheckinTarget } from './ports-BY2ph0_y.cjs';
6
+ import { W as WidgetPet, P as PetProfileInput } from './petsRepository-B_gKbAzJ.cjs';
7
+ import { U as UrgencyDisplayLevel, L as LifecyclePort, E as EverfurChatDraftStore } from './attachments-D_SECjr1.cjs';
8
+
9
+ /** Where a picked image comes from: the host's photo library, or its camera. */
10
+ type AttachmentSource = 'photo' | 'camera';
11
+
12
+ /** The host's own action for the two vet-care tiers, in place of Everfur's pill. */
13
+ type RenderVetAction = (level: UrgencyDisplayLevel) => ReactNode;
14
+
15
+ /**
16
+ * The host's image picker for chat attachments. The SDK depends on no picker or camera module: open your own
17
+ * (for example `expo-image-picker`'s `launchImageLibraryAsync({ mediaTypes: ['images'] })`, or your camera
18
+ * screen) and resolve `null` when the user cancels, else one `FileHandle` or several (a multi-select pick),
19
+ * each with the local `uri`, the image `mimeType` (`image/jpeg`, `image/png`, `image/webp`, `image/heic`,
20
+ * `image/heif`) and `sizeBytes`. The queue validates type and size (10 MiB) before any request.
21
+ *
22
+ * RESIZING AND EXIF ARE YOURS. The consumer app resizes to 1920 px, re-encodes as JPEG 0.85 and strips EXIF
23
+ * (location, device) before an upload; the SDK uploads the bytes at the `uri` as they are, so do the same in
24
+ * `pick` (for example with `expo-image-manipulator`) before resolving.
25
+ */
26
+ interface EverfurChatAttachments {
27
+ readonly pick: (source: AttachmentSource) => Promise<FileHandle | readonly FileHandle[] | null>;
28
+ /** The sources to offer, one popover tile each; default `['photo']`. */
29
+ readonly sources?: readonly AttachmentSource[];
30
+ /** Images per message; default 1 (the app's composer), at most 5 (the server's cap). */
31
+ readonly maxPerMessage?: number;
32
+ }
33
+ interface EverfurChatProps {
34
+ readonly petRef?: PetRef;
35
+ readonly conversationId?: ConversationId;
36
+ readonly style?: StyleProp<ViewStyle>;
37
+ /**
38
+ * Your own placeholder for the two moments Everfur would otherwise draw a waiting view of its own: the
39
+ * entitlement verdict still pending, and the chat still bootstrapping on a cold mount. Return null to draw
40
+ * nothing. A mount `prepare()` warmed up never reaches either. Absent, Everfur's skeleton and delayed spinner.
41
+ */
42
+ readonly renderPending?: () => ReactNode;
43
+ /**
44
+ * Your clipboard (for example `expo-clipboard`'s `setStringAsync`). Given, every message gets the app's
45
+ * copy control; absent, no copy control renders (the SDK depends on no clipboard module).
46
+ */
47
+ readonly onCopy?: (text: string) => Promise<void> | void;
48
+ /** Called after the user picked another pet in the header switcher and the provider re-scoped to it. */
49
+ readonly onPetChange?: (petRef: PetRef) => void;
50
+ /**
51
+ * Your vet-visit preparation screen. Given, the empty thread's `Help me prep for {pet}'s vet visit.` chip
52
+ * routes to it with the pet; absent, that chip is the Everfur vet visit entry inside Chat, shown only
53
+ * while Everfur has it switched on for your tenant, else not shown at all.
54
+ */
55
+ readonly onVetPrep?: (pet: WidgetPet | null) => void;
56
+ /**
57
+ * Your vet finder. On an `emergency` or `schedule_soon` reply the banner's `Find a vet` pill opens the
58
+ * Everfur vet visit entry when it is on for your tenant, else calls this, else does not render.
59
+ */
60
+ readonly onFindVet?: (level: UrgencyDisplayLevel) => void;
61
+ /** Your own control in the banner's action slot for those two tiers, in place of the pill. */
62
+ readonly renderVetAction?: RenderVetAction;
63
+ /** Your image picker: given, the composer gets the app's attachment control, previews and lightbox. */
64
+ readonly attachments?: EverfurChatAttachments;
65
+ /**
66
+ * The pet this chat is about, as YOUR system holds it: the whole partner pet body (name, species, breed,
67
+ * age, weight, and every health field, allergies, medications, supplements and conditions included). Given
68
+ * with `petRef`, the surface registers it with Everfur once, before the first conversation, and then names
69
+ * it in the header and the switcher. Nothing is trimmed: what you pass is what is sent.
70
+ */
71
+ readonly pet?: PetProfileInput;
72
+ /**
73
+ * Your own add-a-pet screen. Given, the switcher gets an `Add another pet` row, and a chat that cannot start
74
+ * because the `petRef` is not registered offers `Add a pet` in place of a retry that could only fail again.
75
+ * Absent, neither control is drawn: the partner plane never shows a route Everfur cannot honour.
76
+ */
77
+ readonly onAddPet?: () => void;
78
+ /**
79
+ * The check-in a tapped Everfur push is about: the `case` target `parseEverfurNotification` returned. Chat
80
+ * opens that thread on mount, once per target, so a due follow-up question is the first thing the member
81
+ * sees instead of something they would have to find in the history drawer. Absent, chat opens as usual.
82
+ */
83
+ readonly checkinTarget?: ChatCheckinTarget;
84
+ /**
85
+ * A question to ask on arrival, in a conversation of its own: the prompt one of your own screens built
86
+ * (an Everfur records "Ask Everfur" pill hands you one). It is asked once, after chat has finished
87
+ * opening, and the thread that was on screen is left behind so the answer is not buried in an unrelated
88
+ * conversation. Pass `composerSeed` instead when the user should decide whether to send it.
89
+ */
90
+ readonly initialAsk?: string;
91
+ /**
92
+ * Text to put in the composer on arrival. It is never sent for the user: they edit it, send it or clear
93
+ * it. Only an empty composer is seeded, so nothing they typed is ever replaced.
94
+ */
95
+ readonly composerSeed?: string;
96
+ /**
97
+ * Your app's lifecycle signals. Everfur has no socket and no polling here, so a message the platform
98
+ * writes into the thread (a follow-up check-in, a reminder) is not visible until something re-reads it.
99
+ * Tell Everfur when your app comes back to the foreground, when connectivity returns and when a push
100
+ * announced a change, and the thread and the unread dot catch up on that signal alone. Without this, chat
101
+ * refreshes only when the user does something.
102
+ */
103
+ readonly lifecycle?: LifecyclePort;
104
+ /**
105
+ * Your own storage for an unsent draft. Given, what the user typed and did not send survives leaving this
106
+ * screen; absent, the draft lives in memory for as long as the surface is mounted and nowhere else.
107
+ * Everfur writes a draft down only through this.
108
+ */
109
+ readonly draftStore?: EverfurChatDraftStore;
110
+ /**
111
+ * The KEY of a return destination your tenant registered with Everfur. Every vet entry inside chat (the
112
+ * header, the urgency banner's pill and the empty thread's vet-prep chip) then sends the user back to your
113
+ * app when the visit ends.
114
+ */
115
+ readonly vetReturnTo?: string;
116
+ /**
117
+ * The user's US state (for example `'CA'`). Set it and no vet entry is drawn until Everfur confirms a visit
118
+ * is available there, so it is never offered to someone who could not book.
119
+ */
120
+ readonly vetUsState?: string;
121
+ }
122
+ /**
123
+ * Entitlement-gated, four-state chat surface. Entitlement-OFF renders the CapabilityGate OffState;
124
+ * otherwise the body maps the controller snapshot to exactly one deliberate state.
125
+ */
126
+ declare function EverfurChat(props: EverfurChatProps): ReactNode;
127
+
128
+ export { type AttachmentSource as A, EverfurChat as E, type RenderVetAction as R, type EverfurChatAttachments as a, type EverfurChatProps as b };
@@ -0,0 +1,16 @@
1
+ import { CSSProperties, ReactNode } from 'react';
2
+ import { f as RecordsScreenBaseProps } from './useRecordsDepth-crhBllQK.js';
3
+
4
+ interface EverfurRecordsDepthProps extends Pick<RecordsScreenBaseProps, 'petRef' | 'petName' | 'onNavigate' | 'onBack'> {
5
+ readonly style?: CSSProperties;
6
+ readonly className?: string;
7
+ }
8
+ interface EverfurDocumentContributionsProps extends EverfurRecordsDepthProps {
9
+ /** A `docId` from the record's `documents`. */
10
+ readonly docId: string;
11
+ }
12
+ declare function EverfurRecordsTimeline({ petRef, style, className, onBack }: EverfurRecordsDepthProps): ReactNode;
13
+ declare function EverfurRecordDepth({ petRef, style, className, onBack }: EverfurRecordsDepthProps): ReactNode;
14
+ declare function EverfurDocumentContributions({ petRef, docId, style, className, onBack }: EverfurDocumentContributionsProps): ReactNode;
15
+
16
+ export { EverfurDocumentContributions as E, type EverfurDocumentContributionsProps as a, EverfurRecordDepth as b, type EverfurRecordsDepthProps as c, EverfurRecordsTimeline as d };
@@ -0,0 +1,19 @@
1
+ import { ReactNode } from 'react';
2
+ import { StyleProp, ViewStyle } from 'react-native';
3
+ import { f as RecordsScreenBaseProps } from './useRecordsDepth-C6rjEaLn.cjs';
4
+
5
+ interface EverfurRecordsDepthProps extends Pick<RecordsScreenBaseProps, 'petRef' | 'petName' | 'onNavigate' | 'onBack'> {
6
+ readonly style?: StyleProp<ViewStyle>;
7
+ }
8
+ interface EverfurDocumentContributionsProps extends EverfurRecordsDepthProps {
9
+ /** A `docId` from the record's `documents`. */
10
+ readonly docId: string;
11
+ }
12
+ /** The consumer timeline screen: `Timeline` over visits, vaccines, weights and medications merged newest first. */
13
+ declare function EverfurRecordsTimeline({ petRef, style, onBack }: EverfurRecordsDepthProps): ReactNode;
14
+ /** The four sections the base record withholds: lab work, visits, physical exams and visit notes. */
15
+ declare function EverfurRecordDepth({ petRef, style, onBack }: EverfurRecordsDepthProps): ReactNode;
16
+ /** What one published document contributed to the record, in the record's own row vocabulary. */
17
+ declare function EverfurDocumentContributions({ petRef, docId, style, onBack }: EverfurDocumentContributionsProps): ReactNode;
18
+
19
+ export { EverfurDocumentContributions as E, type EverfurDocumentContributionsProps as a, EverfurRecordDepth as b, type EverfurRecordsDepthProps as c, EverfurRecordsTimeline as d };
@@ -0,0 +1,16 @@
1
+ import { CSSProperties, ReactNode } from 'react';
2
+ import { f as RecordsScreenBaseProps } from './useRecordsDepth-C6rjEaLn.cjs';
3
+
4
+ interface EverfurRecordsDepthProps extends Pick<RecordsScreenBaseProps, 'petRef' | 'petName' | 'onNavigate' | 'onBack'> {
5
+ readonly style?: CSSProperties;
6
+ readonly className?: string;
7
+ }
8
+ interface EverfurDocumentContributionsProps extends EverfurRecordsDepthProps {
9
+ /** A `docId` from the record's `documents`. */
10
+ readonly docId: string;
11
+ }
12
+ declare function EverfurRecordsTimeline({ petRef, style, className, onBack }: EverfurRecordsDepthProps): ReactNode;
13
+ declare function EverfurRecordDepth({ petRef, style, className, onBack }: EverfurRecordsDepthProps): ReactNode;
14
+ declare function EverfurDocumentContributions({ petRef, docId, style, className, onBack }: EverfurDocumentContributionsProps): ReactNode;
15
+
16
+ export { EverfurDocumentContributions as E, type EverfurDocumentContributionsProps as a, EverfurRecordDepth as b, type EverfurRecordsDepthProps as c, EverfurRecordsTimeline as d };
@@ -0,0 +1,19 @@
1
+ import { ReactNode } from 'react';
2
+ import { StyleProp, ViewStyle } from 'react-native';
3
+ import { f as RecordsScreenBaseProps } from './useRecordsDepth-crhBllQK.js';
4
+
5
+ interface EverfurRecordsDepthProps extends Pick<RecordsScreenBaseProps, 'petRef' | 'petName' | 'onNavigate' | 'onBack'> {
6
+ readonly style?: StyleProp<ViewStyle>;
7
+ }
8
+ interface EverfurDocumentContributionsProps extends EverfurRecordsDepthProps {
9
+ /** A `docId` from the record's `documents`. */
10
+ readonly docId: string;
11
+ }
12
+ /** The consumer timeline screen: `Timeline` over visits, vaccines, weights and medications merged newest first. */
13
+ declare function EverfurRecordsTimeline({ petRef, style, onBack }: EverfurRecordsDepthProps): ReactNode;
14
+ /** The four sections the base record withholds: lab work, visits, physical exams and visit notes. */
15
+ declare function EverfurRecordDepth({ petRef, style, onBack }: EverfurRecordsDepthProps): ReactNode;
16
+ /** What one published document contributed to the record, in the record's own row vocabulary. */
17
+ declare function EverfurDocumentContributions({ petRef, docId, style, onBack }: EverfurDocumentContributionsProps): ReactNode;
18
+
19
+ export { EverfurDocumentContributions as E, type EverfurDocumentContributionsProps as a, EverfurRecordDepth as b, type EverfurRecordsDepthProps as c, EverfurRecordsTimeline as d };
@@ -0,0 +1,22 @@
1
+ import { b as EverfurErrorCode, E as EverfurError } from './EverfurResult-DN9pL2Ab.cjs';
2
+
3
+ /**
4
+ * Recovery policy. A host may narrow retry ceilings (e.g. a metered plan) but can never widen the SDK's
5
+ * settle-don't-throw contract. `attempt` is 0-based (the first try is attempt 0).
6
+ */
7
+ interface ErrorPolicyPort {
8
+ /** Whether to retry `code` on this attempt. Default: `isAutoRetryable(code) && attempt < maxAttempts(code)`. */
9
+ shouldRetry(code: EverfurErrorCode, attempt: number): boolean;
10
+ /** Total attempts (the initial try plus retries) before the terminal error surfaces. Default 4. */
11
+ maxAttempts(code: EverfurErrorCode): number;
12
+ /** Observation hook for a handled, product-expected failure. Never rendered, never thrown. */
13
+ onExpectedFailure?(error: EverfurError): void;
14
+ }
15
+ /**
16
+ * The shipped default policy (applied when EverfurConfig omits `errorPolicy`). Pure and total.
17
+ * `authExpired` is deliberately NOT auto-retried here: it is a token refresh + single replay handled by the
18
+ * controller / authedSend, not a backoff retry (SPEC-00 §3.2 / §4.3).
19
+ */
20
+ declare const defaultErrorPolicy: ErrorPolicyPort;
21
+
22
+ export { type ErrorPolicyPort as E, defaultErrorPolicy as d };
@@ -0,0 +1,22 @@
1
+ import { b as EverfurErrorCode, E as EverfurError } from './EverfurResult-DN9pL2Ab.js';
2
+
3
+ /**
4
+ * Recovery policy. A host may narrow retry ceilings (e.g. a metered plan) but can never widen the SDK's
5
+ * settle-don't-throw contract. `attempt` is 0-based (the first try is attempt 0).
6
+ */
7
+ interface ErrorPolicyPort {
8
+ /** Whether to retry `code` on this attempt. Default: `isAutoRetryable(code) && attempt < maxAttempts(code)`. */
9
+ shouldRetry(code: EverfurErrorCode, attempt: number): boolean;
10
+ /** Total attempts (the initial try plus retries) before the terminal error surfaces. Default 4. */
11
+ maxAttempts(code: EverfurErrorCode): number;
12
+ /** Observation hook for a handled, product-expected failure. Never rendered, never thrown. */
13
+ onExpectedFailure?(error: EverfurError): void;
14
+ }
15
+ /**
16
+ * The shipped default policy (applied when EverfurConfig omits `errorPolicy`). Pure and total.
17
+ * `authExpired` is deliberately NOT auto-retried here: it is a token refresh + single replay handled by the
18
+ * controller / authedSend, not a backoff retry (SPEC-00 §3.2 / §4.3).
19
+ */
20
+ declare const defaultErrorPolicy: ErrorPolicyPort;
21
+
22
+ export { type ErrorPolicyPort as E, defaultErrorPolicy as d };
@@ -131,6 +131,12 @@ interface EverfurError {
131
131
  readonly requestId?: string;
132
132
  /** Site-relative documentation path for the wire code, from the contract registry. No host is implied. */
133
133
  readonly docUrl?: string;
134
+ /**
135
+ * The server's stable sub-reason for this failure, when it sent one (for example `pet_not_registered` or
136
+ * `species_unsupported` on the records routes). Safe to branch on, unlike `wireMessage`. Only a lowercase
137
+ * snake_case token is kept; anything else is dropped rather than carried.
138
+ */
139
+ readonly reasonCode?: string;
134
140
  /** raw wire text; telemetry / logs only, NEVER rendered. NON-ENUMERABLE. */
135
141
  readonly wireMessage?: string;
136
142
  /** Opaque parsed wire payload for debugging (untrusted, unvalidated). NON-ENUMERABLE. */
@@ -155,20 +161,15 @@ interface MakeEverfurErrorOptions {
155
161
  * the code exactly as the server sent it; a code that is not in the registry simply yields no docUrl.
156
162
  */
157
163
  readonly wireCode?: string | null;
164
+ /** The envelope the wire code arrived in, when known; a code registered on both envelopes resolves to its own row. */
165
+ readonly wireEnvelope?: 'http_envelope' | 'sse_frame';
158
166
  /** Untrusted wire text. Carried NON-ENUMERABLY for telemetry; never rendered. */
159
167
  readonly wireMessage?: string | null;
168
+ /** The server's `reason_code`, kept only when it is a lowercase snake_case token (see `EverfurError.reasonCode`). */
169
+ readonly reasonCode?: string | null;
160
170
  /** Opaque parsed wire payload. Carried NON-ENUMERABLY for debugging; never rendered. */
161
171
  readonly raw?: unknown;
162
172
  }
163
- /**
164
- * Build a normalized, frozen `EverfurError` from a normalized code plus optional wire/HTTP context.
165
- *
166
- * `displayMessage` is always the SAFE code-derived string. `retryable` defaults to the code's policy
167
- * (`isRetryableCode`) unless the caller overrides it, e.g. a frame carrying explicit `retryable:true`.
168
- * `requestId` and `docUrl` are the two support-facing additions: the id a partner quotes, and the
169
- * site-relative registry path for the wire code. `wireMessage` and `raw` are carried NON-ENUMERABLY and
170
- * are dropped when empty.
171
- */
172
173
  declare function makeEverfurError(code: EverfurErrorCode, opts?: MakeEverfurErrorOptions): EverfurError;
173
174
 
174
175
  /**
@@ -237,4 +238,4 @@ declare class EverfurConfigError extends Error {
237
238
  constructor(kind: 'not-initialized' | 'invalid-argument' | 'missing-peer-dependency', message: string);
238
239
  }
239
240
 
240
- export { AUTO_RETRYABLE_CODES as A, BACKOFF_BASE_MS as B, type EverfurResult as E, MAX_RETRY_ATTEMPTS as M, RETRYABLE_CONTRACT_CODES as R, type EverfurErrorCode as a, BACKOFF_CAP_MS as b, EVERFUR_ERROR_CATEGORIES as c, EVERFUR_ERROR_CODES as d, EverfurConfigError as e, type EverfurError as f, type EverfurErrorCategory as g, EverfurThrownError as h, type MakeEverfurErrorOptions as i, backoffDelayMs as j, canRecreateOnNotFound as k, categoryFor as l, err as m, fromHttpStatus as n, fromWire as o, isAutoRetryable as p, isErr as q, isOk as r, isRetryableCode as s, makeEverfurError as t, ok as u, shouldRetry as v, unwrap as w, userFacingError as x };
241
+ export { AUTO_RETRYABLE_CODES as A, BACKOFF_BASE_MS as B, type EverfurError as E, MAX_RETRY_ATTEMPTS as M, RETRYABLE_CONTRACT_CODES as R, type EverfurErrorCategory as a, type EverfurErrorCode as b, type EverfurResult as c, EverfurConfigError as d, EverfurThrownError as e, categoryFor as f, isOk as g, isRetryableCode as h, isErr as i, userFacingError as j, BACKOFF_CAP_MS as k, EVERFUR_ERROR_CATEGORIES as l, EVERFUR_ERROR_CODES as m, type MakeEverfurErrorOptions as n, backoffDelayMs as o, canRecreateOnNotFound as p, err as q, fromHttpStatus as r, fromWire as s, isAutoRetryable as t, unwrap as u, makeEverfurError as v, ok as w, shouldRetry as x };