@schlessera/brain-ui-react 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 (311) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +70 -0
  3. package/dist/components/chat/ask-user-card.d.ts +12 -0
  4. package/dist/components/chat/ask-user-card.d.ts.map +1 -0
  5. package/dist/components/chat/ask-user-card.js +185 -0
  6. package/dist/components/chat/ask-user-card.js.map +1 -0
  7. package/dist/components/chat/brain-markdown.d.ts +35 -0
  8. package/dist/components/chat/brain-markdown.d.ts.map +1 -0
  9. package/dist/components/chat/brain-markdown.js +363 -0
  10. package/dist/components/chat/brain-markdown.js.map +1 -0
  11. package/dist/components/chat/chat-page.d.ts +2 -0
  12. package/dist/components/chat/chat-page.d.ts.map +1 -0
  13. package/dist/components/chat/chat-page.js +442 -0
  14. package/dist/components/chat/chat-page.js.map +1 -0
  15. package/dist/components/chat/command-palette.d.ts +5 -0
  16. package/dist/components/chat/command-palette.d.ts.map +1 -0
  17. package/dist/components/chat/command-palette.js +18 -0
  18. package/dist/components/chat/command-palette.js.map +1 -0
  19. package/dist/components/chat/markdown-content.d.ts +4 -0
  20. package/dist/components/chat/markdown-content.d.ts.map +1 -0
  21. package/dist/components/chat/markdown-content.js +6 -0
  22. package/dist/components/chat/markdown-content.js.map +1 -0
  23. package/dist/components/chat/message-bubble.d.ts +9 -0
  24. package/dist/components/chat/message-bubble.d.ts.map +1 -0
  25. package/dist/components/chat/message-bubble.js +129 -0
  26. package/dist/components/chat/message-bubble.js.map +1 -0
  27. package/dist/components/chat/message-share.d.ts +10 -0
  28. package/dist/components/chat/message-share.d.ts.map +1 -0
  29. package/dist/components/chat/message-share.js +65 -0
  30. package/dist/components/chat/message-share.js.map +1 -0
  31. package/dist/components/chat/renderers/claude-tools.d.ts +3 -0
  32. package/dist/components/chat/renderers/claude-tools.d.ts.map +1 -0
  33. package/dist/components/chat/renderers/claude-tools.js +38 -0
  34. package/dist/components/chat/renderers/claude-tools.js.map +1 -0
  35. package/dist/components/chat/renderers/generic.d.ts +9 -0
  36. package/dist/components/chat/renderers/generic.d.ts.map +1 -0
  37. package/dist/components/chat/renderers/generic.js +68 -0
  38. package/dist/components/chat/renderers/generic.js.map +1 -0
  39. package/dist/components/chat/renderers/index.d.ts +5 -0
  40. package/dist/components/chat/renderers/index.d.ts.map +1 -0
  41. package/dist/components/chat/renderers/index.js +17 -0
  42. package/dist/components/chat/renderers/index.js.map +1 -0
  43. package/dist/components/chat/risk-hints.d.ts +20 -0
  44. package/dist/components/chat/risk-hints.d.ts.map +1 -0
  45. package/dist/components/chat/risk-hints.js +81 -0
  46. package/dist/components/chat/risk-hints.js.map +1 -0
  47. package/dist/components/chat/session-drawer.d.ts +6 -0
  48. package/dist/components/chat/session-drawer.d.ts.map +1 -0
  49. package/dist/components/chat/session-drawer.js +96 -0
  50. package/dist/components/chat/session-drawer.js.map +1 -0
  51. package/dist/components/chat/share-block.d.ts +9 -0
  52. package/dist/components/chat/share-block.d.ts.map +1 -0
  53. package/dist/components/chat/share-block.js +70 -0
  54. package/dist/components/chat/share-block.js.map +1 -0
  55. package/dist/components/chat/tool-call-timeline.d.ts +8 -0
  56. package/dist/components/chat/tool-call-timeline.d.ts.map +1 -0
  57. package/dist/components/chat/tool-call-timeline.js +100 -0
  58. package/dist/components/chat/tool-call-timeline.js.map +1 -0
  59. package/dist/components/chat/tool-views.d.ts +116 -0
  60. package/dist/components/chat/tool-views.d.ts.map +1 -0
  61. package/dist/components/chat/tool-views.js +628 -0
  62. package/dist/components/chat/tool-views.js.map +1 -0
  63. package/dist/components/chat/welcome-state.d.ts +4 -0
  64. package/dist/components/chat/welcome-state.d.ts.map +1 -0
  65. package/dist/components/chat/welcome-state.js +10 -0
  66. package/dist/components/chat/welcome-state.js.map +1 -0
  67. package/dist/components/connectivity/connection-gate.d.ts +5 -0
  68. package/dist/components/connectivity/connection-gate.d.ts.map +1 -0
  69. package/dist/components/connectivity/connection-gate.js +42 -0
  70. package/dist/components/connectivity/connection-gate.js.map +1 -0
  71. package/dist/components/connectivity/login-screen.d.ts +9 -0
  72. package/dist/components/connectivity/login-screen.d.ts.map +1 -0
  73. package/dist/components/connectivity/login-screen.js +99 -0
  74. package/dist/components/connectivity/login-screen.js.map +1 -0
  75. package/dist/components/files/file-panel.d.ts +5 -0
  76. package/dist/components/files/file-panel.d.ts.map +1 -0
  77. package/dist/components/files/file-panel.js +46 -0
  78. package/dist/components/files/file-panel.js.map +1 -0
  79. package/dist/components/files/file-tree.d.ts +2 -0
  80. package/dist/components/files/file-tree.d.ts.map +1 -0
  81. package/dist/components/files/file-tree.js +63 -0
  82. package/dist/components/files/file-tree.js.map +1 -0
  83. package/dist/components/files/file-viewer-binary.d.ts +5 -0
  84. package/dist/components/files/file-viewer-binary.d.ts.map +1 -0
  85. package/dist/components/files/file-viewer-binary.js +20 -0
  86. package/dist/components/files/file-viewer-binary.js.map +1 -0
  87. package/dist/components/files/file-viewer-html.d.ts +4 -0
  88. package/dist/components/files/file-viewer-html.d.ts.map +1 -0
  89. package/dist/components/files/file-viewer-html.js +5 -0
  90. package/dist/components/files/file-viewer-html.js.map +1 -0
  91. package/dist/components/files/file-viewer-markdown.d.ts +4 -0
  92. package/dist/components/files/file-viewer-markdown.d.ts.map +1 -0
  93. package/dist/components/files/file-viewer-markdown.js +10 -0
  94. package/dist/components/files/file-viewer-markdown.js.map +1 -0
  95. package/dist/components/files/file-viewer-raw.d.ts +5 -0
  96. package/dist/components/files/file-viewer-raw.d.ts.map +1 -0
  97. package/dist/components/files/file-viewer-raw.js +15 -0
  98. package/dist/components/files/file-viewer-raw.js.map +1 -0
  99. package/dist/components/files/file-viewer.d.ts +2 -0
  100. package/dist/components/files/file-viewer.d.ts.map +1 -0
  101. package/dist/components/files/file-viewer.js +175 -0
  102. package/dist/components/files/file-viewer.js.map +1 -0
  103. package/dist/components/files/frontmatter-panel.d.ts +5 -0
  104. package/dist/components/files/frontmatter-panel.d.ts.map +1 -0
  105. package/dist/components/files/frontmatter-panel.js +12 -0
  106. package/dist/components/files/frontmatter-panel.js.map +1 -0
  107. package/dist/components/layout/app-shell.d.ts +5 -0
  108. package/dist/components/layout/app-shell.d.ts.map +1 -0
  109. package/dist/components/layout/app-shell.js +10 -0
  110. package/dist/components/layout/app-shell.js.map +1 -0
  111. package/dist/components/layout/mobile-tab-bar.d.ts +2 -0
  112. package/dist/components/layout/mobile-tab-bar.d.ts.map +1 -0
  113. package/dist/components/layout/mobile-tab-bar.js +16 -0
  114. package/dist/components/layout/mobile-tab-bar.js.map +1 -0
  115. package/dist/components/layout/side-rail.d.ts +2 -0
  116. package/dist/components/layout/side-rail.d.ts.map +1 -0
  117. package/dist/components/layout/side-rail.js +26 -0
  118. package/dist/components/layout/side-rail.js.map +1 -0
  119. package/dist/components/layout/slide-panel.d.ts +9 -0
  120. package/dist/components/layout/slide-panel.d.ts.map +1 -0
  121. package/dist/components/layout/slide-panel.js +18 -0
  122. package/dist/components/layout/slide-panel.js.map +1 -0
  123. package/dist/components/quick-actions/streaming-modal.d.ts +8 -0
  124. package/dist/components/quick-actions/streaming-modal.d.ts.map +1 -0
  125. package/dist/components/quick-actions/streaming-modal.js +92 -0
  126. package/dist/components/quick-actions/streaming-modal.js.map +1 -0
  127. package/dist/components/quick-actions/whatsup-modal.d.ts +5 -0
  128. package/dist/components/quick-actions/whatsup-modal.d.ts.map +1 -0
  129. package/dist/components/quick-actions/whatsup-modal.js +82 -0
  130. package/dist/components/quick-actions/whatsup-modal.js.map +1 -0
  131. package/dist/components/settings/passkey-panel.d.ts +10 -0
  132. package/dist/components/settings/passkey-panel.d.ts.map +1 -0
  133. package/dist/components/settings/passkey-panel.js +118 -0
  134. package/dist/components/settings/passkey-panel.js.map +1 -0
  135. package/dist/components/share/share-menu.d.ts +23 -0
  136. package/dist/components/share/share-menu.d.ts.map +1 -0
  137. package/dist/components/share/share-menu.js +58 -0
  138. package/dist/components/share/share-menu.js.map +1 -0
  139. package/dist/components/voice/dictation-sheet.d.ts +6 -0
  140. package/dist/components/voice/dictation-sheet.d.ts.map +1 -0
  141. package/dist/components/voice/dictation-sheet.js +91 -0
  142. package/dist/components/voice/dictation-sheet.js.map +1 -0
  143. package/dist/components/voice/mic-button.d.ts +6 -0
  144. package/dist/components/voice/mic-button.d.ts.map +1 -0
  145. package/dist/components/voice/mic-button.js +9 -0
  146. package/dist/components/voice/mic-button.js.map +1 -0
  147. package/dist/components/voice/review-card.d.ts +8 -0
  148. package/dist/components/voice/review-card.d.ts.map +1 -0
  149. package/dist/components/voice/review-card.js +8 -0
  150. package/dist/components/voice/review-card.js.map +1 -0
  151. package/dist/config.d.ts +19 -0
  152. package/dist/config.d.ts.map +1 -0
  153. package/dist/config.js +10 -0
  154. package/dist/config.js.map +1 -0
  155. package/dist/hooks/use-vpn-status.d.ts +2 -0
  156. package/dist/hooks/use-vpn-status.d.ts.map +1 -0
  157. package/dist/hooks/use-vpn-status.js +71 -0
  158. package/dist/hooks/use-vpn-status.js.map +1 -0
  159. package/dist/hooks/use-websocket.d.ts +8 -0
  160. package/dist/hooks/use-websocket.d.ts.map +1 -0
  161. package/dist/hooks/use-websocket.js +366 -0
  162. package/dist/hooks/use-websocket.js.map +1 -0
  163. package/dist/index.d.ts +25 -0
  164. package/dist/index.d.ts.map +1 -0
  165. package/dist/index.js +31 -0
  166. package/dist/index.js.map +1 -0
  167. package/dist/lib/api-client.d.ts +115 -0
  168. package/dist/lib/api-client.d.ts.map +1 -0
  169. package/dist/lib/api-client.js +70 -0
  170. package/dist/lib/api-client.js.map +1 -0
  171. package/dist/lib/backend.d.ts +7 -0
  172. package/dist/lib/backend.d.ts.map +1 -0
  173. package/dist/lib/backend.js +33 -0
  174. package/dist/lib/backend.js.map +1 -0
  175. package/dist/lib/frontmatter.d.ts +21 -0
  176. package/dist/lib/frontmatter.d.ts.map +1 -0
  177. package/dist/lib/frontmatter.js +88 -0
  178. package/dist/lib/frontmatter.js.map +1 -0
  179. package/dist/lib/image-attachments.d.ts +36 -0
  180. package/dist/lib/image-attachments.d.ts.map +1 -0
  181. package/dist/lib/image-attachments.js +175 -0
  182. package/dist/lib/image-attachments.js.map +1 -0
  183. package/dist/lib/passkeys.d.ts +18 -0
  184. package/dist/lib/passkeys.d.ts.map +1 -0
  185. package/dist/lib/passkeys.js +36 -0
  186. package/dist/lib/passkeys.js.map +1 -0
  187. package/dist/lib/share.d.ts +53 -0
  188. package/dist/lib/share.d.ts.map +1 -0
  189. package/dist/lib/share.js +144 -0
  190. package/dist/lib/share.js.map +1 -0
  191. package/dist/lib/strip-markdown.d.ts +10 -0
  192. package/dist/lib/strip-markdown.d.ts.map +1 -0
  193. package/dist/lib/strip-markdown.js +37 -0
  194. package/dist/lib/strip-markdown.js.map +1 -0
  195. package/dist/lib/tool-names.d.ts +17 -0
  196. package/dist/lib/tool-names.d.ts.map +1 -0
  197. package/dist/lib/tool-names.js +23 -0
  198. package/dist/lib/tool-names.js.map +1 -0
  199. package/dist/lib/utils.d.ts +3 -0
  200. package/dist/lib/utils.d.ts.map +1 -0
  201. package/dist/lib/utils.js +6 -0
  202. package/dist/lib/utils.js.map +1 -0
  203. package/dist/lib/ws-client.d.ts +26 -0
  204. package/dist/lib/ws-client.d.ts.map +1 -0
  205. package/dist/lib/ws-client.js +93 -0
  206. package/dist/lib/ws-client.js.map +1 -0
  207. package/dist/stores/chat-store.d.ts +131 -0
  208. package/dist/stores/chat-store.d.ts.map +1 -0
  209. package/dist/stores/chat-store.js +376 -0
  210. package/dist/stores/chat-store.js.map +1 -0
  211. package/dist/stores/connection-store.d.ts +11 -0
  212. package/dist/stores/connection-store.d.ts.map +1 -0
  213. package/dist/stores/connection-store.js +8 -0
  214. package/dist/stores/connection-store.js.map +1 -0
  215. package/dist/stores/file-store.d.ts +53 -0
  216. package/dist/stores/file-store.d.ts.map +1 -0
  217. package/dist/stores/file-store.js +284 -0
  218. package/dist/stores/file-store.js.map +1 -0
  219. package/dist/stores/provider-store.d.ts +24 -0
  220. package/dist/stores/provider-store.d.ts.map +1 -0
  221. package/dist/stores/provider-store.js +56 -0
  222. package/dist/stores/provider-store.js.map +1 -0
  223. package/dist/stores/ui-store.d.ts +21 -0
  224. package/dist/stores/ui-store.d.ts.map +1 -0
  225. package/dist/stores/ui-store.js +23 -0
  226. package/dist/stores/ui-store.js.map +1 -0
  227. package/dist/styles.css +2 -0
  228. package/dist/voice/asr-clients.d.ts +2 -0
  229. package/dist/voice/asr-clients.d.ts.map +1 -0
  230. package/dist/voice/asr-clients.js +33 -0
  231. package/dist/voice/asr-clients.js.map +1 -0
  232. package/dist/voice/asr-deepgram.d.ts +38 -0
  233. package/dist/voice/asr-deepgram.d.ts.map +1 -0
  234. package/dist/voice/asr-deepgram.js +307 -0
  235. package/dist/voice/asr-deepgram.js.map +1 -0
  236. package/dist/voice/asr-webspeech.d.ts +23 -0
  237. package/dist/voice/asr-webspeech.d.ts.map +1 -0
  238. package/dist/voice/asr-webspeech.js +93 -0
  239. package/dist/voice/asr-webspeech.js.map +1 -0
  240. package/dist/voice/use-dictation.d.ts +6 -0
  241. package/dist/voice/use-dictation.d.ts.map +1 -0
  242. package/dist/voice/use-dictation.js +174 -0
  243. package/dist/voice/use-dictation.js.map +1 -0
  244. package/dist/voice/voice-store.d.ts +26 -0
  245. package/dist/voice/voice-store.d.ts.map +1 -0
  246. package/dist/voice/voice-store.js +27 -0
  247. package/dist/voice/voice-store.js.map +1 -0
  248. package/package.json +71 -0
  249. package/src/components/chat/ask-user-card.tsx +451 -0
  250. package/src/components/chat/brain-markdown.tsx +547 -0
  251. package/src/components/chat/chat-page.tsx +820 -0
  252. package/src/components/chat/command-palette.tsx +68 -0
  253. package/src/components/chat/markdown-content.tsx +5 -0
  254. package/src/components/chat/message-bubble.tsx +362 -0
  255. package/src/components/chat/message-share.ts +78 -0
  256. package/src/components/chat/renderers/claude-tools.tsx +53 -0
  257. package/src/components/chat/renderers/generic.tsx +85 -0
  258. package/src/components/chat/renderers/index.ts +19 -0
  259. package/src/components/chat/risk-hints.ts +95 -0
  260. package/src/components/chat/session-drawer.tsx +213 -0
  261. package/src/components/chat/share-block.tsx +128 -0
  262. package/src/components/chat/tool-call-timeline.tsx +322 -0
  263. package/src/components/chat/tool-views.tsx +898 -0
  264. package/src/components/chat/welcome-state.tsx +105 -0
  265. package/src/components/connectivity/connection-gate.tsx +137 -0
  266. package/src/components/connectivity/login-screen.tsx +169 -0
  267. package/src/components/files/file-panel.tsx +116 -0
  268. package/src/components/files/file-tree.tsx +143 -0
  269. package/src/components/files/file-viewer-binary.tsx +63 -0
  270. package/src/components/files/file-viewer-html.tsx +10 -0
  271. package/src/components/files/file-viewer-markdown.tsx +14 -0
  272. package/src/components/files/file-viewer-raw.tsx +44 -0
  273. package/src/components/files/file-viewer.tsx +290 -0
  274. package/src/components/files/frontmatter-panel.tsx +78 -0
  275. package/src/components/layout/app-shell.tsx +25 -0
  276. package/src/components/layout/mobile-tab-bar.tsx +54 -0
  277. package/src/components/layout/side-rail.tsx +128 -0
  278. package/src/components/layout/slide-panel.tsx +64 -0
  279. package/src/components/quick-actions/streaming-modal.tsx +168 -0
  280. package/src/components/quick-actions/whatsup-modal.tsx +149 -0
  281. package/src/components/settings/passkey-panel.tsx +281 -0
  282. package/src/components/share/share-menu.tsx +121 -0
  283. package/src/components/voice/dictation-sheet.tsx +217 -0
  284. package/src/components/voice/mic-button.tsx +31 -0
  285. package/src/components/voice/review-card.tsx +66 -0
  286. package/src/config.ts +27 -0
  287. package/src/hooks/use-vpn-status.ts +75 -0
  288. package/src/hooks/use-websocket.ts +403 -0
  289. package/src/index.ts +46 -0
  290. package/src/lib/api-client.ts +173 -0
  291. package/src/lib/backend.ts +35 -0
  292. package/src/lib/frontmatter.ts +99 -0
  293. package/src/lib/image-attachments.ts +221 -0
  294. package/src/lib/passkeys.ts +50 -0
  295. package/src/lib/share.ts +167 -0
  296. package/src/lib/strip-markdown.ts +38 -0
  297. package/src/lib/tool-names.ts +27 -0
  298. package/src/lib/utils.ts +6 -0
  299. package/src/lib/ws-client.ts +109 -0
  300. package/src/stores/chat-store.ts +619 -0
  301. package/src/stores/connection-store.ts +23 -0
  302. package/src/stores/file-store.ts +344 -0
  303. package/src/stores/provider-store.ts +85 -0
  304. package/src/stores/ui-store.ts +48 -0
  305. package/src/styles.css +4 -0
  306. package/src/theme.css +425 -0
  307. package/src/voice/asr-clients.ts +45 -0
  308. package/src/voice/asr-deepgram.ts +325 -0
  309. package/src/voice/asr-webspeech.ts +135 -0
  310. package/src/voice/use-dictation.ts +187 -0
  311. package/src/voice/voice-store.ts +55 -0
