@everfur/sdk 0.1.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 (89) hide show
  1. package/CHANGELOG.md +74 -0
  2. package/LICENSE +21 -0
  3. package/README.md +161 -0
  4. package/animations/package.json +8 -0
  5. package/chat/package.json +8 -0
  6. package/client/package.json +8 -0
  7. package/core/package.json +8 -0
  8. package/dist/CameraPort-Cv31Pz7g.d.cts +29 -0
  9. package/dist/CameraPort-Cv31Pz7g.d.ts +29 -0
  10. package/dist/ChatController-CKdBvPj2.d.ts +146 -0
  11. package/dist/ChatController-CpUMvvZf.d.cts +146 -0
  12. package/dist/EverfurResult-D92-uL82.d.cts +240 -0
  13. package/dist/EverfurResult-D92-uL82.d.ts +240 -0
  14. package/dist/FilePort-BabWrv7I.d.cts +22 -0
  15. package/dist/FilePort-BabWrv7I.d.ts +22 -0
  16. package/dist/PhotoController-BItt5M7u.d.cts +43 -0
  17. package/dist/PhotoController-D8zMTdcW.d.ts +43 -0
  18. package/dist/TelemetryPort-BDNr00hu.d.cts +12 -0
  19. package/dist/TelemetryPort-BDNr00hu.d.ts +12 -0
  20. package/dist/animations/index.cjs +1997 -0
  21. package/dist/animations/index.d.cts +517 -0
  22. package/dist/animations/index.d.ts +517 -0
  23. package/dist/animations/index.js +1972 -0
  24. package/dist/cacheEpoch-DknKn3S0.d.cts +36 -0
  25. package/dist/cacheEpoch-DknKn3S0.d.ts +36 -0
  26. package/dist/chat/index.cjs +1170 -0
  27. package/dist/chat/index.d.cts +59 -0
  28. package/dist/chat/index.d.ts +59 -0
  29. package/dist/chat/index.js +1167 -0
  30. package/dist/client/index.cjs +2317 -0
  31. package/dist/client/index.d.cts +65 -0
  32. package/dist/client/index.d.ts +65 -0
  33. package/dist/client/index.js +2217 -0
  34. package/dist/config-BSjBdxrZ.d.cts +501 -0
  35. package/dist/config-CiJ0PVBB.d.ts +501 -0
  36. package/dist/core/index.cjs +3175 -0
  37. package/dist/core/index.d.cts +70 -0
  38. package/dist/core/index.d.ts +70 -0
  39. package/dist/core/index.js +3163 -0
  40. package/dist/identity-Brl-lDd6.d.cts +91 -0
  41. package/dist/identity-DK9zORrG.d.ts +91 -0
  42. package/dist/ids-CJ1S6adf.d.cts +46 -0
  43. package/dist/ids-CJ1S6adf.d.ts +46 -0
  44. package/dist/index.cjs +4488 -0
  45. package/dist/index.d.cts +156 -0
  46. package/dist/index.d.ts +156 -0
  47. package/dist/index.js +4464 -0
  48. package/dist/petsRepository-BEGb97M9.d.cts +326 -0
  49. package/dist/petsRepository-Bu18r2kK.d.ts +326 -0
  50. package/dist/photo/index.cjs +2189 -0
  51. package/dist/photo/index.d.cts +43 -0
  52. package/dist/photo/index.d.ts +43 -0
  53. package/dist/photo/index.js +2186 -0
  54. package/dist/projection-CeIUsbSk.d.cts +8 -0
  55. package/dist/projection-CeIUsbSk.d.ts +8 -0
  56. package/dist/records/index.cjs +2840 -0
  57. package/dist/records/index.d.cts +224 -0
  58. package/dist/records/index.d.ts +224 -0
  59. package/dist/records/index.js +2834 -0
  60. package/dist/requestFunnel-DuUH-kAe.d.cts +28 -0
  61. package/dist/requestFunnel-dio5OmR9.d.ts +28 -0
  62. package/dist/resolve-Dq_4_agU.d.cts +86 -0
  63. package/dist/resolve-Dq_4_agU.d.ts +86 -0
  64. package/dist/runtime-BgQnA594.d.cts +349 -0
  65. package/dist/runtime-CBA-LvdM.d.ts +349 -0
  66. package/dist/server/index.cjs +533 -0
  67. package/dist/server/index.d.cts +48 -0
  68. package/dist/server/index.d.ts +48 -0
  69. package/dist/server/index.js +530 -0
  70. package/dist/testing/index.cjs +825 -0
  71. package/dist/testing/index.d.cts +113 -0
  72. package/dist/testing/index.d.ts +113 -0
  73. package/dist/testing/index.js +822 -0
  74. package/dist/testing/rn/index.cjs +449 -0
  75. package/dist/testing/rn/index.d.cts +49 -0
  76. package/dist/testing/rn/index.d.ts +49 -0
  77. package/dist/testing/rn/index.js +444 -0
  78. package/dist/video/index.cjs +1941 -0
  79. package/dist/video/index.d.cts +66 -0
  80. package/dist/video/index.d.ts +66 -0
  81. package/dist/video/index.js +1938 -0
  82. package/package.json +311 -0
  83. package/photo/package.json +8 -0
  84. package/records/package.json +8 -0
  85. package/server/device-blocked.cjs +15 -0
  86. package/server/package.json +9 -0
  87. package/testing/package.json +8 -0
  88. package/testing/rn/package.json +8 -0
  89. package/video/package.json +8 -0
