@uplifted/react 0.22.6

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 (221) hide show
  1. package/dist/AddClientSheet.d.ts +39 -0
  2. package/dist/AddClientSheet.d.ts.map +1 -0
  3. package/dist/AddClientSheet.js +108 -0
  4. package/dist/AddClientSheet.js.map +1 -0
  5. package/dist/AiSettingsSheet.d.ts +20 -0
  6. package/dist/AiSettingsSheet.d.ts.map +1 -0
  7. package/dist/AiSettingsSheet.js +274 -0
  8. package/dist/AiSettingsSheet.js.map +1 -0
  9. package/dist/AssistantGrid.d.ts +30 -0
  10. package/dist/AssistantGrid.d.ts.map +1 -0
  11. package/dist/AssistantGrid.js +68 -0
  12. package/dist/AssistantGrid.js.map +1 -0
  13. package/dist/AttachmentPicker.d.ts +38 -0
  14. package/dist/AttachmentPicker.d.ts.map +1 -0
  15. package/dist/AttachmentPicker.js +173 -0
  16. package/dist/AttachmentPicker.js.map +1 -0
  17. package/dist/BulkGenerateSheet.d.ts +25 -0
  18. package/dist/BulkGenerateSheet.d.ts.map +1 -0
  19. package/dist/BulkGenerateSheet.js +65 -0
  20. package/dist/BulkGenerateSheet.js.map +1 -0
  21. package/dist/ChannelBadge.d.ts +16 -0
  22. package/dist/ChannelBadge.d.ts.map +1 -0
  23. package/dist/ChannelBadge.js +19 -0
  24. package/dist/ChannelBadge.js.map +1 -0
  25. package/dist/ChannelExplainer.d.ts +17 -0
  26. package/dist/ChannelExplainer.d.ts.map +1 -0
  27. package/dist/ChannelExplainer.js +25 -0
  28. package/dist/ChannelExplainer.js.map +1 -0
  29. package/dist/ClientList.d.ts +43 -0
  30. package/dist/ClientList.d.ts.map +1 -0
  31. package/dist/ClientList.js +76 -0
  32. package/dist/ClientList.js.map +1 -0
  33. package/dist/ClosedWindowBanner.d.ts +12 -0
  34. package/dist/ClosedWindowBanner.d.ts.map +1 -0
  35. package/dist/ClosedWindowBanner.js +15 -0
  36. package/dist/ClosedWindowBanner.js.map +1 -0
  37. package/dist/Composer.d.ts +49 -0
  38. package/dist/Composer.d.ts.map +1 -0
  39. package/dist/Composer.js +99 -0
  40. package/dist/Composer.js.map +1 -0
  41. package/dist/ComposerExtras.d.ts +15 -0
  42. package/dist/ComposerExtras.d.ts.map +1 -0
  43. package/dist/ComposerExtras.js +14 -0
  44. package/dist/ComposerExtras.js.map +1 -0
  45. package/dist/ConversationPane.d.ts +33 -0
  46. package/dist/ConversationPane.d.ts.map +1 -0
  47. package/dist/ConversationPane.js +126 -0
  48. package/dist/ConversationPane.js.map +1 -0
  49. package/dist/DeliveryReceipt.d.ts +7 -0
  50. package/dist/DeliveryReceipt.d.ts.map +1 -0
  51. package/dist/DeliveryReceipt.js +13 -0
  52. package/dist/DeliveryReceipt.js.map +1 -0
  53. package/dist/DraftGrid.d.ts +17 -0
  54. package/dist/DraftGrid.d.ts.map +1 -0
  55. package/dist/DraftGrid.js +43 -0
  56. package/dist/DraftGrid.js.map +1 -0
  57. package/dist/HostPreviewPane.d.ts +37 -0
  58. package/dist/HostPreviewPane.d.ts.map +1 -0
  59. package/dist/HostPreviewPane.js +106 -0
  60. package/dist/HostPreviewPane.js.map +1 -0
  61. package/dist/InlineDrafts.d.ts +14 -0
  62. package/dist/InlineDrafts.d.ts.map +1 -0
  63. package/dist/InlineDrafts.js +19 -0
  64. package/dist/InlineDrafts.js.map +1 -0
  65. package/dist/ItemActions.d.ts +23 -0
  66. package/dist/ItemActions.d.ts.map +1 -0
  67. package/dist/ItemActions.js +83 -0
  68. package/dist/ItemActions.js.map +1 -0
  69. package/dist/MediaAttachment.d.ts +7 -0
  70. package/dist/MediaAttachment.d.ts.map +1 -0
  71. package/dist/MediaAttachment.js +37 -0
  72. package/dist/MediaAttachment.js.map +1 -0
  73. package/dist/OfferSheet.d.ts +32 -0
  74. package/dist/OfferSheet.d.ts.map +1 -0
  75. package/dist/OfferSheet.js +84 -0
  76. package/dist/OfferSheet.js.map +1 -0
  77. package/dist/ProactiveOptionsSheet.d.ts +14 -0
  78. package/dist/ProactiveOptionsSheet.d.ts.map +1 -0
  79. package/dist/ProactiveOptionsSheet.js +58 -0
  80. package/dist/ProactiveOptionsSheet.js.map +1 -0
  81. package/dist/QuickSend.d.ts +15 -0
  82. package/dist/QuickSend.d.ts.map +1 -0
  83. package/dist/QuickSend.js +90 -0
  84. package/dist/QuickSend.js.map +1 -0
  85. package/dist/SegmentEditor.d.ts +25 -0
  86. package/dist/SegmentEditor.d.ts.map +1 -0
  87. package/dist/SegmentEditor.js +95 -0
  88. package/dist/SegmentEditor.js.map +1 -0
  89. package/dist/Sheet.d.ts +13 -0
  90. package/dist/Sheet.d.ts.map +1 -0
  91. package/dist/Sheet.js +64 -0
  92. package/dist/Sheet.js.map +1 -0
  93. package/dist/ThreadFeed.d.ts +27 -0
  94. package/dist/ThreadFeed.d.ts.map +1 -0
  95. package/dist/ThreadFeed.js +42 -0
  96. package/dist/ThreadFeed.js.map +1 -0
  97. package/dist/UpliftPanel.d.ts +40 -0
  98. package/dist/UpliftPanel.d.ts.map +1 -0
  99. package/dist/UpliftPanel.js +219 -0
  100. package/dist/UpliftPanel.js.map +1 -0
  101. package/dist/UpliftProvider.d.ts +15 -0
  102. package/dist/UpliftProvider.d.ts.map +1 -0
  103. package/dist/UpliftProvider.js +19 -0
  104. package/dist/UpliftProvider.js.map +1 -0
  105. package/dist/WaitingTemplateGhost.d.ts +12 -0
  106. package/dist/WaitingTemplateGhost.d.ts.map +1 -0
  107. package/dist/WaitingTemplateGhost.js +16 -0
  108. package/dist/WaitingTemplateGhost.js.map +1 -0
  109. package/dist/channels.d.ts +22 -0
  110. package/dist/channels.d.ts.map +1 -0
  111. package/dist/channels.js +31 -0
  112. package/dist/channels.js.map +1 -0
  113. package/dist/errors.d.ts +6 -0
  114. package/dist/errors.d.ts.map +1 -0
  115. package/dist/errors.js +20 -0
  116. package/dist/errors.js.map +1 -0
  117. package/dist/host.d.ts +45 -0
  118. package/dist/host.d.ts.map +1 -0
  119. package/dist/host.js +35 -0
  120. package/dist/host.js.map +1 -0
  121. package/dist/icons.d.ts +48 -0
  122. package/dist/icons.d.ts.map +1 -0
  123. package/dist/icons.js +71 -0
  124. package/dist/icons.js.map +1 -0
  125. package/dist/index.d.ts +58 -0
  126. package/dist/index.d.ts.map +1 -0
  127. package/dist/index.js +36 -0
  128. package/dist/index.js.map +1 -0
  129. package/dist/labels.d.ts +58 -0
  130. package/dist/labels.d.ts.map +1 -0
  131. package/dist/labels.js +86 -0
  132. package/dist/labels.js.map +1 -0
  133. package/dist/phone.d.ts +18 -0
  134. package/dist/phone.d.ts.map +1 -0
  135. package/dist/phone.js +27 -0
  136. package/dist/phone.js.map +1 -0
  137. package/dist/proactiveIcons.d.ts +6 -0
  138. package/dist/proactiveIcons.d.ts.map +1 -0
  139. package/dist/proactiveIcons.js +39 -0
  140. package/dist/proactiveIcons.js.map +1 -0
  141. package/dist/purposes.d.ts +19 -0
  142. package/dist/purposes.d.ts.map +1 -0
  143. package/dist/purposes.js +20 -0
  144. package/dist/purposes.js.map +1 -0
  145. package/dist/segments.d.ts +29 -0
  146. package/dist/segments.d.ts.map +1 -0
  147. package/dist/segments.js +75 -0
  148. package/dist/segments.js.map +1 -0
  149. package/dist/smsSegments.d.ts +28 -0
  150. package/dist/smsSegments.d.ts.map +1 -0
  151. package/dist/smsSegments.js +100 -0
  152. package/dist/smsSegments.js.map +1 -0
  153. package/dist/styles.d.ts +15 -0
  154. package/dist/styles.d.ts.map +1 -0
  155. package/dist/styles.js +545 -0
  156. package/dist/styles.js.map +1 -0
  157. package/dist/time.d.ts +14 -0
  158. package/dist/time.d.ts.map +1 -0
  159. package/dist/time.js +80 -0
  160. package/dist/time.js.map +1 -0
  161. package/dist/useAiSettings.d.ts +11 -0
  162. package/dist/useAiSettings.d.ts.map +1 -0
  163. package/dist/useAiSettings.js +21 -0
  164. package/dist/useAiSettings.js.map +1 -0
  165. package/dist/useBilling.d.ts +40 -0
  166. package/dist/useBilling.d.ts.map +1 -0
  167. package/dist/useBilling.js +155 -0
  168. package/dist/useBilling.js.map +1 -0
  169. package/dist/useBulkDrafts.d.ts +41 -0
  170. package/dist/useBulkDrafts.d.ts.map +1 -0
  171. package/dist/useBulkDrafts.js +112 -0
  172. package/dist/useBulkDrafts.js.map +1 -0
  173. package/dist/useClients.d.ts +16 -0
  174. package/dist/useClients.d.ts.map +1 -0
  175. package/dist/useClients.js +22 -0
  176. package/dist/useClients.js.map +1 -0
  177. package/dist/useDeliveryStatus.d.ts +7 -0
  178. package/dist/useDeliveryStatus.d.ts.map +1 -0
  179. package/dist/useDeliveryStatus.js +39 -0
  180. package/dist/useDeliveryStatus.js.map +1 -0
  181. package/dist/useDrafts.d.ts +19 -0
  182. package/dist/useDrafts.d.ts.map +1 -0
  183. package/dist/useDrafts.js +60 -0
  184. package/dist/useDrafts.js.map +1 -0
  185. package/dist/useInstructions.d.ts +9 -0
  186. package/dist/useInstructions.d.ts.map +1 -0
  187. package/dist/useInstructions.js +20 -0
  188. package/dist/useInstructions.js.map +1 -0
  189. package/dist/useLiveUpdates.d.ts +9 -0
  190. package/dist/useLiveUpdates.d.ts.map +1 -0
  191. package/dist/useLiveUpdates.js +48 -0
  192. package/dist/useLiveUpdates.js.map +1 -0
  193. package/dist/usePolling.d.ts +6 -0
  194. package/dist/usePolling.d.ts.map +1 -0
  195. package/dist/usePolling.js +31 -0
  196. package/dist/usePolling.js.map +1 -0
  197. package/dist/usePreviewDrafts.d.ts +15 -0
  198. package/dist/usePreviewDrafts.d.ts.map +1 -0
  199. package/dist/usePreviewDrafts.js +77 -0
  200. package/dist/usePreviewDrafts.js.map +1 -0
  201. package/dist/useProactiveOptions.d.ts +15 -0
  202. package/dist/useProactiveOptions.d.ts.map +1 -0
  203. package/dist/useProactiveOptions.js +39 -0
  204. package/dist/useProactiveOptions.js.map +1 -0
  205. package/dist/useSend.d.ts +16 -0
  206. package/dist/useSend.d.ts.map +1 -0
  207. package/dist/useSend.js +50 -0
  208. package/dist/useSend.js.map +1 -0
  209. package/dist/useStickToBottom.d.ts +12 -0
  210. package/dist/useStickToBottom.d.ts.map +1 -0
  211. package/dist/useStickToBottom.js +71 -0
  212. package/dist/useStickToBottom.js.map +1 -0
  213. package/dist/useThread.d.ts +26 -0
  214. package/dist/useThread.d.ts.map +1 -0
  215. package/dist/useThread.js +76 -0
  216. package/dist/useThread.js.map +1 -0
  217. package/dist/useWhatsAppWindow.d.ts +8 -0
  218. package/dist/useWhatsAppWindow.d.ts.map +1 -0
  219. package/dist/useWhatsAppWindow.js +22 -0
  220. package/dist/useWhatsAppWindow.js.map +1 -0
  221. package/package.json +36 -0