@@ -0,0 +1,7 @@
1
+ /** Base URL for API calls. Empty BACKEND_URL = same-origin "/api". */
2
+ export declare const API_BASE: string;
3
+ /** WebSocket URL. Derives wss/ws + host from BACKEND_URL, else same-origin. */
4
+ export declare function getWsUrl(): string;
5
+ /** Base URL for direct fetch calls (streaming endpoints). */
6
+ export declare function getBackendUrl(path: string): string;
7
+ //# sourceMappingURL=backend.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"backend.d.ts","sourceRoot":"","sources":["../../src/lib/backend.ts"],"names":[],"mappings":"AAgBA,sEAAsE;AACtE,eAAO,MAAM,QAAQ,QAAuB,CAAC;AAE7C,+EAA+E;AAC/E,wBAAgB,QAAQ,IAAI,MAAM,CASjC;AAED,6DAA6D;AAC7D,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAElD"}
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Backend URL configuration.
3
+ *
4
+ * Default topology is SAME-ORIGIN: the server serves the built client and the
5
+ * API/WS from one origin, so API calls go to "/api" and the WebSocket derives
6
+ * its host from window.location. No build-time configuration is needed.
7
+ *
8
+ * VITE_BACKEND_URL is optional advanced config for a SPLIT topology (client and
9
+ * backend on different origins, e.g. a public frontend with the backend reached
10
+ * over a VPN). When set at build time, API and WS calls target that origin.
11
+ * The read is defensive — outside a Vite build (bun test, Node import of the
12
+ * dist) `import.meta.env` does not exist.
13
+ */
14
+ const viteEnv = import.meta.env;
15
+ const BACKEND_URL = viteEnv?.VITE_BACKEND_URL?.replace(/\/$/, "") ?? "";
16
+ /** Base URL for API calls. Empty BACKEND_URL = same-origin "/api". */
17
+ export const API_BASE = `${BACKEND_URL}/api`;
18
+ /** WebSocket URL. Derives wss/ws + host from BACKEND_URL, else same-origin. */
19
+ export function getWsUrl() {
20
+ if (BACKEND_URL) {
21
+ const url = new URL("/ws", BACKEND_URL);
22
+ url.protocol = url.protocol === "https:" ? "wss:" : "ws:";
23
+ return url.toString();
24
+ }
25
+ // Same-origin (default).
26
+ const protocol = window.location.protocol === "https:" ? "wss:" : "ws:";
27
+ return `${protocol}//${window.location.host}/ws`;
28
+ }
29
+ /** Base URL for direct fetch calls (streaming endpoints). */
30
+ export function getBackendUrl(path) {
31
+ return `${BACKEND_URL}${path}`;
32
+ }
33
+ //# sourceMappingURL=backend.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"backend.js","sourceRoot":"","sources":["../../src/lib/backend.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,MAAM,OAAO,GAAI,MAAM,CAAC,IAAqD,CAAC,GAAG,CAAC;AAClF,MAAM,WAAW,GAAG,OAAO,EAAE,gBAAgB,EAAE,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,EAAE,CAAC;AAExE,sEAAsE;AACtE,MAAM,CAAC,MAAM,QAAQ,GAAG,GAAG,WAAW,MAAM,CAAC;AAE7C,+EAA+E;AAC/E,MAAM,UAAU,QAAQ;IACtB,IAAI,WAAW,EAAE,CAAC;QAChB,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,KAAK,EAAE,WAAW,CAAC,CAAC;QACxC,GAAG,CAAC,QAAQ,GAAG,GAAG,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC;QAC1D,OAAO,GAAG,CAAC,QAAQ,EAAE,CAAC;IACxB,CAAC;IACD,yBAAyB;IACzB,MAAM,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC;IACxE,OAAO,GAAG,QAAQ,KAAK,MAAM,CAAC,QAAQ,CAAC,IAAI,KAAK,CAAC;AACnD,CAAC;AAED,6DAA6D;AAC7D,MAAM,UAAU,aAAa,CAAC,IAAY;IACxC,OAAO,GAAG,WAAW,GAAG,IAAI,EAAE,CAAC;AACjC,CAAC"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Minimal YAML-frontmatter splitter for brain repo markdown files.
3
+ *
4
+ * Brain frontmatter is single-line key:value with the occasional inline
5
+ * array (`tags: [a, b, c]`) and quoted string. We don't need a full YAML
6
+ * parser — a small focused split keeps the bundle tiny and the behaviour
7
+ * predictable.
8
+ */
9
+ export interface FrontmatterField {
10
+ key: string;
11
+ /** Raw value as it appears in the file (quotes stripped). */
12
+ value: string;
13
+ /** Parsed array elements when value was `[a, b, c]`-shaped. */
14
+ list?: string[];
15
+ }
16
+ export interface FrontmatterSplit {
17
+ fields: FrontmatterField[];
18
+ body: string;
19
+ }
20
+ export declare function splitFrontmatter(md: string): FrontmatterSplit;
21
+ //# sourceMappingURL=frontmatter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"frontmatter.d.ts","sourceRoot":"","sources":["../../src/lib/frontmatter.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,MAAM,WAAW,gBAAgB;IAC/B,GAAG,EAAE,MAAM,CAAC;IACZ,6DAA6D;IAC7D,KAAK,EAAE,MAAM,CAAC;IACd,+DAA+D;IAC/D,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;CACjB;AAED,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,gBAAgB,EAAE,CAAC;IAC3B,IAAI,EAAE,MAAM,CAAC;CACd;AAID,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,MAAM,GAAG,gBAAgB,CAsB7D"}
@@ -0,0 +1,88 @@
1
+ /**
2
+ * Minimal YAML-frontmatter splitter for brain repo markdown files.
3
+ *
4
+ * Brain frontmatter is single-line key:value with the occasional inline
5
+ * array (`tags: [a, b, c]`) and quoted string. We don't need a full YAML
6
+ * parser — a small focused split keeps the bundle tiny and the behaviour
7
+ * predictable.
8
+ */
9
+ const OPEN = /^---\r?\n/;
10
+ export function splitFrontmatter(md) {
11
+ if (!OPEN.test(md))
12
+ return { fields: [], body: md };
13
+ // Find closing `---` on its own line after the opener.
14
+ const afterOpen = md.replace(OPEN, "");
15
+ const closeMatch = afterOpen.match(/\r?\n---\r?\n/);
16
+ if (!closeMatch || closeMatch.index === undefined) {
17
+ return { fields: [], body: md };
18
+ }
19
+ const rawFrontmatter = afterOpen.slice(0, closeMatch.index);
20
+ const body = afterOpen.slice(closeMatch.index + closeMatch[0].length);
21
+ const fields = [];
22
+ for (const line of rawFrontmatter.split(/\r?\n/)) {
23
+ if (!line.trim() || line.trimStart().startsWith("#"))
24
+ continue;
25
+ const sep = line.indexOf(":");
26
+ if (sep < 0)
27
+ continue;
28
+ const key = line.slice(0, sep).trim();
29
+ if (!key)
30
+ continue;
31
+ const raw = line.slice(sep + 1).trim();
32
+ fields.push(parseField(key, raw));
33
+ }
34
+ return { fields, body };
35
+ }
36
+ function parseField(key, raw) {
37
+ // Inline array: [a, "b", c]
38
+ if (raw.startsWith("[") && raw.endsWith("]")) {
39
+ const inner = raw.slice(1, -1);
40
+ const list = splitArray(inner).map(unquote).filter(Boolean);
41
+ return { key, value: raw, list };
42
+ }
43
+ return { key, value: unquote(raw) };
44
+ }
45
+ function unquote(s) {
46
+ const trimmed = s.trim();
47
+ if (trimmed.length >= 2) {
48
+ const first = trimmed[0];
49
+ const last = trimmed[trimmed.length - 1];
50
+ if ((first === '"' && last === '"') || (first === "'" && last === "'")) {
51
+ return trimmed.slice(1, -1);
52
+ }
53
+ }
54
+ return trimmed;
55
+ }
56
+ /** Split on top-level commas, respecting quoted segments. */
57
+ function splitArray(s) {
58
+ const out = [];
59
+ let buf = "";
60
+ let quote = null;
61
+ for (let i = 0; i < s.length; i++) {
62
+ const ch = s[i];
63
+ if (quote) {
64
+ buf += ch;
65
+ if (ch === quote && s[i - 1] !== "\\")
66
+ quote = null;
67
+ continue;
68
+ }
69
+ if (ch === '"' || ch === "'") {
70
+ quote = ch;
71
+ buf += ch;
72
+ continue;
73
+ }
74
+ if (ch === ",") {
75
+ const piece = buf.trim();
76
+ if (piece)
77
+ out.push(piece);
78
+ buf = "";
79
+ continue;
80
+ }
81
+ buf += ch;
82
+ }
83
+ const tail = buf.trim();
84
+ if (tail)
85
+ out.push(tail);
86
+ return out;
87
+ }
88
+ //# sourceMappingURL=frontmatter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"frontmatter.js","sourceRoot":"","sources":["../../src/lib/frontmatter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,36 @@
1
+ import type { ChatImageAttachment } from "@schlessera/brain-ui-sdk/protocol";
2
+ /** A processed attachment plus a local object URL for the composer preview. */
3
+ export interface PendingAttachment {
4
+ attachment: ChatImageAttachment;
5
+ previewUrl: string;
6
+ /** Decoded byte length (post-downscale) — used for total-size validation. */
7
+ bytes: number;
8
+ /** Original file name, for error messages. */
9
+ name: string;
10
+ }
11
+ type FileToAttachmentResult = {
12
+ attachment: ChatImageAttachment;
13
+ previewUrl: string;
14
+ bytes: number;
15
+ } | {
16
+ error: string;
17
+ };
18
+ /**
19
+ * Turn a picked/pasted image File into a wire-ready attachment plus a preview
20
+ * URL. GIFs pass through un-re-encoded (size-checked only) so animation
21
+ * survives; everything else is downscaled to `DOWNSCALE_MAX_EDGE` and
22
+ * re-encoded to JPEG. Rejects (with a human message) on unsupported types,
23
+ * decode failure, or oversize-after-downscale.
24
+ */
25
+ export declare function fileToAttachment(file: File): Promise<FileToAttachmentResult>;
26
+ /**
27
+ * Enforce message-level caps against a proposed set of attachments (existing
28
+ * pending + newly added). Returns the accepted subset and per-file rejection
29
+ * reasons; never mutates the input.
30
+ */
31
+ export declare function validateAttachments(pending: PendingAttachment[]): {
32
+ accepted: PendingAttachment[];
33
+ errors: string[];
34
+ };
35
+ export {};
36
+ //# sourceMappingURL=image-attachments.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"image-attachments.d.ts","sourceRoot":"","sources":["../../src/lib/image-attachments.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,mCAAmC,CAAC;AAe7E,+EAA+E;AAC/E,MAAM,WAAW,iBAAiB;IAChC,UAAU,EAAE,mBAAmB,CAAC;IAChC,UAAU,EAAE,MAAM,CAAC;IACnB,6EAA6E;IAC7E,KAAK,EAAE,MAAM,CAAC;IACd,8CAA8C;IAC9C,IAAI,EAAE,MAAM,CAAC;CACd;AAED,KAAK,sBAAsB,GACvB;IAAE,UAAU,EAAE,mBAAmB,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GACtE;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AA8DtB;;;;;;GAMG;AACH,wBAAsB,gBAAgB,CACpC,IAAI,EAAE,IAAI,GACT,OAAO,CAAC,sBAAsB,CAAC,CAqFjC;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,iBAAiB,EAAE,GAAG;IACjE,QAAQ,EAAE,iBAAiB,EAAE,CAAC;IAC9B,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB,CAuBA"}
@@ -0,0 +1,175 @@
1
+ import { DOWNSCALE_MAX_EDGE, MAX_IMAGES_PER_MESSAGE, MAX_IMAGE_BYTES, MAX_TOTAL_IMAGE_BYTES, } from "@schlessera/brain-ui-sdk/protocol";
2
+ /**
3
+ * The vision API silently drops images below a minimum pixel size (a 2x2 PNG
4
+ * is stripped with a misleading "could not be processed" note; 64x64 is fine).
5
+ * Reject anything smaller than this on either edge so the failure is explicit.
6
+ */
7
+ const MIN_IMAGE_EDGE = 32;
8
+ /** base64 length → decoded byte count (accounts for `=` padding). */
9
+ function decodedBytesFromBase64(b64) {
10
+ const padding = b64.endsWith("==") ? 2 : b64.endsWith("=") ? 1 : 0;
11
+ return Math.floor((b64.length * 3) / 4) - padding;
12
+ }
13
+ function blobToBase64(blob) {
14
+ return new Promise((resolve, reject) => {
15
+ const reader = new FileReader();
16
+ reader.onload = () => {
17
+ const result = reader.result;
18
+ // Strip the `data:<mime>;base64,` prefix — protocol wants raw base64.
19
+ const comma = result.indexOf(",");
20
+ resolve(comma >= 0 ? result.slice(comma + 1) : result);
21
+ };
22
+ reader.onerror = () => reject(reader.error ?? new Error("read_failed"));
23
+ reader.readAsDataURL(blob);
24
+ });
25
+ }
26
+ /**
27
+ * Decode a file to raw pixels. Prefers `createImageBitmap` (honors EXIF
28
+ * orientation) and falls back to an `<img>` decode when it rejects (e.g.
29
+ * older Safari, some codecs).
30
+ */
31
+ async function decodeImage(file) {
32
+ try {
33
+ const bitmap = await createImageBitmap(file, { imageOrientation: "from-image" });
34
+ return {
35
+ width: bitmap.width,
36
+ height: bitmap.height,
37
+ draw: (ctx, w, h) => {
38
+ ctx.drawImage(bitmap, 0, 0, w, h);
39
+ bitmap.close();
40
+ },
41
+ };
42
+ }
43
+ catch {
44
+ // Fallback: HTMLImageElement decode via an object URL.
45
+ const url = URL.createObjectURL(file);
46
+ try {
47
+ const img = new Image();
48
+ img.src = url;
49
+ await img.decode();
50
+ const width = img.naturalWidth;
51
+ const height = img.naturalHeight;
52
+ return {
53
+ width,
54
+ height,
55
+ draw: (ctx, w, h) => ctx.drawImage(img, 0, 0, w, h),
56
+ };
57
+ }
58
+ catch {
59
+ return null;
60
+ }
61
+ finally {
62
+ URL.revokeObjectURL(url);
63
+ }
64
+ }
65
+ }
66
+ /**
67
+ * Turn a picked/pasted image File into a wire-ready attachment plus a preview
68
+ * URL. GIFs pass through un-re-encoded (size-checked only) so animation
69
+ * survives; everything else is downscaled to `DOWNSCALE_MAX_EDGE` and
70
+ * re-encoded to JPEG. Rejects (with a human message) on unsupported types,
71
+ * decode failure, or oversize-after-downscale.
72
+ */
73
+ export async function fileToAttachment(file) {
74
+ const type = file.type || "";
75
+ // GIF: keep the raw bytes (canvas would flatten the animation). Measure its
76
+ // dimensions for the min-size guard without re-encoding, then size-check.
77
+ if (type === "image/gif") {
78
+ try {
79
+ const bmp = await createImageBitmap(file);
80
+ const tooSmall = bmp.width < MIN_IMAGE_EDGE || bmp.height < MIN_IMAGE_EDGE;
81
+ bmp.close();
82
+ if (tooSmall) {
83
+ return {
84
+ error: `${file.name}: image too small (min ${MIN_IMAGE_EDGE}px per edge)`,
85
+ };
86
+ }
87
+ }
88
+ catch {
89
+ // Couldn't measure — fall through and let the size check gate it.
90
+ }
91
+ const data = await blobToBase64(file);
92
+ const bytes = decodedBytesFromBase64(data);
93
+ if (bytes > MAX_IMAGE_BYTES) {
94
+ return { error: `${file.name}: GIF too large (max ${mb(MAX_IMAGE_BYTES)})` };
95
+ }
96
+ return {
97
+ attachment: { data, mediaType: "image/gif" },
98
+ previewUrl: URL.createObjectURL(file),
99
+ bytes,
100
+ };
101
+ }
102
+ if (!type.startsWith("image/")) {
103
+ return { error: `${file.name}: not an image` };
104
+ }
105
+ const decoded = await decodeImage(file);
106
+ if (!decoded) {
107
+ return {
108
+ error: `${file.name}: couldn't read this image (unsupported format?)`,
109
+ };
110
+ }
111
+ const { width, height } = decoded;
112
+ if (!width || !height) {
113
+ return { error: `${file.name}: couldn't read this image` };
114
+ }
115
+ if (width < MIN_IMAGE_EDGE || height < MIN_IMAGE_EDGE) {
116
+ return {
117
+ error: `${file.name}: image too small (min ${MIN_IMAGE_EDGE}px per edge)`,
118
+ };
119
+ }
120
+ // Scale so the longest edge is at most DOWNSCALE_MAX_EDGE.
121
+ const scale = Math.min(1, DOWNSCALE_MAX_EDGE / Math.max(width, height));
122
+ const targetW = Math.max(1, Math.round(width * scale));
123
+ const targetH = Math.max(1, Math.round(height * scale));
124
+ const canvas = document.createElement("canvas");
125
+ canvas.width = targetW;
126
+ canvas.height = targetH;
127
+ const ctx = canvas.getContext("2d");
128
+ if (!ctx) {
129
+ return { error: `${file.name}: canvas unavailable` };
130
+ }
131
+ decoded.draw(ctx, targetW, targetH);
132
+ const blob = await new Promise((resolve) => canvas.toBlob(resolve, "image/jpeg", 0.85));
133
+ if (!blob) {
134
+ return { error: `${file.name}: failed to encode` };
135
+ }
136
+ const data = await blobToBase64(blob);
137
+ const bytes = decodedBytesFromBase64(data);
138
+ if (bytes > MAX_IMAGE_BYTES) {
139
+ return {
140
+ error: `${file.name}: still ${mb(bytes)} after downscale (max ${mb(MAX_IMAGE_BYTES)})`,
141
+ };
142
+ }
143
+ return {
144
+ attachment: { data, mediaType: "image/jpeg" },
145
+ previewUrl: URL.createObjectURL(blob),
146
+ bytes,
147
+ };
148
+ }
149
+ /**
150
+ * Enforce message-level caps against a proposed set of attachments (existing
151
+ * pending + newly added). Returns the accepted subset and per-file rejection
152
+ * reasons; never mutates the input.
153
+ */
154
+ export function validateAttachments(pending) {
155
+ const accepted = [];
156
+ const errors = [];
157
+ let total = 0;
158
+ for (const item of pending) {
159
+ if (accepted.length >= MAX_IMAGES_PER_MESSAGE) {
160
+ errors.push(`${item.name}: over the ${MAX_IMAGES_PER_MESSAGE}-image limit`);
161
+ continue;
162
+ }
163
+ if (total + item.bytes > MAX_TOTAL_IMAGE_BYTES) {
164
+ errors.push(`${item.name}: over the ${mb(MAX_TOTAL_IMAGE_BYTES)} total-size limit`);
165
+ continue;
166
+ }
167
+ total += item.bytes;
168
+ accepted.push(item);
169
+ }
170
+ return { accepted, errors };
171
+ }
172
+ function mb(bytes) {
173
+ return `${(bytes / 1_000_000).toFixed(1)} MB`;
174
+ }
175
+ //# sourceMappingURL=image-attachments.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"image-attachments.js","sourceRoot":"","sources":["../../src/lib/image-attachments.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Thin ceremony wrappers around @simplewebauthn/browser. All server calls go
3
+ * through api-client; success means the server set the session cookie.
4
+ */
5
+ export declare function supportsPasskeys(): boolean;
6
+ export declare function supportsAutofill(): Promise<boolean>;
7
+ /** True for the user dismissing/cancelling the OS passkey prompt. */
8
+ export declare function isUserCancel(err: unknown): boolean;
9
+ /**
10
+ * Full login ceremony. With `useBrowserAutofill`, resolves only if the user
11
+ * picks a passkey from the input's autofill suggestions (conditional UI).
12
+ */
13
+ export declare function loginWithPasskey(opts?: {
14
+ useBrowserAutofill?: boolean;
15
+ }): Promise<void>;
16
+ /** Full registration ceremony (requires an authenticated session). */
17
+ export declare function registerPasskey(label?: string): Promise<void>;
18
+ //# sourceMappingURL=passkeys.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"passkeys.d.ts","sourceRoot":"","sources":["../../src/lib/passkeys.ts"],"names":[],"mappings":"AAQA;;;GAGG;AAEH,wBAAgB,gBAAgB,IAAI,OAAO,CAE1C;AAED,wBAAgB,gBAAgB,IAAI,OAAO,CAAC,OAAO,CAAC,CAEnD;AAED,qEAAqE;AACrE,wBAAgB,YAAY,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAKlD;AAED;;;GAGG;AACH,wBAAsB,gBAAgB,CAAC,IAAI,CAAC,EAAE;IAC5C,kBAAkB,CAAC,EAAE,OAAO,CAAC;CAC9B,GAAG,OAAO,CAAC,IAAI,CAAC,CAOhB;AAED,sEAAsE;AACtE,wBAAsB,eAAe,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAInE"}
@@ -0,0 +1,36 @@
1
+ import { startAuthentication, startRegistration, browserSupportsWebAuthn, browserSupportsWebAuthnAutofill, } from "@simplewebauthn/browser";
2
+ import { api } from "./api-client.js";
3
+ /**
4
+ * Thin ceremony wrappers around @simplewebauthn/browser. All server calls go
5
+ * through api-client; success means the server set the session cookie.
6
+ */
7
+ export function supportsPasskeys() {
8
+ return browserSupportsWebAuthn();
9
+ }
10
+ export function supportsAutofill() {
11
+ return browserSupportsWebAuthnAutofill();
12
+ }
13
+ /** True for the user dismissing/cancelling the OS passkey prompt. */
14
+ export function isUserCancel(err) {
15
+ return (err instanceof Error &&
16
+ (err.name === "NotAllowedError" || err.name === "AbortError"));
17
+ }
18
+ /**
19
+ * Full login ceremony. With `useBrowserAutofill`, resolves only if the user
20
+ * picks a passkey from the input's autofill suggestions (conditional UI).
21
+ */
22
+ export async function loginWithPasskey(opts) {
23
+ const optionsJSON = await api.passkeyLoginOptions();
24
+ const response = await startAuthentication({
25
+ optionsJSON,
26
+ useBrowserAutofill: opts?.useBrowserAutofill ?? false,
27
+ });
28
+ await api.passkeyLoginVerify(response);
29
+ }
30
+ /** Full registration ceremony (requires an authenticated session). */
31
+ export async function registerPasskey(label) {
32
+ const optionsJSON = await api.passkeyRegisterOptions();
33
+ const response = await startRegistration({ optionsJSON });
34
+ await api.passkeyRegisterVerify(response, label);
35
+ }
36
+ //# sourceMappingURL=passkeys.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"passkeys.js","sourceRoot":"","sources":["../../src/lib/passkeys.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,mBAAmB,EACnB,iBAAiB,EACjB,uBAAuB,EACvB,+BAA+B,GAChC,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,GAAG,EAAE,MAAM,iBAAiB,CAAC;AAEtC;;;GAGG;AAEH,MAAM,UAAU,gBAAgB;IAC9B,OAAO,uBAAuB,EAAE,CAAC;AACnC,CAAC;AAED,MAAM,UAAU,gBAAgB;IAC9B,OAAO,+BAA+B,EAAE,CAAC;AAC3C,CAAC;AAED,qEAAqE;AACrE,MAAM,UAAU,YAAY,CAAC,GAAY;IACvC,OAAO,CACL,GAAG,YAAY,KAAK;QACpB,CAAC,GAAG,CAAC,IAAI,KAAK,iBAAiB,IAAI,GAAG,CAAC,IAAI,KAAK,YAAY,CAAC,CAC9D,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,IAEtC;IACC,MAAM,WAAW,GAAG,MAAM,GAAG,CAAC,mBAAmB,EAAE,CAAC;IACpD,MAAM,QAAQ,GAAG,MAAM,mBAAmB,CAAC;QACzC,WAAW;QACX,kBAAkB,EAAE,IAAI,EAAE,kBAAkB,IAAI,KAAK;KACtD,CAAC,CAAC;IACH,MAAM,GAAG,CAAC,kBAAkB,CAAC,QAAQ,CAAC,CAAC;AACzC,CAAC;AAED,sEAAsE;AACtE,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,KAAc;IAClD,MAAM,WAAW,GAAG,MAAM,GAAG,CAAC,sBAAsB,EAAE,CAAC;IACvD,MAAM,QAAQ,GAAG,MAAM,iBAAiB,CAAC,EAAE,WAAW,EAAE,CAAC,CAAC;IAC1D,MAAM,GAAG,CAAC,qBAAqB,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;AACnD,CAAC"}
@@ -0,0 +1,53 @@
1
+ import type { RenderRequest } from "@schlessera/brain-ui-sdk/protocol";
2
+ export type ShareKind = "file" | "text" | "richtext";
3
+ /**
4
+ * True when the browser supports navigator.share at all. Note this doesn't
5
+ * guarantee that a specific payload is shareable — call canShareFiles too.
6
+ */
7
+ export declare function isShareSupported(): boolean;
8
+ /**
9
+ * Share a File via the OS share sheet. Falls back to a browser download
10
+ * when the platform can't share files (desktop Chrome / Firefox).
11
+ *
12
+ * Returns true if the share dialog (or fallback) was triggered, false if
13
+ * the user dismissed it.
14
+ */
15
+ export declare function shareFile(file: File, opts?: {
16
+ title?: string;
17
+ text?: string;
18
+ }): Promise<boolean>;
19
+ /**
20
+ * Share plain text / a URL via the OS share sheet. Falls back to clipboard
21
+ * copy when unavailable.
22
+ */
23
+ export declare function shareText(data: {
24
+ text: string;
25
+ title?: string;
26
+ url?: string;
27
+ }): Promise<boolean>;
28
+ /**
29
+ * Copy rich text (HTML + plain) to the clipboard. Best-effort: on browsers
30
+ * that don't support ClipboardItem, falls back to plain text only.
31
+ */
32
+ export declare function copyRichText(html: string, plain: string): Promise<boolean>;
33
+ /**
34
+ * Fetch a URL into a File. Used to wrap the existing
35
+ * /api/files/content?raw=1 endpoint for share-the-bytes flows.
36
+ */
37
+ export declare function fetchAsFile(url: string, filename: string, mime?: string): Promise<File>;
38
+ /**
39
+ * POST to /api/render and return the resulting File. Throws on non-2xx.
40
+ */
41
+ export declare function renderToFile(req: RenderRequest, filename: string): Promise<File>;
42
+ /**
43
+ * One-call helper: render content to PNG/PDF and dispatch the share sheet.
44
+ */
45
+ export declare function renderAndShare(opts: {
46
+ content: string;
47
+ contentType: RenderRequest["contentType"];
48
+ format: RenderRequest["format"];
49
+ filename: string;
50
+ title?: string;
51
+ text?: string;
52
+ }): Promise<boolean>;
53
+ //# sourceMappingURL=share.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"share.d.ts","sourceRoot":"","sources":["../../src/lib/share.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mCAAmC,CAAC;AAEvE,MAAM,MAAM,SAAS,GAAG,MAAM,GAAG,MAAM,GAAG,UAAU,CAAC;AAErD;;;GAGG;AACH,wBAAgB,gBAAgB,IAAI,OAAO,CAE1C;AAsBD;;;;;;GAMG;AACH,wBAAsB,SAAS,CAC7B,IAAI,EAAE,IAAI,EACV,IAAI,GAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAO,GAC3C,OAAO,CAAC,OAAO,CAAC,CAalB;AAED;;;GAGG;AACH,wBAAsB,SAAS,CAC7B,IAAI,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,GACnD,OAAO,CAAC,OAAO,CAAC,CAiBlB;AAED;;;GAGG;AACH,wBAAsB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAgBhF;AAED;;;GAGG;AACH,wBAAsB,WAAW,CAC/B,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,MAAM,EAChB,IAAI,CAAC,EAAE,MAAM,GACZ,OAAO,CAAC,IAAI,CAAC,CAKf;AAED;;GAEG;AACH,wBAAsB,YAAY,CAChC,GAAG,EAAE,aAAa,EAClB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,IAAI,CAAC,CAsBf;AAED;;GAEG;AACH,wBAAsB,cAAc,CAAC,IAAI,EAAE;IACzC,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,aAAa,CAAC,aAAa,CAAC,CAAC;IAC1C,MAAM,EAAE,aAAa,CAAC,QAAQ,CAAC,CAAC;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,GAAG,OAAO,CAAC,OAAO,CAAC,CAMnB"}