@@ -0,0 +1,444 @@
1
+ import { createContext, useMemo, useRef, useEffect, useState, useContext } from 'react';
2
+ import 'react-native-safe-area-context';
3
+ import { View, Animated, StyleSheet, Easing, Text } from 'react-native';
4
+ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
5
+
6
+ // src/rn/testing.ts
7
+
8
+ // src/client/errors/EverfurResult.ts
9
+ var EverfurConfigError = class _EverfurConfigError extends Error {
10
+ constructor(kind, message) {
11
+ super(message);
12
+ this.name = "EverfurConfigError";
13
+ this.kind = kind;
14
+ Object.setPrototypeOf(this, _EverfurConfigError.prototype);
15
+ }
16
+ };
17
+
18
+ // src/client/theme/tokens.ts
19
+ function deepFreeze(value) {
20
+ if (value !== null && typeof value === "object" && !Object.isFrozen(value)) {
21
+ Object.freeze(value);
22
+ for (const key of Object.keys(value)) {
23
+ deepFreeze(value[key]);
24
+ }
25
+ }
26
+ return value;
27
+ }
28
+ var SPACE = { xs: 4, sm: 8, md: 12, lg: 16, xl: 24, xxl: 32 };
29
+ var RADIUS = { tile: 5, xs: 6, sm: 10, md: 14, lg: 20, xl: 28, pill: 500 };
30
+ var TYPE_SIZE = {
31
+ nano: 8,
32
+ small: 9,
33
+ micro: 10,
34
+ tiny: 11,
35
+ caption: 12,
36
+ bodyTight: 13,
37
+ body: 14,
38
+ subtitle: 16,
39
+ heading: 18,
40
+ verdict: 24
41
+ };
42
+ var LINE_HEIGHT = { tight: 1.15, snug: 1.3, normal: 1.4, relaxed: 1.55 };
43
+ var WEIGHT = { regular: "400", medium: "500", bold: "700" };
44
+ var LETTER_SPACING = {
45
+ eyebrow: 1,
46
+ monoWide: 0.9,
47
+ headerBrand: -0.42,
48
+ tight: -0.35
49
+ };
50
+ function baseType() {
51
+ return {
52
+ family: "System",
53
+ mono: "monospace",
54
+ fontUrl: null,
55
+ size: TYPE_SIZE,
56
+ lineHeight: LINE_HEIGHT,
57
+ weight: WEIGHT,
58
+ letterSpacing: LETTER_SPACING
59
+ };
60
+ }
61
+ var MOTION = {
62
+ duration: { instant: 80, fast: 140, normal: 220, slow: 320 },
63
+ spring: { gentle: { damping: 18, stiffness: 200 } },
64
+ easing: { standard: "cubic-bezier(0.4, 0, 0.2, 1)" },
65
+ reducedMotion: false
66
+ };
67
+ var LIGHT_COLOR = {
68
+ brand: "#10462E",
69
+ brandSoft: "rgba(16,70,46,0.10)",
70
+ brandSofter: "rgba(16,70,46,0.15)",
71
+ brandBorder: "rgba(16,70,46,0.18)",
72
+ borderHairlineGreen: "rgba(16,70,46,0.25)",
73
+ surface: "#FFFFFF",
74
+ surfaceCream: "#FDFBF8",
75
+ surfaceSubtle: "#EFE9E3",
76
+ background: "#FFFFFF",
77
+ borderRingCream: "#D8D2C8",
78
+ text: {
79
+ primary: "#111111",
80
+ secondary: "#0E462E",
81
+ muted: "#6E6660",
82
+ placeholder: "rgba(0,0,0,0.30)",
83
+ onBrand: "#FFFFFF",
84
+ metaCool: "#3D3D3D"
85
+ },
86
+ primary: "#10462E",
87
+ onPrimary: "#FFFFFF",
88
+ accent: "#10462E",
89
+ onAccent: "#FFFFFF",
90
+ accentEdge: "#07C168",
91
+ success: "#07C168",
92
+ danger: "#B91C1C",
93
+ errorRed: "#FF1B00",
94
+ warningStrong: "#A45610",
95
+ cautionAccent: "#D9821D",
96
+ riskConcern: "#EFA700",
97
+ badgeBgPositive: "rgba(7,193,104,0.12)",
98
+ badgeBgCaution: "rgba(217,130,29,0.14)",
99
+ badgeBgCritical: "rgba(185,28,28,0.12)",
100
+ badgeBgNeutral: "rgba(110,102,96,0.12)",
101
+ bubbleUser: "#10462E",
102
+ bubbleAssistant: "#FFFFFF",
103
+ skeleton: "#EFE9E3",
104
+ scanButtonPink: "#FFC3BC",
105
+ checkupCardLowRiskBg: "rgba(7,193,104,0.10)",
106
+ checkupCardConcernBg: "rgba(239,167,0,0.10)"
107
+ };
108
+ var EVERFUR_LIGHT = deepFreeze({
109
+ brightness: "light",
110
+ meta: { displayName: "Everfur", logoUrl: null, placeholder: null, hidePoweredBy: false },
111
+ color: LIGHT_COLOR,
112
+ space: SPACE,
113
+ radius: RADIUS,
114
+ type: baseType(),
115
+ motion: MOTION
116
+ });
117
+ var DARK_COLOR = {
118
+ brand: "#6BD39A",
119
+ brandSoft: "rgba(107,211,154,0.12)",
120
+ brandSofter: "rgba(107,211,154,0.18)",
121
+ brandBorder: "rgba(107,211,154,0.22)",
122
+ borderHairlineGreen: "rgba(107,211,154,0.28)",
123
+ surface: "#1C1F23",
124
+ surfaceCream: "#23272C",
125
+ surfaceSubtle: "#23272C",
126
+ background: "#15171A",
127
+ borderRingCream: "#3A3F45",
128
+ text: {
129
+ primary: "#F5F3F0",
130
+ secondary: "#A9E4C4",
131
+ muted: "#9A938C",
132
+ placeholder: "rgba(255,255,255,0.35)",
133
+ onBrand: "#0E1F17",
134
+ metaCool: "#C9C9C9"
135
+ },
136
+ primary: "#6BD39A",
137
+ onPrimary: "#0E1F17",
138
+ accent: "#6BD39A",
139
+ onAccent: "#0E1F17",
140
+ accentEdge: "#34D888",
141
+ success: "#07C168",
142
+ danger: "#B91C1C",
143
+ errorRed: "#FF1B00",
144
+ warningStrong: "#A45610",
145
+ cautionAccent: "#D9821D",
146
+ riskConcern: "#EFA700",
147
+ badgeBgPositive: "rgba(7,193,104,0.18)",
148
+ badgeBgCaution: "rgba(217,130,29,0.20)",
149
+ badgeBgCritical: "rgba(185,28,28,0.22)",
150
+ badgeBgNeutral: "rgba(255,255,255,0.10)",
151
+ bubbleUser: "#6BD39A",
152
+ bubbleAssistant: "#1C1F23",
153
+ skeleton: "#23272C",
154
+ scanButtonPink: "#FFC3BC",
155
+ checkupCardLowRiskBg: "rgba(7,193,104,0.16)",
156
+ checkupCardConcernBg: "rgba(239,167,0,0.16)"
157
+ };
158
+ deepFreeze({
159
+ brightness: "dark",
160
+ meta: { displayName: "Everfur", logoUrl: null, placeholder: null, hidePoweredBy: false },
161
+ color: DARK_COLOR,
162
+ space: SPACE,
163
+ radius: RADIUS,
164
+ type: baseType(),
165
+ motion: MOTION
166
+ });
167
+ var EVERFUR_THEME_CONTEXT_SYMBOL = /* @__PURE__ */ Symbol.for("@everfur/sdk#EverfurThemeContext@v1");
168
+ var globalThemeHost = globalThis;
169
+ var EverfurThemeContext = globalThemeHost[EVERFUR_THEME_CONTEXT_SYMBOL] ?? (globalThemeHost[EVERFUR_THEME_CONTEXT_SYMBOL] = createContext(EVERFUR_LIGHT));
170
+ EverfurThemeContext.displayName ??= "EverfurThemeContext";
171
+ function useEverfurTheme() {
172
+ return useContext(EverfurThemeContext);
173
+ }
174
+
175
+ // src/rn/facade.ts
176
+ var EVERFUR_CONTEXT_SYMBOL = /* @__PURE__ */ Symbol.for("@everfur/sdk#EverfurContext@v1");
177
+ var globalContextHost = globalThis;
178
+ var EverfurContext = globalContextHost[EVERFUR_CONTEXT_SYMBOL] ?? (globalContextHost[EVERFUR_CONTEXT_SYMBOL] = createContext(null));
179
+ EverfurContext.displayName ??= "EverfurContext";
180
+ function useEverfurContext() {
181
+ const ctx = useContext(EverfurContext);
182
+ if (ctx === null) {
183
+ throw new EverfurConfigError(
184
+ "not-initialized",
185
+ "Everfur hooks must be called inside <EverfurProvider>. Wrap your tree once, high."
186
+ );
187
+ }
188
+ return ctx;
189
+ }
190
+ var DOT_SIZE = 6;
191
+ var LOOP_MS = 520;
192
+ var STAGGER_MS = Math.round(LOOP_MS * 0.18);
193
+ var OPACITY_REST = 0.44;
194
+ var OPACITY_STATIC = 0.5;
195
+ var TRI_IN = [0, 0.5, 1];
196
+ var DOT_INDICES = [0, 1, 2];
197
+ function TypingIndicator() {
198
+ const theme = useEverfurTheme();
199
+ const styles = useMemo(() => makeStyles(theme), [theme]);
200
+ const animate = !theme.motion.reducedMotion;
201
+ return /* @__PURE__ */ jsx(
202
+ View,
203
+ {
204
+ style: styles.card,
205
+ accessible: true,
206
+ accessibilityRole: "text",
207
+ accessibilityLabel: "Assistant is typing",
208
+ accessibilityLiveRegion: "polite",
209
+ accessibilityState: { busy: true },
210
+ children: DOT_INDICES.map(
211
+ (index) => animate ? /* @__PURE__ */ jsx(AnimatedDot, { index, style: styles.dot }, index) : /* @__PURE__ */ jsx(View, { style: [styles.dot, styles.dotStatic] }, index)
212
+ )
213
+ }
214
+ );
215
+ }
216
+ function AnimatedDot({ index, style }) {
217
+ const t = useRef(new Animated.Value(0)).current;
218
+ useEffect(() => {
219
+ const anim = Animated.sequence([
220
+ Animated.delay(index * STAGGER_MS),
221
+ Animated.loop(Animated.timing(t, { toValue: 1, duration: LOOP_MS, useNativeDriver: true }))
222
+ ]);
223
+ anim.start();
224
+ return () => anim.stop();
225
+ }, [t, index]);
226
+ const opacity = t.interpolate({ inputRange: TRI_IN, outputRange: [OPACITY_REST, 1, OPACITY_REST] });
227
+ const translateY = t.interpolate({ inputRange: TRI_IN, outputRange: [0, -3.5, 0] });
228
+ return /* @__PURE__ */ jsx(Animated.View, { style: [style, { opacity, transform: [{ translateY }] }] });
229
+ }
230
+ function makeStyles(theme) {
231
+ const c = theme.color;
232
+ const s = theme.space;
233
+ const r = theme.radius;
234
+ return StyleSheet.create({
235
+ card: {
236
+ alignSelf: "flex-start",
237
+ flexDirection: "row",
238
+ alignItems: "center",
239
+ gap: s.xs,
240
+ paddingHorizontal: s.md,
241
+ paddingVertical: s.sm,
242
+ backgroundColor: c.surfaceCream,
243
+ borderRadius: r.md,
244
+ borderWidth: StyleSheet.hairlineWidth,
245
+ borderColor: c.brandBorder
246
+ },
247
+ dot: { width: DOT_SIZE, height: DOT_SIZE, borderRadius: r.pill, backgroundColor: c.brand },
248
+ dotStatic: { opacity: OPACITY_STATIC }
249
+ });
250
+ }
251
+ var ROTATION_PERIOD_MS = 1400;
252
+ var REVEAL_DELAY_MS = 300;
253
+ function AnalyzingIndicator() {
254
+ const theme = useEverfurTheme();
255
+ const styles = useMemo(() => makeStyles2(theme), [theme]);
256
+ const reduced = theme.motion.reducedMotion;
257
+ const [visible, setVisible] = useState(false);
258
+ useEffect(() => {
259
+ const id = setTimeout(() => setVisible(true), REVEAL_DELAY_MS);
260
+ return () => clearTimeout(id);
261
+ }, []);
262
+ const spin = useRef(new Animated.Value(0)).current;
263
+ useEffect(() => {
264
+ if (reduced || !visible) return;
265
+ const loop = Animated.loop(
266
+ Animated.timing(spin, {
267
+ toValue: 1,
268
+ duration: ROTATION_PERIOD_MS,
269
+ easing: Easing.linear,
270
+ useNativeDriver: true
271
+ })
272
+ );
273
+ loop.start();
274
+ return () => loop.stop();
275
+ }, [reduced, visible, spin]);
276
+ const arcMotionStyle = reduced ? null : { transform: [{ rotate: spin.interpolate({ inputRange: [0, 1], outputRange: ["0deg", "360deg"] }) }] };
277
+ return /* @__PURE__ */ jsx(
278
+ View,
279
+ {
280
+ style: styles.wrap,
281
+ accessible: true,
282
+ accessibilityState: { busy: true },
283
+ accessibilityLabel: "Analyzing photo",
284
+ children: visible ? /* @__PURE__ */ jsxs(Fragment, { children: [
285
+ /* @__PURE__ */ jsx(Animated.View, { style: [styles.ring, arcMotionStyle] }),
286
+ /* @__PURE__ */ jsx(Text, { style: styles.statusLine, children: "Analyzing" })
287
+ ] }) : null
288
+ }
289
+ );
290
+ }
291
+ function makeStyles2(theme) {
292
+ const { color, space, radius, type } = theme;
293
+ const medium = type.weight.medium;
294
+ const ringSize = space.xxl * 2;
295
+ const ringThickness = space.xs;
296
+ return StyleSheet.create({
297
+ wrap: {
298
+ flexGrow: 1,
299
+ alignItems: "center",
300
+ justifyContent: "center",
301
+ padding: space.xl,
302
+ gap: space.md
303
+ },
304
+ // One rotating ring: success on the top/right, cream on the remainder. Only the success sweep is perceptible
305
+ // (the cream half is uniform), so this reads as a cream ring with a rotating success arc - the mobile look.
306
+ ring: {
307
+ width: ringSize,
308
+ height: ringSize,
309
+ borderRadius: radius.pill,
310
+ borderWidth: ringThickness,
311
+ borderTopColor: color.success,
312
+ borderRightColor: color.success,
313
+ borderBottomColor: color.borderRingCream,
314
+ borderLeftColor: color.borderRingCream
315
+ },
316
+ // Neutral SDK-owned structural status word (not clinical / product copy), on the brand-green secondary ramp
317
+ // so it sits in the same family as the verdict hero. Legible in both themes via the token.
318
+ statusLine: {
319
+ color: color.text.secondary,
320
+ fontFamily: type.family,
321
+ fontSize: type.size.subtitle,
322
+ lineHeight: type.size.subtitle * type.lineHeight.snug,
323
+ fontWeight: medium,
324
+ letterSpacing: type.letterSpacing.tight,
325
+ textAlign: "center"
326
+ }
327
+ });
328
+ }
329
+ var PULSE_PERIOD_MS = 1100;
330
+ var PULSE_MAX_SCALE = 1.6;
331
+ var PULSE_START_OPACITY = 0.35;
332
+ function toneSpec(theme, tier) {
333
+ const { color } = theme;
334
+ switch (tier) {
335
+ case "low_risk":
336
+ return { accent: color.success, wash: color.badgeBgPositive, label: "Low risk", pulse: false };
337
+ case "concern":
338
+ return { accent: color.cautionAccent, wash: color.badgeBgCaution, label: "Concern", pulse: true };
339
+ case "uncertain":
340
+ return { accent: color.text.muted, wash: color.badgeBgNeutral, label: "Uncertain", pulse: false };
341
+ }
342
+ }
343
+ function SeverityBadge({ riskTier }) {
344
+ const theme = useEverfurTheme();
345
+ const styles = useMemo(() => makeStyles3(theme), [theme]);
346
+ const pulse = useRef(new Animated.Value(0)).current;
347
+ const spec = riskTier === null ? null : toneSpec(theme, riskTier);
348
+ const shouldPulse = spec !== null && spec.pulse && !theme.motion.reducedMotion;
349
+ useEffect(() => {
350
+ if (!shouldPulse) return;
351
+ const loop = Animated.loop(
352
+ Animated.timing(pulse, {
353
+ toValue: 1,
354
+ duration: PULSE_PERIOD_MS,
355
+ easing: Easing.out(Easing.quad),
356
+ useNativeDriver: true
357
+ })
358
+ );
359
+ loop.start();
360
+ return () => loop.stop();
361
+ }, [shouldPulse, pulse]);
362
+ if (spec === null) return null;
363
+ return /* @__PURE__ */ jsxs(
364
+ View,
365
+ {
366
+ style: [styles.pill, { backgroundColor: spec.wash }],
367
+ accessible: true,
368
+ accessibilityRole: "text",
369
+ accessibilityLabel: spec.label,
370
+ children: [
371
+ /* @__PURE__ */ jsxs(View, { style: styles.dotWrap, children: [
372
+ shouldPulse ? /* @__PURE__ */ jsx(
373
+ Animated.View,
374
+ {
375
+ pointerEvents: "none",
376
+ style: [
377
+ styles.dotRing,
378
+ {
379
+ backgroundColor: spec.accent,
380
+ opacity: pulse.interpolate({ inputRange: [0, 1], outputRange: [PULSE_START_OPACITY, 0] }),
381
+ transform: [{ scale: pulse.interpolate({ inputRange: [0, 1], outputRange: [1, PULSE_MAX_SCALE] }) }]
382
+ }
383
+ ]
384
+ }
385
+ ) : null,
386
+ /* @__PURE__ */ jsx(View, { style: [styles.dot, { backgroundColor: spec.accent }] })
387
+ ] }),
388
+ /* @__PURE__ */ jsx(Text, { style: [styles.label, { color: spec.accent }], children: spec.label })
389
+ ]
390
+ }
391
+ );
392
+ }
393
+ function makeStyles3(theme) {
394
+ const { space, radius, type } = theme;
395
+ const bold = type.weight.bold;
396
+ const dotSize = space.sm;
397
+ return StyleSheet.create({
398
+ pill: {
399
+ alignSelf: "flex-start",
400
+ flexDirection: "row",
401
+ alignItems: "center",
402
+ gap: space.sm,
403
+ paddingHorizontal: space.md,
404
+ paddingVertical: space.xs,
405
+ borderRadius: radius.pill
406
+ },
407
+ dotWrap: {
408
+ width: dotSize,
409
+ height: dotSize,
410
+ alignItems: "center",
411
+ justifyContent: "center"
412
+ },
413
+ dot: {
414
+ width: dotSize,
415
+ height: dotSize,
416
+ borderRadius: radius.pill
417
+ },
418
+ // The pulsing attention ring behind the dot (concern only). backgroundColor + animated opacity/scale set inline.
419
+ dotRing: {
420
+ position: "absolute",
421
+ width: dotSize,
422
+ height: dotSize,
423
+ borderRadius: radius.pill
424
+ },
425
+ label: {
426
+ fontFamily: type.family,
427
+ fontSize: type.size.caption,
428
+ lineHeight: type.size.caption * type.lineHeight.snug,
429
+ fontWeight: bold,
430
+ letterSpacing: type.letterSpacing.eyebrow
431
+ }
432
+ });
433
+ }
434
+
435
+ // src/rn/testing.ts
436
+ function useEverfurTestEntitlements() {
437
+ const { runtime } = useEverfurContext();
438
+ return useMemo(
439
+ () => ({ apply: (snapshot) => runtime.updateEntitlements(snapshot) }),
440
+ [runtime]
441
+ );
442
+ }
443
+
444
+ export { AnalyzingIndicator, SeverityBadge, TypingIndicator, useEverfurTestEntitlements };