@@ -0,0 +1,19 @@
1
+ import type { DraftSet, DraftsInput, UpliftError } from "@uplifted/sdk";
2
+ export type DraftsStatus = "idle" | "loading" | "ready" | "error";
3
+ export interface DraftsState {
4
+ status: DraftsStatus;
5
+ drafts: DraftSet | null;
6
+ error: UpliftError | null;
7
+ /** Seconds left on a rate limit; null when generation is allowed. */
8
+ retryIn: number | null;
9
+ /** Ask Uplift for four drafts. Ignored while loading or rate limited. */
10
+ generate: (input?: DraftsInput) => void;
11
+ /** Forget drafts and errors (used when the composer is cleared after a send). */
12
+ clear: () => void;
13
+ /** Show drafts that already exist (prepared reply drafts, bulk results) without a request. */
14
+ seed: (set: DraftSet) => void;
15
+ }
16
+ /** Four-tone drafts for one client, from the same engine as native Uplift Coach. `seed` shows drafts
17
+ * already produced (Bulk generate) without a new request. */
18
+ export declare function useDrafts(clientId: string | null, seed?: DraftSet | null): DraftsState;
19
+ //# sourceMappingURL=useDrafts.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useDrafts.d.ts","sourceRoot":"","sources":["../src/useDrafts.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAIxE,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,SAAS,GAAG,OAAO,GAAG,OAAO,CAAC;AAElE,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,YAAY,CAAC;IACrB,MAAM,EAAE,QAAQ,GAAG,IAAI,CAAC;IACxB,KAAK,EAAE,WAAW,GAAG,IAAI,CAAC;IAC1B,qEAAqE;IACrE,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,yEAAyE;IACzE,QAAQ,EAAE,CAAC,KAAK,CAAC,EAAE,WAAW,KAAK,IAAI,CAAC;IACxC,iFAAiF;IACjF,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,8FAA8F;IAC9F,IAAI,EAAE,CAAC,GAAG,EAAE,QAAQ,KAAK,IAAI,CAAC;CAC/B;AAED;6DAC6D;AAC7D,wBAAgB,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,EAAE,IAAI,GAAE,QAAQ,GAAG,IAAW,GAAG,WAAW,CAiD5F"}
@@ -0,0 +1,60 @@
1
+ import { useCallback, useEffect, useRef, useState } from "react";
2
+ import { useUplift } from "./UpliftProvider.js";
3
+ import { asUpliftError, retryAfterSeconds } from "./errors.js";
4
+ /** Four-tone drafts for one client, from the same engine as native Uplift Coach. `seed` shows drafts
5
+ * already produced (Bulk generate) without a new request. */
6
+ export function useDrafts(clientId, seed = null) {
7
+ const { client } = useUplift();
8
+ const [status, setStatus] = useState(seed ? "ready" : "idle");
9
+ const [drafts, setDrafts] = useState(seed);
10
+ const [error, setError] = useState(null);
11
+ const [retryIn, setRetryIn] = useState(null);
12
+ const requestId = useRef(0);
13
+ const clear = useCallback(() => {
14
+ requestId.current++;
15
+ setStatus("idle");
16
+ setDrafts(null);
17
+ setError(null);
18
+ setRetryIn(null);
19
+ }, []);
20
+ const first = useRef(true);
21
+ useEffect(() => {
22
+ if (first.current) {
23
+ first.current = false;
24
+ return;
25
+ }
26
+ clear();
27
+ }, [clientId, clear]);
28
+ useEffect(() => {
29
+ if (retryIn === null)
30
+ return;
31
+ if (retryIn <= 0) {
32
+ setRetryIn(null);
33
+ return;
34
+ }
35
+ const t = setTimeout(() => setRetryIn((s) => (s === null ? null : s - 1)), 1000);
36
+ return () => clearTimeout(t);
37
+ }, [retryIn]);
38
+ const generate = useCallback((input = {}) => {
39
+ if (!clientId || status === "loading" || retryIn !== null)
40
+ return;
41
+ const id = ++requestId.current;
42
+ setStatus("loading");
43
+ setError(null);
44
+ client.drafts(clientId, input).then((set) => { if (id === requestId.current) {
45
+ setDrafts(set);
46
+ setStatus("ready");
47
+ } }, (err) => {
48
+ if (id !== requestId.current)
49
+ return;
50
+ const e = asUpliftError(err);
51
+ setError(e);
52
+ setStatus("error");
53
+ if (e.code === "rate_limited")
54
+ setRetryIn(retryAfterSeconds(e));
55
+ });
56
+ }, [client, clientId, status, retryIn]);
57
+ const seedDrafts = useCallback((set) => { requestId.current++; setDrafts(set); setError(null); setStatus("ready"); }, []);
58
+ return { status, drafts, error, retryIn, generate, clear, seed: seedDrafts };
59
+ }
60
+ //# sourceMappingURL=useDrafts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useDrafts.js","sourceRoot":"","sources":["../src/useDrafts.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAEjE,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAChD,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAkB/D;6DAC6D;AAC7D,MAAM,UAAU,SAAS,CAAC,QAAuB,EAAE,OAAwB,IAAI;IAC7E,MAAM,EAAE,MAAM,EAAE,GAAG,SAAS,EAAE,CAAC;IAC/B,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,QAAQ,CAAe,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;IAC5E,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,QAAQ,CAAkB,IAAI,CAAC,CAAC;IAC5D,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAqB,IAAI,CAAC,CAAC;IAC7D,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,QAAQ,CAAgB,IAAI,CAAC,CAAC;IAC5D,MAAM,SAAS,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;IAE5B,MAAM,KAAK,GAAG,WAAW,CAAC,GAAG,EAAE;QAC7B,SAAS,CAAC,OAAO,EAAE,CAAC;QACpB,SAAS,CAAC,MAAM,CAAC,CAAC;QAClB,SAAS,CAAC,IAAI,CAAC,CAAC;QAChB,QAAQ,CAAC,IAAI,CAAC,CAAC;QACf,UAAU,CAAC,IAAI,CAAC,CAAC;IACnB,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC;IAC3B,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,KAAK,CAAC,OAAO,EAAE,CAAC;YAAC,KAAK,CAAC,OAAO,GAAG,KAAK,CAAC;YAAC,OAAO;QAAC,CAAC;QACrD,KAAK,EAAE,CAAC;IACV,CAAC,EAAE,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC,CAAC;IAEtB,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,OAAO,KAAK,IAAI;YAAE,OAAO;QAC7B,IAAI,OAAO,IAAI,CAAC,EAAE,CAAC;YAAC,UAAU,CAAC,IAAI,CAAC,CAAC;YAAC,OAAO;QAAC,CAAC;QAC/C,MAAM,CAAC,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC;QACjF,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;IAC/B,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;IAEd,MAAM,QAAQ,GAAG,WAAW,CAAC,CAAC,QAAqB,EAAE,EAAE,EAAE;QACvD,IAAI,CAAC,QAAQ,IAAI,MAAM,KAAK,SAAS,IAAI,OAAO,KAAK,IAAI;YAAE,OAAO;QAClE,MAAM,EAAE,GAAG,EAAE,SAAS,CAAC,OAAO,CAAC;QAC/B,SAAS,CAAC,SAAS,CAAC,CAAC;QACrB,QAAQ,CAAC,IAAI,CAAC,CAAC;QACf,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC,IAAI,CACjC,CAAC,GAAG,EAAE,EAAE,GAAG,IAAI,EAAE,KAAK,SAAS,CAAC,OAAO,EAAE,CAAC;YAAC,SAAS,CAAC,GAAG,CAAC,CAAC;YAAC,SAAS,CAAC,OAAO,CAAC,CAAC;QAAC,CAAC,CAAC,CAAC,EAClF,CAAC,GAAY,EAAE,EAAE;YACf,IAAI,EAAE,KAAK,SAAS,CAAC,OAAO;gBAAE,OAAO;YACrC,MAAM,CAAC,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC;YAC7B,QAAQ,CAAC,CAAC,CAAC,CAAC;YACZ,SAAS,CAAC,OAAO,CAAC,CAAC;YACnB,IAAI,CAAC,CAAC,IAAI,KAAK,cAAc;gBAAE,UAAU,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,CAAC;QAClE,CAAC,CACF,CAAC;IACJ,CAAC,EAAE,CAAC,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IAExC,MAAM,UAAU,GAAG,WAAW,CAAC,CAAC,GAAa,EAAE,EAAE,GAAG,SAAS,CAAC,OAAO,EAAE,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAEpI,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC;AAC/E,CAAC"}
@@ -0,0 +1,9 @@
1
+ import type { InstructionSurface, InstructionsResponse } from "@uplifted/sdk";
2
+ export interface InstructionsState {
3
+ /** Null until loaded (or when loading failed: the Config AI control then stays hidden). */
4
+ data: InstructionsResponse | null;
5
+ save: (surface: InstructionSurface, content: string) => Promise<InstructionsResponse>;
6
+ }
7
+ /** The coach's custom AI instructions, loaded once per panel (native Settings › AI). */
8
+ export declare function useInstructions(): InstructionsState;
9
+ //# sourceMappingURL=useInstructions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useInstructions.d.ts","sourceRoot":"","sources":["../src/useInstructions.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,kBAAkB,EAAE,oBAAoB,EAAe,MAAM,eAAe,CAAC;AAG3F,MAAM,WAAW,iBAAiB;IAChC,2FAA2F;IAC3F,IAAI,EAAE,oBAAoB,GAAG,IAAI,CAAC;IAClC,IAAI,EAAE,CAAC,OAAO,EAAE,kBAAkB,EAAE,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,oBAAoB,CAAC,CAAC;CACvF;AAED,wFAAwF;AACxF,wBAAgB,eAAe,IAAI,iBAAiB,CAcnD"}
@@ -0,0 +1,20 @@
1
+ import { useCallback, useEffect, useState } from "react";
2
+ import { useUplift } from "./UpliftProvider.js";
3
+ /** The coach's custom AI instructions, loaded once per panel (native Settings › AI). */
4
+ export function useInstructions() {
5
+ const { client } = useUplift();
6
+ const [data, setData] = useState(null);
7
+ useEffect(() => {
8
+ let live = true;
9
+ client.getInstructions().then((d) => { if (live)
10
+ setData(d); }, (_e) => { });
11
+ return () => { live = false; };
12
+ }, [client]);
13
+ const save = useCallback(async (surface, content) => {
14
+ const d = await client.setInstructions(surface, content);
15
+ setData(d);
16
+ return d;
17
+ }, [client]);
18
+ return { data, save };
19
+ }
20
+ //# sourceMappingURL=useInstructions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useInstructions.js","sourceRoot":"","sources":["../src/useInstructions.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAEzD,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAQhD,wFAAwF;AACxF,MAAM,UAAU,eAAe;IAC7B,MAAM,EAAE,MAAM,EAAE,GAAG,SAAS,EAAE,CAAC;IAC/B,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,QAAQ,CAA8B,IAAI,CAAC,CAAC;IACpE,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,IAAI,GAAG,IAAI,CAAC;QAChB,MAAM,CAAC,eAAe,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,GAAG,IAAI,IAAI;YAAE,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,EAAe,EAAE,EAAE,GAAgC,CAAC,CAAC,CAAC;QACvH,OAAO,GAAG,EAAE,GAAG,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;IACjC,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC;IACb,MAAM,IAAI,GAAG,WAAW,CAAC,KAAK,EAAE,OAA2B,EAAE,OAAe,EAAE,EAAE;QAC9E,MAAM,CAAC,GAAG,MAAM,MAAM,CAAC,eAAe,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QACzD,OAAO,CAAC,CAAC,CAAC,CAAC;QACX,OAAO,CAAC,CAAC;IACX,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC;IACb,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;AACxB,CAAC"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Push updates from Uplift (partner GET /stream, proxied by the host), like native's RealtimeContext:
3
+ * one stream per panel, reconnecting with backoff (2s → 30s). `onClientChanged` fires per event;
4
+ * `connected` tells the panel it can relax its fallback polling.
5
+ */
6
+ export declare function useLiveUpdates(onClientChanged: (clientId: string) => void, enabled?: boolean): {
7
+ connected: boolean;
8
+ };
9
+ //# sourceMappingURL=useLiveUpdates.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useLiveUpdates.d.ts","sourceRoot":"","sources":["../src/useLiveUpdates.ts"],"names":[],"mappings":"AAGA;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,eAAe,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,EAAE,OAAO,UAAO,GAAG;IAAE,SAAS,EAAE,OAAO,CAAA;CAAE,CA8BlH"}
@@ -0,0 +1,48 @@
1
+ import { useEffect, useRef, useState } from "react";
2
+ import { useUplift } from "./UpliftProvider.js";
3
+ /**
4
+ * Push updates from Uplift (partner GET /stream, proxied by the host), like native's RealtimeContext:
5
+ * one stream per panel, reconnecting with backoff (2s → 30s). `onClientChanged` fires per event;
6
+ * `connected` tells the panel it can relax its fallback polling.
7
+ */
8
+ export function useLiveUpdates(onClientChanged, enabled = true) {
9
+ const { client } = useUplift();
10
+ const [connected, setConnected] = useState(false);
11
+ const cb = useRef(onClientChanged);
12
+ cb.current = onClientChanged;
13
+ useEffect(() => {
14
+ if (!enabled)
15
+ return;
16
+ const ctl = new AbortController();
17
+ let delay = 2000;
18
+ let timer = null;
19
+ const run = async () => {
20
+ if (ctl.signal.aborted)
21
+ return;
22
+ try {
23
+ await client.stream((e) => {
24
+ if (e.type === "connected") {
25
+ setConnected(true);
26
+ delay = 2000;
27
+ }
28
+ else if (e.type === "client_changed") {
29
+ const id = e.data?.clientId;
30
+ if (id)
31
+ cb.current(id);
32
+ }
33
+ }, { signal: ctl.signal });
34
+ }
35
+ catch { /* reconnect below */ }
36
+ setConnected(false);
37
+ if (ctl.signal.aborted)
38
+ return;
39
+ timer = setTimeout(() => { void run(); }, delay);
40
+ delay = Math.min(delay * 2, 30000);
41
+ };
42
+ void run();
43
+ return () => { ctl.abort(); if (timer)
44
+ clearTimeout(timer); setConnected(false); };
45
+ }, [client, enabled]);
46
+ return { connected };
47
+ }
48
+ //# sourceMappingURL=useLiveUpdates.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useLiveUpdates.js","sourceRoot":"","sources":["../src/useLiveUpdates.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AACpD,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAEhD;;;;GAIG;AACH,MAAM,UAAU,cAAc,CAAC,eAA2C,EAAE,OAAO,GAAG,IAAI;IACxF,MAAM,EAAE,MAAM,EAAE,GAAG,SAAS,EAAE,CAAC;IAC/B,MAAM,CAAC,SAAS,EAAE,YAAY,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAClD,MAAM,EAAE,GAAG,MAAM,CAAC,eAAe,CAAC,CAAC;IACnC,EAAE,CAAC,OAAO,GAAG,eAAe,CAAC;IAC7B,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,CAAC,OAAO;YAAE,OAAO;QACrB,MAAM,GAAG,GAAG,IAAI,eAAe,EAAE,CAAC;QAClC,IAAI,KAAK,GAAG,IAAI,CAAC;QACjB,IAAI,KAAK,GAAyC,IAAI,CAAC;QACvD,MAAM,GAAG,GAAG,KAAK,IAAI,EAAE;YACrB,IAAI,GAAG,CAAC,MAAM,CAAC,OAAO;gBAAE,OAAO;YAC/B,IAAI,CAAC;gBACH,MAAM,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE;oBACxB,IAAI,CAAC,CAAC,IAAI,KAAK,WAAW,EAAE,CAAC;wBAAC,YAAY,CAAC,IAAI,CAAC,CAAC;wBAAC,KAAK,GAAG,IAAI,CAAC;oBAAC,CAAC;yBAC5D,IAAI,CAAC,CAAC,IAAI,KAAK,gBAAgB,EAAE,CAAC;wBACrC,MAAM,EAAE,GAAI,CAAC,CAAC,IAAqC,EAAE,QAAQ,CAAC;wBAC9D,IAAI,EAAE;4BAAE,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;oBACzB,CAAC;gBACH,CAAC,EAAE,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC;YAC7B,CAAC;YAAC,MAAM,CAAC,CAAC,qBAAqB,CAAC,CAAC;YACjC,YAAY,CAAC,KAAK,CAAC,CAAC;YACpB,IAAI,GAAG,CAAC,MAAM,CAAC,OAAO;gBAAE,OAAO;YAC/B,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE,GAAG,KAAK,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;YACjD,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,GAAG,CAAC,EAAE,KAAK,CAAC,CAAC;QACrC,CAAC,CAAC;QACF,KAAK,GAAG,EAAE,CAAC;QACX,OAAO,GAAG,EAAE,GAAG,GAAG,CAAC,KAAK,EAAE,CAAC,CAAC,IAAI,KAAK;YAAE,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IACrF,CAAC,EAAE,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IACtB,OAAO,EAAE,SAAS,EAAE,CAAC;AACvB,CAAC"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * A tick every `everyMs` while the page is visible (interim live updates until the partner stream
3
+ * token, T21). Pauses in background tabs; fires once immediately when the tab comes back.
4
+ */
5
+ export declare function usePolling(everyMs: number, enabled?: boolean): number;
6
+ //# sourceMappingURL=usePolling.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"usePolling.d.ts","sourceRoot":"","sources":["../src/usePolling.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,wBAAgB,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,UAAO,GAAG,MAAM,CAalE"}
@@ -0,0 +1,31 @@
1
+ import { useEffect, useState } from "react";
2
+ /**
3
+ * A tick every `everyMs` while the page is visible (interim live updates until the partner stream
4
+ * token, T21). Pauses in background tabs; fires once immediately when the tab comes back.
5
+ */
6
+ export function usePolling(everyMs, enabled = true) {
7
+ const [tick, setTick] = useState(0);
8
+ useEffect(() => {
9
+ if (!enabled || everyMs <= 0)
10
+ return;
11
+ let timer = null;
12
+ const start = () => { if (timer === null)
13
+ timer = setInterval(() => setTick((t) => t + 1), everyMs); };
14
+ const stop = () => { if (timer !== null) {
15
+ clearInterval(timer);
16
+ timer = null;
17
+ } };
18
+ const onVis = () => { if (document.visibilityState === "visible") {
19
+ setTick((t) => t + 1);
20
+ start();
21
+ }
22
+ else
23
+ stop(); };
24
+ if (typeof document === "undefined" || document.visibilityState === "visible")
25
+ start();
26
+ document.addEventListener("visibilitychange", onVis);
27
+ return () => { stop(); document.removeEventListener("visibilitychange", onVis); };
28
+ }, [everyMs, enabled]);
29
+ return tick;
30
+ }
31
+ //# sourceMappingURL=usePolling.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"usePolling.js","sourceRoot":"","sources":["../src/usePolling.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAE5C;;;GAGG;AACH,MAAM,UAAU,UAAU,CAAC,OAAe,EAAE,OAAO,GAAG,IAAI;IACxD,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;IACpC,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,CAAC,OAAO,IAAI,OAAO,IAAI,CAAC;YAAE,OAAO;QACrC,IAAI,KAAK,GAA0C,IAAI,CAAC;QACxD,MAAM,KAAK,GAAG,GAAG,EAAE,GAAG,IAAI,KAAK,KAAK,IAAI;YAAE,KAAK,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;QACvG,MAAM,IAAI,GAAG,GAAG,EAAE,GAAG,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;YAAC,aAAa,CAAC,KAAK,CAAC,CAAC;YAAC,KAAK,GAAG,IAAI,CAAC;QAAC,CAAC,CAAC,CAAC,CAAC;QACnF,MAAM,KAAK,GAAG,GAAG,EAAE,GAAG,IAAI,QAAQ,CAAC,eAAe,KAAK,SAAS,EAAE,CAAC;YAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;YAAC,KAAK,EAAE,CAAC;QAAC,CAAC;;YAAM,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;QACrH,IAAI,OAAO,QAAQ,KAAK,WAAW,IAAI,QAAQ,CAAC,eAAe,KAAK,SAAS;YAAE,KAAK,EAAE,CAAC;QACvF,QAAQ,CAAC,gBAAgB,CAAC,kBAAkB,EAAE,KAAK,CAAC,CAAC;QACrD,OAAO,GAAG,EAAE,GAAG,IAAI,EAAE,CAAC,CAAC,QAAQ,CAAC,mBAAmB,CAAC,kBAAkB,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IACpF,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC;IACvB,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -0,0 +1,15 @@
1
+ import type { PreviewEvent } from "@uplifted/sdk";
2
+ import type { DraftsState } from "./useDrafts.js";
3
+ /**
4
+ * Preview drafts for a host client that is not on Uplift (D19): drafted from the host's own
5
+ * activity through the stateless preview endpoint. Same state shape as useDrafts so AssistantGrid
6
+ * renders it unchanged. At most the last 10 events are sent (D27).
7
+ */
8
+ export declare function usePreviewDrafts(input: {
9
+ clientName: string;
10
+ coachName?: string | undefined;
11
+ events: ReadonlyArray<PreviewEvent>;
12
+ } | null): DraftsState;
13
+ /** Only the fields the preview endpoint accepts (it rejects unknown keys such as a host's own id). */
14
+ export declare function toPreviewEvent({ type, occurredAt, exercise, sets, reps, weight, unit, sessionName }: PreviewEvent): PreviewEvent;
15
+ //# sourceMappingURL=usePreviewDrafts.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"usePreviewDrafts.d.ts","sourceRoot":"","sources":["../src/usePreviewDrafts.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAyB,YAAY,EAAe,MAAM,eAAe,CAAC;AAGtF,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAElD;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAAC,MAAM,EAAE,aAAa,CAAC,YAAY,CAAC,CAAA;CAAE,GAAG,IAAI,GAAG,WAAW,CAgDvJ;AAED,sGAAsG;AACtG,wBAAgB,cAAc,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,EAAE,EAAE,YAAY,GAAG,YAAY,CAShI"}
@@ -0,0 +1,77 @@
1
+ import { useCallback, useEffect, useRef, useState } from "react";
2
+ import { useUplift } from "./UpliftProvider.js";
3
+ import { asUpliftError, retryAfterSeconds } from "./errors.js";
4
+ /**
5
+ * Preview drafts for a host client that is not on Uplift (D19): drafted from the host's own
6
+ * activity through the stateless preview endpoint. Same state shape as useDrafts so AssistantGrid
7
+ * renders it unchanged. At most the last 10 events are sent (D27).
8
+ */
9
+ export function usePreviewDrafts(input) {
10
+ const { client } = useUplift();
11
+ const [status, setStatus] = useState("idle");
12
+ const [drafts, setDrafts] = useState(null);
13
+ const [error, setError] = useState(null);
14
+ const [retryIn, setRetryIn] = useState(null);
15
+ const requestId = useRef(0);
16
+ const clear = useCallback(() => {
17
+ requestId.current++;
18
+ setStatus("idle");
19
+ setDrafts(null);
20
+ setError(null);
21
+ setRetryIn(null);
22
+ }, []);
23
+ useEffect(() => {
24
+ if (retryIn === null)
25
+ return;
26
+ if (retryIn <= 0) {
27
+ setRetryIn(null);
28
+ return;
29
+ }
30
+ const t = setTimeout(() => setRetryIn((s) => (s === null ? null : s - 1)), 1000);
31
+ return () => clearTimeout(t);
32
+ }, [retryIn]);
33
+ const generate = useCallback((opts = {}) => {
34
+ if (!input || status === "loading" || retryIn !== null)
35
+ return;
36
+ const id = ++requestId.current;
37
+ setStatus("loading");
38
+ setError(null);
39
+ const events = [...input.events]
40
+ .sort((a, b) => b.occurredAt.localeCompare(a.occurredAt))
41
+ .slice(0, 10)
42
+ .map(toPreviewEvent);
43
+ const purpose = opts.purpose && opts.purpose !== "general" ? opts.purpose : undefined;
44
+ client.previewDrafts({ clientName: input.clientName, ...(input.coachName ? { coachName: input.coachName } : {}), events, ...(purpose ? { purpose } : {}) }).then((set) => { if (id === requestId.current) {
45
+ setDrafts(set);
46
+ setStatus("ready");
47
+ } }, (err) => {
48
+ if (id !== requestId.current)
49
+ return;
50
+ const e = asUpliftError(err);
51
+ setError(e);
52
+ setStatus("error");
53
+ if (e.code === "rate_limited")
54
+ setRetryIn(retryAfterSeconds(e));
55
+ });
56
+ }, [client, input, status, retryIn]);
57
+ const seed = useCallback((set) => { requestId.current++; setDrafts(set); setError(null); setStatus("ready"); }, []);
58
+ return { status, drafts, error, retryIn, generate, clear, seed };
59
+ }
60
+ /** Only the fields the preview endpoint accepts (it rejects unknown keys such as a host's own id). */
61
+ export function toPreviewEvent({ type, occurredAt, exercise, sets, reps, weight, unit, sessionName }) {
62
+ const e = { type, occurredAt };
63
+ if (exercise)
64
+ e.exercise = exercise;
65
+ if (sets != null)
66
+ e.sets = sets;
67
+ if (reps != null)
68
+ e.reps = reps;
69
+ if (weight != null)
70
+ e.weight = weight;
71
+ if (unit)
72
+ e.unit = unit;
73
+ if (sessionName)
74
+ e.sessionName = sessionName;
75
+ return e;
76
+ }
77
+ //# sourceMappingURL=usePreviewDrafts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"usePreviewDrafts.js","sourceRoot":"","sources":["../src/usePreviewDrafts.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ import type { ProactiveOptionInput, UpliftError } from "@uplifted/sdk";
2
+ import { type Purpose } from "./purposes.js";
3
+ export interface ProactiveOptionsState {
4
+ /** The coach's list, or the built-ins until it loads (never empty, so the menu never flashes blank). */
5
+ purposes: readonly Purpose[];
6
+ isCustom: boolean;
7
+ loaded: boolean;
8
+ saving: boolean;
9
+ error: UpliftError | null;
10
+ /** Replace the list; null restores the built-ins. Resolves true on success. */
11
+ save: (options: ProactiveOptionInput[] | null) => Promise<boolean>;
12
+ }
13
+ /** The coach's ✨ menu options, shared with native Settings › AI › Proactive. */
14
+ export declare function useProactiveOptions(): ProactiveOptionsState;
15
+ //# sourceMappingURL=useProactiveOptions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useProactiveOptions.d.ts","sourceRoot":"","sources":["../src/useProactiveOptions.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,oBAAoB,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAEvE,OAAO,EAA6B,KAAK,OAAO,EAAE,MAAM,eAAe,CAAC;AAGxE,MAAM,WAAW,qBAAqB;IACpC,wGAAwG;IACxG,QAAQ,EAAE,SAAS,OAAO,EAAE,CAAC;IAC7B,QAAQ,EAAE,OAAO,CAAC;IAClB,MAAM,EAAE,OAAO,CAAC;IAChB,MAAM,EAAE,OAAO,CAAC;IAChB,KAAK,EAAE,WAAW,GAAG,IAAI,CAAC;IAC1B,+EAA+E;IAC/E,IAAI,EAAE,CAAC,OAAO,EAAE,oBAAoB,EAAE,GAAG,IAAI,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;CACpE;AAED,gFAAgF;AAChF,wBAAgB,mBAAmB,IAAI,qBAAqB,CAkC3D"}
@@ -0,0 +1,39 @@
1
+ import { useCallback, useEffect, useState } from "react";
2
+ import { asUpliftError } from "./errors.js";
3
+ import { hydratePurposes, PURPOSES } from "./purposes.js";
4
+ import { useUplift } from "./UpliftProvider.js";
5
+ /** The coach's ✨ menu options, shared with native Settings › AI › Proactive. */
6
+ export function useProactiveOptions() {
7
+ const { client } = useUplift();
8
+ const [purposes, setPurposes] = useState(PURPOSES);
9
+ const [isCustom, setIsCustom] = useState(false);
10
+ const [loaded, setLoaded] = useState(false);
11
+ const [saving, setSaving] = useState(false);
12
+ const [error, setError] = useState(null);
13
+ useEffect(() => {
14
+ let live = true;
15
+ client.getProactiveOptions().then((r) => { if (!live)
16
+ return; setPurposes(hydratePurposes(r.options) ?? PURPOSES); setIsCustom(r.isCustom); setLoaded(true); }, () => { if (live)
17
+ setLoaded(true); });
18
+ return () => { live = false; };
19
+ }, [client]);
20
+ const save = useCallback(async (options) => {
21
+ setSaving(true);
22
+ setError(null);
23
+ try {
24
+ const r = await client.setProactiveOptions(options);
25
+ setPurposes(hydratePurposes(r.options) ?? PURPOSES);
26
+ setIsCustom(r.isCustom);
27
+ return true;
28
+ }
29
+ catch (err) {
30
+ setError(asUpliftError(err));
31
+ return false;
32
+ }
33
+ finally {
34
+ setSaving(false);
35
+ }
36
+ }, [client]);
37
+ return { purposes, isCustom, loaded, saving, error, save };
38
+ }
39
+ //# sourceMappingURL=useProactiveOptions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useProactiveOptions.js","sourceRoot":"","sources":["../src/useProactiveOptions.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAEzD,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAgB,MAAM,eAAe,CAAC;AACxE,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAahD,gFAAgF;AAChF,MAAM,UAAU,mBAAmB;IACjC,MAAM,EAAE,MAAM,EAAE,GAAG,SAAS,EAAE,CAAC;IAC/B,MAAM,CAAC,QAAQ,EAAE,WAAW,CAAC,GAAG,QAAQ,CAAqB,QAAQ,CAAC,CAAC;IACvE,MAAM,CAAC,QAAQ,EAAE,WAAW,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAChD,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAC5C,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAC5C,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAqB,IAAI,CAAC,CAAC;IAE7D,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,IAAI,GAAG,IAAI,CAAC;QAChB,MAAM,CAAC,mBAAmB,EAAE,CAAC,IAAI,CAC/B,CAAC,CAAC,EAAE,EAAE,GAAG,IAAI,CAAC,IAAI;YAAE,OAAO,CAAC,WAAW,CAAC,eAAe,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,QAAQ,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAC5H,GAAG,EAAE,GAAG,IAAI,IAAI;YAAE,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CACrC,CAAC;QACF,OAAO,GAAG,EAAE,GAAG,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;IACjC,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC;IAEb,MAAM,IAAI,GAAG,WAAW,CAAC,KAAK,EAAE,OAAsC,EAAE,EAAE;QACxE,SAAS,CAAC,IAAI,CAAC,CAAC;QAChB,QAAQ,CAAC,IAAI,CAAC,CAAC;QACf,IAAI,CAAC;YACH,MAAM,CAAC,GAAG,MAAM,MAAM,CAAC,mBAAmB,CAAC,OAAO,CAAC,CAAC;YACpD,WAAW,CAAC,eAAe,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,QAAQ,CAAC,CAAC;YACpD,WAAW,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;YACxB,OAAO,IAAI,CAAC;QACd,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,QAAQ,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC;YAC7B,OAAO,KAAK,CAAC;QACf,CAAC;gBAAS,CAAC;YACT,SAAS,CAAC,KAAK,CAAC,CAAC;QACnB,CAAC;IACH,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC;IAEb,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;AAC7D,CAAC"}
@@ -0,0 +1,16 @@
1
+ import type { Attachment, SendResult, UpliftError } from "@uplifted/sdk";
2
+ export type SendStatus = "idle" | "sending" | "sent" | "error";
3
+ export interface SendState {
4
+ status: SendStatus;
5
+ error: UpliftError | null;
6
+ result: SendResult | null;
7
+ /**
8
+ * Send `body`. Resolves with the result, or null on failure (read `error`). The same text
9
+ * keeps the same Idempotency-Key until it succeeds, so Retry can never double send (C21, T24).
10
+ */
11
+ send: (body: string, attachments?: Attachment[]) => Promise<SendResult | null>;
12
+ /** Back to idle; the key for the current text is kept. */
13
+ reset: () => void;
14
+ }
15
+ export declare function useSend(clientId: string | null): SendState;
16
+ //# sourceMappingURL=useSend.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useSend.d.ts","sourceRoot":"","sources":["../src/useSend.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAIzE,MAAM,MAAM,UAAU,GAAG,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,OAAO,CAAC;AAE/D,MAAM,WAAW,SAAS;IACxB,MAAM,EAAE,UAAU,CAAC;IACnB,KAAK,EAAE,WAAW,GAAG,IAAI,CAAC;IAC1B,MAAM,EAAE,UAAU,GAAG,IAAI,CAAC;IAC1B;;;OAGG;IACH,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,UAAU,EAAE,KAAK,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CAAC;IAC/E,0DAA0D;IAC1D,KAAK,EAAE,MAAM,IAAI,CAAC;CACnB;AAQD,wBAAgB,OAAO,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAuC1D"}
@@ -0,0 +1,50 @@
1
+ import { useCallback, useEffect, useRef, useState } from "react";
2
+ import { useUplift } from "./UpliftProvider.js";
3
+ import { asUpliftError } from "./errors.js";
4
+ function newKey() {
5
+ const c = globalThis.crypto;
6
+ if (c && typeof c.randomUUID === "function")
7
+ return c.randomUUID();
8
+ return `k_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 12)}`;
9
+ }
10
+ export function useSend(clientId) {
11
+ const { client } = useUplift();
12
+ const [status, setStatus] = useState("idle");
13
+ const [error, setError] = useState(null);
14
+ const [result, setResult] = useState(null);
15
+ const keyFor = useRef(null);
16
+ useEffect(() => {
17
+ keyFor.current = null;
18
+ setStatus("idle");
19
+ setError(null);
20
+ setResult(null);
21
+ }, [clientId]);
22
+ const send = useCallback(async (body, attachments = []) => {
23
+ if (!clientId || status === "sending")
24
+ return null;
25
+ const text = body.trim();
26
+ if (!text && attachments.length === 0)
27
+ return null;
28
+ // The key follows the exact payload (text plus media), so a retry of the same thing replays.
29
+ const fingerprint = `${text}\n${attachments.map((a) => a.url).join("\n")}`;
30
+ if (!keyFor.current || keyFor.current.body !== fingerprint)
31
+ keyFor.current = { body: fingerprint, key: newKey() };
32
+ setStatus("sending");
33
+ setError(null);
34
+ try {
35
+ const res = await client.send(clientId, { body: text, ...(attachments.length ? { attachments } : {}), idempotencyKey: keyFor.current.key });
36
+ keyFor.current = null;
37
+ setResult(res);
38
+ setStatus("sent");
39
+ return res;
40
+ }
41
+ catch (err) {
42
+ setError(asUpliftError(err));
43
+ setStatus("error");
44
+ return null;
45
+ }
46
+ }, [client, clientId, status]);
47
+ const reset = useCallback(() => { setStatus("idle"); setError(null); setResult(null); }, []);
48
+ return { status, error, result, send, reset };
49
+ }
50
+ //# sourceMappingURL=useSend.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useSend.js","sourceRoot":"","sources":["../src/useSend.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Chat scrolling for a feed: it opens at the newest message and follows new ones while the coach is
3
+ * at the bottom; once they scroll up to read, it leaves them there, and a prepended older page keeps
4
+ * the same messages on screen. Images loading and the feed resizing (the drafts grid opening under it)
5
+ * re-pin it when it was pinned. Spread the returned props onto the scrolling element.
6
+ */
7
+ export declare function useStickToBottom<T extends HTMLElement>(firstKey: string | undefined): {
8
+ ref: import("react").RefObject<T | null>;
9
+ onScroll: () => void;
10
+ onLoadCapture: () => void;
11
+ };
12
+ //# sourceMappingURL=useStickToBottom.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useStickToBottom.d.ts","sourceRoot":"","sources":["../src/useStickToBottom.ts"],"names":[],"mappings":"AAKA;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,SAAS,WAAW,EAAE,QAAQ,EAAE,MAAM,GAAG,SAAS;;;;EAqDnF"}
@@ -0,0 +1,71 @@
1
+ import { useCallback, useEffect, useLayoutEffect, useRef } from "react";
2
+ /** How close to the bottom (px) still counts as "at the newest message". */
3
+ const NEAR = 48;
4
+ /**
5
+ * Chat scrolling for a feed: it opens at the newest message and follows new ones while the coach is
6
+ * at the bottom; once they scroll up to read, it leaves them there, and a prepended older page keeps
7
+ * the same messages on screen. Images loading and the feed resizing (the drafts grid opening under it)
8
+ * re-pin it when it was pinned. Spread the returned props onto the scrolling element.
9
+ */
10
+ export function useStickToBottom(firstKey) {
11
+ const ref = useRef(null);
12
+ const pinned = useRef(true);
13
+ /** scrollHeight - scrollTop at the last scroll or render: what to restore after a prepend. */
14
+ const fromBottom = useRef(0);
15
+ const first = useRef(firstKey);
16
+ const lastTop = useRef(0);
17
+ const ro = useRef(null);
18
+ const pin = useCallback(() => {
19
+ const el = ref.current;
20
+ if (!el || !pinned.current)
21
+ return;
22
+ el.scrollTop = el.scrollHeight;
23
+ lastTop.current = el.scrollTop;
24
+ fromBottom.current = el.scrollHeight - el.scrollTop;
25
+ }, []);
26
+ // Every render: stay at the bottom when pinned. Otherwise, when an older page landed above the
27
+ // reader (the first message changed), keep their distance from the bottom so the same messages stay
28
+ // on screen; anything added below them leaves them where they are.
29
+ useLayoutEffect(() => {
30
+ const el = ref.current;
31
+ if (!el)
32
+ return;
33
+ const prepended = first.current !== undefined && firstKey !== first.current;
34
+ first.current = firstKey;
35
+ // Watch every item too: an image loading or a card growing changes the content, not the feed's box.
36
+ for (const child of Array.from(el.children))
37
+ ro.current?.observe(child);
38
+ if (pinned.current) {
39
+ pin();
40
+ return;
41
+ }
42
+ if (prepended)
43
+ el.scrollTop = el.scrollHeight - fromBottom.current;
44
+ fromBottom.current = el.scrollHeight - el.scrollTop;
45
+ });
46
+ useEffect(() => {
47
+ const el = ref.current;
48
+ if (!el || typeof ResizeObserver === "undefined")
49
+ return;
50
+ ro.current = new ResizeObserver(() => pin());
51
+ ro.current.observe(el);
52
+ for (const child of Array.from(el.children))
53
+ ro.current.observe(child);
54
+ return () => { ro.current?.disconnect(); ro.current = null; };
55
+ }, [pin]);
56
+ // Only the reader scrolling up unpins. Content growing above them can also move scrollTop (the
57
+ // browser's scroll anchoring), but only ever down, so that never counts as leaving the bottom.
58
+ const onScroll = useCallback(() => {
59
+ const el = ref.current;
60
+ if (!el)
61
+ return;
62
+ if (el.scrollHeight - el.scrollTop - el.clientHeight < NEAR)
63
+ pinned.current = true;
64
+ else if (el.scrollTop < lastTop.current)
65
+ pinned.current = false;
66
+ lastTop.current = el.scrollTop;
67
+ fromBottom.current = el.scrollHeight - el.scrollTop;
68
+ }, []);
69
+ return { ref, onScroll, onLoadCapture: pin };
70
+ }
71
+ //# sourceMappingURL=useStickToBottom.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useStickToBottom.js","sourceRoot":"","sources":["../src/useStickToBottom.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ import type { DraftSet, Message, UpliftError } from "@uplifted/sdk";
2
+ import type { LoadStatus } from "./useClients.js";
3
+ export interface ThreadState {
4
+ status: LoadStatus;
5
+ /** Oldest first. */
6
+ messages: Message[];
7
+ error: UpliftError | null;
8
+ hasMore: boolean;
9
+ loadingOlder: boolean;
10
+ /** Prepend the previous page. No-op while loading or when nothing older exists. */
11
+ loadOlder: () => void;
12
+ /** Add a message the panel just sent, without a round trip. */
13
+ append: (message: Message) => void;
14
+ reload: () => void;
15
+ /** Reply drafts Uplift prepared when the client last wrote (shown without a request). */
16
+ replyDrafts: DraftSet | null;
17
+ unreadCount: number;
18
+ setReplyDrafts: (d: DraftSet | null) => void;
19
+ /** Refetch the first page quietly and merge anything new (polling). */
20
+ refresh: () => void;
21
+ /** Patch one message in place (delivery status). */
22
+ patch: (id: string, changes: Partial<Message>) => void;
23
+ }
24
+ /** One client's conversation: messages and host activity events in one timeline. */
25
+ export declare function useThread(clientId: string | null): ThreadState;
26
+ //# sourceMappingURL=useThread.d.ts.map