@harperfast/harper 5.2.8 → 5.2.10

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 (189) hide show
  1. package/config-root.schema.json +10 -0
  2. package/dist/resources/DatabaseTransaction.d.ts +3 -0
  3. package/dist/resources/DatabaseTransaction.js +90 -2
  4. package/dist/resources/DatabaseTransaction.js.map +1 -1
  5. package/dist/resources/PrimaryRocksDatabase.js +2 -1
  6. package/dist/resources/PrimaryRocksDatabase.js.map +1 -1
  7. package/dist/resources/RocksIndexStore.js +2 -1
  8. package/dist/resources/RocksIndexStore.js.map +1 -1
  9. package/dist/resources/Table.js +13 -5
  10. package/dist/resources/Table.js.map +1 -1
  11. package/dist/resources/auditStore.js +142 -53
  12. package/dist/resources/auditStore.js.map +1 -1
  13. package/dist/resources/databases.d.ts +9 -0
  14. package/dist/resources/databases.js +315 -76
  15. package/dist/resources/databases.js.map +1 -1
  16. package/dist/resources/search.d.ts +1 -0
  17. package/dist/resources/search.js +41 -13
  18. package/dist/resources/search.js.map +1 -1
  19. package/dist/server/storageReclamation.d.ts +7 -0
  20. package/dist/server/storageReclamation.js +10 -0
  21. package/dist/server/storageReclamation.js.map +1 -1
  22. package/dist/server/threads/manageThreads.d.ts +1 -0
  23. package/dist/server/threads/manageThreads.js +7 -0
  24. package/dist/server/threads/manageThreads.js.map +1 -1
  25. package/dist/utility/hdbTerms.d.ts +2 -0
  26. package/dist/utility/hdbTerms.js +2 -0
  27. package/dist/utility/hdbTerms.js.map +1 -1
  28. package/dist/utility/rocksMemoryConfig.js +7 -4
  29. package/dist/utility/rocksMemoryConfig.js.map +1 -1
  30. package/dist/validation/configValidator.js +2 -0
  31. package/dist/validation/configValidator.js.map +1 -1
  32. package/npm-shrinkwrap.json +41 -41
  33. package/package.json +2 -2
  34. package/resources/DatabaseTransaction.ts +88 -2
  35. package/resources/PrimaryRocksDatabase.ts +2 -1
  36. package/resources/RocksIndexStore.ts +2 -1
  37. package/resources/Table.ts +13 -5
  38. package/resources/auditStore.ts +144 -52
  39. package/resources/databases.ts +296 -70
  40. package/resources/search.ts +43 -14
  41. package/server/storageReclamation.ts +10 -0
  42. package/server/threads/manageThreads.js +7 -0
  43. package/studio/web/assets/Chat-Br06zdMA.js +2267 -0
  44. package/studio/web/assets/FloatingChat-BWImX5fA.js +23 -0
  45. package/studio/web/assets/{abnfDiagram-VCTEODGH-C0_BAZyO.js → abnfDiagram-VCTEODGH-B0BebmD2.js} +1 -1
  46. package/studio/web/assets/{alertDialog-DIHt7Z0r.js → alertDialog-CQyAJJhl.js} +1 -1
  47. package/studio/web/assets/{apiToken-CrPb_98N.js → apiToken-DN0nmDsq.js} +1 -1
  48. package/studio/web/assets/applications-kSxVoyeU.js +296 -0
  49. package/studio/web/assets/architecture-7GRP2DOG-LB-MLAAb.js +1 -0
  50. package/studio/web/assets/{architectureDiagram-5GKGNRK7-BWzrASgm.js → architectureDiagram-5GKGNRK7-7SW3GD-K.js} +1 -1
  51. package/studio/web/assets/authStore-C3Nfubqr.js +3 -0
  52. package/studio/web/assets/{blockDiagram-NRAW4CY4-BdJX9Khj.js → blockDiagram-I7D4REHJ-BqguiadH.js} +2 -2
  53. package/studio/web/assets/{button-DhiX-njv.js → button-BIsUKRZq.js} +2 -2
  54. package/studio/web/assets/{c4Diagram-UCG6FXSJ-CI6MzGmQ.js → c4Diagram-7LVT6UL2-LBNf8t_X.js} +1 -1
  55. package/studio/web/assets/channel-yictG-U-.js +1 -0
  56. package/studio/web/assets/{chevron-up-Df2c8uoU.js → chevron-up-DtKGqDn3.js} +1 -1
  57. package/studio/web/assets/{chunk-TEH6E4GO-P87k5mNi.js → chunk-4HAMMTFA-DWtTut21.js} +1 -1
  58. package/studio/web/assets/{chunk-75Z2AOVW-BT8tVmks.js → chunk-75Z2AOVW-QGQD6th2.js} +1 -1
  59. package/studio/web/assets/{chunk-DU6HZSFF-9kAOOmI6.js → chunk-DU6HZSFF-Chq20Ba5.js} +1 -1
  60. package/studio/web/assets/{chunk-F27PBJKO-BW7ao8AY.js → chunk-F27PBJKO-BVA5EPhV.js} +1 -1
  61. package/studio/web/assets/{chunk-GMAD6QVW-BNyXpoQO.js → chunk-GMAD6QVW-BeS7S07A.js} +1 -1
  62. package/studio/web/assets/{chunk-OBVCFTLP-D4wWOqDQ.js → chunk-GVQU2GXP-sbwVIQ8i.js} +1 -1
  63. package/studio/web/assets/{chunk-G27WJ6UU-COyLMcgK.js → chunk-IMKFNOWR-Bnh3tAVd.js} +1 -1
  64. package/studio/web/assets/{chunk-JQ64N6SF-Cyz1IeLf.js → chunk-L3NEJ4N5-COfUyKII.js} +1 -1
  65. package/studio/web/assets/chunk-OSK3NFVY-ByciRftO.js +10 -0
  66. package/studio/web/assets/{chunk-P2QGCYS3-DmIFY4d7.js → chunk-P2QGCYS3-CP1VhG_c.js} +1 -1
  67. package/studio/web/assets/{chunk-POPQ4Y6H-BPrvMyKz.js → chunk-POPQ4Y6H-ClWhhkwW.js} +1 -1
  68. package/studio/web/assets/{chunk-PWAF6VOD-2zB6IW9i.js → chunk-PWAF6VOD-1z1THyS5.js} +1 -1
  69. package/studio/web/assets/{chunk-RHFEMEQ7-2FgyI8YU.js → chunk-SHT3W25Y-LpQkMsah.js} +2 -2
  70. package/studio/web/assets/{chunk-SVP7TREG-FwtbH2QC.js → chunk-SVP7TREG-jtdAHw0S.js} +1 -1
  71. package/studio/web/assets/{chunk-LCL6LL3I-HOzK_ppE.js → chunk-TICWLB2K-VOwzetX-.js} +1 -1
  72. package/studio/web/assets/classDiagram-ZZMXUADV-VaEwSy_g.js +1 -0
  73. package/studio/web/assets/classDiagram-v2-VYDZK3BY-VaEwSy_g.js +1 -0
  74. package/studio/web/assets/{createLucideIcon-BKGPfjm2.js → createLucideIcon-CzW9508A.js} +1 -1
  75. package/studio/web/assets/{cssMode-D8ceA4av.js → cssMode-C1JeufH5.js} +1 -1
  76. package/studio/web/assets/{cynefin-OW5HDTMX-BRkpLFQV.js → cynefin-OW5HDTMX-BbdbCvub.js} +1 -1
  77. package/studio/web/assets/{cynefinDiagram-5FMLGOSQ-CHT1DaX6.js → cynefinDiagram-5FMLGOSQ-TP-aIqbt.js} +1 -1
  78. package/studio/web/assets/{dagre-3AP2YEHR-DpUXBh63.js → dagre-GXQ25YYZ-DShnGpGo.js} +1 -1
  79. package/studio/web/assets/{diagram-S7CK7UJ4-BuymVFZT.js → diagram-S7CK7UJ4-aoCVTtcy.js} +1 -1
  80. package/studio/web/assets/{diagram-UQ7AKVKN-CyP148RM.js → diagram-UQ7AKVKN-DglXtQ6x.js} +1 -1
  81. package/studio/web/assets/{diagram-VSXAHHWV-CoCAg3M9.js → diagram-VSXAHHWV-fhEdmkwM.js} +1 -1
  82. package/studio/web/assets/{diagram-VX7I27RA-BpOqCFca.js → diagram-VX7I27RA-DccVJet6.js} +1 -1
  83. package/studio/web/assets/{diagram-Z3DM3KII-Bfpw7Vbj.js → diagram-Z3DM3KII-D-RyJJb7.js} +1 -1
  84. package/studio/web/assets/{dialog-CBf0Mr1d.js → dialog-Cn2uWgD4.js} +1 -1
  85. package/studio/web/assets/{dist-lkA3O3eM.js → dist-DP8UjMB_.js} +1 -1
  86. package/studio/web/assets/{download-BtTOBem-.js → download-B5T5r7ss.js} +1 -1
  87. package/studio/web/assets/{ebnfDiagram-PWID7BFC-DS_6aWqL.js → ebnfDiagram-PWID7BFC-DJGpIpz_.js} +1 -1
  88. package/studio/web/assets/{editor-C-jlLd1G.js → editor-qoo9CrGO.js} +1 -1
  89. package/studio/web/assets/{erDiagram-SSCWMZ5O-DJNk6Fgw.js → erDiagram-RLTQ6QDP-CIfNlgkC.js} +1 -1
  90. package/studio/web/assets/eventmodeling-NTZA5JFV-CLxnp2CR.js +1 -0
  91. package/studio/web/assets/flowDiagram-HODETNUW-BIbhmz9f.js +1 -0
  92. package/studio/web/assets/{ganttDiagram-EL5Y4UJY-2pOExxMY.js → ganttDiagram-EL5Y4UJY-BxToTzzD.js} +1 -1
  93. package/studio/web/assets/{getAnalytics-D4LKGeVy.js → getAnalytics-GHK8ORfM.js} +1 -1
  94. package/studio/web/assets/{gitGraph-4MIJSDKK-CH5ZxwzF.js → gitGraph-4MIJSDKK-D2s2w8lE.js} +1 -1
  95. package/studio/web/assets/{gitGraphDiagram-WWUBYQGX-DVIsIhbO.js → gitGraphDiagram-WWUBYQGX-Dwntd4-x.js} +1 -1
  96. package/studio/web/assets/{html-BnuKFPjv.js → html-Dt4IIy04.js} +1 -1
  97. package/studio/web/assets/{htmlMode-DXM6YYUw.js → htmlMode-DXgKKr4C.js} +1 -1
  98. package/studio/web/assets/index-6onkYFOG.js +824 -0
  99. package/studio/web/assets/{index-Cxj2_wsl.css → index-7RMEgVG1.css} +1 -1
  100. package/studio/web/assets/index.lazy-BrCFnpNJ.js +2 -0
  101. package/studio/web/assets/{info-A6RAGUB7-CPQfTnaG.js → info-A6RAGUB7-DYjkvb0C.js} +1 -1
  102. package/studio/web/assets/{infoDiagram-RXCK75RN-DlwLYlwm.js → infoDiagram-27XIBGKW-Bnp1FJE5.js} +1 -1
  103. package/studio/web/assets/{ishikawaDiagram-5VMMS53U-BRXRp29U.js → ishikawaDiagram-5VMMS53U-D9Xh2r6X.js} +1 -1
  104. package/studio/web/assets/{javascript-CAuAkYxc.js → javascript-DNCQGUBc.js} +1 -1
  105. package/studio/web/assets/{journeyDiagram-EYS64GPL-B0ou8k0n.js → journeyDiagram-3NMN7TZE-CokIi6ll.js} +2 -2
  106. package/studio/web/assets/{jsonMode-Dny8hrU7.js → jsonMode-CR6HWruP.js} +1 -1
  107. package/studio/web/assets/{kanban-definition-3QL26DDD-uYg7iYzp.js → kanban-definition-UXKFOSKX-CukSFJfX.js} +1 -1
  108. package/studio/web/assets/{languageServices-D1uNqC6s.js → languageServices-BM4fI4rS.js} +1 -1
  109. package/studio/web/assets/{lspLanguageFeatures-Bh-bvkyK.js → lspLanguageFeatures-DSa1ttcD.js} +1 -1
  110. package/studio/web/assets/{mermaid-parser.core-Ck-fC8b7.js → mermaid-parser.core-BlEsOWNO.js} +3 -3
  111. package/studio/web/assets/{mermaid.core-CP8aNNYm.js → mermaid.core-BlkGaMIH.js} +5 -5
  112. package/studio/web/assets/{mindmap-definition-FBJOCRG2-CgTZ-rit.js → mindmap-definition-YA3MSWOX-IprMc_0j.js} +1 -1
  113. package/studio/web/assets/{notifications-DsE0S3zT.js → notifications-BHXLnh6x.js} +1 -1
  114. package/studio/web/assets/notifications-CUmtIA6z.js +1 -0
  115. package/studio/web/assets/{packet-AYTQ26CC-DEyoPtPb.js → packet-AYTQ26CC-Bi3V04Zi.js} +1 -1
  116. package/studio/web/assets/{pegDiagram-XKGWAZYB-DrD-7sD9.js → pegDiagram-XKGWAZYB-BNuPDLZY.js} +1 -1
  117. package/studio/web/assets/{pie-WAS4IAKB-wjj-EI1d.js → pie-WAS4IAKB-_6DoDbng.js} +1 -1
  118. package/studio/web/assets/{pieDiagram-E7YTZNPT-GntqDCzv.js → pieDiagram-E7YTZNPT-DqNb6Ht2.js} +1 -1
  119. package/studio/web/assets/{profile-BIeCZr-w.js → profile-8BeFSF3j.js} +1 -1
  120. package/studio/web/assets/{quadrantDiagram-AXDQQJYC-0UeqXQGd.js → quadrantDiagram-AXDQQJYC-BGH9E2YR.js} +1 -1
  121. package/studio/web/assets/{radar-RG4KPBEZ-DFSA5h7k.js → radar-RG4KPBEZ-DDdVczcL.js} +1 -1
  122. package/studio/web/assets/{railroad-74A4TZTK-CaOUG9wR.js → railroad-74A4TZTK-BJUP4Jds.js} +1 -1
  123. package/studio/web/assets/railroad-abnf-HS5TGJTU-Bm3L1L0h.js +1 -0
  124. package/studio/web/assets/railroad-ebnf-LZEXJU2U-CKzLGlkw.js +1 -0
  125. package/studio/web/assets/railroad-peg-WCYAUIDC-S8xLjslx.js +1 -0
  126. package/studio/web/assets/{railroadDiagram-O6MQD6OU-yHUELZaV.js → railroadDiagram-O6MQD6OU-DGTPh2KZ.js} +1 -1
  127. package/studio/web/assets/{regions-B5lGduv5.js → regions-C8qR0HhD.js} +1 -1
  128. package/studio/web/assets/{register-Cvc1TpmQ.js → register-B4n5i0SD.js} +3 -3
  129. package/studio/web/assets/{requirementDiagram-EFPCY7ZU-DNEGFjuW.js → requirementDiagram-BXWQKSXE-BJnO6uLz.js} +1 -1
  130. package/studio/web/assets/{sankeyDiagram-P5KCCOFB-DpyAmSVR.js → sankeyDiagram-P5KCCOFB-0vSOdymH.js} +1 -1
  131. package/studio/web/assets/{sequenceDiagram-WJ2MYXX4-TyaT7xNk.js → sequenceDiagram-WJ2MYXX4-hETizDWE.js} +1 -1
  132. package/studio/web/assets/{setComponentFile-D8ZLDWhU.js → setComponentFile-g0_B0lgX.js} +1 -1
  133. package/studio/web/assets/{setup-D2az-Ue_.js → setup-B0CTj_Q5.js} +2 -2
  134. package/studio/web/assets/{stateDiagram-HBIQ2CUA-CeEdTArZ.js → stateDiagram-D77RDMKH-CdYQ_KtC.js} +1 -1
  135. package/studio/web/assets/stateDiagram-v2-MP3YSRHH-CdKuzQMT.js +1 -0
  136. package/studio/web/assets/status-C6Yib7-K.js +61 -0
  137. package/studio/web/assets/{swimlanes-XN3QIQJK-B54FmF46.js → swimlanes-42K2YHIH-B8cHIpU4.js} +1 -1
  138. package/studio/web/assets/swimlanesDiagram-VR7AAH4N-DmOSJwaH.js +8 -0
  139. package/studio/web/assets/{tabs-B_G5zscN.js → tabs-BrHu7gJi.js} +1 -1
  140. package/studio/web/assets/{timeline-definition-24CTP7MA-D-a9ujbo.js → timeline-definition-24CTP7MA-BJWYSXqF.js} +1 -1
  141. package/studio/web/assets/{toggleHighContrast-BdIEw2rK.js → toggleHighContrast-Dgta7bVi.js} +1 -1
  142. package/studio/web/assets/{treeView-Q6P3EWNA-CrW_6JnS.js → treeView-Q6P3EWNA-qxe_v6CQ.js} +1 -1
  143. package/studio/web/assets/{treemap-WGGIJYW6-BxyYLdP_.js → treemap-WGGIJYW6-dDo97XXF.js} +1 -1
  144. package/studio/web/assets/{tsMode-CulNMwI9.js → tsMode-CH_jHvU-.js} +1 -1
  145. package/studio/web/assets/{typescript-BpRqjmvQ.js → typescript-Co9LCXd5.js} +1 -1
  146. package/studio/web/assets/{useEntityRestURL-C7x-Yz9r.js → useEntityRestURL-wKC8NsC_.js} +1 -1
  147. package/studio/web/assets/{useLocalStorage-Dtj1QS8_.js → useLocalStorage-BqMR3D8_.js} +1 -1
  148. package/studio/web/assets/vendor-core-c2JRRJpV.js +58 -0
  149. package/studio/web/assets/vendor-datadog-CLUcJXOo.js +6 -0
  150. package/studio/web/assets/{vendor-react-Dyj4O3HE.js → vendor-react-CJV_K1u4.js} +1 -1
  151. package/studio/web/assets/vendor-tanstack-DxzraizX.js +1 -0
  152. package/studio/web/assets/{vendor-ui-vhu-UHhF.js → vendor-ui-BUjK0h8a.js} +2 -2
  153. package/studio/web/assets/{vennDiagram-4TSXK5OY-Cy7s7Mpy.js → vennDiagram-4TSXK5OY-A3i-lCdl.js} +1 -1
  154. package/studio/web/assets/{wardley-WFR3VGLG-BeBL35g2.js → wardley-WFR3VGLG-B0ik-_6g.js} +1 -1
  155. package/studio/web/assets/{wardleyDiagram-VM6X3IG4-BylmIGSg.js → wardleyDiagram-VM6X3IG4-CjrkKWUR.js} +1 -1
  156. package/studio/web/assets/{workers-B2WpJDK9.js → workers-CWeLxCXA.js} +1 -1
  157. package/studio/web/assets/x-DIzaLEdK.js +1 -0
  158. package/studio/web/assets/{xml-CZnimVSX.js → xml-BadC-0Rk.js} +1 -1
  159. package/studio/web/assets/{xychartDiagram-S5SC5T6Z-CoKALMXr.js → xychartDiagram-S5SC5T6Z-Biok4GYV.js} +1 -1
  160. package/studio/web/assets/{yaml-BwNuyZS-.js → yaml-BiUfxPbC.js} +1 -1
  161. package/studio/web/index.html +14 -14
  162. package/utility/hdbTerms.ts +2 -0
  163. package/utility/rocksMemoryConfig.ts +7 -4
  164. package/validation/configValidator.ts +2 -0
  165. package/studio/web/assets/Chat-DDlysEi_.js +0 -2067
  166. package/studio/web/assets/FloatingChat-DdJ3DZJX.js +0 -23
  167. package/studio/web/assets/applications-C6Y4nL_X.js +0 -296
  168. package/studio/web/assets/architecture-7GRP2DOG-DNdx5tEU.js +0 -1
  169. package/studio/web/assets/authStore-qKmCZcaf.js +0 -3
  170. package/studio/web/assets/channel-DtCV8PTL.js +0 -1
  171. package/studio/web/assets/chunk-R7TYR2AO-Irip67yr.js +0 -10
  172. package/studio/web/assets/classDiagram-DTDB5LWJ-DbO_dCNE.js +0 -1
  173. package/studio/web/assets/classDiagram-v2-JRS7N3AN-DbO_dCNE.js +0 -1
  174. package/studio/web/assets/eventmodeling-NTZA5JFV-5jbe4A5P.js +0 -1
  175. package/studio/web/assets/flowDiagram-A5DVABFB-Dp9Ezlow.js +0 -1
  176. package/studio/web/assets/index-BtTvoLf8.js +0 -824
  177. package/studio/web/assets/index.lazy-PVbC6xQh.js +0 -2
  178. package/studio/web/assets/notifications-DPTOF-SX.js +0 -1
  179. package/studio/web/assets/railroad-abnf-HS5TGJTU-Bc0Qi0WH.js +0 -1
  180. package/studio/web/assets/railroad-ebnf-LZEXJU2U-G8rVVZ2C.js +0 -1
  181. package/studio/web/assets/railroad-peg-WCYAUIDC-CrehKBhC.js +0 -1
  182. package/studio/web/assets/stateDiagram-v2-4QOOHH4V-D4tuw9Su.js +0 -1
  183. package/studio/web/assets/status-BJegPrWN.js +0 -61
  184. package/studio/web/assets/swimlanesDiagram-VK2B7HYN-XOhmNEvq.js +0 -8
  185. package/studio/web/assets/vendor-core-RCcadM3e.js +0 -73
  186. package/studio/web/assets/vendor-datadog-BRv-mOv1.js +0 -6
  187. package/studio/web/assets/vendor-tanstack-BiFWSB3W.js +0 -1
  188. package/studio/web/assets/x-B9o9hsep.js +0 -1
  189. /package/studio/web/assets/{sizeCapture-X5ZJPWSS-B0uUizjq.js → sizeCapture-INFHLROL-B0uUizjq.js} +0 -0
@@ -1,2067 +0,0 @@
1
- import{r as e,t}from"./rolldown-runtime-hePW80VL.js";import{C as n,S as r,_ as i,b as a,c as o,f as s,g as c,h as l,i as u,l as d,m as f,n as p,o as m,p as h,r as g,s as _,u as v,v as ee,x as te,y}from"./vendor-core-RCcadM3e.js";import{i as b,t as x}from"./button-DhiX-njv.js";import{H as ne,L as re,k as ie,z as ae}from"./vendor-tanstack-BiFWSB3W.js";import{a as oe}from"./vendor-datadog-BRv-mOv1.js";import{r as se}from"./vendor-react-Dyj4O3HE.js";import{n as ce}from"./setSessionStorage-B0bf71m4.js";import{It as le}from"./vendor-ui-vhu-UHhF.js";import{t as S}from"./createLucideIcon-BKGPfjm2.js";import{n as ue,r as de,t as fe}from"./chevron-up-Df2c8uoU.js";import{c as pe,f as me,g as he,h as ge,i as _e,l as ve,m as ye,p as be,r as xe,t as Se,u as Ce}from"./setComponentFile-D8ZLDWhU.js";import{t as we}from"./x-B9o9hsep.js";import{n as Te}from"./setLocalStorage-D_kflv4U.js";import{t as Ee}from"./useLocalStorage-Dtj1QS8_.js";import{An as De,En as Oe,Er as ke,H as Ae,It as je,Mt as Me,Nr as Ne,Nt as Pe,Or as Fe,Pt as Ie,V as Le,Z as Re,br as ze,c as Be,cr as Ve,d as He,dr as Ue,f as We,ft as Ge,gr as Ke,in as qe,kr as Je,m as Ye,or as Xe,pr as Ze,ur as Qe,ut as $e,xr as et,yt as tt}from"./index-BtTvoLf8.js";import{t as nt}from"./useEntityRestURL-C7x-Yz9r.js";import{n as rt,t as it}from"./FloatingChat-DdJ3DZJX.js";import{n as at}from"./getAnalytics-D4LKGeVy.js";var ot=S(`between-horizontal-start`,[[`rect`,{width:`13`,height:`7`,x:`8`,y:`3`,rx:`1`,key:`pkso9a`}],[`path`,{d:`m2 9 3 3-3 3`,key:`1agib5`}],[`rect`,{width:`13`,height:`7`,x:`8`,y:`14`,rx:`1`,key:`1q5fc1`}]]),st=S(`book`,[[`path`,{d:`M4 19.5v-15A2.5 2.5 0 0 1 6.5 2H19a1 1 0 0 1 1 1v18a1 1 0 0 1-1 1H6.5a1 1 0 0 1 0-5H20`,key:`k3hazp`}]]),ct=S(`chart-area`,[[`path`,{d:`M3 3v16a2 2 0 0 0 2 2h16`,key:`c24i48`}],[`path`,{d:`M7 11.207a.5.5 0 0 1 .146-.353l2-2a.5.5 0 0 1 .708 0l3.292 3.292a.5.5 0 0 0 .708 0l4.292-4.292a.5.5 0 0 1 .854.353V16a1 1 0 0 1-1 1H8a1 1 0 0 1-1-1z`,key:`q0gr47`}]]),lt=S(`circle-x`,[[`circle`,{cx:`12`,cy:`12`,r:`10`,key:`1mglay`}],[`path`,{d:`m15 9-6 6`,key:`1uzhvr`}],[`path`,{d:`m9 9 6 6`,key:`z0biqf`}]]),ut=S(`file-pen`,[[`path`,{d:`M12.659 22H18a2 2 0 0 0 2-2V8a2.4 2.4 0 0 0-.706-1.706l-3.588-3.588A2.4 2.4 0 0 0 14 2H6a2 2 0 0 0-2 2v9.34`,key:`o6klzx`}],[`path`,{d:`M14 2v5a1 1 0 0 0 1 1h5`,key:`wfsgrz`}],[`path`,{d:`M10.378 12.622a1 1 0 0 1 3 3.003L8.36 20.637a2 2 0 0 1-.854.506l-2.867.837a.5.5 0 0 1-.62-.62l.836-2.869a2 2 0 0 1 .506-.853z`,key:`zhnas1`}]]),dt=S(`logs`,[[`path`,{d:`M3 5h1`,key:`1mv5vm`}],[`path`,{d:`M3 12h1`,key:`lp3yf2`}],[`path`,{d:`M3 19h1`,key:`w6f3n9`}],[`path`,{d:`M8 5h1`,key:`1nxr5w`}],[`path`,{d:`M8 12h1`,key:`1con00`}],[`path`,{d:`M8 19h1`,key:`k7p10e`}],[`path`,{d:`M13 5h8`,key:`a7qcls`}],[`path`,{d:`M13 12h8`,key:`h98zly`}],[`path`,{d:`M13 19h8`,key:`c3s6r1`}]]),ft=S(`message-square-heart`,[[`path`,{d:`M22 17a2 2 0 0 1-2 2H6.828a2 2 0 0 0-1.414.586l-2.202 2.202A.71.71 0 0 1 2 21.286V5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2z`,key:`18887p`}],[`path`,{d:`M7.5 9.5c0 .687.265 1.383.697 1.844l3.009 3.264a1.14 1.14 0 0 0 .407.314 1 1 0 0 0 .783-.004 1.14 1.14 0 0 0 .398-.31l3.008-3.264A2.77 2.77 0 0 0 16.5 9.5 2.5 2.5 0 0 0 12 8a2.5 2.5 0 0 0-4.5 1.5`,key:`1faxuh`}]]),pt=S(`send`,[[`path`,{d:`M14.536 21.686a.5.5 0 0 0 .937-.024l6.5-19a.496.496 0 0 0-.635-.635l-19 6.5a.5.5 0 0 0-.024.937l7.93 3.18a2 2 0 0 1 1.112 1.11z`,key:`1ffxy3`}],[`path`,{d:`m21.854 2.147-10.94 10.939`,key:`12cjpa`}]]),mt=S(`wrench`,[[`path`,{d:`M14.7 6.3a1 1 0 0 0 0 1.4l1.6 1.6a1 1 0 0 0 1.4 0l3.106-3.105c.32-.322.863-.22.983.218a6 6 0 0 1-8.259 7.057l-7.91 7.91a1 1 0 0 1-2.999-3l7.91-7.91a6 6 0 0 1 7.057-8.259c.438.12.54.662.219.984z`,key:`1ngwbx`}]]);async function ht(){await b.delete(`/Chat/Messages/`)}var C=e(oe(),1),w=se();function gt({setMessages:e}){let[t,n]=(0,C.useState)(!1),r=(0,C.useCallback)(async()=>{if(!t){n(!0);try{await ht(),e([])}catch(e){console.error(`Failed to clear chat:`,e)}finally{n(!1)}}},[t,e]);return(0,w.jsxs)(`button`,{type:`button`,className:`clear-chat-button gap-1`,onClick:r,disabled:t,title:`Clear chat`,children:[t?(0,w.jsx)(ze,{className:`animate-spin`,size:18}):(0,w.jsx)(Qe,{size:18}),`Clear`]})}async function _t(){let{data:e}=await b.get(`/Chat/Messages/`);return e}var vt=`vercel.ai.error`,yt=Symbol.for(vt),bt,xt,T=class e extends (xt=Error,bt=yt,xt){constructor({name:e,message:t,cause:n}){super(t),this[bt]=!0,this.name=e,this.cause=n}static isInstance(t){return e.hasMarker(t,vt)}static hasMarker(e,t){let n=Symbol.for(t);return typeof e==`object`&&!!e&&n in e&&typeof e[n]==`boolean`&&e[n]===!0}};function St(e){return e==null?`unknown error`:typeof e==`string`?e:e instanceof Error?e.toString():JSON.stringify(e)}var Ct=`AI_InvalidArgumentError`,wt=`vercel.ai.error.${Ct}`,Tt=Symbol.for(wt),Et,Dt,Ot=class extends (Dt=T,Et=Tt,Dt){constructor({message:e,cause:t,argument:n}){super({name:Ct,message:e,cause:t}),this[Et]=!0,this.argument=n}static isInstance(e){return T.hasMarker(e,wt)}},kt=`AI_JSONParseError`,At=`vercel.ai.error.${kt}`,jt=Symbol.for(At),Mt,Nt,Pt=class extends (Nt=T,Mt=jt,Nt){constructor({text:e,cause:t}){super({name:kt,message:`JSON parsing failed: Text: ${e}.
2
- Error message: ${St(t)}`,cause:t}),this[Mt]=!0,this.text=e}static isInstance(e){return T.hasMarker(e,At)}},Ft=`AI_TypeValidationError`,It=`vercel.ai.error.${Ft}`,Lt=Symbol.for(It),Rt,zt,E=class e extends (zt=T,Rt=Lt,zt){constructor({value:e,cause:t,context:n}){let r=`Type validation failed`;if(n?.field&&(r+=` for ${n.field}`),n?.entityName||n?.entityId){r+=` (`;let e=[];n.entityName&&e.push(n.entityName),n.entityId&&e.push(`id: "${n.entityId}"`),r+=e.join(`, `),r+=`)`}super({name:Ft,message:`${r}: Value: ${JSON.stringify(e)}.
3
- Error message: ${St(t)}`,cause:t}),this[Rt]=!0,this.value=e,this.context=n}static isInstance(e){return T.hasMarker(e,It)}static wrap({value:t,cause:n,context:r}){return e.isInstance(n)&&n.value===t&&n.context?.field===r?.field&&n.context?.entityName===r?.entityName&&n.context?.entityId===r?.entityId?n:new e({value:t,cause:n,context:r})}},Bt=class extends Error{constructor(e,t){super(e),this.name=`ParseError`,this.type=t.type,this.field=t.field,this.value=t.value,this.line=t.line}},Vt=10,Ht=13,D=32;function Ut(e){}function Wt(e){if(typeof e==`function`)throw TypeError("`config` must be an object, got a function instead. Did you mean `createParser({onEvent: fn})`?");let{onEvent:t=Ut,onError:n=Ut,onRetry:r=Ut,onComment:i,maxBufferSize:a}=e,o=[],s=0,c=!0,l,u=``,d=0,f,p=!1;function m(e){if(p)throw Error("Cannot feed parser: it was terminated after exceeding the configured max buffer size. Call `reset()` to resume parsing.");if(c&&(c=!1,e.charCodeAt(0)===239&&e.charCodeAt(1)===187&&e.charCodeAt(2)===191&&(e=e.slice(3))),o.length===0){let t=g(e);t!==``&&(o.push(t),s=t.length),h();return}if(e.indexOf(`
4
- `)===-1&&e.indexOf(`\r`)===-1){o.push(e),s+=e.length,h();return}o.push(e);let t=o.join(``);o.length=0,s=0;let n=g(t);n!==``&&(o.push(n),s=n.length),h()}function h(){a!==void 0&&(s+u.length<=a||(p=!0,o.length=0,s=0,l=void 0,u=``,d=0,f=void 0,n(new Bt(`Buffered data exceeded max buffer size of ${a} characters`,{type:`max-buffer-size-exceeded`}))))}function g(e){let n=0;if(e.indexOf(`\r`)===-1){let r=e.indexOf(`
5
- `,n);for(;r!==-1;){if(n===r){d>0&&t({id:l,event:f,data:u}),l=void 0,u=``,d=0,f=void 0,n=r+1,r=e.indexOf(`
6
- `,n);continue}let i=e.charCodeAt(n);if(Gt(e,n,i)){let i=e.charCodeAt(n+5)===D?n+6:n+5,a=e.slice(i,r);if(d===0&&e.charCodeAt(r+1)===Vt){t({id:l,event:f,data:a}),l=void 0,u=``,f=void 0,n=r+2,r=e.indexOf(`
7
- `,n);continue}u=d===0?a:`${u}
8
- ${a}`,d++}else Kt(e,n,i)?f=e.slice(e.charCodeAt(n+6)===D?n+7:n+6,r)||void 0:_(e,n,r);n=r+1,r=e.indexOf(`
9
- `,n)}return e.slice(n)}for(;n<e.length;){let t=e.indexOf(`\r`,n),r=e.indexOf(`
10
- `,n),i=-1;if(t!==-1&&r!==-1?i=t<r?t:r:t===-1?r!==-1&&(i=r):i=t===e.length-1?-1:t,i===-1)break;_(e,n,i),n=i+1,e.charCodeAt(n-1)===Ht&&e.charCodeAt(n)===Vt&&n++}return e.slice(n)}function _(e,t,n){if(t===n){ee();return}let r=e.charCodeAt(t);if(Gt(e,t,r)){let r=e.charCodeAt(t+5)===D?t+6:t+5,i=e.slice(r,n);u=d===0?i:`${u}
11
- ${i}`,d++;return}if(Kt(e,t,r)){f=e.slice(e.charCodeAt(t+6)===D?t+7:t+6,n)||void 0;return}if(r===105&&e.charCodeAt(t+1)===100&&e.charCodeAt(t+2)===58){let r=e.slice(e.charCodeAt(t+3)===D?t+4:t+3,n);r.includes(`\0`)||(l=r);return}if(r===58){if(i){let r=e.slice(t,n);i(r.slice(e.charCodeAt(t+1)===D?2:1))}return}let a=e.slice(t,n),o=a.indexOf(`:`);if(o===-1){v(a,``,a);return}let s=a.slice(0,o),c=a.charCodeAt(o+1)===D?2:1;v(s,a.slice(o+c),a)}function v(e,t,i){switch(e){case`event`:f=t||void 0;break;case`data`:u=d===0?t:`${u}
12
- ${t}`,d++;break;case`id`:t.includes(`\0`)||(l=t);break;case`retry`:/^\d+$/.test(t)?r(parseInt(t,10)):n(new Bt(`Invalid \`retry\` value: "${t}"`,{type:`invalid-retry`,value:t,line:i}));break;default:n(new Bt(`Unknown field "${e.length>20?`${e.slice(0,20)}\u2026`:e}"`,{type:`unknown-field`,field:e,value:t,line:i}))}}function ee(){d>0&&t({id:l,event:f,data:u}),l=void 0,u=``,d=0,f=void 0}function te(e={}){if(e.consume&&o.length>0){let e=o.join(``);_(e,0,e.length)}c=!0,l=void 0,u=``,d=0,f=void 0,o.length=0,s=0,p=!1}return{feed:m,reset:te}}function Gt(e,t,n){return n===100&&e.charCodeAt(t+1)===97&&e.charCodeAt(t+2)===116&&e.charCodeAt(t+3)===97&&e.charCodeAt(t+4)===58}function Kt(e,t,n){return n===101&&e.charCodeAt(t+1)===118&&e.charCodeAt(t+2)===101&&e.charCodeAt(t+3)===110&&e.charCodeAt(t+4)===116&&e.charCodeAt(t+5)===58}var qt=class extends TransformStream{constructor({onError:e,onRetry:t,onComment:n,maxBufferSize:r}={}){let i;super({start(a){i=Wt({onEvent:e=>{a.enqueue(e)},onError(t){typeof e==`function`&&e(t),(e===`terminate`||t.type===`max-buffer-size-exceeded`)&&a.error(t)},onRetry:t,onComment:n,maxBufferSize:r})},transform(e){i.feed(e)}})}};new TextDecoder;var{btoa:Jt,atob:Yt}=globalThis,Xt=globalThis.fetch;Zt(Xt);function Zt(e){if(typeof e!=`function`)return!1;let t=Function.prototype.toString.call(e);return t.includes(`internal/deps/undici`)||t.includes(`lazy loading of undici`)}var O=({prefix:e,size:t=16,alphabet:n=`0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz`,separator:r=`-`}={})=>{let i=()=>{let e=n.length,r=Array(t);for(let i=0;i<t;i++)r[i]=n[Math.random()*e|0];return r.join(``)};if(e==null)return i;if(n.includes(r))throw new Ot({argument:`separator`,message:`The separator "${r}" must not be part of the alphabet "${n}".`});return()=>`${e}${r}${i()}`},Qt=O();function k(e){if(e==null)return{};let t={};if(e instanceof Headers)e.forEach((e,n)=>{t[n.toLowerCase()]=e});else{Array.isArray(e)||(e=Object.entries(e));for(let[n,r]of e)r!=null&&(t[n.toLowerCase()]=r)}return t}function $t(e){return globalThis.Buffer?.isBuffer(e)??!1}var en=/"(?:_|\\u005[Ff])(?:_|\\u005[Ff])(?:p|\\u0070)(?:r|\\u0072)(?:o|\\u006[Ff])(?:t|\\u0074)(?:o|\\u006[Ff])(?:_|\\u005[Ff])(?:_|\\u005[Ff])"\s*:/,tn=/"(?:c|\\u0063)(?:o|\\u006[Ff])(?:n|\\u006[Ee])(?:s|\\u0073)(?:t|\\u0074)(?:r|\\u0072)(?:u|\\u0075)(?:c|\\u0063)(?:t|\\u0074)(?:o|\\u006[Ff])(?:r|\\u0072)"\s*:/;function nn(e){let t=JSON.parse(e);return typeof t!=`object`||!t||en.test(e)===!1&&tn.test(e)===!1?t:rn(t)}function rn(e){let t=[e];for(;t.length;){let e=t;t=[];for(let n of e){if(Object.prototype.hasOwnProperty.call(n,`__proto__`)||Object.prototype.hasOwnProperty.call(n,`constructor`)&&n.constructor!==null&&typeof n.constructor==`object`&&Object.prototype.hasOwnProperty.call(n.constructor,`prototype`))throw SyntaxError(`Object contains forbidden prototype property`);for(let e in n){let r=n[e];r&&typeof r==`object`&&t.push(r)}}}return e}function an(e){let{stackTraceLimit:t}=Error;try{Error.stackTraceLimit=0}catch{return nn(e)}try{return nn(e)}finally{Error.stackTraceLimit=t}}function on(e){if(e.type===`object`||Array.isArray(e.type)&&e.type.includes(`object`)){e.additionalProperties=!1;let{properties:t}=e;if(t!=null)for(let e of Object.keys(t))t[e]=A(t[e])}e.items!=null&&(e.items=Array.isArray(e.items)?e.items.map(A):A(e.items)),e.anyOf!=null&&(e.anyOf=e.anyOf.map(A)),e.allOf!=null&&(e.allOf=e.allOf.map(A)),e.oneOf!=null&&(e.oneOf=e.oneOf.map(A));let{definitions:t}=e;if(t!=null)for(let e of Object.keys(t))t[e]=A(t[e]);return e}function A(e){return typeof e==`boolean`?e:on(e)}var sn=Symbol(`Let zodToJsonSchema decide on which parser to use`),cn={name:void 0,$refStrategy:`root`,basePath:[`#`],effectStrategy:`input`,pipeStrategy:`all`,dateStrategy:`format:date-time`,mapStrategy:`entries`,removeAdditionalStrategy:`passthrough`,allowedAdditionalProperties:!0,rejectedAdditionalProperties:!1,definitionPath:`definitions`,strictUnions:!1,definitions:{},errorMessages:!1,patternStrategy:`escape`,applyRegexFlags:!1,emailStrategy:`format:email`,base64Strategy:`contentEncoding:base64`,nameStrategy:`ref`},ln=e=>typeof e==`string`?{...cn,name:e}:{...cn,...e};function j(){return{}}function un(e,t){let n={type:`array`};return e.type?._def&&e.type?._def?.typeName!==`ZodAny`&&(n.items=F(e.type._def,{...t,currentPath:[...t.currentPath,`items`]})),e.minLength&&(n.minItems=e.minLength.value),e.maxLength&&(n.maxItems=e.maxLength.value),e.exactLength&&(n.minItems=e.exactLength.value,n.maxItems=e.exactLength.value),n}function dn(e){let t={type:`integer`,format:`int64`};if(!e.checks)return t;for(let n of e.checks)switch(n.kind){case`min`:n.inclusive?t.minimum=n.value:t.exclusiveMinimum=n.value;break;case`max`:n.inclusive?t.maximum=n.value:t.exclusiveMaximum=n.value;break;case`multipleOf`:t.multipleOf=n.value}return t}function fn(){return{type:`boolean`}}function pn(e,t){return F(e.type._def,t)}var mn=(e,t)=>F(e.innerType._def,t);function hn(e,t,n){let r=n??t.dateStrategy;if(Array.isArray(r))return{anyOf:r.map(n=>hn(e,t,n))};switch(r){case`string`:case`format:date-time`:return{type:`string`,format:`date-time`};case`format:date`:return{type:`string`,format:`date`};case`integer`:return gn(e)}}var gn=e=>{let t={type:`integer`,format:`unix-time`};for(let n of e.checks)switch(n.kind){case`min`:t.minimum=n.value;break;case`max`:t.maximum=n.value}return t};function _n(e,t){return{...F(e.innerType._def,t),default:e.defaultValue()}}function vn(e,t){return t.effectStrategy===`input`?F(e.schema._def,t):j()}function yn(e){return{type:`string`,enum:Array.from(e.values)}}var bn=e=>`type`in e&&e.type===`string`?!1:`allOf`in e;function xn(e,t){let n=[F(e.left._def,{...t,currentPath:[...t.currentPath,`allOf`,`0`]}),F(e.right._def,{...t,currentPath:[...t.currentPath,`allOf`,`1`]})].filter(e=>!!e),r=[];return n.forEach(e=>{if(bn(e))r.push(...e.allOf);else{let t=e;if(`additionalProperties`in e&&e.additionalProperties===!1){let{additionalProperties:n,...r}=e;t=r}r.push(t)}}),r.length?{allOf:r}:void 0}function Sn(e){let t=typeof e.value;return t!==`bigint`&&t!==`number`&&t!==`boolean`&&t!==`string`?{type:Array.isArray(e.value)?`array`:`object`}:{type:t===`bigint`?`integer`:t,const:e.value}}var Cn=void 0,M={cuid:/^[cC][^\s-]{8,}$/,cuid2:/^[0-9a-z]+$/,ulid:/^[0-9A-HJKMNP-TV-Z]{26}$/,email:/^(?!\.)(?!.*\.\.)([a-zA-Z0-9_'+\-\.]*)[a-zA-Z0-9_+-]@([a-zA-Z0-9][a-zA-Z0-9\-]*\.)+[a-zA-Z]{2,}$/,emoji:()=>(Cn===void 0&&(Cn=RegExp(`^(\\p{Extended_Pictographic}|\\p{Emoji_Component})+$`,`u`)),Cn),uuid:/^[0-9a-fA-F]{8}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{12}$/,ipv4:/^(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])$/,ipv4Cidr:/^(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\/(3[0-2]|[12]?[0-9])$/,ipv6:/^(([a-f0-9]{1,4}:){7}|::([a-f0-9]{1,4}:){0,6}|([a-f0-9]{1,4}:){1}:([a-f0-9]{1,4}:){0,5}|([a-f0-9]{1,4}:){2}:([a-f0-9]{1,4}:){0,4}|([a-f0-9]{1,4}:){3}:([a-f0-9]{1,4}:){0,3}|([a-f0-9]{1,4}:){4}:([a-f0-9]{1,4}:){0,2}|([a-f0-9]{1,4}:){5}:([a-f0-9]{1,4}:){0,1})([a-f0-9]{1,4}|(((25[0-5])|(2[0-4][0-9])|(1[0-9]{2})|([0-9]{1,2}))\.){3}((25[0-5])|(2[0-4][0-9])|(1[0-9]{2})|([0-9]{1,2})))$/,ipv6Cidr:/^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))\/(12[0-8]|1[01][0-9]|[1-9]?[0-9])$/,base64:/^([0-9a-zA-Z+/]{4})*(([0-9a-zA-Z+/]{2}==)|([0-9a-zA-Z+/]{3}=))?$/,base64url:/^([0-9a-zA-Z-_]{4})*(([0-9a-zA-Z-_]{2}(==)?)|([0-9a-zA-Z-_]{3}(=)?))?$/,nanoid:/^[a-zA-Z0-9_-]{21}$/,jwt:/^[A-Za-z0-9-_]+\.[A-Za-z0-9-_]+\.[A-Za-z0-9-_]*$/};function wn(e,t){let n={type:`string`};if(e.checks)for(let r of e.checks)switch(r.kind){case`min`:n.minLength=typeof n.minLength==`number`?Math.max(n.minLength,r.value):r.value;break;case`max`:n.maxLength=typeof n.maxLength==`number`?Math.min(n.maxLength,r.value):r.value;break;case`email`:switch(t.emailStrategy){case`format:email`:N(n,`email`,r.message,t);break;case`format:idn-email`:N(n,`idn-email`,r.message,t);break;case`pattern:zod`:P(n,M.email,r.message,t)}break;case`url`:N(n,`uri`,r.message,t);break;case`uuid`:N(n,`uuid`,r.message,t);break;case`regex`:P(n,r.regex,r.message,t);break;case`cuid`:P(n,M.cuid,r.message,t);break;case`cuid2`:P(n,M.cuid2,r.message,t);break;case`startsWith`:P(n,RegExp(`^${Tn(r.value,t)}`),r.message,t);break;case`endsWith`:P(n,RegExp(`${Tn(r.value,t)}$`),r.message,t);break;case`datetime`:N(n,`date-time`,r.message,t);break;case`date`:N(n,`date`,r.message,t);break;case`time`:N(n,`time`,r.message,t);break;case`duration`:N(n,`duration`,r.message,t);break;case`length`:n.minLength=typeof n.minLength==`number`?Math.max(n.minLength,r.value):r.value,n.maxLength=typeof n.maxLength==`number`?Math.min(n.maxLength,r.value):r.value;break;case`includes`:P(n,RegExp(Tn(r.value,t)),r.message,t);break;case`ip`:r.version!==`v6`&&N(n,`ipv4`,r.message,t),r.version!==`v4`&&N(n,`ipv6`,r.message,t);break;case`base64url`:P(n,M.base64url,r.message,t);break;case`jwt`:P(n,M.jwt,r.message,t);break;case`cidr`:r.version!==`v6`&&P(n,M.ipv4Cidr,r.message,t),r.version!==`v4`&&P(n,M.ipv6Cidr,r.message,t);break;case`emoji`:P(n,M.emoji(),r.message,t);break;case`ulid`:P(n,M.ulid,r.message,t);break;case`base64`:switch(t.base64Strategy){case`format:binary`:N(n,`binary`,r.message,t);break;case`contentEncoding:base64`:n.contentEncoding=`base64`;break;case`pattern:zod`:P(n,M.base64,r.message,t)}break;case`nanoid`:P(n,M.nanoid,r.message,t)}return n}function Tn(e,t){return t.patternStrategy===`escape`?Dn(e):e}var En=new Set(`ABCDEFGHIJKLMNOPQRSTUVXYZabcdefghijklmnopqrstuvxyz0123456789`);function Dn(e){let t=``;for(let n=0;n<e.length;n++)En.has(e[n])||(t+=`\\`),t+=e[n];return t}function N(e,t,n,r){e.format||e.anyOf?.some(e=>e.format)?(e.anyOf||=[],e.format&&(e.anyOf.push({format:e.format}),delete e.format),e.anyOf.push({format:t,...n&&r.errorMessages&&{errorMessage:{format:n}}})):e.format=t}function P(e,t,n,r){e.pattern||e.allOf?.some(e=>e.pattern)?(e.allOf||=[],e.pattern&&(e.allOf.push({pattern:e.pattern}),delete e.pattern),e.allOf.push({pattern:On(t,r),...n&&r.errorMessages&&{errorMessage:{pattern:n}}})):e.pattern=On(t,r)}function On(e,t){if(!t.applyRegexFlags||!e.flags)return e.source;let n={i:e.flags.includes(`i`),m:e.flags.includes(`m`),s:e.flags.includes(`s`)},r=n.i?e.source.toLowerCase():e.source,i=``,a=!1,o=!1,s=!1;for(let e=0;e<r.length;e++){if(a){i+=r[e],a=!1;continue}if(n.i){if(o){if(r[e].match(/[a-z]/)){s?(i+=r[e],i+=`${r[e-2]}-${r[e]}`.toUpperCase(),s=!1):r[e+1]===`-`&&r[e+2]?.match(/[a-z]/)?(i+=r[e],s=!0):i+=`${r[e]}${r[e].toUpperCase()}`;continue}}else if(r[e].match(/[a-z]/)){i+=`[${r[e]}${r[e].toUpperCase()}]`;continue}}if(n.m){if(r[e]===`^`){i+=`(^|(?<=[\r
13
- ]))`;continue}if(r[e]===`$`){i+=`($|(?=[\r
14
- ]))`;continue}}if(n.s&&r[e]===`.`){i+=o?`${r[e]}\r
15
- `:`[${r[e]}\r
16
- ]`;continue}i+=r[e],r[e]===`\\`?a=!0:o&&r[e]===`]`?o=!1:!o&&r[e]===`[`&&(o=!0)}try{new RegExp(i)}catch{return console.warn(`Could not convert regex pattern at ${t.currentPath.join(`/`)} to a flag-independent form! Falling back to the flag-ignorant source`),e.source}return i}function kn(e,t){let n={type:`object`,additionalProperties:F(e.valueType._def,{...t,currentPath:[...t.currentPath,`additionalProperties`]})??t.allowedAdditionalProperties};if(e.keyType?._def.typeName===`ZodString`&&e.keyType._def.checks?.length){let{type:r,...i}=wn(e.keyType._def,t);return{...n,propertyNames:i}}if(e.keyType?._def.typeName===`ZodEnum`)return{...n,propertyNames:{enum:e.keyType._def.values}};if(e.keyType?._def.typeName===`ZodBranded`&&e.keyType._def.type._def.typeName===`ZodString`&&e.keyType._def.type._def.checks?.length){let{type:r,...i}=pn(e.keyType._def,t);return{...n,propertyNames:i}}return n}function An(e,t){return t.mapStrategy===`record`?kn(e,t):{type:`array`,maxItems:125,items:{type:`array`,items:[F(e.keyType._def,{...t,currentPath:[...t.currentPath,`items`,`items`,`0`]})||j(),F(e.valueType._def,{...t,currentPath:[...t.currentPath,`items`,`items`,`1`]})||j()],minItems:2,maxItems:2}}}function jn(e){let t=e.values,n=Object.keys(e.values).filter(e=>typeof t[t[e]]!=`number`).map(e=>t[e]),r=Array.from(new Set(n.map(e=>typeof e)));return{type:r.length===1?r[0]===`string`?`string`:`number`:[`string`,`number`],enum:n}}function Mn(){return{not:j()}}function Nn(){return{type:`null`}}var Pn={ZodString:`string`,ZodNumber:`number`,ZodBigInt:`integer`,ZodBoolean:`boolean`,ZodNull:`null`};function Fn(e,t){let n=e.options instanceof Map?Array.from(e.options.values()):e.options;if(n.every(e=>e._def.typeName in Pn&&(!e._def.checks||!e._def.checks.length))){let e=n.reduce((e,t)=>{let n=Pn[t._def.typeName];return n&&!e.includes(n)?[...e,n]:e},[]);return{type:e.length>1?e:e[0]}}if(n.every(e=>e._def.typeName===`ZodLiteral`&&!e.description)){let e=n.reduce((e,t)=>{let n=typeof t._def.value;switch(n){case`string`:case`number`:case`boolean`:return[...e,n];case`bigint`:return[...e,`integer`];case`object`:if(t._def.value===null)return[...e,`null`];default:return e}},[]);if(e.length===n.length){let t=e.filter((e,t,n)=>n.indexOf(e)===t);return{type:t.length>1?t:t[0],enum:n.reduce((e,t)=>e.includes(t._def.value)?e:[...e,t._def.value],[])}}}else if(n.every(e=>e._def.typeName===`ZodEnum`))return{type:`string`,enum:n.reduce((e,t)=>[...e,...t._def.values.filter(t=>!e.includes(t))],[])};return In(e,t)}var In=(e,t)=>{let n=(e.options instanceof Map?Array.from(e.options.values()):e.options).map((e,n)=>F(e._def,{...t,currentPath:[...t.currentPath,`anyOf`,`${n}`]})).filter(e=>!!e&&(!t.strictUnions||typeof e==`object`&&Object.keys(e).length>0));return n.length?{anyOf:n}:void 0};function Ln(e,t){if([`ZodString`,`ZodNumber`,`ZodBigInt`,`ZodBoolean`,`ZodNull`].includes(e.innerType._def.typeName)&&(!e.innerType._def.checks||!e.innerType._def.checks.length))return{type:[Pn[e.innerType._def.typeName],`null`]};let n=F(e.innerType._def,{...t,currentPath:[...t.currentPath,`anyOf`,`0`]});return n&&{anyOf:[n,{type:`null`}]}}function Rn(e){let t={type:`number`};if(!e.checks)return t;for(let n of e.checks)switch(n.kind){case`int`:t.type=`integer`;break;case`min`:n.inclusive?t.minimum=n.value:t.exclusiveMinimum=n.value;break;case`max`:n.inclusive?t.maximum=n.value:t.exclusiveMaximum=n.value;break;case`multipleOf`:t.multipleOf=n.value}return t}function zn(e,t){let n={type:`object`,properties:{}},r=[],i=e.shape();for(let e in i){let a=i[e];if(a===void 0||a._def===void 0)continue;let o=Vn(a),s=F(a._def,{...t,currentPath:[...t.currentPath,`properties`,e],propertyPath:[...t.currentPath,`properties`,e]});s!==void 0&&(n.properties[e]=s,o||r.push(e))}r.length&&(n.required=r);let a=Bn(e,t);return a!==void 0&&(n.additionalProperties=a),n}function Bn(e,t){if(e.catchall._def.typeName!==`ZodNever`)return F(e.catchall._def,{...t,currentPath:[...t.currentPath,`additionalProperties`]});switch(e.unknownKeys){case`passthrough`:return t.allowedAdditionalProperties;case`strict`:return t.rejectedAdditionalProperties;case`strip`:return t.removeAdditionalStrategy===`strict`?t.allowedAdditionalProperties:t.rejectedAdditionalProperties}}function Vn(e){try{return e.isOptional()}catch{return!0}}var Hn=(e,t)=>{if(t.currentPath.toString()===t.propertyPath?.toString())return F(e.innerType._def,t);let n=F(e.innerType._def,{...t,currentPath:[...t.currentPath,`anyOf`,`1`]});return n?{anyOf:[{not:j()},n]}:j()},Un=(e,t)=>{if(t.pipeStrategy===`input`)return F(e.in._def,t);if(t.pipeStrategy===`output`)return F(e.out._def,t);let n=F(e.in._def,{...t,currentPath:[...t.currentPath,`allOf`,`0`]});return{allOf:[n,F(e.out._def,{...t,currentPath:[...t.currentPath,`allOf`,n?`1`:`0`]})].filter(e=>e!==void 0)}};function Wn(e,t){return F(e.type._def,t)}function Gn(e,t){let n={type:`array`,uniqueItems:!0,items:F(e.valueType._def,{...t,currentPath:[...t.currentPath,`items`]})};return e.minSize&&(n.minItems=e.minSize.value),e.maxSize&&(n.maxItems=e.maxSize.value),n}function Kn(e,t){return e.rest?{type:`array`,minItems:e.items.length,items:e.items.map((e,n)=>F(e._def,{...t,currentPath:[...t.currentPath,`items`,`${n}`]})).reduce((e,t)=>t===void 0?e:[...e,t],[]),additionalItems:F(e.rest._def,{...t,currentPath:[...t.currentPath,`additionalItems`]})}:{type:`array`,minItems:e.items.length,maxItems:e.items.length,items:e.items.map((e,n)=>F(e._def,{...t,currentPath:[...t.currentPath,`items`,`${n}`]})).reduce((e,t)=>t===void 0?e:[...e,t],[])}}function qn(){return{not:j()}}function Jn(){return j()}var Yn=(e,t)=>F(e.innerType._def,t),Xn=(e,t,n)=>{switch(t){case`ZodString`:return wn(e,n);case`ZodNumber`:return Rn(e);case`ZodObject`:return zn(e,n);case`ZodBigInt`:return dn(e);case`ZodBoolean`:return fn();case`ZodDate`:return hn(e,n);case`ZodUndefined`:return qn();case`ZodNull`:return Nn();case`ZodArray`:return un(e,n);case`ZodUnion`:case`ZodDiscriminatedUnion`:return Fn(e,n);case`ZodIntersection`:return xn(e,n);case`ZodTuple`:return Kn(e,n);case`ZodRecord`:return kn(e,n);case`ZodLiteral`:return Sn(e);case`ZodEnum`:return yn(e);case`ZodNativeEnum`:return jn(e);case`ZodNullable`:return Ln(e,n);case`ZodOptional`:return Hn(e,n);case`ZodMap`:return An(e,n);case`ZodSet`:return Gn(e,n);case`ZodLazy`:return()=>e.getter()._def;case`ZodPromise`:return Wn(e,n);case`ZodNaN`:case`ZodNever`:return Mn();case`ZodEffects`:return vn(e,n);case`ZodAny`:return j();case`ZodUnknown`:return Jn();case`ZodDefault`:return _n(e,n);case`ZodBranded`:return pn(e,n);case`ZodReadonly`:return Yn(e,n);case`ZodCatch`:return mn(e,n);case`ZodPipeline`:return Un(e,n);case`ZodFunction`:case`ZodVoid`:case`ZodSymbol`:return;default:return(e=>void 0)(t)}},Zn=(e,t)=>{let n=0;for(;n<e.length&&n<t.length&&e[n]===t[n];n++);return[(e.length-n).toString(),...t.slice(n)].join(`/`)};function F(e,t,n=!1){let r=t.seen.get(e);if(t.override){let i=t.override?.call(t,e,t,r,n);if(i!==sn)return i}if(r&&!n){let e=Qn(r,t);if(e!==void 0)return e}let i={def:e,path:t.currentPath,jsonSchema:void 0};t.seen.set(e,i);let a=Xn(e,e.typeName,t),o=typeof a==`function`?F(a(),t):a;if(o&&$n(e,t,o),t.postProcess){let n=t.postProcess(o,e,t);return i.jsonSchema=o,n}return i.jsonSchema=o,o}var Qn=(e,t)=>{switch(t.$refStrategy){case`root`:return{$ref:e.path.join(`/`)};case`relative`:return{$ref:Zn(t.currentPath,e.path)};case`none`:case`seen`:return e.path.length<t.currentPath.length&&e.path.every((e,n)=>t.currentPath[n]===e)?(console.warn(`Recursive reference detected at ${t.currentPath.join(`/`)}! Defaulting to any`),j()):t.$refStrategy===`seen`?j():void 0}},$n=(e,t,n)=>(e.description&&(n.description=e.description),n),er=e=>{let t=ln(e),n=t.name===void 0?t.basePath:[...t.basePath,t.definitionPath,t.name];return{...t,currentPath:n,propertyPath:void 0,seen:new Map(Object.entries(t.definitions).map(([e,n])=>[n._def,{def:n._def,path:[...t.basePath,t.definitionPath,e],jsonSchema:void 0}]))}},tr=(e,t)=>{let n=er(t),r=typeof t==`object`&&t.definitions?Object.entries(t.definitions).reduce((e,[t,r])=>({...e,[t]:F(r._def,{...n,currentPath:[...n.basePath,n.definitionPath,t]},!0)??j()}),{}):void 0,i=typeof t==`string`?t:t?.nameStrategy===`title`?void 0:t?.name,a=F(e._def,i===void 0?n:{...n,currentPath:[...n.basePath,n.definitionPath,i]},!1)??j(),o=typeof t==`object`&&t.name!==void 0&&t.nameStrategy===`title`?t.name:void 0;o!==void 0&&(a.title=o);let s=i===void 0?r?{...a,[n.definitionPath]:r}:a:{$ref:[...n.$refStrategy===`relative`?[]:n.basePath,n.definitionPath,i].join(`/`),[n.definitionPath]:{...r,[i]:a}};return s.$schema=`http://json-schema.org/draft-07/schema#`,s},nr=Symbol.for(`vercel.ai.schema`);function rr(e){let t;return()=>(t??=e(),t)}function ir(e,{validate:t}={}){return{[nr]:!0,_type:void 0,get jsonSchema(){return typeof e==`function`&&(e=e()),e},validate:t}}function ar(e){return typeof e==`object`&&!!e&&nr in e&&e[nr]===!0&&`jsonSchema`in e&&`validate`in e}function or(e){return e==null?ir({type:`object`,properties:{},additionalProperties:!1}):ar(e)?e:`~standard`in e?e[`~standard`].vendor===`zod`?fr(e):sr(e):e()}function sr(e){return ir(()=>{if(!cr(e))throw Error(`Standard schema vendor '${e[`~standard`].vendor}' does not support JSON Schema conversion.`);return on(e[`~standard`].jsonSchema.input({target:`draft-07`}))},{validate:async t=>{let n=await e[`~standard`].validate(t);return`value`in n?{success:!0,value:n.value}:{success:!1,error:new E({value:t,cause:n.issues})}}})}function cr(e){return e[`~standard`].jsonSchema!=null}function lr(e,t){let n=t?.useReferences??!1;return ir(()=>tr(e,{$refStrategy:n?`root`:`none`}),{validate:async t=>{let n=await e.safeParseAsync(t);return n.success?{success:!0,value:n.data}:{success:!1,error:n.error}}})}function ur(e,t){let i=t?.useReferences??!1;return ir(()=>on(n(e,{target:`draft-7`,io:`input`,reused:i?`ref`:`inline`})),{validate:async t=>{let n=await r(e,t);return n.success?{success:!0,value:n.data}:{success:!1,error:n.error}}})}function dr(e){return`_zod`in e}function fr(e,t){return dr(e)?ur(e,t):lr(e,t)}async function pr({value:e,schema:t,context:n}){let r=await mr({value:e,schema:t,context:n});if(!r.success)throw E.wrap({value:e,cause:r.error,context:n});return r.value}async function mr({value:e,schema:t,context:n}){let r=or(t);try{if(r.validate==null)return{success:!0,value:e,rawValue:e};let t=await r.validate(e);return t.success?{success:!0,value:t.value,rawValue:e}:{success:!1,error:E.wrap({value:e,cause:t.error,context:n}),rawValue:e}}catch(t){return{success:!1,error:E.wrap({value:e,cause:t,context:n}),rawValue:e}}}async function I({text:e,schema:t}){try{let n=an(e);return t==null?{success:!0,value:n,rawValue:n}:await mr({value:n,schema:t})}catch(t){return{success:!1,error:Pt.isInstance(t)?t:new Pt({text:e,cause:t}),rawValue:void 0}}}function hr({stream:e,schema:t}){return e.pipeThrough(new TextDecoderStream).pipeThrough(new qt).pipeThrough(new TransformStream({async transform({data:e},n){e!==`[DONE]`&&n.enqueue(await I({text:e,schema:t}))}}))}async function L(e){return typeof e==`function`&&(e=e()),Promise.resolve(e)}new TextDecoder;var gr=Object.defineProperty,_r=(e,t)=>{for(var n in t)gr(e,n,{get:t[n],enumerable:!0})},vr=`AI_NoObjectGeneratedError`,yr=`vercel.ai.error.${vr}`,br=Symbol.for(yr),xr,R=class extends T{constructor({message:e=`No object generated.`,cause:t,text:n,response:r,usage:i,finishReason:a}){super({name:vr,message:e,cause:t}),this[xr]=!0,this.text=n,this.response=r,this.usage=i,this.finishReason=a}static isInstance(e){return T.hasMarker(e,yr)}};xr=br;var Sr=`AI_UIMessageStreamError`,Cr=`vercel.ai.error.${Sr}`,wr=Symbol.for(Cr),Tr,z=class extends T{constructor({chunkType:e,chunkId:t,message:n}){super({name:Sr,message:n}),this[Tr]=!0,this.chunkType=e,this.chunkId=t}static isInstance(e){return T.hasMarker(e,Cr)}};Tr=wr;function Er(e,t){if(e===void 0&&t===void 0)return;if(e===void 0)return t;if(t===void 0)return e;let n={...e};for(let r in t)if(r!==`__proto__`&&r!==`constructor`&&r!==`prototype`&&Object.prototype.hasOwnProperty.call(t,r)){let i=t[r];if(i===void 0)continue;let a=r in e?e[r]:void 0,o=typeof i==`object`&&!!i&&!Array.isArray(i)&&!(i instanceof Date)&&!(i instanceof RegExp),s=typeof a==`object`&&!!a&&!Array.isArray(a)&&!(a instanceof Date)&&!(a instanceof RegExp);n[r]=o&&s?Er(a,i):i}return n}var B={array:_,boolean:o,custom:d,discriminatedUnion:v,enum:p,instanceof:g,lazy:s,literal:h,looseObject:f,never:l,null:u,number:c,object:i,record:ee,string:y,union:a,unknown:te},V=B.lazy(()=>B.union([B.null(),B.string(),B.number(),B.boolean(),B.record(B.string(),V.optional()),B.array(V)])),H=B.record(B.string(),B.record(B.string(),V.optional())),U=B.union([B.string(),B.instanceof(Uint8Array),B.instanceof(ArrayBuffer),B.custom($t,{message:`Must be a Buffer`})]),Dr=B.record(B.string(),B.string()),Or=B.object({type:B.literal(`text`),text:B.string(),providerOptions:H.optional()}),kr=B.object({type:B.literal(`image`),image:B.union([U,B.instanceof(URL),Dr]),mediaType:B.string().optional(),providerOptions:H.optional()}),Ar=B.discriminatedUnion(`type`,[B.object({type:B.literal(`data`),data:U}),B.object({type:B.literal(`url`),url:B.instanceof(URL)}),B.object({type:B.literal(`reference`),reference:Dr}),B.object({type:B.literal(`text`),text:B.string()})]),jr=B.discriminatedUnion(`type`,[B.object({type:B.literal(`data`),data:U}),B.object({type:B.literal(`url`),url:B.instanceof(URL)})]),Mr=B.object({type:B.literal(`file`),data:B.union([Ar,U,B.instanceof(URL),Dr]),filename:B.string().optional(),mediaType:B.string(),providerOptions:H.optional()}),Nr=B.object({type:B.literal(`reasoning`),text:B.string(),providerOptions:H.optional()}),Pr=B.object({type:B.literal(`custom`),kind:B.string().transform(e=>e),providerOptions:H.optional()}),Fr=B.object({type:B.literal(`reasoning-file`),data:B.union([jr,U,B.instanceof(URL)]),mediaType:B.string(),providerOptions:H.optional()}),Ir=B.object({type:B.literal(`tool-call`),toolCallId:B.string(),toolName:B.string(),input:B.unknown(),providerOptions:H.optional(),providerExecuted:B.boolean().optional()}),Lr=B.discriminatedUnion(`type`,[B.object({type:B.literal(`text`),value:B.string(),providerOptions:H.optional()}),B.object({type:B.literal(`json`),value:V,providerOptions:H.optional()}),B.object({type:B.literal(`execution-denied`),reason:B.string().optional(),providerOptions:H.optional()}),B.object({type:B.literal(`error-text`),value:B.string(),providerOptions:H.optional()}),B.object({type:B.literal(`error-json`),value:V,providerOptions:H.optional()}),B.object({type:B.literal(`content`),value:B.array(B.union([B.object({type:B.literal(`text`),text:B.string(),providerOptions:H.optional()}),B.object({type:B.literal(`file`),data:Ar,mediaType:B.string(),filename:B.string().optional(),providerOptions:H.optional()}),B.object({type:B.literal(`file-data`),data:B.string(),mediaType:B.string(),filename:B.string().optional(),providerOptions:H.optional()}),B.object({type:B.literal(`file-url`),url:B.string(),mediaType:B.string().optional(),providerOptions:H.optional()}),B.object({type:B.literal(`file-id`),fileId:B.union([B.string(),B.record(B.string(),B.string())]),providerOptions:H.optional()}),B.object({type:B.literal(`file-reference`),providerReference:B.record(B.string(),B.string()),providerOptions:H.optional()}),B.object({type:B.literal(`image-data`),data:B.string(),mediaType:B.string(),providerOptions:H.optional()}),B.object({type:B.literal(`image-url`),url:B.string(),providerOptions:H.optional()}),B.object({type:B.literal(`image-file-id`),fileId:B.union([B.string(),B.record(B.string(),B.string())]),providerOptions:H.optional()}),B.object({type:B.literal(`image-file-reference`),providerReference:B.record(B.string(),B.string()),providerOptions:H.optional()}),B.object({type:B.literal(`custom`),providerOptions:H.optional()})]))})]),Rr=B.object({type:B.literal(`tool-result`),toolCallId:B.string(),toolName:B.string(),output:Lr,providerOptions:H.optional()}),zr=B.object({type:B.literal(`tool-approval-request`),approvalId:B.string(),toolCallId:B.string()}),Br=B.object({type:B.literal(`tool-approval-response`),approvalId:B.string(),approved:B.boolean(),reason:B.string().optional()}),Vr=B.object({role:B.literal(`system`),content:B.string(),providerOptions:H.optional()}),Hr=B.object({role:B.literal(`user`),content:B.union([B.string(),B.array(B.union([Or,kr,Mr]))]),providerOptions:H.optional()}),Ur=B.object({role:B.literal(`assistant`),content:B.union([B.string(),B.array(B.union([Or,Pr,Mr,Nr,Fr,Ir,Rr,zr]))]),providerOptions:H.optional()}),Wr=B.object({role:B.literal(`tool`),content:B.array(B.union([Rr,Br])),providerOptions:H.optional()});B.union([Vr,Hr,Ur,Wr]),_r({},{array:()=>Jr,choice:()=>Yr,json:()=>Xr,object:()=>qr,text:()=>Kr});function Gr(e){let t=[`ROOT`],n=-1,r=null,i=0;function a(e){return e>=`0`&&e<=`9`||e>=`A`&&e<=`F`||e>=`a`&&e<=`f`}function o(e,i,a){switch(e){case`"`:n=i,t.pop(),t.push(a),t.push(`INSIDE_STRING`);break;case`f`:case`t`:case`n`:n=i,r=i,t.pop(),t.push(a),t.push(`INSIDE_LITERAL`);break;case`-`:t.pop(),t.push(a),t.push(`INSIDE_NUMBER`);break;case`0`:case`1`:case`2`:case`3`:case`4`:case`5`:case`6`:case`7`:case`8`:case`9`:n=i,t.pop(),t.push(a),t.push(`INSIDE_NUMBER`);break;case`{`:n=i,t.pop(),t.push(a),t.push(`INSIDE_OBJECT_START`);break;case`[`:n=i,t.pop(),t.push(a),t.push(`INSIDE_ARRAY_START`)}}function s(e,r){switch(e){case`,`:t.pop(),t.push(`INSIDE_OBJECT_AFTER_COMMA`);break;case`}`:n=r,t.pop()}}function c(e,r){switch(e){case`,`:t.pop(),t.push(`INSIDE_ARRAY_AFTER_COMMA`);break;case`]`:n=r,t.pop()}}for(let l=0;l<e.length;l++){let u=e[l];switch(t[t.length-1]){case`ROOT`:o(u,l,`FINISH`);break;case`INSIDE_OBJECT_START`:switch(u){case`"`:t.pop(),t.push(`INSIDE_OBJECT_KEY`);break;case`}`:n=l,t.pop()}break;case`INSIDE_OBJECT_AFTER_COMMA`:u===`"`&&(t.pop(),t.push(`INSIDE_OBJECT_KEY`));break;case`INSIDE_OBJECT_KEY`:u===`"`&&(t.pop(),t.push(`INSIDE_OBJECT_AFTER_KEY`));break;case`INSIDE_OBJECT_AFTER_KEY`:u===`:`&&(t.pop(),t.push(`INSIDE_OBJECT_BEFORE_VALUE`));break;case`INSIDE_OBJECT_BEFORE_VALUE`:o(u,l,`INSIDE_OBJECT_AFTER_VALUE`);break;case`INSIDE_OBJECT_AFTER_VALUE`:s(u,l);break;case`INSIDE_STRING`:switch(u){case`"`:t.pop(),n=l;break;case`\\`:t.push(`INSIDE_STRING_ESCAPE`);break;default:n=l}break;case`INSIDE_ARRAY_START`:switch(u){case`]`:n=l,t.pop();break;default:n=l,o(u,l,`INSIDE_ARRAY_AFTER_VALUE`)}break;case`INSIDE_ARRAY_AFTER_VALUE`:switch(u){case`,`:t.pop(),t.push(`INSIDE_ARRAY_AFTER_COMMA`);break;case`]`:n=l,t.pop();break;default:n=l}break;case`INSIDE_ARRAY_AFTER_COMMA`:o(u,l,`INSIDE_ARRAY_AFTER_VALUE`);break;case`INSIDE_STRING_ESCAPE`:t.pop(),u===`u`?(i=0,t.push(`INSIDE_STRING_UNICODE_ESCAPE`)):n=l;break;case`INSIDE_STRING_UNICODE_ESCAPE`:a(u)&&(i++,i===4&&(t.pop(),n=l));break;case`INSIDE_NUMBER`:switch(u){case`0`:case`1`:case`2`:case`3`:case`4`:case`5`:case`6`:case`7`:case`8`:case`9`:n=l;break;case`e`:case`E`:case`-`:case`.`:break;case`,`:t.pop(),t[t.length-1]===`INSIDE_ARRAY_AFTER_VALUE`&&c(u,l),t[t.length-1]===`INSIDE_OBJECT_AFTER_VALUE`&&s(u,l);break;case`}`:t.pop(),t[t.length-1]===`INSIDE_OBJECT_AFTER_VALUE`&&s(u,l);break;case`]`:t.pop(),t[t.length-1]===`INSIDE_ARRAY_AFTER_VALUE`&&c(u,l);break;default:t.pop()}break;case`INSIDE_LITERAL`:{let i=e.substring(r,l+1);!`false`.startsWith(i)&&!`true`.startsWith(i)&&!`null`.startsWith(i)?(t.pop(),t[t.length-1]===`INSIDE_OBJECT_AFTER_VALUE`?s(u,l):t[t.length-1]===`INSIDE_ARRAY_AFTER_VALUE`&&c(u,l)):n=l;break}}}let l=e.slice(0,n+1);for(let n=t.length-1;n>=0;n--)switch(t[n]){case`INSIDE_STRING`:l+=`"`;break;case`INSIDE_OBJECT_KEY`:case`INSIDE_OBJECT_AFTER_KEY`:case`INSIDE_OBJECT_AFTER_COMMA`:case`INSIDE_OBJECT_START`:case`INSIDE_OBJECT_BEFORE_VALUE`:case`INSIDE_OBJECT_AFTER_VALUE`:l+=`}`;break;case`INSIDE_ARRAY_START`:case`INSIDE_ARRAY_AFTER_COMMA`:case`INSIDE_ARRAY_AFTER_VALUE`:l+=`]`;break;case`INSIDE_LITERAL`:{let t=e.substring(r,e.length);`true`.startsWith(t)?l+=`true`.slice(t.length):`false`.startsWith(t)?l+=`false`.slice(t.length):`null`.startsWith(t)&&(l+=`null`.slice(t.length))}}return l}async function W(e){if(e===void 0)return{value:void 0,state:`undefined-input`};let t=await I({text:e});return t.success?{value:t.value,state:`successful-parse`}:(t=await I({text:Gr(e)}),t.success?{value:t.value,state:`repaired-parse`}:{value:void 0,state:`failed-parse`})}var Kr=()=>({name:`text`,responseFormat:Promise.resolve({type:`text`}),async parseCompleteOutput({text:e}){return e},async parsePartialOutput({text:e}){return{partial:e}},createElementStreamTransform(){}}),qr=({schema:e,name:t,description:n})=>{let r=or(e);return{name:`object`,responseFormat:L(r.jsonSchema).then(e=>({type:`json`,schema:e,...t!=null&&{name:t},...n!=null&&{description:n}})),async parseCompleteOutput({text:e},t){let n=await I({text:e});if(!n.success)throw new R({message:`No object generated: could not parse the response.`,cause:n.error,text:e,response:t.response,usage:t.usage,finishReason:t.finishReason});let i=await mr({value:n.value,schema:r});if(!i.success)throw new R({message:`No object generated: response did not match schema.`,cause:i.error,text:e,response:t.response,usage:t.usage,finishReason:t.finishReason});return i.value},async parsePartialOutput({text:e}){let t=await W(e);switch(t.state){case`failed-parse`:case`undefined-input`:return;case`repaired-parse`:case`successful-parse`:return{partial:t.value}}},createElementStreamTransform(){}}},Jr=({element:e,name:t,description:n})=>{let r=or(e);return{name:`array`,responseFormat:L(r.jsonSchema).then(e=>{let{$schema:r,definitions:i,$defs:a,...o}=e;return{type:`json`,schema:{$schema:`http://json-schema.org/draft-07/schema#`,...i!=null&&{definitions:i},...a!=null&&{$defs:a},type:`object`,properties:{elements:{type:`array`,items:o}},required:[`elements`],additionalProperties:!1},...t!=null&&{name:t},...n!=null&&{description:n}}}),async parseCompleteOutput({text:e},t){let n=await I({text:e});if(!n.success)throw new R({message:`No object generated: could not parse the response.`,cause:n.error,text:e,response:t.response,usage:t.usage,finishReason:t.finishReason});let i=n.value;if(typeof i!=`object`||!i||!(`elements`in i)||!Array.isArray(i.elements))throw new R({message:`No object generated: response did not match schema.`,cause:new E({value:i,cause:`response must be an object with an elements array`}),text:e,response:t.response,usage:t.usage,finishReason:t.finishReason});let a=[];for(let n of i.elements){let i=await mr({value:n,schema:r});if(!i.success)throw new R({message:`No object generated: response did not match schema.`,cause:i.error,text:e,response:t.response,usage:t.usage,finishReason:t.finishReason});a.push(i.value)}return a},async parsePartialOutput({text:e}){let t=await W(e);switch(t.state){case`failed-parse`:case`undefined-input`:return;case`repaired-parse`:case`successful-parse`:{let e=t.value;if(typeof e!=`object`||!e||!(`elements`in e)||!Array.isArray(e.elements))return;let n=t.state===`repaired-parse`&&e.elements.length>0?e.elements.slice(0,-1):e.elements,i=[];for(let e of n){let t=await mr({value:e,schema:r});t.success&&i.push(t.value)}return{partial:i}}}},createElementStreamTransform(){let e=0;return new TransformStream({transform({partialOutput:t},n){if(t!=null)for(;e<t.length;e++)n.enqueue(t[e])}})}}},Yr=({options:e,name:t,description:n})=>({name:`choice`,responseFormat:Promise.resolve({type:`json`,schema:{$schema:`http://json-schema.org/draft-07/schema#`,type:`object`,properties:{result:{type:`string`,enum:e}},required:[`result`],additionalProperties:!1},...t!=null&&{name:t},...n!=null&&{description:n}}),async parseCompleteOutput({text:t},n){let r=await I({text:t});if(!r.success)throw new R({message:`No object generated: could not parse the response.`,cause:r.error,text:t,response:n.response,usage:n.usage,finishReason:n.finishReason});let i=r.value;if(typeof i!=`object`||!i||!(`result`in i)||typeof i.result!=`string`||!e.includes(i.result))throw new R({message:`No object generated: response did not match schema.`,cause:new E({value:i,cause:`response must be an object that contains a choice value.`}),text:t,response:n.response,usage:n.usage,finishReason:n.finishReason});return i.result},async parsePartialOutput({text:t}){let n=await W(t);switch(n.state){case`failed-parse`:case`undefined-input`:return;case`repaired-parse`:case`successful-parse`:{let t=n.value;if(typeof t!=`object`||!t||!(`result`in t)||typeof t.result!=`string`)return;let r=e.filter(e=>e.startsWith(t.result));return n.state===`successful-parse`?r.includes(t.result)?{partial:t.result}:void 0:r.length===1?{partial:r[0]}:void 0}}},createElementStreamTransform(){}}),Xr=({name:e,description:t}={})=>({name:`json`,responseFormat:Promise.resolve({type:`json`,...e!=null&&{name:e},...t!=null&&{description:t}}),async parseCompleteOutput({text:e},t){let n=await I({text:e});if(!n.success)throw new R({message:`No object generated: could not parse the response.`,cause:n.error,text:e,response:t.response,usage:t.usage,finishReason:t.finishReason});return n.value},async parsePartialOutput({text:e}){let t=await W(e);switch(t.state){case`failed-parse`:case`undefined-input`:return;case`repaired-parse`:case`successful-parse`:return t.value===void 0?void 0:{partial:t.value}}},createElementStreamTransform(){}});new TextEncoder,new TextEncoder,O({prefix:`aitxt`,size:24}),O({prefix:`call`,size:24}),TransformStream;var G=B.record(B.string(),V.optional()),Zr=rr(()=>fr(B.union([B.looseObject({type:B.literal(`text-start`),id:B.string(),providerMetadata:H.optional()}),B.looseObject({type:B.literal(`text-delta`),id:B.string(),delta:B.string(),providerMetadata:H.optional()}),B.looseObject({type:B.literal(`text-end`),id:B.string(),providerMetadata:H.optional()}),B.looseObject({type:B.literal(`error`),errorText:B.string()}),B.looseObject({type:B.literal(`tool-input-start`),toolCallId:B.string(),toolName:B.string(),providerExecuted:B.boolean().optional(),providerMetadata:H.optional(),toolMetadata:G.optional(),dynamic:B.boolean().optional(),title:B.string().optional()}),B.looseObject({type:B.literal(`tool-input-delta`),toolCallId:B.string(),inputTextDelta:B.string()}),B.looseObject({type:B.literal(`tool-input-available`),toolCallId:B.string(),toolName:B.string(),input:B.unknown(),providerExecuted:B.boolean().optional(),providerMetadata:H.optional(),toolMetadata:G.optional(),dynamic:B.boolean().optional(),title:B.string().optional()}),B.looseObject({type:B.literal(`tool-input-error`),toolCallId:B.string(),toolName:B.string(),input:B.unknown(),providerExecuted:B.boolean().optional(),providerMetadata:H.optional(),toolMetadata:G.optional(),dynamic:B.boolean().optional(),errorText:B.string(),title:B.string().optional()}),B.looseObject({type:B.literal(`tool-approval-request`),approvalId:B.string(),toolCallId:B.string(),isAutomatic:B.boolean().optional(),signature:B.string().optional()}),B.looseObject({type:B.literal(`tool-approval-response`),approvalId:B.string(),approved:B.boolean(),reason:B.string().optional(),providerExecuted:B.boolean().optional(),providerMetadata:H.optional()}),B.looseObject({type:B.literal(`tool-output-available`),toolCallId:B.string(),output:B.unknown(),providerExecuted:B.boolean().optional(),providerMetadata:H.optional(),toolMetadata:G.optional(),dynamic:B.boolean().optional(),preliminary:B.boolean().optional()}),B.looseObject({type:B.literal(`tool-output-error`),toolCallId:B.string(),errorText:B.string(),providerExecuted:B.boolean().optional(),providerMetadata:H.optional(),toolMetadata:G.optional(),dynamic:B.boolean().optional()}),B.looseObject({type:B.literal(`tool-output-denied`),toolCallId:B.string()}),B.looseObject({type:B.literal(`reasoning-start`),id:B.string(),providerMetadata:H.optional()}),B.looseObject({type:B.literal(`reasoning-delta`),id:B.string(),delta:B.string(),providerMetadata:H.optional()}),B.looseObject({type:B.literal(`reasoning-end`),id:B.string(),providerMetadata:H.optional()}),B.looseObject({type:B.literal(`custom`),kind:B.string().transform(e=>e),providerMetadata:H.optional()}),B.looseObject({type:B.literal(`source-url`),sourceId:B.string(),url:B.string(),title:B.string().optional(),providerMetadata:H.optional()}),B.looseObject({type:B.literal(`source-document`),sourceId:B.string(),mediaType:B.string(),title:B.string(),filename:B.string().optional(),providerMetadata:H.optional()}),B.looseObject({type:B.literal(`file`),url:B.string(),mediaType:B.string(),providerMetadata:H.optional()}),B.looseObject({type:B.literal(`reasoning-file`),url:B.string(),mediaType:B.string(),providerMetadata:H.optional()}),B.looseObject({type:B.custom(e=>typeof e==`string`&&e.startsWith(`data-`),{message:`Type must start with "data-"`}),id:B.string().optional(),data:B.unknown(),transient:B.boolean().optional()}),B.looseObject({type:B.literal(`start-step`)}),B.looseObject({type:B.literal(`finish-step`)}),B.looseObject({type:B.literal(`reset-step`)}),B.looseObject({type:B.literal(`start`),messageId:B.string().optional(),messageMetadata:B.unknown().optional()}),B.looseObject({type:B.literal(`finish`),finishReason:B.enum([`stop`,`length`,`content-filter`,`tool-calls`,`error`,`other`]).optional(),messageMetadata:B.unknown().optional()}),B.looseObject({type:B.literal(`abort`),reason:B.string().optional()}),B.looseObject({type:B.literal(`message-metadata`),messageMetadata:B.unknown()})])));function Qr(e){return e.type.startsWith(`data-`)}function K(){return Object.create(null)}function $r(e){return e.type===`text`}function ei(e){return e.type.startsWith(`tool-`)}function ti(e){return e.type===`dynamic-tool`}function q(e){return ei(e)||ti(e)}function ni(e){return e.type.split(`-`).slice(1).join(`-`)}function ri(e){return ti(e)?e.toolName:ni(e)}function ii({lastMessage:e,messageId:t}){return{message:e?.role===`assistant`?e:{id:t,metadata:void 0,role:`assistant`,parts:[]},activeTextParts:K(),activeReasoningParts:K(),partialToolCalls:K()}}function ai({stream:e,messageMetadataSchema:t,dataPartSchemas:n,runUpdateMessageJob:r,onError:i,onToolCall:a,onData:o}){return e.pipeThrough(new TransformStream({async transform(e,s){await r(async({state:r,write:c})=>{function l(){let e=r.message.parts,t=e.length-1;for(;t>=0&&e[t].type!==`step-start`;)t--;return e.slice(t+1)}function u(){return l().filter(q)}function d(e){let t=u().find(t=>t.toolCallId===e);if(t==null){let n=r.message.parts;for(let r=n.length-1;r>=0;r--){let i=n[r];if(q(i)&&i.toolCallId===e){t=i;break}}}if(t==null)throw new z({chunkType:`tool-invocation`,chunkId:e,message:`No tool invocation found for tool call ID "${e}".`});return t}function f(e){let t=r.message.parts.filter(q).find(t=>t.approval?.id===e);if(t==null)throw new z({chunkType:`tool-approval-response`,chunkId:e,message:`No tool invocation found for approval ID "${e}".`});return t}function p(e,t){let n=t??l().find(t=>ei(t)&&t.toolCallId===e.toolCallId),i=e,a=n;if(n!=null){n.state=e.state,a.input=i.input,a.output=i.output,a.errorText=i.errorText,a.rawInput=i.rawInput,a.preliminary=i.preliminary,e.title!==void 0&&(a.title=e.title),e.toolMetadata!==void 0&&(a.toolMetadata=e.toolMetadata),a.providerExecuted=i.providerExecuted??n.providerExecuted;let t=i.providerMetadata;if(t!=null){if(e.state===`output-available`||e.state===`output-error`){let e=n;e.resultProviderMetadata=t}else n.callProviderMetadata=t}}else r.message.parts.push({type:`tool-${e.toolName}`,toolCallId:e.toolCallId,state:e.state,title:e.title,...e.toolMetadata===void 0?{}:{toolMetadata:e.toolMetadata},input:i.input,output:i.output,rawInput:i.rawInput,errorText:i.errorText,providerExecuted:i.providerExecuted,preliminary:i.preliminary,...i.providerMetadata!=null&&(e.state===`output-available`||e.state===`output-error`)?{resultProviderMetadata:i.providerMetadata}:{},...i.providerMetadata!=null&&e.state!==`output-available`&&e.state!==`output-error`?{callProviderMetadata:i.providerMetadata}:{}})}function m(e,t){let n=t??l().find(t=>t.type===`dynamic-tool`&&t.toolCallId===e.toolCallId),i=e,a=n;if(n!=null){n.state=e.state,a.toolName=e.toolName,a.input=i.input,a.output=i.output,a.errorText=i.errorText,a.rawInput=i.rawInput??a.rawInput,a.preliminary=i.preliminary,e.title!==void 0&&(a.title=e.title),e.toolMetadata!==void 0&&(a.toolMetadata=e.toolMetadata),a.providerExecuted=i.providerExecuted??n.providerExecuted;let t=i.providerMetadata;if(t!=null){if(e.state===`output-available`||e.state===`output-error`){let e=n;e.resultProviderMetadata=t}else n.callProviderMetadata=t}}else r.message.parts.push({type:`dynamic-tool`,toolName:e.toolName,toolCallId:e.toolCallId,state:e.state,input:i.input,output:i.output,errorText:i.errorText,preliminary:i.preliminary,providerExecuted:i.providerExecuted,title:e.title,...e.toolMetadata===void 0?{}:{toolMetadata:e.toolMetadata},...i.providerMetadata!=null&&(e.state===`output-available`||e.state===`output-error`)?{resultProviderMetadata:i.providerMetadata}:{},...i.providerMetadata!=null&&e.state!==`output-available`&&e.state!==`output-error`?{callProviderMetadata:i.providerMetadata}:{}})}async function h(e){if(e!=null){let n=r.message.metadata==null?e:Er(r.message.metadata,e);t!=null&&await pr({value:n,schema:t,context:{field:`message.metadata`,entityId:r.message.id}}),r.message.metadata=n}}switch(e.type){case`text-start`:{let t={type:`text`,text:``,providerMetadata:e.providerMetadata,state:`streaming`};r.activeTextParts[e.id]=t,r.message.parts.push(t),c();break}case`text-delta`:{let t=r.activeTextParts[e.id];if(t==null)throw new z({chunkType:`text-delta`,chunkId:e.id,message:`Received text-delta for missing text part with ID "${e.id}". Ensure a "text-start" chunk is sent before any "text-delta" chunks.`});t.text+=e.delta,t.providerMetadata=e.providerMetadata??t.providerMetadata,c();break}case`text-end`:{let t=r.activeTextParts[e.id];if(t==null)throw new z({chunkType:`text-end`,chunkId:e.id,message:`Received text-end for missing text part with ID "${e.id}". Ensure a "text-start" chunk is sent before any "text-end" chunks.`});t.state=`done`,t.providerMetadata=e.providerMetadata??t.providerMetadata,delete r.activeTextParts[e.id],c();break}case`custom`:{let t={type:`custom`,kind:e.kind,providerMetadata:e.providerMetadata};r.message.parts.push(t),c();break}case`reasoning-start`:{let t={type:`reasoning`,id:e.id,text:``,providerMetadata:e.providerMetadata,state:`streaming`};r.activeReasoningParts[e.id]=t,r.message.parts.push(t),c();break}case`reasoning-delta`:{let t=r.activeReasoningParts[e.id];if(t==null)throw new z({chunkType:`reasoning-delta`,chunkId:e.id,message:`Received reasoning-delta for missing reasoning part with ID "${e.id}". Ensure a "reasoning-start" chunk is sent before any "reasoning-delta" chunks.`});t.text+=e.delta,t.providerMetadata=e.providerMetadata??t.providerMetadata,c();break}case`reasoning-end`:{let t=r.activeReasoningParts[e.id];if(t==null)throw new z({chunkType:`reasoning-end`,chunkId:e.id,message:`Received reasoning-end for missing reasoning part with ID "${e.id}". Ensure a "reasoning-start" chunk is sent before any "reasoning-end" chunks.`});t.providerMetadata=e.providerMetadata??t.providerMetadata,t.state=`done`,delete r.activeReasoningParts[e.id],c();break}case`file`:case`reasoning-file`:r.message.parts.push({type:e.type,mediaType:e.mediaType,url:e.url,...e.providerMetadata==null?{}:{providerMetadata:e.providerMetadata}}),c();break;case`source-url`:r.message.parts.push({type:`source-url`,sourceId:e.sourceId,url:e.url,title:e.title,providerMetadata:e.providerMetadata}),c();break;case`source-document`:r.message.parts.push({type:`source-document`,sourceId:e.sourceId,mediaType:e.mediaType,title:e.title,filename:e.filename,providerMetadata:e.providerMetadata}),c();break;case`tool-input-start`:{let t=l().filter(ei);r.partialToolCalls[e.toolCallId]={text:``,toolName:e.toolName,index:t.length,dynamic:e.dynamic,title:e.title,toolMetadata:e.toolMetadata},e.dynamic?m({toolCallId:e.toolCallId,toolName:e.toolName,state:`input-streaming`,input:void 0,providerExecuted:e.providerExecuted,title:e.title,toolMetadata:e.toolMetadata,providerMetadata:e.providerMetadata}):p({toolCallId:e.toolCallId,toolName:e.toolName,state:`input-streaming`,input:void 0,providerExecuted:e.providerExecuted,title:e.title,toolMetadata:e.toolMetadata,providerMetadata:e.providerMetadata}),c();break}case`tool-input-delta`:{let t=r.partialToolCalls[e.toolCallId];if(t==null)throw new z({chunkType:`tool-input-delta`,chunkId:e.toolCallId,message:`Received tool-input-delta for missing tool call with ID "${e.toolCallId}". Ensure a "tool-input-start" chunk is sent before any "tool-input-delta" chunks.`});t.text+=e.inputTextDelta;let{value:n}=await W(t.text);t.dynamic?m({toolCallId:e.toolCallId,toolName:t.toolName,state:`input-streaming`,input:n,title:t.title,toolMetadata:t.toolMetadata}):p({toolCallId:e.toolCallId,toolName:t.toolName,state:`input-streaming`,input:n,title:t.title,toolMetadata:t.toolMetadata}),c();break}case`tool-input-available`:e.dynamic?m({toolCallId:e.toolCallId,toolName:e.toolName,state:`input-available`,input:e.input,providerExecuted:e.providerExecuted,providerMetadata:e.providerMetadata,title:e.title,toolMetadata:e.toolMetadata}):p({toolCallId:e.toolCallId,toolName:e.toolName,state:`input-available`,input:e.input,providerExecuted:e.providerExecuted,providerMetadata:e.providerMetadata,title:e.title,toolMetadata:e.toolMetadata}),c(),a&&!e.providerExecuted&&await a({toolCall:e});break;case`tool-input-error`:{let t=l().filter(q).find(t=>t.toolCallId===e.toolCallId);(t==null?e.dynamic:t.type===`dynamic-tool`)?m({toolCallId:e.toolCallId,toolName:e.toolName,state:`output-error`,input:e.input,errorText:e.errorText,providerExecuted:e.providerExecuted,providerMetadata:e.providerMetadata,toolMetadata:e.toolMetadata}):p({toolCallId:e.toolCallId,toolName:e.toolName,state:`output-error`,input:void 0,rawInput:e.input,errorText:e.errorText,providerExecuted:e.providerExecuted,providerMetadata:e.providerMetadata,toolMetadata:e.toolMetadata}),c();break}case`tool-approval-request`:{let t=d(e.toolCallId);t.state=`approval-requested`,t.approval={id:e.approvalId,...e.isAutomatic===!0?{isAutomatic:!0}:{},...e.signature==null?{}:{signature:e.signature}},c();break}case`tool-approval-response`:{let t=f(e.approvalId),n=t.approval==null?{id:e.approvalId}:t.approval;t.state=`approval-responded`,t.approval={id:e.approvalId,approved:e.approved,...e.reason==null?{}:{reason:e.reason},...n.isAutomatic===!0?{isAutomatic:!0}:{},...n.signature==null?{}:{signature:n.signature}},e.providerExecuted!=null&&(t.providerExecuted=e.providerExecuted),e.providerMetadata!=null&&(t.callProviderMetadata=e.providerMetadata),c();break}case`tool-output-denied`:{let t=d(e.toolCallId);t.state=`output-denied`,c();break}case`tool-output-available`:{let t=d(e.toolCallId);t.type===`dynamic-tool`?m({toolCallId:e.toolCallId,toolName:t.toolName,state:`output-available`,input:t.input,output:e.output,preliminary:e.preliminary,providerExecuted:e.providerExecuted,providerMetadata:e.providerMetadata,title:t.title,toolMetadata:t.toolMetadata},t):p({toolCallId:e.toolCallId,toolName:ni(t),state:`output-available`,input:t.input,output:e.output,providerExecuted:e.providerExecuted,preliminary:e.preliminary,providerMetadata:e.providerMetadata,title:t.title,toolMetadata:t.toolMetadata},t),c();break}case`tool-output-error`:{let t=d(e.toolCallId);t.type===`dynamic-tool`?m({toolCallId:e.toolCallId,toolName:t.toolName,state:`output-error`,input:t.input,errorText:e.errorText,providerExecuted:e.providerExecuted,providerMetadata:e.providerMetadata,title:t.title,toolMetadata:t.toolMetadata},t):p({toolCallId:e.toolCallId,toolName:ni(t),state:`output-error`,input:t.input,rawInput:t.rawInput,errorText:e.errorText,providerExecuted:e.providerExecuted,providerMetadata:e.providerMetadata,title:t.title,toolMetadata:t.toolMetadata},t),c();break}case`start-step`:r.message.parts.push({type:`step-start`});break;case`finish-step`:r.activeTextParts=K(),r.activeReasoningParts=K();break;case`reset-step`:{let e=l();r.activeTextParts=K(),r.activeReasoningParts=K(),r.partialToolCalls=K(),e.length>0&&(r.message.parts.splice(r.message.parts.length-e.length,e.length),c());break}case`start`:e.messageId!=null&&(r.message.id=e.messageId),await h(e.messageMetadata),(e.messageId!=null||e.messageMetadata!=null)&&c({updateStatus:!1});break;case`finish`:e.finishReason!=null&&(r.finishReason=e.finishReason),await h(e.messageMetadata),e.messageMetadata!=null&&c();break;case`message-metadata`:await h(e.messageMetadata),e.messageMetadata!=null&&c();break;case`error`:i?.(Error(e.errorText));break;default:if(Qr(e)){if(n?.[e.type]!=null){let t=r.message.parts.findIndex(t=>`id`in t&&`data`in t&&t.id===e.id&&t.type===e.type),i=t>=0?t:r.message.parts.length;await pr({value:e.data,schema:n[e.type],context:{field:`message.parts[${i}].data`,entityName:e.type,entityId:e.id}})}let t=e;if(t.transient){o?.(t);break}let i=t.id==null?void 0:r.message.parts.find(e=>t.type===e.type&&t.id===e.id);i==null?r.message.parts.push(t):i.data=t.data,o?.(t),c()}}s.enqueue(e)})}}))}async function oi({stream:e,onError:t,abortSignal:n}){let r=e.getReader(),i=()=>{r.cancel().catch(()=>{})};n?.aborted?i():n?.addEventListener(`abort`,i,{once:!0});try{for(;;){let{done:e}=await r.read();if(e)break}}catch(e){t?.(e)}finally{n?.removeEventListener(`abort`,i),r.releaseLock()}}O({prefix:`aitxt`,size:24}),O({prefix:`call`,size:24}),O({prefix:`aitxt`,size:24}),O({prefix:`call`,size:24}),B.record(B.string(),V.optional()),B.record(B.string(),B.string()),O({prefix:`call`,size:24}),O({prefix:`call`,size:24}),O({prefix:`aiobj`,size:24});var si=class{constructor(){this.queue=[],this.isProcessing=!1}async processQueue(){if(!this.isProcessing){for(this.isProcessing=!0;this.queue.length>0;)await this.queue[0](),this.queue.shift();this.isProcessing=!1}}async run(e){return new Promise((t,n)=>{this.queue.push(async()=>{try{await e(),t()}catch(e){n(e)}}),this.processQueue()})}};O({prefix:`aiobj`,size:24}),O({prefix:`call`,size:24});async function ci(e){if(e==null)return[];if(!globalThis.FileList||!(e instanceof globalThis.FileList))throw Error(`FileList is not supported in the current environment`);return Promise.all(Array.from(e).map(async e=>{let{name:t,type:n}=e;return{type:`file`,mediaType:n,filename:t,url:await new Promise((t,n)=>{let r=new FileReader;r.onload=e=>{t(e.target?.result)},r.onerror=e=>n(e),r.readAsDataURL(e)})}}))}var li=class{constructor({api:e=`/api/chat`,credentials:t,headers:n,body:r,fetch:i,prepareSendMessagesRequest:a,prepareReconnectToStreamRequest:o}){this.api=e,this.credentials=t,this.headers=n,this.body=r,this.fetch=i,this.prepareSendMessagesRequest=a,this.prepareReconnectToStreamRequest=o}async sendMessages({abortSignal:e,...t}){let n=await L(this.body),r=await L(this.headers),i=await L(this.credentials),a={...k(r),...k(t.headers)},o=await this.prepareSendMessagesRequest?.call(this,{api:this.api,id:t.chatId,messages:t.messages,body:{...n,...t.body},headers:a,credentials:i,requestMetadata:t.metadata,trigger:t.trigger,messageId:t.messageId}),s=o?.api??this.api,c=o?.headers===void 0?a:k(o.headers),l=o?.body===void 0?{...n,...t.body,id:t.chatId,messages:t.messages,trigger:t.trigger,messageId:t.messageId}:o.body,u=o?.credentials??i,d=await(this.fetch??globalThis.fetch)(s,{method:`POST`,headers:{"Content-Type":`application/json`,...c},body:JSON.stringify(l),credentials:u,signal:e});if(!d.ok)throw Error(await d.text()??`Failed to fetch the chat response.`);if(!d.body)throw Error(`The response body is empty.`);return this.processResponseStream(d.body)}async reconnectToStream(e){let t=await L(this.body),n=await L(this.headers),r=await L(this.credentials),i={...k(n),...k(e.headers)},a=await this.prepareReconnectToStreamRequest?.call(this,{api:this.api,id:e.chatId,body:{...t,...e.body},headers:i,credentials:r,requestMetadata:e.metadata}),o=a?.api??`${this.api}/${e.chatId}/stream`,s=a?.headers===void 0?i:k(a.headers),c=a?.credentials??r,l=await(this.fetch??globalThis.fetch)(o,{method:`GET`,headers:s,credentials:c,signal:e.abortSignal});if(l.status===204)return null;if(!l.ok)throw Error(await l.text()??`Failed to fetch the chat response.`);if(!l.body)throw Error(`The response body is empty.`);return this.processResponseStream(l.body)}},ui=class extends li{constructor(e={}){super(e)}processResponseStream(e){return hr({stream:e,schema:Zr}).pipeThrough(new TransformStream({async transform(e,t){if(!e.success)throw e.error;t.enqueue(e.value)}}))}},di=class{constructor({generateId:e=Qt,id:t=e(),transport:n=new ui,messageMetadataSchema:r,dataPartSchemas:i,state:a,onError:o,onToolCall:s,onFinish:c,onData:l,sendAutomaticallyWhen:u}){this.pendingMessagePreparations=new Set,this.activeResponse=void 0,this.activeResumeRequest=void 0,this.jobExecutor=new si,this.sendMessage=async(e,t)=>{if(e==null){await this.makeRequest({trigger:`submit-message`,messageId:this.lastMessage?.id,...t});return}let n;if(`text`in e||`files`in e){let t=new AbortController;this.pendingMessagePreparations.add(t);let r;try{r=Array.isArray(e.files)?e.files:await ci(e.files)}finally{this.pendingMessagePreparations.delete(t)}if(t.signal.aborted)return;n={parts:[...r,...`text`in e&&e.text!=null?[{type:`text`,text:e.text}]:[]]}}else n=e;if(e.messageId!=null){let t=this.state.messages.findIndex(t=>t.id===e.messageId);if(t===-1)throw Error(`message with id ${e.messageId} not found`);if(this.state.messages[t].role!==`user`)throw Error(`message with id ${e.messageId} is not a user message`);this.state.messages=this.state.messages.slice(0,t+1),this.state.replaceMessage(t,{...n,id:e.messageId,role:n.role??`user`,metadata:e.metadata})}else this.state.pushMessage({...n,id:n.id??this.generateId(),role:n.role??`user`,metadata:e.metadata});await this.makeRequest({trigger:`submit-message`,messageId:e.messageId,...t})},this.regenerate=async({messageId:e,...t}={})=>{let n=e==null?this.state.messages.length-1:this.state.messages.findIndex(t=>t.id===e);if(n===-1)throw Error(`message ${e} not found`);this.state.messages=this.state.messages.slice(0,this.messages[n].role===`assistant`?n:n+1),await this.makeRequest({trigger:`regenerate-message`,messageId:e,...t})},this.resumeStream=async(e={})=>{await this.makeRequest({trigger:`resume-stream`,...e})},this.clearError=()=>{this.status===`error`&&(this.state.error=void 0,this.setStatus({status:`ready`}))},this.addToolApprovalResponse=async({id:e,approved:t,reason:n,options:r})=>this.jobExecutor.run(async()=>{let i=this.state.messages,a=i[i.length-1],o=r=>q(r)&&r.state===`approval-requested`&&r.approval.id===e?{...r,state:`approval-responded`,approval:{...r.approval,id:e,approved:t,reason:n}}:r;this.state.replaceMessage(i.length-1,{...a,parts:a.parts.map(o)}),this.activeResponse&&(this.activeResponse.state.message.parts=this.activeResponse.state.message.parts.map(o)),this.status!==`streaming`&&this.status!==`submitted`&&this.sendAutomaticallyWhen&&this.shouldSendAutomatically().then(e=>{e&&this.makeRequest({trigger:`submit-message`,messageId:this.lastMessage?.id,...r})})}),this.addToolOutput=async({state:e=`output-available`,toolCallId:t,output:n,errorText:r,options:i})=>this.jobExecutor.run(async()=>{let a=this.state.messages,o=a[a.length-1],s=i=>q(i)&&i.toolCallId===t?{...i,state:e,output:n,errorText:r}:i;this.state.replaceMessage(a.length-1,{...o,parts:o.parts.map(s)}),this.activeResponse&&(this.activeResponse.state.message.parts=this.activeResponse.state.message.parts.map(s)),this.status!==`streaming`&&this.status!==`submitted`&&this.sendAutomaticallyWhen&&this.shouldSendAutomatically().then(e=>{e&&this.makeRequest({trigger:`submit-message`,messageId:this.lastMessage?.id,...i})})}),this.addToolResult=this.addToolOutput,this.stop=async()=>{var e,t;for(let e of this.pendingMessagePreparations)e.abort();(e=this.activeResumeRequest)==null||e.abortController.abort(),(t=this.activeResponse)==null||t.abortController.abort()},this.id=t,this.transport=n,this.generateId=e,this.messageMetadataSchema=r,this.dataPartSchemas=i,this.state=a,this.onError=o,this.onToolCall=s,this.onFinish=c,this.onData=l,this.sendAutomaticallyWhen=u}get status(){return this.state.status}setStatus({status:e,error:t}){this.status!==e&&(this.state.status=e,this.state.error=t)}get error(){return this.state.error}get messages(){return this.state.messages}get lastMessage(){return this.state.messages[this.state.messages.length-1]}set messages(e){this.state.messages=e}async shouldSendAutomatically(){if(!this.sendAutomaticallyWhen)return!1;let e=this.sendAutomaticallyWhen({messages:this.state.messages});return e&&typeof e==`object`&&`then`in e?await e:e}async makeRequest({trigger:e,metadata:t,headers:n,body:r,messageId:i}){var a,o;let s=new AbortController,c=e===`resume-stream`?{abortController:s}:void 0;c&&((a=this.activeResumeRequest)==null||a.abortController.abort(),this.activeResumeRequest=c);let l=()=>c==null||this.activeResumeRequest===c,u=()=>{this.activeResumeRequest===c&&(this.activeResumeRequest=void 0)},d;if(e===`resume-stream`)try{let e=await this.transport.reconnectToStream({chatId:this.id,abortSignal:s.signal,metadata:t,headers:n,body:r});if(s.signal.aborted||!l()){await e?.cancel().catch(()=>{}),l()&&this.setStatus({status:`ready`}),u();return}if(e==null){this.setStatus({status:`ready`}),u();return}d=e}catch(e){if(s.signal.aborted||e.name===`AbortError`){l()&&this.setStatus({status:`ready`}),u();return}if(!l())return;this.onError&&e instanceof Error&&this.onError(e),this.setStatus({status:`error`,error:e}),u();return}this.setStatus({status:`submitted`,error:void 0});let f=this.lastMessage,p=!1,m=!1,h=!1,g;try{let a={state:ii({lastMessage:e===`resume-stream`||e===`regenerate-message`?void 0:this.state.snapshot(f),messageId:this.generateId()}),abortController:s};g=a,a.abortController.signal.addEventListener(`abort`,()=>{p=!0}),this.activeResponse=a;let o;if(o=e===`resume-stream`?d:await this.transport.sendMessages({chatId:this.id,messages:this.state.messages,abortSignal:a.abortController.signal,metadata:t,headers:n,body:r,trigger:e,messageId:i}),await oi({stream:ai({stream:o,onToolCall:this.onToolCall,onData:this.onData,messageMetadataSchema:this.messageMetadataSchema,dataPartSchemas:this.dataPartSchemas,runUpdateMessageJob:e=>this.jobExecutor.run(()=>a.abortController.signal.aborted?Promise.resolve():e({state:a.state,write:({updateStatus:e=!0}={})=>{a.abortController.signal.aborted||(e&&this.setStatus({status:`streaming`}),a.state.message.id===this.lastMessage?.id?this.state.replaceMessage(this.state.messages.length-1,a.state.message):this.state.pushMessage(a.state.message))}})),onError:e=>{throw e}}),abortSignal:a.abortController.signal,onError:e=>{throw e}}),p)return l()&&this.setStatus({status:`ready`}),null;l()&&this.setStatus({status:`ready`})}catch(e){if(p||e.name===`AbortError`)return p=!0,l()&&this.setStatus({status:`ready`}),null;if(!l())return null;h=!0,e instanceof TypeError&&(e.message.toLowerCase().includes(`fetch`)||e.message.toLowerCase().includes(`network`))&&(m=!0),this.onError&&e instanceof Error&&this.onError(e),this.setStatus({status:`error`,error:e})}finally{try{g&&((o=this.onFinish)==null||o.call(this,{message:g.state.message,messages:this.state.messages,isAbort:p,isDisconnect:m,isError:h,finishReason:g.state.finishReason}))}finally{this.activeResponse===g&&(this.activeResponse=void 0),u()}}!h&&await this.shouldSendAutomatically()&&await this.makeRequest({trigger:`submit-message`,messageId:this.lastMessage?.id,metadata:t,headers:n,body:r})}};function fi({messages:e}){let t=e[e.length-1];if(!t||t.role!==`assistant`)return!1;let n=t.parts.reduce((e,t,n)=>t.type===`step-start`?n:e,-1),r=t.parts.slice(n+1).filter(q).filter(e=>!e.providerExecuted);return r.length>0&&r.every(e=>e.state===`output-available`||e.state===`output-error`)}function pi(e){return new ui({api:ye(`/`,`Chat/Messages/`),credentials:`include`,body:{orgId:e}})}var mi=e(t(((e,t)=>{function n(e,t){if(typeof e!=`function`)throw TypeError(`Expected the first argument to be a \`function\`, got \`${typeof e}\`.`);let n,r=0;return function(...i){clearTimeout(n);let a=Date.now(),o=t-(a-r);o<=0?(r=a,e.apply(this,i)):n=setTimeout(()=>{r=Date.now(),e.apply(this,i)},o)}}t.exports=n}))(),1),hi=(e,t,n)=>{if(!t.has(e))throw TypeError(`Cannot `+n)},J=(e,t,n)=>(hi(e,t,`read from private field`),n?n.call(e):t.get(e)),Y=(e,t,n)=>{if(t.has(e))throw TypeError(`Cannot add the same private member more than once`);t instanceof WeakSet?t.add(e):t.set(e,n)},X=(e,t,n,r)=>(hi(e,t,`write to private field`),r?r.call(e,n):t.set(e,n),n);function gi(e,t){return t==null?e:(0,mi.default)(e,t)}function _i(e){return Array.isArray(e)?[...e]:typeof e==`object`&&e&&(Object.getPrototypeOf(e)===Object.prototype||Object.getPrototypeOf(e)===null)?{...e}:e}var Z,vi,yi,bi,xi,Si,Q,Ci,wi,Ti=class{constructor(e=[]){Y(this,Z,void 0),Y(this,vi,`ready`),Y(this,yi,void 0),Y(this,bi,new Set),Y(this,xi,new Set),Y(this,Si,new Set),this.pushMessage=e=>{X(this,Z,J(this,Z).concat(e)),J(this,Q).call(this)},this.popMessage=()=>{X(this,Z,J(this,Z).slice(0,-1)),J(this,Q).call(this)},this.replaceMessage=(e,t)=>{X(this,Z,[...J(this,Z).slice(0,e),this.snapshot(t),...J(this,Z).slice(e+1)]),J(this,Q).call(this)},this.snapshot=e=>{if(typeof e!=`object`||!e||!(`parts`in e)||!Array.isArray(e.parts))return e;let t=e,n={...t,parts:t.parts.map(e=>({...e}))};return`metadata`in t&&(n.metadata=_i(t.metadata)),n},this[`~registerMessagesCallback`]=(e,t)=>{let n=t?gi(e,t):e;return J(this,bi).add(n),()=>{J(this,bi).delete(n)}},this[`~registerStatusCallback`]=e=>(J(this,xi).add(e),()=>{J(this,xi).delete(e)}),this[`~registerErrorCallback`]=e=>(J(this,Si).add(e),()=>{J(this,Si).delete(e)}),Y(this,Q,()=>{J(this,bi).forEach(e=>e())}),Y(this,Ci,()=>{J(this,xi).forEach(e=>e())}),Y(this,wi,()=>{J(this,Si).forEach(e=>e())}),X(this,Z,e)}get status(){return J(this,vi)}set status(e){X(this,vi,e),J(this,Ci).call(this)}get error(){return J(this,yi)}set error(e){X(this,yi,e),J(this,wi).call(this)}get messages(){return J(this,Z)}set messages(e){X(this,Z,[...e]),J(this,Q).call(this)}};Z=new WeakMap,vi=new WeakMap,yi=new WeakMap,bi=new WeakMap,xi=new WeakMap,Si=new WeakMap,Q=new WeakMap,Ci=new WeakMap,wi=new WeakMap;var $,Ei=class extends di{constructor({messages:e,...t}){let n=new Ti(e);super({...t,state:n}),Y(this,$,void 0),this[`~registerMessagesCallback`]=(e,t)=>J(this,$)[`~registerMessagesCallback`](e,t),this[`~registerStatusCallback`]=e=>J(this,$)[`~registerStatusCallback`](e),this[`~registerErrorCallback`]=e=>J(this,$)[`~registerErrorCallback`](e),X(this,$,n)}};$=new WeakMap;function Di({throttle:e,experimental_throttle:t,resume:n=!1,...r}={}){let i=e??t,a=(0,C.useRef)({});`chat`in r||(a.current={onToolCall:r.onToolCall,onData:r.onData,onFinish:r.onFinish,onError:r.onError,sendAutomaticallyWhen:r.sendAutomaticallyWhen,transport:r.transport});let o,s=()=>a.current.transport??(o??=new ui),c={...r,transport:{sendMessages:e=>s().sendMessages(e),reconnectToStream:e=>s().reconnectToStream(e)},onToolCall:e=>{var t;return(t=a.current).onToolCall?.call(t,e)},onData:e=>{var t;return(t=a.current).onData?.call(t,e)},onFinish:e=>{var t;return(t=a.current).onFinish?.call(t,e)},onError:e=>{var t;return(t=a.current).onError?.call(t,e)},sendAutomaticallyWhen:e=>{var t;return(t=a.current).sendAutomaticallyWhen?.call(t,e)??!1}},l=(0,C.useRef)(`chat`in r?r.chat:new Ei(c));(`chat`in r&&r.chat!==l.current||`id`in r&&r.id!=null&&l.current.id!==r.id)&&(l.current=`chat`in r?r.chat:new Ei(c));let u=l.current,d=(0,C.useRef)({chat:u,messages:u.messages});d.current.chat!==u&&(d.current={chat:u,messages:u.messages});let f=(0,C.useCallback)(e=>{let t=!0,n=u[`~registerMessagesCallback`](()=>{!t||d.current.chat!==u||(d.current={chat:u,messages:u.messages},e())},i);return d.current={chat:u,messages:u.messages},()=>{t=!1,n()}},[u,i]),p=(0,C.useCallback)(()=>d.current.messages,[]),m=(0,C.useSyncExternalStore)(f,p,p),h=(0,C.useCallback)(e=>u[`~registerStatusCallback`](()=>{d.current.chat===u&&((u.status===`ready`||u.status===`error`)&&(d.current={chat:u,messages:u.messages}),e())}),[u]),g=(0,C.useCallback)(()=>u.status,[u]),_=(0,C.useSyncExternalStore)(h,g,g),v=(0,C.useSyncExternalStore)(l.current[`~registerErrorCallback`],()=>l.current.error,()=>l.current.error),ee=(0,C.useCallback)(e=>{typeof e==`function`&&(e=e(l.current.messages)),l.current.messages=e},[l]);return(0,C.useEffect)(()=>{n&&l.current.resumeStream()},[n,l]),{id:l.current.id,messages:m,setMessages:ee,sendMessage:l.current.sendMessage,regenerate:l.current.regenerate,clearError:l.current.clearError,stop:l.current.stop,error:v,resumeStream:l.current.resumeStream,status:_,addToolResult:l.current.addToolOutput,addToolOutput:l.current.addToolOutput,addToolApprovalResponse:l.current.addToolApprovalResponse}}function Oi({input:e,setInput:t,onSubmit:n,disabled:r,autoFocus:i}){let a=(0,C.useRef)(null);return(0,C.useEffect)(()=>{i&&!r&&a.current?.focus()},[i,r]),(0,w.jsxs)(`form`,{onSubmit:n,className:`input-area`,children:[(0,w.jsx)(`input`,{ref:a,value:e,onChange:e=>t(e.target.value),placeholder:`Type a message...`,disabled:r}),(0,w.jsx)(`button`,{type:`submit`,disabled:r||!e.trim(),children:(0,w.jsx)(pt,{size:18})})]})}function ki(){return(0,w.jsxs)(`div`,{className:`loading-state`,children:[(0,w.jsx)(ze,{className:`animate-spin`,size:24}),(0,w.jsx)(`p`,{children:`Loading conversation...`})]})}var Ai={name:`collectFeedback`,description:`Collects feedback from the user by fetching a link to a pre-populated GitHub Discussion. Use this if the user lets us know we did something well, or if the user seems frustrated, or wants to report a bug.`,inputSchema:i({feedbackSummary:y().describe(`A brief summary of the feedback, used as the discussion title.`),feedbackDetails:y().describe(`Detailed feedback from the user or agent observation.`),recap:y().describe(`A sanitized recap of what the agent and user did together and if it was successful. No sensitive information.`)})};async function ji({input:{feedbackSummary:e,feedbackDetails:t,recap:n}}){let r=e,i=`${t}\n\n${n}`;return{success:!0,url:`https://github.com/HarperFast/harper-agent/discussions/new?category=usage-feedback&title=${encodeURIComponent(r)}&body=${encodeURIComponent(i)}`,message:`Feedback URL created! Ask the user to open it in their browser, and they will be brought to a form to approve the details of the feedback.`}}var Mi={...Ai,icon:ft,execute:ji},Ni={name:`createApp`,description:`Create a new Harper app with the specified name and template type.`,inputSchema:i({name:y().trim(),type:p(be)})};async function Pi({input:{name:e,type:t},instanceClientParams:n,baseURL:r}){let i=qe(e),a=ve(me,`id`,t);if(!a)return{success:!1,message:`Error: Invalid template type, ${t}, please choose from: ${me.map(e=>e.id).join(`, `)}`};let o=le.loading(`Creating from template...`,{description:`This may take a bit.`,duration:3e5});try{await Ce({...n,project:i,template:a.npm||a.githubUrl})}catch(e){return{success:!1,message:`Error: ${e}`}}je(`ReloadApplicationRootEntries`,!0),le.loading(`Created successfully!`,{description:`${i} created! Restarting the HTTP service...`,id:o,duration:3e5});try{await tt({...n,operation:`restart_service`,replicated:n.entityType===`cluster`})}catch(e){return{success:!1,message:`Error: ${e}`}}return le.success(`Created successfully!`,{description:`${i} created!`,id:o,duration:5e3}),{success:!0,message:`App "${i}" created successfully.`,webURL:r}}var Fi={...Ni,icon:et,execute:Pi,requiresApproval:!0},Ii={name:`deleteTableRecords`,description:`Deletes records in a particular table in a particular database on the server by their primary keys.`,inputSchema:i({database:y().trim(),table:y().trim(),primaryKeys:_(y())})};async function Li({input:{database:e,table:t,primaryKeys:n},instanceClientParams:r,params:i}){try{let a=await We({...r,databaseName:e,tableName:t,hashValues:n}),{databaseName:o,tableName:s}=i;return await Xe.invalidateQueries({queryKey:[r.entityId,o,s]}),{success:!0,data:a}}catch(e){return{success:!1,message:`Error: ${e}`}}}var Ri={...Ii,icon:ot,execute:Li,requiresApproval:!0},zi={name:`dropComponentFile`,description:`Drops a component file by its full path (which was returned by getComponents)`,inputSchema:i({path:y().trim()})};async function Bi({input:{path:e},instanceClientParams:t}){try{let n=e.split(`/`),r=n.shift(),i=n.join(`/`);return{success:!0,data:await pe({...t,file:i,project:r})}}catch(e){return{success:!1,message:`Error: ${e}`}}}var Vi={...zi,icon:Ue,execute:Bi,requiresApproval:!0},Hi={name:`getAnalytics`,description:`Retrieves analytics metrics for the server, such as CPU usage or database operations (reads, writes, messages).`,inputSchema:i({metricName:y().describe(`The name of the metric to retrieve.`),startTime:c().describe(`The start of the time range for the metric, in milliseconds since the Unix epoch.`),endTime:c().describe(`The end of the time range for the metric, in milliseconds since the Unix epoch.`)})};async function Ui({input:e,instanceClientParams:t}){try{let{metricName:n,startTime:r,endTime:i}=e;return{success:!0,data:await at({metric:n,startTime:r,endTime:i,instanceParams:t})}}catch(e){return{success:!1,message:`Error retrieving analytics: ${e}`}}}var Wi={...Hi,icon:ct,execute:Ui},Gi={name:`getComponentFile`,description:`Returns the contents of a component file by its full path (which was returned by getComponents)`,inputSchema:i({path:y().trim()})};async function Ki({input:{path:e},instanceClientParams:t}){try{let n=e.split(`/`),r=n.shift(),i=n.join(`/`);return{success:!0,data:await Ye({...t,file:i,project:r})}}catch(e){return{success:!1,message:`Error: ${e}`}}}var qi={...Gi,icon:he,execute:Ki},Ji={name:`getComponents`,description:`Retrieves a tree of all the component (files and folders) names and sizes stored on the server.`,inputSchema:i({})};async function Yi({instanceClientParams:e}){try{let t=await Ge(e),{rootEntries:n}=xe(t.entries);return{success:!0,items:_e(n).items}}catch(e){return{success:!1,message:`Error: ${e}`}}}var Xi={...Ji,icon:ge,execute:Yi},Zi={name:`getDescribeAll`,description:`Retrieves a map of the names of databases and their tables stored on the server.`,inputSchema:i({})};async function Qi({instanceClientParams:e}){try{return{success:!0,map:await $e(e)}}catch(e){return{success:!1,message:`Error: ${e}`}}}var $i={...Zi,icon:Je,execute:Qi},ea={name:`getDescribeTable`,description:`Returns the schema metadata describing a particular table in a particular database on the server.`,inputSchema:i({database:y().trim(),table:y().trim()})};async function ta({input:{database:e,table:t},instanceClientParams:n}){try{return{success:!0,data:await Le({...n,databaseName:e,tableName:t})}}catch(e){return{success:!1,message:`Error: ${e}`}}}var na={...ea,icon:Ze,execute:ta},ra={name:`getUserContext`,description:`Retrieves the context of what the user is looking at on their screen, such as the current page, the file they are viewing, the database and table visible to them, that sort of thing.`,inputSchema:i({})};async function ia({instanceClientParams:e,params:t}){let n=Oe();if(n.includes(`/databases`)){let{databaseName:e,tableName:n}=t;return{success:!0,description:`viewing the database`,data:{databaseName:e,tableName:n}}}if(n.endsWith(`/apis`))return{success:!0,description:`viewing the APIs`};if(n.endsWith(`/status`))return{success:!0,description:`viewing the status graphs`};if(n.endsWith(`/logs`))return{success:!0,description:`viewing the logs`};if(n.includes(`/config/`))return{success:!0,description:`viewing the configuration pages`};let r=ce(`FileFocused/${e.entityId}`,void 0),i=ce(`FolderOpened/${e.entityId}`,[]),a=ce(`FileSelected/${e.entityId}`,[]);return r?{success:!0,description:`editing application files`,data:{openedPath:r,expandedItems:i,selectedItems:a}}:{success:!0,description:n}}var aa={...ra,icon:Ve,execute:ia},oa={name:`insertTableRecords`,description:`Inserts one or more records into a particular table in a particular database on the server.`,inputSchema:i({database:y().trim(),table:y().trim(),records:_(m())})};async function sa({input:{database:e,table:t,records:n},instanceClientParams:r,params:i}){try{let a=await Re({...r,databaseName:e,tableName:t,records:n}),{databaseName:o,tableName:s}=i;return await Xe.invalidateQueries({queryKey:[r.entityId,o,s]}),{success:!0,data:a}}catch(e){return{success:!1,message:`Error: ${e}`}}}var ca={...oa,icon:ot,execute:sa,requiresApproval:!0},la={name:`listAnalyticsMetrics`,description:`Lists the available analytics metric names available for calling getAnalytics upon.`,inputSchema:i({metricTypes:p([`builtin`,`custom`]),customWindowMS:c().optional().describe(`Default to one week time window for finding custom metrics.`)})};async function ua({metricTypes:e,customWindowMS:t,instanceParams:n}){let{data:r}=await n.instanceClient.post(`/`,{operation:`list_analytics_metrics`,metricTypes:e,customWindowMS:t});return r}async function da({input:e,instanceClientParams:t}){try{let{metricTypes:n,customWindowMS:r}=e;return{success:!0,metricNames:await ua({metricTypes:n,customWindowMS:r,instanceParams:t})}}catch(e){return{success:!1,message:`Error retrieving analytics: ${e}`}}}var fa={...la,icon:ct,execute:da},pa=[`adding-tables-with-schemas`,`automatic-apis`,`caching`,`checking-authentication`,`creating-a-fabric-account-and-cluster`,`creating-harper-apps`,`custom-resources`,`defining-relationships`,`delegating-to-the-built-in-agent`,`deploying-to-harper-fabric`,`extending-tables`,`handling-binary-data`,`load-env`,`logging`,`programmatic-table-requests`,`querying-rest-apis`,`real-time-apps`,`schema-design-tooling`,`serving-web-content`,`typescript-type-stripping`,`using-blob-datatype`,`v5-upgrade`,`vector-indexing`],ma={"adding-tables-with-schemas":"---\nname: adding-tables-with-schemas\ndescription: Guidelines for adding tables to a Harper database using GraphQL schemas.\nmetadata:\n mode: synthesized\n---\n\n# Adding Tables with Schemas\n\nInstructions for the agent to follow when adding tables to a Harper database.\n\n## When to Use\n\nUse this skill when you need to define new data structures or modify existing ones in a Harper database.\n\n## How It Works\n\n1. **Create Dedicated Schema Files**: Prefer having a dedicated schema `.graphql` file for each table. Check the `config.yaml` file under `graphqlSchema.files` to see how it's configured. It typically accepts wildcards (e.g., `schemas/*.graphql`), but may be configured to point at a single file.\n2. **Use Directives**: All available directives for defining your schema are defined in `node_modules/harper/schema.graphql`. Common directives include `@table`, `@export`, `@primaryKey`, `@indexed`, and `@relationship`.\n3. **Define Relationships**: Link tables together using the `@relationship` directive. For more details, see the [Defining Relationships](defining-relationships.md) skill.\n4. **Enable Automatic APIs**: If you add `@table @export` to a schema type, Harper automatically sets up REST and WebSocket APIs for basic CRUD operations against that table. **Important**: REST endpoints also require `rest: true` in `config.yaml` — without it, `@export`ed tables will not respond to HTTP requests. For a detailed list of available endpoints and how to use them, see the [Automatic REST APIs](automatic-apis.md) skill.\n - `GET /{TableName}`: Describes the schema itself.\n - `GET /{TableName}/`: Lists all records (supports filtering, sorting, and pagination via query parameters). See the [Querying REST APIs](querying-rest-apis.md) skill for details.\n - `GET /{TableName}/{id}`: Retrieves a single record by its ID.\n - `POST /{TableName}/`: Creates a new record.\n - `PUT /{TableName}/{id}`: Updates an existing record.\n - `PATCH /{TableName}/{id}`: Performs a partial update on a record.\n - `DELETE /{TableName}/`: Deletes all records or filtered records.\n - `DELETE /{TableName}/{id}`: Deletes a single record by its ID.\n5. **Consider Table Extensions**: If you are going to [extend the table](./extending-tables.md) in your resources, then do not `@export` the table from the schema.\n\n## Examples\n\nIn a hypothetical `schemas/ExamplePerson.graphql`:\n\n```graphql\ntype ExamplePerson @table @export {\n id: ID @primaryKey\n name: String\n tag: String @indexed\n}\n```\n","automatic-apis":`---
17
- name: automatic-apis
18
- description: How to use Harper's automatically generated REST and WebSocket APIs.
19
- metadata:
20
- mode: generate
21
- sources:
22
- - reference/v5/rest/overview.md
23
- - reference/v5/rest/websockets.md
24
- sourceCommit: 3749d0c54be457a2a65d9a63c738a5dc88989ecd
25
- inputHash: 6c7013b1307d9f7b
26
- ---
27
-
28
- # Automatic APIs
29
-
30
- Instructions for the agent to follow when enabling and using Harper's automatically generated REST and WebSocket APIs.
31
-
32
- ## When to Use
33
-
34
- Apply this rule when adding REST or WebSocket API access to Harper tables or custom resources. Use it when configuring \`config.yaml\` to expose endpoints, mapping HTTP methods to resource operations, or implementing real-time WebSocket connections on a resource class.
35
-
36
- ## How It Works
37
-
38
- 1. **Enable the REST plugin**: Add \`rest: true\` to your application's \`config.yaml\`. This activates the HTTP REST interface on the application server port (default \`9926\`) and enables WebSocket support automatically.
39
-
40
- \`\`\`yaml
41
- rest: true
42
- \`\`\`
43
-
44
- To configure options explicitly:
45
-
46
- \`\`\`yaml
47
- rest:
48
- lastModified: true # enables Last-Modified response header support
49
- webSocket: false # disables automatic WebSocket support (enabled by default)
50
- \`\`\`
51
-
52
- 2. **Export your resource in the schema**: Tables are not exposed by default. Use the \`@export\` directive in your schema definition to expose a table as a REST endpoint. The exported name defines the base URL path.
53
-
54
- 3. **Use the correct URL structure**: Target resources using these path conventions:
55
-
56
- | Path | Description |
57
- | -------------------------------------------- | ----------------------------------------------------------- |
58
- | \`/my-resource\` | Returns resource metadata |
59
- | \`/my-resource/\` | Collection — all records; append query parameters to search |
60
- | \`/my-resource/record-id\` | Specific record by primary key |
61
- | \`/my-resource/record-id/\` | Collection of records with the given id prefix |
62
- | \`/my-resource/record-id/with/multiple/parts\` | Record id with multiple path segments |
63
-
64
- 4. **Map operations to HTTP methods**: Each HTTP method maps to a resource method:
65
- - **GET** — Retrieve a record or search. Calls \`get()\`. Responses include an \`ETag\` header; send \`If-None-Match\` on subsequent requests to receive \`304 Not Modified\` when unchanged.
66
- - **PUT** — Create or replace a record (upsert). Calls \`put(record)\`. The stored record exactly matches the submitted body; omitted properties are removed.
67
- - **POST** — Create a record without specifying a primary key. Calls \`post(data)\`. The assigned key is returned in the \`Location\` response header.
68
- - **PATCH** — Partially update a record, merging only provided top-level properties. Calls the resource's patch handler. Merge is **shallow** — nested objects are replaced entirely, not deep-merged.
69
- - **DELETE** — Delete a record by id or all records matching a query.
70
-
71
- 5. **Connect via WebSocket**: A WebSocket connection to a resource URL subscribes to that resource and streams change events. See [real-time-apps.md](real-time-apps.md) for full real-time patterns.
72
-
73
- \`\`\`javascript
74
- let ws = new WebSocket('wss://server/my-resource/341');
75
- ws.onmessage = (event) => {
76
- let data = JSON.parse(event.data);
77
- };
78
- \`\`\`
79
-
80
- 6. **Implement a custom \`connect()\` handler** on a resource class to control WebSocket behavior. The method receives \`incomingMessages\` and must return an async iterable producing messages to send to the client.
81
-
82
- 7. **Retrieve the OpenAPI spec**: Harper auto-generates an OpenAPI specification for all exported resources, available at:
83
-
84
- \`\`\`
85
- GET /openapi
86
- \`\`\`
87
-
88
- ## Examples
89
-
90
- **Simple echo WebSocket server**:
91
-
92
- \`\`\`javascript
93
- export class Echo extends Resource {
94
- async *connect(incomingMessages) {
95
- for await (let message of incomingMessages) {
96
- yield message; // echo each message back
97
- }
98
- }
99
- }
100
- \`\`\`
101
-
102
- **Custom \`connect()\` using the default iterable with \`send()\` and \`close\` event**:
103
-
104
- \`\`\`javascript
105
- export class Example extends Resource {
106
- connect(incomingMessages) {
107
- let outgoingMessages = super.connect();
108
-
109
- let timer = setInterval(() => {
110
- outgoingMessages.send({ greeting: 'hi again!' });
111
- }, 1000);
112
-
113
- incomingMessages.on('data', (message) => {
114
- outgoingMessages.send(message); // echo incoming messages
115
- });
116
-
117
- outgoingMessages.on('close', () => {
118
- clearInterval(timer);
119
- });
120
-
121
- return outgoingMessages;
122
- }
123
- }
124
- \`\`\`
125
-
126
- **Common REST operations**:
127
-
128
- \`\`\`
129
- GET /MyTable/123
130
- GET /MyTable/?name=Harper
131
- PUT /MyTable/123
132
- PATCH /MyTable/123
133
- DELETE /MyTable/?status=archived
134
- \`\`\`
135
-
136
- \`\`\`json
137
- { "name": "some data" }
138
- \`\`\`
139
-
140
- ## Notes
141
-
142
- - \`rest: true\` is the minimal config to enable both REST and WebSocket support. Set \`webSocket: false\` under the \`rest\` key to disable WebSocket only.
143
- - The \`@export\` directive in the schema is required for any table to appear as a REST endpoint — tables are not exported by default.
144
- - PATCH merges are shallow (top-level only). Nested objects in the request body replace the entire existing sub-object. Dot-path keys (e.g., \`"settings.theme"\`) are stored as literal keys, not interpreted as paths.
145
- - For MQTT over WebSocket, set the sub-protocol header \`Sec-WebSocket-Protocol: mqtt\`.
146
- - In distributed environments, non-retained messages are delivered in arrival order; retained messages (PUT/updated records) keep only the latest timestamp as the winning record.
147
- - For full query syntax on GET and DELETE, see [querying-rest-apis.md](querying-rest-apis.md).
148
- - For building real-time features with WebSocket subscriptions, see [real-time-apps.md](real-time-apps.md).
149
- `,caching:`---
150
- name: caching
151
- description: How to implement integrated data caching in Harper from external sources.
152
- metadata:
153
- mode: generate
154
- sources:
155
- - learn/developers/caching-with-harper.md
156
- sourceCommit: 4fe4c9c95e0974eaa77032f6f10e36fbd8ec64ac
157
- inputHash: 60ad55fa37b5eec5
158
- ---
159
-
160
- # Caching External Data Sources in Harper
161
-
162
- Instructions for the agent to implement integrated data caching from external sources using Harper's cache table directives and \`sourcedFrom\` API.
163
-
164
- ## When to Use
165
-
166
- Apply this rule when an application needs to wrap an external API, microservice, or database with a fast local cache. Use it when you need to define TTL-based cache expiration, connect an upstream data source to a Harper table, or implement on-demand cache invalidation.
167
-
168
- ## How It Works
169
-
170
- 1. **Define a cache table with \`expiration\`**: Add the \`expiration\` argument to the \`@table\` directive in \`schema.graphql\`. The value is in seconds. When a record becomes stale, the next request fetches a fresh copy from the upstream source.
171
-
172
- \`\`\`graphql
173
- type JokeCache @table(expiration: 60) @export {
174
- id: ID @primaryKey
175
- setup: String
176
- punchline: String
177
- }
178
- \`\`\`
179
-
180
- 2. **Implement an upstream source object**: In \`resources.js\`, create an object with a \`get(id)\` method that fetches data from the external API.
181
-
182
- \`\`\`javascript
183
- const jokeAPI = {
184
- async get(id) {
185
- const response = await fetch(\`https://official-joke-api.appspot.com/jokes/\${id}\`);
186
- return response.json();
187
- },
188
- };
189
- \`\`\`
190
-
191
- 3. **Connect the source with \`sourcedFrom\`**: Call \`sourcedFrom\` on the table to register the upstream source. Harper will call \`jokeAPI.get()\` automatically when a record is missing or stale.
192
-
193
- \`\`\`javascript
194
- tables.JokeCache.sourcedFrom(jokeAPI);
195
- \`\`\`
196
-
197
- Harper's request flow after \`sourcedFrom\` is registered:
198
- - Request arrives for \`/JokeCache/1\`.
199
- - Harper checks if the record exists and is not stale.
200
- - If fresh, Harper returns it immediately.
201
- - If missing or stale, Harper calls \`jokeAPI.get()\`, stores the result in \`JokeCache\`, and returns it.
202
- - Multiple simultaneous requests for the same missing or stale record wait on a single upstream call — Harper prevents cache stampedes automatically.
203
-
204
- 4. **Configure plugins in \`config.yaml\`**: Enable \`graphqlSchema\`, \`rest\`, and \`jsResource\`.
205
-
206
- \`\`\`yaml
207
- graphqlSchema:
208
- files: 'schema.graphql'
209
- rest: true
210
- jsResource:
211
- files: 'resources.js'
212
- \`\`\`
213
-
214
- 5. **Implement on-demand invalidation**: To invalidate a cache entry before its TTL expires, export a class extending the table and call \`this.invalidate(target)\` in a \`post\` handler. Remove \`@export\` from the schema when using this pattern — the exported class provides the endpoint.
215
-
216
- \`\`\`javascript
217
- export class JokeCache extends tables.JokeCache {
218
- static async post(target, data) {
219
- const body = await data;
220
- if (body?.action === 'invalidate') {
221
- this.invalidate(target);
222
- return { status: 200, data: { message: 'invalidated' } };
223
- }
224
- }
225
- }
226
- \`\`\`
227
-
228
- Update the schema to remove \`@export\`:
229
-
230
- \`\`\`graphql
231
- type JokeCache @table(expiration: 60) {
232
- id: ID @primaryKey
233
- setup: String
234
- punchline: String
235
- }
236
- \`\`\`
237
-
238
- ## Examples
239
-
240
- **Complete \`resources.js\`**:
241
-
242
- \`\`\`javascript
243
- // resources.js
244
-
245
- const jokeAPI = {
246
- async get(id) {
247
- const response = await fetch(\`https://official-joke-api.appspot.com/jokes/\${id}\`);
248
- return response.json();
249
- },
250
- };
251
-
252
- tables.JokeCache.sourcedFrom(jokeAPI);
253
-
254
- export class JokeCache extends tables.JokeCache {
255
- static async post(target, data) {
256
- const body = await data;
257
- if (body?.action === 'invalidate') {
258
- this.invalidate(target);
259
- return { status: 200, data: { message: 'invalidated' } };
260
- }
261
- }
262
- }
263
- \`\`\`
264
-
265
- **Complete \`schema.graphql\`**:
266
-
267
- \`\`\`graphql
268
- type JokeCache @table(expiration: 60) {
269
- id: ID @primaryKey
270
- setup: String
271
- punchline: String
272
- }
273
- \`\`\`
274
-
275
- **Fetch a cached record**:
276
-
277
- \`\`\`javascript
278
- const response = await fetch('http://localhost:9926/JokeCache/1');
279
- console.log(response.status); // 200
280
- const etag = response.headers.get('etag'); // e.g. "abCDefGHij"
281
- const joke = await response.json();
282
- \`\`\`
283
-
284
- **Use ETag for conditional requests** (returns \`304 Not Modified\` if unchanged):
285
-
286
- \`\`\`javascript
287
- const second = await fetch('http://localhost:9926/JokeCache/1', {
288
- headers: { 'If-None-Match': etag },
289
- });
290
- console.log(second.status); // 304
291
- \`\`\`
292
-
293
- **Bypass the cache with \`Cache-Control: no-cache\`**:
294
-
295
- \`\`\`javascript
296
- const response = await fetch('http://localhost:9926/JokeCache/1', {
297
- headers: { 'Cache-Control': 'no-cache' },
298
- });
299
- \`\`\`
300
-
301
- **Trigger invalidation via POST**:
302
-
303
- \`\`\`javascript
304
- await fetch('http://localhost:9926/JokeCache/1', {
305
- method: 'POST',
306
- headers: { 'Content-Type': 'application/json' },
307
- body: JSON.stringify({ action: 'invalidate' }),
308
- });
309
- \`\`\`
310
-
311
- ## Notes
312
-
313
- - \`expiration\` is measured in seconds. Harper also supports separate \`eviction\` and \`scanInterval\` arguments on \`@table\` for fine-grained control over physical record removal.
314
- - ETags are automatically computed from a record's last-modified timestamp. Include the double quotes when passing an ETag back in \`If-None-Match\` — they are part of the value.
315
- - Exporting a class with the same name as a table (e.g., \`export class JokeCache extends tables.JokeCache\`) registers it as the HTTP endpoint for that table; \`@export\` in the schema is not required separately.
316
- - For defining custom upstream source behavior beyond a simple \`get\`, see [custom-resources.md](custom-resources.md).
317
- - For details on how \`@table\` and \`@export\` expose REST endpoints automatically, see [automatic-apis.md](automatic-apis.md).
318
- `,"checking-authentication":`---
319
- name: checking-authentication
320
- description: How to handle user authentication and sessions in Harper Resources.
321
- metadata:
322
- mode: generate
323
- sources:
324
- - >-
325
- reference/v5/resources/resource-api.md#\`getCurrentUser(): User |
326
- undefined\`
327
- - reference/v5/resources/resource-api.md#Session and Login from a Resource
328
- - reference/v5/security/jwt-authentication.md
329
- sourceCommit: b7fbddadd42eb4487190b650a9abc4bcfeef5819
330
- inputHash: fdd9ec3b11011490
331
- ---
332
-
333
- # Checking Authentication
334
-
335
- Instructions for the agent to follow when handling user authentication and session management inside Harper Resources.
336
-
337
- ## When to Use
338
-
339
- Apply this rule when implementing authentication checks, login/logout flows, or token issuance inside a custom Resource. Use it any time a Resource needs to identify the current user, establish a session, or issue JWTs to clients. See [custom-resources.md](custom-resources.md) for the general Resource authoring pattern.
340
-
341
- ## How It Works
342
-
343
- 1. **Check the current user** with \`getCurrentUser()\`. Call it inside any Resource method to retrieve the authenticated user or \`undefined\` if no user is authenticated. Guard protected endpoints by returning a \`401\` when the result is \`undefined\`.
344
-
345
- \`\`\`javascript
346
- async get(target) {
347
- const user = this.getCurrentUser();
348
- if (!user) return new Response(null, { status: 401 });
349
- return { username: user.username, role: user.role };
350
- }
351
- \`\`\`
352
-
353
- The returned object exposes \`username\`, \`role\`, and \`role.permission\` flags.
354
-
355
- 2. **Enable sessions** before using session-based login. Set \`authentication.enableSessions: true\` in \`harperdb-config.yaml\`:
356
-
357
- \`\`\`yaml
358
- authentication:
359
- enableSessions: true
360
- \`\`\`
361
-
362
- 3. **Access login and session helpers** via \`getContext()\`. The context object exposes \`context.login\` and \`context.session\` for sign-in/out flows.
363
- - Call \`context.login(username, password)\` to verify credentials and establish a session cookie on success.
364
- - To end a session, delete it via \`context.session.delete(context.session.id)\`.
365
-
366
- 4. **Implement sign-in and sign-out Resources** using the context helpers:
367
-
368
- \`\`\`javascript
369
- export class SignIn extends Resource {
370
- async post(_target, data) {
371
- const context = this.getContext();
372
- try {
373
- await context.login(data.username, data.password);
374
- } catch {
375
- return new Response('Invalid credentials', { status: 403 });
376
- }
377
- return new Response('Logged in', { status: 200 });
378
- }
379
- }
380
-
381
- export class SignOut extends Resource {
382
- async post() {
383
- const context = this.getContext();
384
- if (!context.session) return new Response(null, { status: 401 });
385
- await context.session.delete(context.session.id);
386
- return new Response('Logged out', { status: 200 });
387
- }
388
- }
389
- \`\`\`
390
-
391
- 5. **Issue JWTs for non-browser clients** (CLI tools, mobile apps, service-to-service). Cookie-based sessions are intended for browser clients. For other clients, mint tokens programmatically using \`server.operation()\`:
392
-
393
- \`\`\`javascript
394
- import { Resource, server } from 'harper';
395
-
396
- export class IssueTokens extends Resource {
397
- static async get(_target, context) {
398
- const { operation_token, refresh_token } = await server.operation(
399
- { operation: 'create_authentication_tokens' },
400
- context,
401
- true,
402
- );
403
- return { operation_token, refresh_token };
404
- }
405
-
406
- static async post(_target, data) {
407
- const { username, password } = await data;
408
- if (!username || !password) {
409
- return new Response('username and password required', { status: 400 });
410
- }
411
- const { operation_token, refresh_token } = await server.operation({
412
- operation: 'create_authentication_tokens',
413
- username,
414
- password,
415
- });
416
- return { operation_token, refresh_token };
417
- }
418
- }
419
-
420
- export class RefreshJWT extends Resource {
421
- static async post(_target, data) {
422
- const { refresh_token } = await data;
423
- if (!refresh_token) {
424
- return new Response('refresh_token required', { status: 400 });
425
- }
426
- const { operation_token } = await server.operation({
427
- operation: 'refresh_operation_token',
428
- refresh_token,
429
- });
430
- return { operation_token };
431
- }
432
- }
433
- \`\`\`
434
-
435
- Pass \`true\` as the third argument to \`server.operation()\` when the operation should run as the current authenticated user. Omit it or pass \`false\` when the operation supplies its own credentials.
436
-
437
- 6. **Configure JWT token expiry** in \`harperdb-config.yaml\` under the \`authentication\` section:
438
-
439
- \`\`\`yaml
440
- authentication:
441
- operationTokenTimeout: 1d
442
- refreshTokenTimeout: 30d
443
- \`\`\`
444
-
445
- Duration strings follow the \`jsonwebtoken\` package format (e.g., \`1d\`, \`12h\`, \`60m\`).
446
-
447
- ## Examples
448
-
449
- **Protecting a resource endpoint and returning user info:**
450
-
451
- \`\`\`javascript
452
- async get(target) {
453
- const user = this.getCurrentUser();
454
- if (!user) return new Response(null, { status: 401 });
455
- return { username: user.username, role: user.role };
456
- }
457
- \`\`\`
458
-
459
- **Full session-based sign-in/sign-out flow:**
460
-
461
- \`\`\`javascript
462
- export class SignIn extends Resource {
463
- async post(_target, data) {
464
- const context = this.getContext();
465
- try {
466
- await context.login(data.username, data.password);
467
- } catch {
468
- return new Response('Invalid credentials', { status: 403 });
469
- }
470
- return new Response('Logged in', { status: 200 });
471
- }
472
- }
473
-
474
- export class SignOut extends Resource {
475
- async post() {
476
- const context = this.getContext();
477
- if (!context.session) return new Response(null, { status: 401 });
478
- await context.session.delete(context.session.id);
479
- return new Response('Logged out', { status: 200 });
480
- }
481
- }
482
- \`\`\`
483
-
484
- **JWT token refresh endpoint:**
485
-
486
- \`\`\`javascript
487
- export class RefreshJWT extends Resource {
488
- static async post(_target, data) {
489
- const { refresh_token } = await data;
490
- if (!refresh_token) {
491
- return new Response('refresh_token required', { status: 400 });
492
- }
493
- const { operation_token } = await server.operation({
494
- operation: 'refresh_operation_token',
495
- refresh_token,
496
- });
497
- return { operation_token };
498
- }
499
- }
500
- \`\`\`
501
-
502
- ## Notes
503
-
504
- - \`getCurrentUser()\` and \`getContext()\` are instance methods; call them with \`this\` inside non-static Resource methods.
505
- - \`enableSessions\` must be \`true\` in config before \`context.login\` or \`context.session\` will function.
506
- - Cookie-based sessions target browser clients. Use JWT issuance via \`server.operation()\` for all other client types.
507
- - When both \`operation_token\` and \`refresh_token\` have expired, the client must call \`create_authentication_tokens\` again with credentials.
508
- `,"creating-a-fabric-account-and-cluster":`---
509
- name: creating-a-fabric-account-and-cluster
510
- description: How to create a Harper Fabric account, organization, and cluster.
511
- metadata:
512
- mode: synthesized
513
- ---
514
-
515
- # Creating a Harper Fabric Account and Cluster
516
-
517
- Follow these steps to set up your Harper Fabric environment for deployment.
518
-
519
- ## How It Works
520
-
521
- 1. **Sign Up/In**: Go to [https://fabric.harper.fast/](https://fabric.harper.fast/) and sign up or sign in.
522
- 2. **Create an Organization**: Create an organization (org) to manage your projects.
523
- 3. **Create a Cluster**: Create a new cluster. This can be on the free tier, no credit card required.
524
- 4. **Set Credentials**: During setup, set the cluster username and password to finish configuring it.
525
- 5. **Get Application URL**: Navigate to the **Config** tab and copy the **Application URL**.
526
- 6. **Configure Environment**: Update your \`.env\` file or GitHub Actions secrets with cluster-specific credentials.
527
- 7. **Next Steps**: See the [deploying-to-harper-fabric](deploying-to-harper-fabric.md) rule for detailed instructions on deploying your application successfully.
528
-
529
- ## Examples
530
-
531
- ### Environment Configuration
532
-
533
- \`\`\`bash
534
- CLI_TARGET_USERNAME='YOUR_CLUSTER_USERNAME'
535
- CLI_TARGET_PASSWORD='YOUR_CLUSTER_PASSWORD'
536
- CLI_TARGET='YOUR_CLUSTER_URL'
537
- \`\`\`
538
- `,"creating-harper-apps":`---
539
- name: creating-harper-apps
540
- description: How to initialize a new Harper application using the CLI.
541
- metadata:
542
- mode: synthesized
543
- ---
544
-
545
- # Creating Harper Applications
546
-
547
- The fastest way to start a new Harper project is using the \`create-harper\` CLI tool. This command
548
- initializes a project with a standard folder structure, essential configuration files, and basic
549
- schema definitions.
550
-
551
- ## When to Use
552
-
553
- Use this command when starting a new Harper application or adding a new Harper microservice to an
554
- existing architecture.
555
-
556
- ## Commands
557
-
558
- Initialize a project using your preferred package manager:
559
-
560
- ### NPM
561
-
562
- \`\`\`bash
563
- npm create harper@latest
564
- \`\`\`
565
-
566
- ### PNPM
567
-
568
- \`\`\`bash
569
- pnpm create harper@latest
570
- \`\`\`
571
-
572
- ### Bun
573
-
574
- \`\`\`bash
575
- bun create harper@latest
576
- \`\`\`
577
-
578
- ## Options
579
-
580
- You can specify the project name and template directly:
581
-
582
- \`\`\`bash
583
- npm create harper@latest my-app --template default
584
- \`\`\`
585
-
586
- ## Next Steps
587
-
588
- 1. **Configure Environment**: Set up your \`.env\` file with local or cloud credentials.
589
- 2. **Define Schema**: Modify \`schema.graphql\` to fit your application's data model.
590
- 3. **Start Development**: Run \`npm run dev\` to start the local Harper instance.
591
- 4. **Deploy**: Use \`npm run deploy\` to push your application to Harper Fabric.
592
- `,"custom-resources":`---
593
- name: custom-resources
594
- description: How to define custom REST endpoints with JavaScript or TypeScript in Harper.
595
- metadata:
596
- mode: generate
597
- sources:
598
- - reference/v5/resources/overview.md#Custom External Data Source
599
- - reference/v5/resources/overview.md#Exporting Resources as Endpoints
600
- - reference/v5/components/javascript-environment.md#Module Loading
601
- sourceCommit: f37a8c4021e20d5c74c1d339a6b6c8c196b5603e
602
- inputHash: df69870433c0b3e5
603
- ---
604
-
605
- # Custom Resources
606
-
607
- Instructions for the agent to follow when defining custom REST endpoints with JavaScript or TypeScript in Harper.
608
-
609
- ## When to Use
610
-
611
- Apply this rule when creating custom HTTP endpoints, wrapping external APIs, or registering routes programmatically in a Harper application. Use it any time business logic must live outside a table-backed schema, or when a specific URL shape is required.
612
-
613
- ## How It Works
614
-
615
- 1. **Import \`Resource\` from \`harper\`**: Always import from the \`harper\` package rather than relying on globals.
616
-
617
- \`\`\`javascript
618
- import { tables, Resource } from 'harper';
619
- \`\`\`
620
-
621
- 2. **Define a class that \`extends Resource\`**: Implement HTTP methods as \`static\` methods. Each method receives a \`target\` object.
622
-
623
- \`\`\`javascript
624
- export class CustomEndpoint extends Resource {
625
- static get(target) {
626
- return {
627
- data: doSomething(),
628
- };
629
- }
630
- }
631
- \`\`\`
632
-
633
- 3. **Use \`async\` static methods for external calls**: Await fetch or other async operations inside \`static\` handlers.
634
-
635
- \`\`\`javascript
636
- export class MyExternalData extends Resource {
637
- static async get(target) {
638
- const response = await fetch(\`https://api.example.com/\${target.id}\`);
639
- return response.json();
640
- }
641
-
642
- static async put(target, data) {
643
- return fetch(\`https://api.example.com/\${target.id}\`, {
644
- method: 'PUT',
645
- body: JSON.stringify(await data),
646
- });
647
- }
648
- }
649
- \`\`\`
650
-
651
- 4. **Export the class to create an endpoint**: The export form controls the resulting URL. Choose the form that matches the URL shape you need.
652
-
653
- | Export form | URL | Notes |
654
- | ------------------------------------------- | --------------- | --------------------------------------------------------------- |
655
- | \`export class Foo extends Resource {}\` | \`/Foo/\` | Class name becomes the path segment. Case-sensitive. |
656
- | \`export const Bar = { Foo };\` | \`/Bar/Foo/\` | Nest under an object to add a path prefix. |
657
- | \`export const bar = { 'foo-baz': Foo };\` | \`/bar/foo-baz/\` | Use object keys for lowercase, hyphens, or non-identifier URLs. |
658
- | \`export { Foo as '/widget/:id' }\` | \`/widget/:id\` | Rename the export to set the path directly. |
659
- | \`static path = '/widget/:id'\` (class field) | \`/widget/:id\` | Declare path on the class; overrides the export name. |
660
- | \`server.resources.set('my-path', Foo);\` | \`/my-path/\` | Programmatic registration for dynamic paths. |
661
-
662
- URL path matching is case-sensitive — \`/Foo/\` and \`/foo/\` are different endpoints.
663
-
664
- 5. **Declare path parameters with \`static path\`**: Use \`:name\` for a single segment and \`*name\` as a catch-all. Matched values are bound onto \`target.<name>\`.
665
-
666
- \`\`\`javascript
667
- export class Widget extends Resource {
668
- static path = '/widget/:id/action/:action';
669
- static get(target) {
670
- return { id: target.id, action: target.action };
671
- }
672
- }
673
- \`\`\`
674
-
675
- A \`static path\` takes precedence over the export name. A leading \`/\` makes the path root-relative (top-level). A leading \`./\` or bare name resolves relative to the component directory.
676
-
677
- 6. **Register programmatically when the path is dynamic**: Use \`server.resources.set(\` when the path cannot be known at export time.
678
-
679
- \`\`\`javascript
680
- server.resources.set('my-path', Foo);
681
- \`\`\`
682
-
683
- 7. **Optionally source a table from a custom resource**: Use the resource as a caching layer for a local table.
684
- \`\`\`javascript
685
- tables.MyCache.sourcedFrom(MyExternalData);
686
- \`\`\`
687
-
688
- ## Examples
689
-
690
- ### External API wrapper with GET and PUT
691
-
692
- \`\`\`javascript
693
- import { tables, Resource } from 'harper';
694
-
695
- export class MyExternalData extends Resource {
696
- static async get(target) {
697
- const response = await fetch(\`https://api.example.com/\${target.id}\`);
698
- return response.json();
699
- }
700
-
701
- static async put(target, data) {
702
- return fetch(\`https://api.example.com/\${target.id}\`, {
703
- method: 'PUT',
704
- body: JSON.stringify(await data),
705
- });
706
- }
707
- }
708
-
709
- // Use as a cache source for a local table
710
- tables.MyCache.sourcedFrom(MyExternalData);
711
- \`\`\`
712
-
713
- ### Path parameters with \`static path\`
714
-
715
- \`\`\`javascript
716
- import { Resource } from 'harper';
717
-
718
- export class Widget extends Resource {
719
- // GET /widget/10/action/jump -> target.id === '10', target.action === 'jump'
720
- static path = '/widget/:id/action/:action';
721
- static get(target) {
722
- return { id: target.id, action: target.action };
723
- }
724
- }
725
-
726
- export class Files extends Resource {
727
- // GET /files/a/b/c.txt -> target.rest === 'a/b/c.txt'
728
- static path = '/files/*rest';
729
- static get(target) {
730
- return { path: target.rest };
731
- }
732
- }
733
- \`\`\`
734
-
735
- ### Programmatic registration
736
-
737
- \`\`\`javascript
738
- import { Resource } from 'harper';
739
-
740
- export class Foo extends Resource {
741
- static get(target) {
742
- return { data: doSomething() };
743
- }
744
- }
745
-
746
- server.resources.set('my-path', Foo);
747
- \`\`\`
748
-
749
- ## Notes
750
-
751
- - A bare \`*\` wildcard (no name) binds under \`target.wildcard\`. A wildcard must be the final segment of the path.
752
- - Resolution order: exact/static paths always win over parameterized ones. Among parameterized routes, more specific paths win — a literal segment beats \`:param\`, which beats \`*\`, compared left to right.
753
- - Parameterized routes appear in the generated OpenAPI document as templated paths (e.g. \`/widget/{id}/action/{action}\`) and in MCP \`resources/templates/list\` as \`{param}\` URI templates.
754
- - If a resource \`extends\` an existing table, avoid conflicting exports between the schema and the JavaScript implementation.
755
- - Link the \`harper\` package in your component directory to ensure correct typings: \`npm link harper\`. All installed components have \`harper\` automatically linked.
756
- - Harper runs as a single process — \`tables\`, \`databases\`, and other APIs are the same live, process-wide objects regardless of which component accesses them.
757
- `,"defining-relationships":`---
758
- name: defining-relationships
759
- description: How to define and use relationships between tables in Harper using GraphQL.
760
- metadata:
761
- mode: generate
762
- sources:
763
- - reference/v5/database/schema.md#Relationships
764
- - reference/v5/rest/querying.md#Relationships and Joins
765
- sourceCommit: 3749d0c54be457a2a65d9a63c738a5dc88989ecd
766
- inputHash: fd399fd81a88f13e
767
- ---
768
-
769
- # Defining Relationships Between Tables in Harper
770
-
771
- Instructions for the agent to follow when defining and querying relationships between tables in Harper using the \`@relationship\` directive.
772
-
773
- ## When to Use
774
-
775
- Apply this rule when adding foreign key relationships between schema tables, enabling join queries, or returning nested related records in query results. Use it any time a schema type needs to reference records in another table via a foreign key attribute.
776
-
777
- ## How It Works
778
-
779
- 1. **Use \`@relationship(from: attribute)\` for many-to-one or many-to-many**: Place this on the field in the table that holds the foreign key. The \`from\` parameter names the attribute on this table that stores the foreign key referencing the target table's primary key.
780
-
781
- \`\`\`graphql
782
- type RealityShow @table @export {
783
- id: Long @primaryKey
784
- networkId: Long @indexed
785
- network: Network @relationship(from: networkId) # many-to-one
786
- title: String @indexed
787
- }
788
-
789
- type Network @table @export {
790
- id: Long @primaryKey
791
- name: String @indexed
792
- }
793
- \`\`\`
794
-
795
- If the foreign key attribute is an array, the relationship becomes many-to-many:
796
-
797
- \`\`\`graphql
798
- type RealityShow @table @export {
799
- id: Long @primaryKey
800
- networkIds: [Long] @indexed
801
- networks: [Network] @relationship(from: networkIds)
802
- }
803
- \`\`\`
804
-
805
- 2. **Use \`@relationship(to: attribute)\` for one-to-many or many-to-many**: Place this on the table whose primary key is referenced by the foreign key in the target table. The \`to\` parameter names the attribute on the target table that holds the foreign key. The result type **must** be an array.
806
-
807
- \`\`\`graphql
808
- type Network @table @export {
809
- id: Long @primaryKey
810
- name: String @indexed
811
- shows: [RealityShow] @relationship(to: networkId) # one-to-many
812
- }
813
- \`\`\`
814
-
815
- 3. **Use \`@relationship(from: attribute, to: attribute)\` for foreign key to foreign key joins**: Specify both \`from\` and \`to\` when neither side uses the primary key. Harper resolves the relationship by searching the target table's \`to\` attribute for matches using this record's \`from\` attribute value. The result type must be an array.
816
-
817
- \`\`\`graphql
818
- type OrderItem @table @export {
819
- id: Long @primaryKey
820
- orderId: Long @indexed
821
- productSku: Long @indexed
822
- products: [Product] @relationship(from: productSku, to: sku)
823
- }
824
-
825
- type Product @table @export {
826
- id: Long @primaryKey
827
- sku: Long @indexed
828
- name: String
829
- }
830
- \`\`\`
831
-
832
- 4. **Query across relationships using dot-syntax**: Filter records by related table attributes using chained dot notation. This behaves as an INNER JOIN — only records with a matching related record are returned.
833
-
834
- \`\`\`
835
- GET /Product/?brand.name=Microsoft
836
- GET /Brand/?products.name=Keyboard
837
- \`\`\`
838
-
839
- 5. **Include relationship fields in results using \`select()\`**: Relationship attributes are not returned by default. Use \`select()\` to include them, optionally specifying nested fields with \`{}\`.
840
-
841
- \`\`\`
842
- GET /Product/?brand.name=Microsoft&select(name,brand)
843
- GET /Product/?brand.name=Microsoft&select(name,brand{name})
844
- GET /Product/?name=Keyboard&select(name,brand{name,id})
845
- \`\`\`
846
-
847
- When selecting a relationship without filtering on it, Harper performs a LEFT JOIN — the relationship property is omitted if the foreign key is null or references a non-existent record.
848
-
849
- 6. **Model many-to-many without a junction table**: Store an array of foreign key values and use \`@relationship(from: ...)\` pointing to that array attribute. The array order of the foreign key values is preserved when resolving the relationship.
850
-
851
- \`\`\`graphql
852
- type Product @table @export {
853
- id: Long @primaryKey
854
- name: String
855
- resellerIds: [Long] @indexed
856
- resellers: [Reseller] @relationship(from: "resellerIds")
857
- }
858
- \`\`\`
859
-
860
- 7. **Define self-referential relationships** for parent-child hierarchies by pointing \`@relationship\` back at the same table type.
861
-
862
- ## Examples
863
-
864
- **Full schema with bidirectional relationships:**
865
-
866
- \`\`\`graphql
867
- type Product @table @export {
868
- id: Long @primaryKey
869
- name: String
870
- brandId: Long @indexed
871
- brand: Brand @relationship(from: "brandId")
872
- }
873
-
874
- type Brand @table @export {
875
- id: Long @primaryKey
876
- name: String
877
- products: [Product] @relationship(to: "brandId")
878
- }
879
- \`\`\`
880
-
881
- **Querying with joins and nested select:**
882
-
883
- \`\`\`
884
- GET /Product/?brand.name=Microsoft&select(name,brand{name,id})
885
- GET /Brand/?products.name=Keyboard
886
- \`\`\`
887
-
888
- **Many-to-many query with nested select:**
889
-
890
- \`\`\`
891
- GET /Product/?resellers.name=Cool Shop&select(id,name,resellers{name,id})
892
- \`\`\`
893
-
894
- ## Notes
895
-
896
- - Every attribute named in \`from\` or \`to\` must exist on the respective table and be annotated with \`@indexed\` to support join queries.
897
- - The \`to\`-only and \`from\`+\`to\` forms both require the result field type to be an array (e.g., \`[RealityShow]\`).
898
- - The \`from\`-only form on a non-array attribute produces a many-to-one relationship; on an array attribute it produces many-to-many.
899
- - Self-referential relationships are supported for hierarchical data within a single table.
900
- `,"delegating-to-the-built-in-agent":`---
901
- name: delegating-to-the-built-in-agent
902
- description: How to delegate tasks to Harper's built-in agent via the CLI and the agent operations API.
903
- metadata:
904
- mode: synthesized
905
- ---
906
-
907
- # Delegating to the Built-in Agent
908
-
909
- Harper 5.2+ ships with a **built-in agent** that runs _inside_ the server, on the main thread
910
- adjacent to the operations API. Because it runs in-process, it can do things a remote client
911
- cannot: call the operations API as RBAC-filtered tools, read and write component files under the
912
- instance's components root, attach the V8 inspector to worker threads to debug and profile them,
913
- schedule follow-up work, and consult the Harper best-practices skill. You send it a natural-language
914
- task; it runs a tool-using loop under a super_user identity and reports back.
915
-
916
- ## When to Use
917
-
918
- Delegate to the built-in agent when the work is best done **on the instance itself** rather than
919
- from your local client:
920
-
921
- - Operating on a deployed instance in place — inspect the schema, build or adjust a component,
922
- restart, run an operation.
923
- - Debugging or profiling a running instance — attach to a worker thread, capture a CPU profile,
924
- set a logpoint.
925
- - Handing off a larger, multi-step task to an agent that already has the instance's tools,
926
- filesystem, and credentials in context.
927
-
928
- Do the work in your own client instead when it's purely local (editing source before deploy) or
929
- when you don't want a server-side agent making changes.
930
-
931
- **Prerequisites:** the target instance must have the agent enabled (an \`agent:\` config block with
932
- \`enabled: true\`) and a configured generative model backend. All agent operations require
933
- **super_user**.
934
-
935
- ## How It Works
936
-
937
- The lifecycle assumes you have already deployed to and authenticated with the target instance (see
938
- [deploying-to-harper-fabric.md](deploying-to-harper-fabric.md) — \`harper login\` stores a token so
939
- you don't repeat credentials). Delegation reuses that same target and credentials.
940
-
941
- There are two equivalent ways to drive the agent.
942
-
943
- ### Option A — the \`harper agent\` CLI (simplest)
944
-
945
- A thin client over the agent operations API that reuses your stored \`harper login\` credentials, so
946
- no connector setup is needed:
947
-
948
- \`\`\`bash
949
- # One-shot: send a task, print the reply, exit
950
- harper agent "Describe the schema, then add a price index to the Product table."
951
-
952
- # Interactive session (REPL)
953
- harper agent
954
-
955
- # Against a specific remote instead of the logged-in default
956
- harper agent --target <Application URL> "List the databases and tables."
957
- \`\`\`
958
-
959
- The CLI polls the run to completion and renders the transcript (tool calls, results, and the
960
- agent's reply). When a run needs approval for a destructive action, it prompts you inline.
961
-
962
- ### Option B — the agent operations API (programmatic)
963
-
964
- Call the operations API directly (HTTP POST to the ops endpoint, super_user auth). This is the path
965
- to use from scripts and services.
966
-
967
- 1. **Start a task** with \`agent_prompt\`. Returns a \`session_id\` and a \`status\`.
968
-
969
- \`\`\`bash
970
- curl -s -u <user>:<pass> <ops-endpoint> \\
971
- -H 'Content-Type: application/json' \\
972
- -d '{"operation":"agent_prompt","message":"Build a Customer table (id, email, name) exported over REST."}'
973
- \`\`\`
974
-
975
- 2. **Poll for progress** with \`get_agent_session\`, passing the \`session_id\`. The returned session
976
- carries the \`status\`, the \`messages\` transcript, and any \`pendingApprovals\`.
977
-
978
- \`\`\`bash
979
- curl -s -u <user>:<pass> <ops-endpoint> \\
980
- -H 'Content-Type: application/json' \\
981
- -d '{"operation":"get_agent_session","session_id":"<id>"}'
982
- \`\`\`
983
-
984
- Poll until \`status\` leaves \`running\` — terminal states are \`completed\`, \`aborted\`, and \`error\`;
985
- \`awaiting_approval\` means it is paused for an approval decision (see step 3).
986
-
987
- 3. **Approve or deny a paused action.** When the agent enabled configuration has \`autoApprove:false\`,
988
- a destructive tool call pauses the run with a \`pendingApprovals[]\` entry. Resolve it with
989
- \`approve_agent_action\`, then poll again — approval executes the saved call, denial hands the
990
- rejection back to the agent so it can adjust.
991
-
992
- \`\`\`bash
993
- curl -s -u <user>:<pass> <ops-endpoint> \\
994
- -H 'Content-Type: application/json' \\
995
- -d '{"operation":"approve_agent_action","session_id":"<id>","approval_id":"<approval-id>","approved":true}'
996
- \`\`\`
997
-
998
- 4. **Continue the conversation** by passing the same \`session_id\` back into \`agent_prompt\` with a
999
- new \`message\`. Omit \`session_id\` to start a fresh session.
1000
-
1001
- Supporting operations: \`list_agent_sessions\` (recent sessions), \`cancel_agent_run\` (terminate a
1002
- running or paused session), and \`set_agent_config\` (adjust \`autoApprove\`, \`allowDestructive\`,
1003
- \`model\`, and related settings on a running instance).
1004
-
1005
- ## Examples
1006
-
1007
- **Delegate a build to a deployed Fabric instance and wait for the result:**
1008
-
1009
- \`\`\`bash
1010
- harper login <Application URL>
1011
- harper agent --target <Application URL> \\
1012
- "Create a Product table (id, name, price) exported over REST, then confirm the endpoint responds."
1013
- \`\`\`
1014
-
1015
- **Programmatic start-and-poll loop:**
1016
-
1017
- \`\`\`bash
1018
- SID=$(curl -s -u <user>:<pass> <ops-endpoint> -H 'Content-Type: application/json' \\
1019
- -d '{"operation":"agent_prompt","message":"Add a vector index to the Document.embedding field."}' \\
1020
- | jq -r .session_id)
1021
-
1022
- while [ "$(curl -s -u <user>:<pass> <ops-endpoint> -H 'Content-Type: application/json' \\
1023
- -d "{\\"operation\\":\\"get_agent_session\\",\\"session_id\\":\\"$SID\\"}" | jq -r .status)" = "running" ]; do
1024
- sleep 3
1025
- done
1026
- \`\`\`
1027
-
1028
- ## Notes
1029
-
1030
- - **All agent operations require super_user.** Authenticate with \`harper login\`, which stores a
1031
- short-lived JWT (operation token) plus a refresh token rather than your password — prefer that
1032
- over passing credentials inline, and never embed a raw password in scripts or client config.
1033
- - **Approvals are your safety gate.** With \`autoApprove:false\`, the agent pauses before destructive
1034
- tools (writing files, deploying, restarting) so an operator decides. Set \`autoApprove:true\` only
1035
- when you want unattended runs.
1036
- - **Sessions are single-active.** A session that is \`running\` or \`awaiting_approval\` rejects a new
1037
- \`agent_prompt\`; resolve the approval or cancel the run first.
1038
- - **MCP alternative.** For MCP-native clients, an instance with MCP enabled exposes the agent as
1039
- curated MCP tools (\`agent_prompt\`, \`get_agent_session\`, \`list_agent_sessions\`) at the ops API's
1040
- \`/mcp\` endpoint — the same delegation loop over the MCP transport instead of raw operations.
1041
- `,"deploying-to-harper-fabric":`---
1042
- name: deploying-to-harper-fabric
1043
- description: How to deploy a Harper application to the Harper Fabric cloud.
1044
- metadata:
1045
- mode: generate
1046
- sources:
1047
- - reference/v5/components/applications.md#Remote Management
1048
- - >-
1049
- fabric/cluster-creation-management.md#Connecting the Harper CLI to a
1050
- Cluster
1051
- sourceCommit: 3749d0c54be457a2a65d9a63c738a5dc88989ecd
1052
- inputHash: 39faf283b6964e93
1053
- ---
1054
-
1055
- # Deploying to Harper Fabric
1056
-
1057
- Instructions for the agent to follow when deploying a Harper application to a remote Harper Fabric cloud instance.
1058
-
1059
- ## When to Use
1060
-
1061
- Apply this rule when deploying a Harper application to a remote Harper Fabric cluster or any remote Harper instance. Use it when setting up CI/CD pipelines that push application packages to a target environment, or when deploying from a local directory or external package source to a remote cluster.
1062
-
1063
- ## How It Works
1064
-
1065
- 1. **Obtain the target URL**: Get the cluster's **Application URL** from the cluster's **Config → Overview** page. This is the hostname passed to all CLI commands as \`target\`.
1066
-
1067
- 2. **Authenticate with \`harper login\`**: Run \`harper login\` once to store an authentication token locally. The CLI also writes \`HARPER_CLI_TARGET\` to a local \`.env\` for subsequent commands.
1068
-
1069
- \`\`\`bash
1070
- harper login <Application URL>
1071
- # Provide cluster username and password when prompted
1072
- \`\`\`
1073
-
1074
- See [creating-a-fabric-account-and-cluster.md](creating-a-fabric-account-and-cluster.md) for setting up a cluster before this step.
1075
-
1076
- 3. **Deploy with \`harper deploy\`**: After logging in, deploy without repeating credentials.
1077
-
1078
- \`\`\`bash
1079
- harper deploy \\
1080
- project=<name> \\
1081
- package=<package> \\
1082
- target=<remote> \\
1083
- restart=true \\
1084
- replicated=true
1085
- \`\`\`
1086
-
1087
- 4. **Use environment variables for CI/CD**: Instead of \`harper login\`, export credentials as environment variables before running \`harper deploy\`.
1088
-
1089
- \`\`\`bash
1090
- export HARPER_CLI_USERNAME=<username>
1091
- export HARPER_CLI_PASSWORD=<password>
1092
- harper deploy \\
1093
- project=<name> \\
1094
- package=<package> \\
1095
- target=<remote> \\
1096
- restart=true \\
1097
- replicated=true
1098
- \`\`\`
1099
-
1100
- 5. **Use inline auth parameters for one-off commands**: Pass \`auth_username\` and \`auth_password\` directly. These take precedence over environment variables and saved login tokens. Not recommended for production.
1101
-
1102
- \`\`\`bash
1103
- harper deploy \\
1104
- project=<name> \\
1105
- package=<package> \\
1106
- auth_username=<username> \\
1107
- auth_password=<password> \\
1108
- target=<remote> \\
1109
- restart=true \\
1110
- replicated=true
1111
- \`\`\`
1112
-
1113
- 6. **Choose a package source**: Set the \`package\` parameter to any valid npm dependency value, or omit it to package and deploy the current local directory.
1114
-
1115
- | Value | Meaning |
1116
- | ---------------------------------------------------- | ---------------------------------------------- |
1117
- | _(omitted)_ | Package and deploy the current local directory |
1118
- | \`"@harperdb/status-check"\` | npm package |
1119
- | \`"HarperDB/status-check"\` | GitHub shorthand |
1120
- | \`"https://github.com/HarperDB/status-check"\` | GitHub full URL |
1121
- | \`"git+ssh://git@github.com:HarperDB/secret-app.git"\` | Private repo via SSH |
1122
- | \`"https://example.com/application.tar.gz"\` | Remote tarball |
1123
-
1124
- For pinned git tags, use the \`semver\` directive:
1125
-
1126
- \`\`\`
1127
- HarperDB/application-template#semver:v1.0.0
1128
- \`\`\`
1129
-
1130
- For SSH-based private repos, register keys with the \`Add SSH Key\` operation before deploying.
1131
-
1132
- ## Examples
1133
-
1134
- **Interactive login then deploy:**
1135
-
1136
- \`\`\`bash
1137
- harper login https://my-cluster.harperdbcloud.com
1138
- # Enter username and password when prompted
1139
-
1140
- harper deploy \\
1141
- project=my-app \\
1142
- package="HarperDB/application-template#semver:v1.0.0" \\
1143
- target=https://my-cluster.harperdbcloud.com \\
1144
- restart=true \\
1145
- replicated=true
1146
- \`\`\`
1147
-
1148
- **CI/CD pipeline deploy using environment variables:**
1149
-
1150
- \`\`\`bash
1151
- export HARPER_CLI_USERNAME=admin
1152
- export HARPER_CLI_PASSWORD=secret
1153
- harper deploy \\
1154
- project=my-app \\
1155
- package="@harperdb/status-check" \\
1156
- target=https://my-cluster.harperdbcloud.com \\
1157
- restart=true \\
1158
- replicated=true
1159
- \`\`\`
1160
-
1161
- **Deploy current local directory:**
1162
-
1163
- \`\`\`bash
1164
- harper deploy \\
1165
- project=my-app \\
1166
- target=https://my-cluster.harperdbcloud.com \\
1167
- restart=true \\
1168
- replicated=true
1169
- \`\`\`
1170
-
1171
- ## Notes
1172
-
1173
- - Authentication precedence (highest to lowest): inline \`auth_username\`/\`auth_password\` parameters → environment variables (\`HARPER_CLI_USERNAME\`/\`HARPER_CLI_PASSWORD\`) → saved login token from \`harper login\`.
1174
- - \`harper login\` writes \`HARPER_CLI_TARGET\` to a local \`.env\`, so subsequent commands do not need \`target\` repeated if that file is present.
1175
- - Harper generates a \`package.json\` from component configurations and resolves packages via \`npm install\`. A local file path creates a symlink, so changes are picked up between restarts without redeploying.
1176
- - For SSH-based private repos, register the SSH key with the \`Add SSH Key\` operation before running \`harper deploy\`.
1177
- `,"extending-tables":`---
1178
- name: extending-tables
1179
- description: How to add custom logic to automatically generated table resources in Harper.
1180
- metadata:
1181
- mode: generate
1182
- sources:
1183
- - reference/v5/resources/overview.md#Extending a Table
1184
- - reference/v5/resources/resource-api.md#Throwing Errors
1185
- sourceCommit: ce0ab713d918d789bc1c9f22e461e963ccc1dff1
1186
- inputHash: 19738fbc732e0a1a
1187
- ---
1188
-
1189
- # Extending Tables
1190
-
1191
- Instructions for the agent to follow when adding custom logic to automatically generated table resources in Harper.
1192
-
1193
- ## When to Use
1194
-
1195
- Apply this rule when you need to add computed properties, intercept writes, enforce validation, or otherwise customize the behavior of a Harper table resource beyond what the default generated endpoints provide. Use it any time a \`@table\` type needs server-side logic attached to its REST handlers.
1196
-
1197
- ## How It Works
1198
-
1199
- 1. **Define the schema without \`@export\`**: Declare the table type in \`schema.graphql\` and omit the \`@export\` directive. Leaving \`@export\` on the schema while also exporting a subclass with the same name produces conflicting endpoints. Let the JavaScript class own the URL instead.
1200
-
1201
- \`\`\`graphql
1202
- # Omit the \`@export\` directive
1203
- type MyTable @table {
1204
- id: Long @primaryKey
1205
- # ...
1206
- }
1207
- \`\`\`
1208
-
1209
- 2. **Extend the generated table class**: In \`resources.js\`, extend from the \`tables.<TypeName>\` global. The class name you export becomes the URL path. The exported class extends tables.
1210
-
1211
- \`\`\`javascript
1212
- export class MyTable extends tables.MyTable {
1213
- static async get(target) {
1214
- const record = await super.get(target);
1215
- return { ...record, computedField: 'value' };
1216
- }
1217
-
1218
- static async post(target, data) {
1219
- this.create({ ...(await data), status: 'pending' });
1220
- }
1221
- }
1222
- \`\`\`
1223
-
1224
- 3. **Call \`super\` to preserve default behavior**: When delegating to \`super\`, match the argument form to the operation:
1225
- - Reads/deletes: \`super.get(target)\` / \`super.delete(target)\`
1226
- - Collection create: \`super.post(target, record)\` — target carries no id
1227
- - Updates: \`super.put(target, data)\` / \`super.patch(target, data)\`
1228
-
1229
- Omit the \`super\` call only if you intend to replace the default behavior entirely.
1230
-
1231
- 4. **Set \`statusCode\` on thrown errors to control HTTP responses**: Uncaught errors are caught by the protocol handler and produce error responses for REST. Use \`.statusCode\` — a plain \`.status\` property is ignored.
1232
-
1233
- \`\`\`javascript
1234
- const error = new Error('Name is required');
1235
- error.statusCode = 400; // use statusCode, NOT status
1236
- throw error;
1237
- \`\`\`
1238
-
1239
- 5. **Configure Harper to load both files**: Ensure your configuration references the schema and resource files.
1240
-
1241
- \`\`\`yaml
1242
- rest: true
1243
- graphqlSchema:
1244
- files: schema.graphql
1245
- jsResource:
1246
- files: resources.js
1247
- \`\`\`
1248
-
1249
- ## Examples
1250
-
1251
- Full end-to-end example — schema, resource class, and error handling:
1252
-
1253
- \`\`\`graphql
1254
- # schema.graphql — omit @export so the JS class owns the endpoint
1255
- type MyTable @table {
1256
- id: Long @primaryKey
1257
- }
1258
- \`\`\`
1259
-
1260
- \`\`\`javascript
1261
- // resources.js
1262
- export class MyTable extends tables.MyTable {
1263
- static async get(target) {
1264
- // get the record from the database
1265
- const record = await super.get(target);
1266
- // add a computed property before returning
1267
- return { ...record, computedField: 'value' };
1268
- }
1269
-
1270
- static async post(target, data) {
1271
- // custom action on POST
1272
- this.create({ ...(await data), status: 'pending' });
1273
- }
1274
- }
1275
- \`\`\`
1276
-
1277
- Throwing a controlled HTTP error:
1278
-
1279
- \`\`\`javascript
1280
- if (!authorized) {
1281
- const error = new Error('Forbidden');
1282
- error.statusCode = 403;
1283
- throw error;
1284
- }
1285
- \`\`\`
1286
-
1287
- ## Notes
1288
-
1289
- - Always omit \`@export\` from the schema type when a JavaScript subclass is exporting the same name. The two registrations conflict.
1290
- - \`super\` must be called with the correct arguments for each operation type — mismatched arguments will not behave as expected.
1291
- - \`statusCode\` is the only recognized property for controlling HTTP status on thrown errors; \`.status\` is ignored.
1292
- `,"handling-binary-data":`---
1293
- name: handling-binary-data
1294
- description: How to store and serve binary data like images or audio in Harper.
1295
- metadata:
1296
- mode: generate
1297
- sources:
1298
- - reference/v5/database/api.md#Accepting Binary in JSON Requests
1299
- - reference/v5/database/api.md#Serving Binary from a Resource
1300
- - reference/v5/rest/content-types.md#Storing Arbitrary Content Types
1301
- sourceCommit: ce0ab713d918d789bc1c9f22e461e963ccc1dff1
1302
- inputHash: fa06480e6fae7614
1303
- ---
1304
-
1305
- # Handling Binary Data
1306
-
1307
- Instructions for the agent to follow when storing and serving binary data (images, audio, arbitrary content types) in Harper.
1308
-
1309
- ## When to Use
1310
-
1311
- Apply this rule when a Harper resource needs to accept, store, or serve binary payloads such as images, audio files, or calendar data. Use it when REST clients send \`base64\`-encoded data inside JSON, when raw binary is uploaded via \`PUT\`/\`POST\`, or when a resource must stream binary back to the client with the correct \`Content-Type\`.
1312
-
1313
- ## How It Works
1314
-
1315
- 1. **Accept base64-encoded binary from JSON clients**: Decode the incoming \`base64\` string with \`Buffer.from\` and wrap it using \`createBlob\`, recording the MIME type. Override \`post\` in your resource class:
1316
-
1317
- \`\`\`typescript
1318
- import { type RequestTargetOrId, tables, createBlob } from 'harper';
1319
-
1320
- export class Photo extends tables.Photo {
1321
- static async post(target: RequestTargetOrId, record: any) {
1322
- if (record.data) {
1323
- record.data = createBlob(Buffer.from(record.data, record.encoding || 'base64'), {
1324
- type: record.contentType || 'application/octet-stream',
1325
- });
1326
- }
1327
- return super.post(target, record);
1328
- }
1329
- }
1330
- \`\`\`
1331
-
1332
- 2. **Serve binary from a resource**: Override \`get\` to return a response object with the blob's MIME type in the \`Content-Type\` header and the blob as the body. Harper streams it to the client:
1333
-
1334
- \`\`\`typescript
1335
- export class Photo extends tables.Photo {
1336
- static async get(target: RequestTargetOrId) {
1337
- const record = await super.get(target);
1338
- if (record?.data) {
1339
- return {
1340
- status: 200,
1341
- headers: { 'Content-Type': record.data.type || 'application/octet-stream' },
1342
- body: record.data,
1343
- };
1344
- }
1345
- return record;
1346
- }
1347
- }
1348
- \`\`\`
1349
-
1350
- 3. **Upload raw binary with a non-standard content type**: Make a \`PUT\` or \`POST\` with any non-standard \`Content-Type\` header. Harper automatically stores the body as a record with \`contentType\` and \`data\` properties:
1351
-
1352
- \`\`\`http
1353
- PUT /my-resource/33
1354
- Content-Type: text/calendar
1355
-
1356
- BEGIN:VCALENDAR
1357
- VERSION:2.0
1358
- ...
1359
- \`\`\`
1360
-
1361
- Harper stores this as:
1362
-
1363
- \`\`\`json
1364
- { "contentType": "text/calendar", "data": "BEGIN:VCALENDAR\\nVERSION:2.0\\n..." }
1365
- \`\`\`
1366
-
1367
- Retrieving that record returns the response with the stored \`Content-Type\` and body. If the content type is not from the \`text\` family, the data is treated as binary (a Node.js \`Buffer\`).
1368
-
1369
- 4. **Upload binary to a specific property**: Use \`application/octet-stream\` (or any image/binary MIME type) and target a sub-path to store binary directly on a property:
1370
-
1371
- \`\`\`http
1372
- PUT /my-resource/33/image
1373
- Content-Type: image/gif
1374
-
1375
- ...image data...
1376
- \`\`\`
1377
-
1378
- ## Examples
1379
-
1380
- **End-to-end: accept base64 JSON, store as blob, serve as binary**
1381
-
1382
- \`\`\`typescript
1383
- import { type RequestTargetOrId, tables, createBlob } from 'harper';
1384
-
1385
- export class Photo extends tables.Photo {
1386
- // Accept base64-encoded uploads in JSON
1387
- static async post(target: RequestTargetOrId, record: any) {
1388
- if (record.data) {
1389
- record.data = createBlob(Buffer.from(record.data, record.encoding || 'base64'), {
1390
- type: record.contentType || 'application/octet-stream',
1391
- });
1392
- }
1393
- return super.post(target, record);
1394
- }
1395
-
1396
- // Stream the blob back with the correct Content-Type
1397
- static async get(target: RequestTargetOrId) {
1398
- const record = await super.get(target);
1399
- if (record?.data) {
1400
- return {
1401
- status: 200,
1402
- headers: { 'Content-Type': record.data.type || 'application/octet-stream' },
1403
- body: record.data,
1404
- };
1405
- }
1406
- return record;
1407
- }
1408
- }
1409
- \`\`\`
1410
-
1411
- ## Notes
1412
-
1413
- - \`createBlob\` takes a \`Buffer\` as its first argument and an options object with a \`type\` property for the MIME type. See [using-blob-datatype.md](using-blob-datatype.md) for full details on the blob data type.
1414
- - Always fall back to \`application/octet-stream\` when no MIME type is known, both when creating and when serving blobs.
1415
- - When Harper retrieves a record that has both \`contentType\` and \`data\` properties, it automatically sets the response \`Content-Type\` and body — no custom \`get\` override is required for that case unless you need additional logic.
1416
- - Non-\`text\` content types cause \`data\` to be stored and returned as a Node.js \`Buffer\`.
1417
- `,"load-env":`---
1418
- name: load-env
1419
- description: >-
1420
- How to load environment variables from .env files into a Harper application
1421
- using the loadEnv plugin.
1422
- metadata:
1423
- mode: generate
1424
- sources:
1425
- - reference/v5/environment-variables/overview.md
1426
- sourceCommit: 3749d0c54be457a2a65d9a63c738a5dc88989ecd
1427
- inputHash: b4db5ede6b93d426
1428
- ---
1429
-
1430
- # Load Environment Variables with loadEnv
1431
-
1432
- Instructions for the agent to follow when loading environment variables from \`.env\` files into a Harper application using the \`loadEnv\` plugin.
1433
-
1434
- ## When to Use
1435
-
1436
- Apply this rule when a Harper application needs to supply secrets, API endpoints, or other configuration values to component code via \`process.env\` without hardcoding them. Use \`loadEnv\` any time you need to load one or more \`.env\` files at application startup.
1437
-
1438
- ## How It Works
1439
-
1440
- 1. **Declare \`loadEnv\` in \`config.yaml\`**: Add \`loadEnv\` as the first entry in \`config.yaml\`. It is built into Harper and requires no installation.
1441
-
1442
- \`\`\`yaml
1443
- loadEnv:
1444
- files: '.env'
1445
- \`\`\`
1446
-
1447
- 2. **Place \`loadEnv\` first**: Harper is a single-process application. List \`loadEnv\` before all other components so that environment variables are available on \`process.env\` before dependent components start.
1448
-
1449
- \`\`\`yaml
1450
- # config.yaml — loadEnv must come first
1451
- loadEnv:
1452
- files: '.env'
1453
-
1454
- rest: true
1455
-
1456
- myApp:
1457
- files: './src/*.js'
1458
- \`\`\`
1459
-
1460
- 3. **Access loaded values in component code**: After \`loadEnv\` runs, all loaded values are available on \`process.env\` and shared across all components.
1461
-
1462
- 4. **Control override behavior**: By default, existing environment variables take precedence over values in \`.env\` files. Set \`override: true\` to make loaded values win instead.
1463
-
1464
- \`\`\`yaml
1465
- loadEnv:
1466
- files: '.env'
1467
- override: true
1468
- \`\`\`
1469
-
1470
- 5. **Load multiple files**: Pass an array of paths or a glob pattern to \`files\`. Files are loaded in the order specified.
1471
-
1472
- \`\`\`yaml
1473
- loadEnv:
1474
- files:
1475
- - '.env'
1476
- - '.env.local'
1477
- \`\`\`
1478
-
1479
- or with a glob:
1480
-
1481
- \`\`\`yaml
1482
- loadEnv:
1483
- files: 'env-vars/*'
1484
- \`\`\`
1485
-
1486
- ### Configuration Options
1487
-
1488
- | Option | Type | Required | Description |
1489
- | ---------- | -------------------- | -------- | -------------------------------------------------------------------------------------- |
1490
- | \`files\` | \`string \\| string[]\` | **Yes** | Path(s) or glob pattern(s) to the env file(s) to load. |
1491
- | \`override\` | \`boolean\` | No | If \`true\`, loaded values override existing environment variables. Defaults to \`false\`. |
1492
-
1493
- ## Examples
1494
-
1495
- **Single file, default behavior:**
1496
-
1497
- \`\`\`yaml
1498
- # config.yaml
1499
- loadEnv:
1500
- files: '.env'
1501
-
1502
- rest: true
1503
-
1504
- myApp:
1505
- files: './src/*.js'
1506
- \`\`\`
1507
-
1508
- **Multiple files with override:**
1509
-
1510
- \`\`\`yaml
1511
- # config.yaml
1512
- loadEnv:
1513
- files:
1514
- - '.env'
1515
- - '.env.local'
1516
- override: true
1517
-
1518
- rest: true
1519
-
1520
- myApp:
1521
- files: './src/*.js'
1522
- \`\`\`
1523
-
1524
- ## Notes
1525
-
1526
- - \`loadEnv\` loads values into \`process.env\` for **application** code only — it does not configure Harper itself.
1527
- - Harper's own instance-wide configuration is composed at startup **before** any component's \`loadEnv\` runs. Variables such as \`HARPER_CONFIG\`, \`HARPER_SET_CONFIG\`, and \`HARPER_DEFAULT_CONFIG\` delivered through a \`.env\` file are read too late and are ignored. Set Harper configuration directly in the configuration file or export variables in the real process/container environment before Harper starts.
1528
- - For production credentials, prefer the encrypted secrets store over a committed \`.env\` file. Secrets are also delivered to components via \`process.env\`.
1529
- `,logging:`---
1530
- name: logging
1531
- description: >-
1532
- Best practices for logging in Harper, including console capture, the granular
1533
- logger interface, and programmatic log retrieval.
1534
- metadata:
1535
- mode: generate
1536
- sources:
1537
- - reference/v5/logging/overview.md
1538
- - reference/v5/logging/api.md
1539
- sourceCommit: b7fbddadd42eb4487190b650a9abc4bcfeef5819
1540
- inputHash: 46cd384598304e3b
1541
- ---
1542
-
1543
- # Harper Logging
1544
-
1545
- Instructions for the agent to follow when implementing logging in Harper applications, including direct logger usage, tagged loggers, and console capture behavior.
1546
-
1547
- ## When to Use
1548
-
1549
- Apply this rule when writing any JavaScript component, plugin, or resource that needs to emit structured log entries, filter logs by component, or capture existing \`console.log\` output into Harper's log system. Use it whenever you need to understand log levels, log entry format, or the \`logger\` global API.
1550
-
1551
- ## How It Works
1552
-
1553
- 1. **Use the \`logger\` global directly** — \`logger\` is available in all JavaScript components without any imports. Call the method matching the desired severity level:
1554
-
1555
- \`\`\`javascript
1556
- logger.trace('detailed trace message');
1557
- logger.debug('debug info', { someContext: 'value' });
1558
- logger.info('informational message');
1559
- logger.warn('potential issue');
1560
- logger.error('error occurred', error);
1561
- logger.fatal('fatal error');
1562
- logger.notify('server is ready');
1563
- \`\`\`
1564
-
1565
- Only entries at or above the configured \`logging.level\` (or \`logging.external.level\`) are written to \`hdb.log\`.
1566
-
1567
- 2. **Create a tagged logger with \`withTag(\`** — Call \`logger.withTag(tag)\` once per module or class to get a \`TaggedLogger\` scoped to that tag. This prefixes every log entry with the tag, making log output filterable by component.
1568
-
1569
- \`\`\`javascript
1570
- const log = logger.withTag('my-resource');
1571
- \`\`\`
1572
-
1573
- Because \`TaggedLogger\` methods for disabled levels are \`null\`, always use optional chaining (\`?.\`) when calling them:
1574
-
1575
- \`\`\`javascript
1576
- log.debug?.('Fetching record', { id });
1577
- log.warn?.('Record not found', { id });
1578
- log.error?.('Failed to update record', err);
1579
- \`\`\`
1580
-
1581
- \`TaggedLogger\` does not have a \`withTag()\` method.
1582
-
1583
- 3. **Understand the interface contracts** — \`MainLogger\` always has all methods defined:
1584
-
1585
- \`\`\`typescript
1586
- interface MainLogger {
1587
- trace(...messages: any[]): void;
1588
- debug(...messages: any[]): void;
1589
- info(...messages: any[]): void;
1590
- warn(...messages: any[]): void;
1591
- error(...messages: any[]): void;
1592
- fatal(...messages: any[]): void;
1593
- notify(...messages: any[]): void;
1594
- withTag(tag: string): TaggedLogger;
1595
- }
1596
- \`\`\`
1597
-
1598
- \`TaggedLogger\` methods may be \`null\`:
1599
-
1600
- \`\`\`typescript
1601
- interface TaggedLogger {
1602
- trace: ((...messages: any[]) => void) | null;
1603
- debug: ((...messages: any[]) => void) | null;
1604
- info: ((...messages: any[]) => void) | null;
1605
- warn: ((...messages: any[]) => void) | null;
1606
- error: ((...messages: any[]) => void) | null;
1607
- fatal: ((...messages: any[]) => void) | null;
1608
- notify: ((...messages: any[]) => void) | null;
1609
- }
1610
- \`\`\`
1611
-
1612
- 4. **Know the log levels** — From least to most severe:
1613
-
1614
- | Level | Description |
1615
- | -------- | -------------------------------------------------------------------- |
1616
- | \`trace\` | Highly detailed internal execution tracing. |
1617
- | \`debug\` | Diagnostic information useful during development. |
1618
- | \`info\` | General operational events. |
1619
- | \`warn\` | Potential issues that don't prevent normal operation. |
1620
- | \`error\` | Errors that affect specific operations. |
1621
- | \`fatal\` | Critical errors causing process termination. |
1622
- | \`notify\` | Important operational milestones. Always logged regardless of level. |
1623
-
1624
- The default log level is \`warn\`. Setting a level includes that level and all more-severe levels.
1625
-
1626
- 5. **Enable console capture when porting existing code** — When \`logging.console: true\` is set, writes via \`console.log\`, \`console.warn\`, \`console.error\`, etc. are appended verbatim to \`hdb.log\`. Captured lines do **not** pass through \`logger\`'s level filter. Prefer \`logger\` directly in production code so that level filtering and tagging apply. Console capture is intended as a convenience for porting existing code and for debugging.
1627
-
1628
- 6. **Know where logs are written** — All standard log output goes to \`<ROOTPATH>/log/hdb.log\` (default: \`~/hdb/log/hdb.log\`). To also log to \`stdout\`/\`stderr\`, set \`logging.stdStreams: true\`.
1629
-
1630
- ## Examples
1631
-
1632
- ### Basic logging in a resource
1633
-
1634
- \`\`\`javascript
1635
- export class MyResource extends Resource {
1636
- async get(id) {
1637
- logger.debug('Fetching record', { id });
1638
- const record = await super.get(id);
1639
- if (!record) {
1640
- logger.warn('Record not found', { id });
1641
- }
1642
- return record;
1643
- }
1644
-
1645
- async put(record) {
1646
- logger.info('Updating record', { id: record.id });
1647
- try {
1648
- return await super.put(record);
1649
- } catch (err) {
1650
- logger.error('Failed to update record', err);
1651
- throw err;
1652
- }
1653
- }
1654
- }
1655
- \`\`\`
1656
-
1657
- ### Tagged logging with \`withTag()\`
1658
-
1659
- \`\`\`javascript
1660
- const log = logger.withTag('my-resource');
1661
-
1662
- export class MyResource extends Resource {
1663
- async get(id) {
1664
- log.debug?.('Fetching record', { id });
1665
- const record = await super.get(id);
1666
- if (!record) {
1667
- log.warn?.('Record not found', { id });
1668
- }
1669
- return record;
1670
- }
1671
-
1672
- async put(record) {
1673
- log.info?.('Updating record', { id: record.id });
1674
- try {
1675
- return await super.put(record);
1676
- } catch (err) {
1677
- log.error?.('Failed to update record', err);
1678
- throw err;
1679
- }
1680
- }
1681
- }
1682
- \`\`\`
1683
-
1684
- Tagged entries appear in \`hdb.log\` with the tag in the header:
1685
-
1686
- \`\`\`
1687
- 2023-03-09T14:25:05.269Z [info] [my-resource]: Updating record
1688
- \`\`\`
1689
-
1690
- ## Notes
1691
-
1692
- - All log output is written to \`<ROOTPATH>/log/hdb.log\`. The \`logger\` global writes to this file at the configured \`logging.external\` level.
1693
- - Log entry format for \`logger\`: \`<timestamp> [<level>] [<thread>/<id>]: <message>\`
1694
- - Log entry format for \`TaggedLogger\`: \`<timestamp> [<level>] [<tag>]: <message>\`
1695
- - \`console.log\` output is only forwarded to \`hdb.log\` when \`logging.console: true\` is explicitly set; it is not forwarded by default.
1696
- - When logging to standard streams, run Harper in the foreground (\`harper\`, not \`harper start\`).
1697
- - \`TaggedLogger\` is bound to the configured log level at creation time — always use \`?.\` on its methods.
1698
- `,"programmatic-table-requests":"---\nname: programmatic-table-requests\ndescription: How to interact with Harper tables programmatically using the `tables` object.\nmetadata:\n mode: generate\n sources:\n - reference/v5/database/api.md#`tables`\n - reference/v5/resources/resource-api.md#Query Object\n - 'reference/v5/database/api.md#`transaction(context?, callback)`'\n - >-\n reference/v5/resources/resource-api.md#`update(target: RequestTarget | Id,\n updates?: object): Promise<Resource>`\n - >-\n reference/v5/resources/resource-api.md#`addTo(property: string, value:\n number)`\n - reference/v5/components/javascript-environment.md#Module Loading\n sourceCommit: 3749d0c54be457a2a65d9a63c738a5dc88989ecd\n inputHash: ace5c3f4a0ad4519\n---\n\n# Programmatic Table Requests\n\nInstructions for the agent to interact with Harper tables programmatically using the `tables` object and its query API.\n\n## When to Use\n\nApply this rule when writing server-side code that reads from or writes to Harper tables directly — for example, in request handlers, background jobs, or SSR rendering — without going through the REST API. Use it whenever you need to construct queries with `conditions`, `select`, `sort`, or `search(`.\n\n## How It Works\n\n1. **Import `tables`**: Pull `tables` from the `harper` package. Each property on `tables` corresponds to a table defined in `schema.graphql`.\n\n ```javascript\n import { tables } from 'harper';\n const { Product } = tables;\n // same as: databases.data.Product\n ```\n\n2. **Define your schema**: Declare tables with `@table` in `schema.graphql`. Each type becomes a property on `tables`.\n\n ```graphql\n type Product @table {\n id: Long @primaryKey\n name: String\n price: Float\n }\n ```\n\n3. **Create and modify records**: Use `create`, `patch`, and `get` for basic CRUD.\n\n ```javascript\n const created = await Product.create({ name: 'Shirt', price: 9.5 });\n await Product.patch(created.id, { price: Math.round(created.price * 0.8 * 100) / 100 });\n const record = await Product.get(created.id);\n ```\n\n4. **Query with `search(`**: Pass a query object to `Product.search(query)`. It returns an async iterable.\n\n ```javascript\n const query = {\n conditions: [{ attribute: 'price', comparator: 'less_than', value: 8.0 }],\n };\n for await (const record of Product.search(query)) {\n // process record\n }\n ```\n\n5. **Build `conditions`**: Each condition object filters records. Nest conditions with `operator` for boolean logic.\n\n | Property | Description |\n | ------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------- |\n | `attribute` | Property name, or array for chained/joined properties (e.g. `['brand', 'name']`) |\n | `value` | The value to match |\n | `comparator` | `equals` (default), `greater_than`, `greater_than_equal`, `less_than`, `less_than_equal`, `starts_with`, `contains`, `ends_with`, `between`, `not_equal` |\n | `conditions` | Nested conditions array |\n | `operator` | `and` (default) or `or` for the nested `conditions` |\n\n6. **Use `select`** to control which properties are returned. Accepts an array of property names, a string for a single property, or nested objects for relationships.\n\n ```javascript\n // Array of names\n Product.search({ select: ['name', 'price'] });\n\n // Nested relationship select\n Book.get({ id: 42, select: ['id', 'title', { name: 'author', select: ['name'] }] });\n ```\n\n Special `select` values:\n - `$id` — returns the primary key regardless of its name\n - `$updatedtime` — returns the last-updated timestamp\n - `$distance` — returns the computed distance when querying a vector index\n\n7. **Use `addTo`** for concurrent-safe numeric increments (CRDT incrementation, safe across threads and nodes).\n\n ```javascript\n const record = await Product.update(target.id);\n record.addTo('quantity', -1);\n ```\n\n8. **Apply `sort`, `limit`, and `offset`** for ordering and pagination. A `sort` attribute must be `@indexed`, or at least one `conditions` entry must be present. Pass `allowFullScan: true` to permit an unconditional ordered scan.\n\n ```javascript\n Product.search({\n conditions: [{ attribute: 'id', comparator: 'greater_than', value: '' }],\n sort: { attribute: 'id' },\n });\n ```\n\n | Sort property | Description |\n | ------------- | ---------------------------------------------------------- |\n | `attribute` | Property name (or array for chained relationship property) |\n | `descending` | Sort descending if `true` (default: `false`) |\n | `next` | Secondary sort to resolve ties (same structure) |\n\n## Examples\n\n**Nested conditions with `or`:**\n\n```javascript\nProduct.search({\n conditions: [\n { attribute: 'price', comparator: 'less_than', value: 100 },\n {\n operator: 'or',\n conditions: [\n { attribute: 'rating', comparator: 'greater_than', value: 4 },\n { attribute: 'featured', value: true },\n ],\n },\n ],\n});\n```\n\n**Chained attribute reference (relationship join):**\n\n```javascript\nProduct.search({ conditions: [{ attribute: ['brand', 'name'], value: 'Harper' }] });\n```\n\n**Deep nested `select` across multiple relationships:**\n\n```javascript\nProduct.search({\n select: [\n 'id',\n 'name',\n { name: 'segments', select: ['id', 'name', { name: 'client', select: ['id', 'name'] }] },\n ],\n});\n```\n\n**SSR usage — read directly from `tables` in a render function:**\n\n```typescript\nimport { tables } from 'harper';\n\nexport async function render(url: string): Promise<string> {\n const product = await tables.Product.get(idFromUrl(url));\n return renderToString(/* <App product={product} /> */);\n}\n```\n\n## Notes\n\n- Scope destructive operations (`update`, `patch`, `delete`) with specific `conditions` and validate the affected set before writing. These operate on live data and are not easily reversible.\n- Sorting by a bare `@primaryKey` with no conditions raises `HdbError: <attribute> is not indexed and not combined with any other conditions`. Add an open-ended condition or pass `allowFullScan: true`.\n- Selecting a relationship field without filtering on it behaves as a **LEFT JOIN**. Adding a condition on a related attribute (e.g. `attribute: ['author', 'name']`) behaves as an **INNER JOIN**.\n- A to-many relationship resolves to an array; `await` the property before iterating when needed.\n- `tables` and `databases.data` reference the same live objects — a record written through one component is immediately visible to all others.\n- Keep `harper` external when bundling for SSR (e.g. `ssr: { external: ['harper'] }` in `vite.config`) so it resolves to the runtime.\n","querying-rest-apis":'---\nname: querying-rest-apis\ndescription: \'How to use query parameters to filter, sort, and paginate Harper REST APIs.\'\nmetadata:\n mode: generate\n sources:\n - reference/v5/rest/querying.md\n sourceCommit: 3749d0c54be457a2a65d9a63c738a5dc88989ecd\n inputHash: d5ed0e937cd2d7e0\n---\n\n# Querying Harper REST APIs\n\nInstructions for the agent to filter, sort, select, and paginate records using Harper\'s URL-based query language on REST collection endpoints.\n\n## When to Use\n\nApply this rule when building or debugging REST API calls against Harper tables that require filtering by attribute values, comparison ranges, sorting, field selection, or result pagination. This rule also covers OR logic, grouping, and querying across related tables via dot-syntax joins. See [automatic-apis.md](automatic-apis.md) for how Harper exposes tables as REST endpoints.\n\n## How It Works\n\n1. **Filter by attribute**: Add query parameters matching attribute names and values. The queried attribute must be indexed.\n\n ```\n GET /Product/?category=software\n GET /Product/?category=software&inStock=true\n ```\n\n2. **Filter for null values**: Use `=null` as the value to match null or non-null records.\n\n ```\n GET /Product/?discount=null\n ```\n\n3. **Apply comparison operators (FIQL syntax)**: Use FIQL operators in query parameters for range and string matching.\n\n | Operator | Meaning |\n | -------------------- | -------------------------------------- |\n | `==` | Equal |\n | `=lt=` | Less than |\n | `=le=` | Less than or equal |\n | `=gt=` | Greater than |\n | `=ge=` | Greater than or equal |\n | `=ne=`, `!=` | Not equal |\n | `=ct=` | Contains (strings) |\n | `=sw=`, `==<value>*` | Starts with (strings) |\n | `=ew=` | Ends with (strings) |\n | `=`, `===` | Strict equality (no type conversion) |\n | `!==` | Strict inequality (no type conversion) |\n\n ```\n GET /Product/?price=gt=100\n GET /Product/?price=le=20\n GET /Product/?name==Keyboard*\n GET /Product/?category=software&price=gt=100&price=lt=200\n ```\n\n For date fields, URL-encode colons as `%3A`:\n\n ```\n GET /Product/?listDate=gt=2017-03-08T09%3A30%3A00.000Z\n ```\n\n4. **Chain conditions for range queries**: Omit the attribute name on the second condition to apply it to the same attribute. Only `gt`/`ge` combined with `lt`/`le` is supported for chaining.\n\n ```\n GET /Product/?price=gt=100&lt=200\n ```\n\n5. **Apply type conversion**: For FIQL comparators, Harper converts values automatically. Use explicit prefixes to force a type.\n\n | Syntax | Behavior |\n | ----------------------------------------- | ------------------------------------------- |\n | `name==null` | Converts to `null` |\n | `name==123` | Converts to number if attribute is untyped |\n | `name==true` | Converts to boolean if attribute is untyped |\n | `name==number:123` | Explicit number conversion |\n | `name==boolean:true` | Explicit boolean conversion |\n | `name==string:some%20text` | Keep as string with URL decode |\n | `name==date:2024-01-05T20%3A07%3A27.955Z` | Explicit Date conversion |\n\n For strict operators (`=`, `===`, `!==`), no automatic type conversion is applied.\n\n6. **Combine conditions with OR logic**: Use `|` instead of `&` to express OR between conditions.\n\n ```\n GET /Product/?rating=5|featured=true\n ```\n\n7. **Group conditions**: Use parentheses or square brackets to control evaluation order. Prefer square brackets when building queries from user input, since `[` and `]` are safely URI-encoded.\n\n ```\n GET /Product/?rating=5|(price=gt=100&price=lt=200)\n GET /Product/?rating=5&[tag=fast|tag=scalable|tag=efficient]\n ```\n\n Build grouped queries in JavaScript:\n\n ```javascript\n let url = `/Product/?rating=5&[${tags.map(encodeURIComponent).join(\'|\')}]`;\n ```\n\n Nest groups for complex conditions:\n\n ```\n GET /Product/?price=lt=100|[rating=5&[tag=fast|tag=scalable|tag=efficient]&inStock=true]\n ```\n\n8. **Select specific properties with `select(`**: Append `select(...)` as a query function separated by `&` to control which fields are returned.\n\n | Syntax | Returns |\n | -------------------------------------- | ------------------------------------------- |\n | `?select(property)` | Values of a single property directly |\n | `?select(property1,property2)` | Objects with only the specified properties |\n | `?select([property1,property2])` | Arrays of property values |\n | `?select(property1,)` | Objects with a single specified property |\n | `?select(property{subProp1,subProp2})` | Nested objects with specific sub-properties |\n\n ```\n GET /Product/?category=software&select(name)\n GET /Product/?brand.name=Microsoft&select(name,brand{name})\n ```\n\n9. **Paginate results with `limit(`**: Use `limit(end)` or `limit(start,end)` to restrict the number of records returned.\n\n ```\n GET /Product/?rating=gt=3&inStock=true&select(rating,name)&limit(20)\n GET /Product/?rating=gt=3&limit(10,30)\n ```\n\n10. **Sort results with `sort(`**: Use `sort(property)` or `sort(+property,-property,...)` to order results. Prefix `+` or no prefix = ascending; `-` = descending.\n\n ```\n GET /Product/?rating=gt=3&sort(+name)\n GET /Product/?sort(+rating,-price)\n ```\n\n11. **Query across relationships using dot-syntax**: Filter on related table attributes using dot-chained property names. Relationships must be defined in the schema with `@relationship`.\n\n ```\n GET /Product/?brand.name=Microsoft\n GET /Brand/?products.name=Keyboard\n ```\n\n Use `select()` to include relationship attributes in the response (they are excluded by default):\n\n ```\n GET /Product/?brand.name=Microsoft&select(name,brand)\n GET /Product/?brand.name=Microsoft&select(name,brand{name})\n ```\n\n12. **Access a specific property by URL**: Append `.propertyName` to a record ID in the URL path. Only works for properties declared in the schema.\n ```\n GET /MyTable/123.propertyName\n ```\n\n## Examples\n\n**Range filter with select and limit**:\n\n```\nGET /Product/?category=software&price=gt=100&price=lt=200&select(name,price)&limit(20)\n```\n\n**Sort and paginate**:\n\n```\nGET /Product/?rating=gt=3&sort(+rating,-price)&limit(10,30)\n```\n\n**OR with grouping**:\n\n```\nGET /Product/?price=lt=100|[rating=5&[tag=fast|tag=scalable|tag=efficient]&inStock=true]\n```\n\n**Join query with nested select** — schema first:\n\n```graphql\ntype Product @table @export {\n id: Long @primaryKey\n name: String\n brandId: Long @indexed\n brand: Brand @relationship(from: "brandId")\n}\ntype Brand @table @export {\n id: Long @primaryKey\n name: String\n products: [Product] @relationship(to: "brandId")\n}\n```\n\nThen query:\n\n```\nGET /Product/?brand.name=Microsoft&select(name,brand{name,id})\n```\n\n**Many-to-many relationship** — schema:\n\n```graphql\ntype Product @table @export {\n id: Long @primaryKey\n name: String\n resellerIds: [Long] @indexed\n resellers: [Reseller] @relationship(from: "resellerIds")\n}\n```\n\nQuery:\n\n```\nGET /Product/?resellers.name=Cool Shop&select(id,name,resellers{name,id})\n```\n\n**Date range with URL-encoded colons**:\n\n```\nGET /Product/?listDate=gt=2017-03-08T09%3A30%3A00.000Z\n```\n\n## Notes\n\n- All filtered attributes must be indexed unless at least one other attribute in the same query is indexed.\n- Null queries (`?attr=null`) require indexes created after null indexing support was added. Rebuild existing indexes (remove and re-add) to enable null queries on them.\n- When selecting a related attribute without filtering on it, the join behaves as a LEFT JOIN — the relationship property is omitted if the foreign key is null or references a non-existent record.\n- The array order of foreign key values (e.g., `resellerIds`) is preserved when resolving many-to-many relationships.\n- Square brackets (`[`, `]`) are preferred over parentheses for grouping when constructing queries programmatically, because standard URI encoding safely encodes them.\n- `directURLMapping: true` can be set on a resource to change URL path handling semantics; see your schema configuration for details.\n',"real-time-apps":`---
1699
- name: real-time-apps
1700
- description: How to build real-time features in Harper using WebSockets and Pub/Sub.
1701
- metadata:
1702
- mode: generate
1703
- sources:
1704
- - reference/v5/rest/websockets.md
1705
- sourceCommit: b7fbddadd42eb4487190b650a9abc4bcfeef5819
1706
- inputHash: a8afd4d3a52f77ba
1707
- ---
1708
-
1709
- # Real-Time Apps with WebSockets and Pub/Sub
1710
-
1711
- Instructions for the agent to follow when building real-time features in Harper using WebSockets and Pub/Sub.
1712
-
1713
- ## When to Use
1714
-
1715
- Apply this rule when implementing any feature that requires real-time bidirectional communication, live data streaming, or push-based updates in a Harper application. This includes chat, live dashboards, sensor feeds, and any scenario where clients must receive resource changes as they happen.
1716
-
1717
- ## How It Works
1718
-
1719
- 1. **Enable WebSocket support**: WebSocket support is enabled automatically when the \`rest\` plugin is enabled. To explicitly disable it, set the following in your config:
1720
-
1721
- \`\`\`yaml
1722
- rest:
1723
- webSocket: false
1724
- \`\`\`
1725
-
1726
- 2. **Connect a client to a resource**: A WebSocket connection to a resource URL automatically subscribes to that resource. When the record changes or a message is published to it, the connection receives the update.
1727
-
1728
- \`\`\`javascript
1729
- let ws = new WebSocket('wss://server/my-resource/341');
1730
- ws.onmessage = (event) => {
1731
- let data = JSON.parse(event.data);
1732
- };
1733
- \`\`\`
1734
-
1735
- \`new WebSocket('wss://server/my-resource/341')\` accesses the resource defined for \`my-resource\` with record id \`341\` and subscribes to it.
1736
-
1737
- 3. **Implement a custom \`connect()\` handler**: Override the \`connect(incomingMessages)\` method on a resource class to control WebSocket behavior. The method must return an async iterable (or generator) that produces messages to send to the client. See [automatic-apis.md](automatic-apis.md) for more on defining resource classes.
1738
-
1739
- 4. **Use the default \`connect()\` for event-style access**: Call \`super.connect()\` to get a streaming iterable that provides:
1740
- - A \`send(message)\` method for pushing outgoing messages
1741
- - A \`close\` event for cleanup on disconnect
1742
-
1743
- 5. **Handle message ordering in distributed environments**: Harper delivers messages to local subscribers immediately without inter-node coordination delay.
1744
-
1745
- | Message Type | Behavior |
1746
- | -------------------------------------------------------- | ----------------------------------------------------------------------- |
1747
- | Non-retained (no \`retain\` flag) | Every message delivered in order received; suitable for chat |
1748
- | Retained (published with \`retain\`, or PUT/updated in DB) | Only the latest-timestamp message is kept; suitable for sensor readings |
1749
-
1750
- 6. **Use MQTT over WebSockets** when needed by setting the sub-protocol header:
1751
- \`\`\`
1752
- Sec-WebSocket-Protocol: mqtt
1753
- \`\`\`
1754
-
1755
- ## Examples
1756
-
1757
- **Simple echo server** — override \`connect(incomingMessages)\` to yield each incoming message back to the client:
1758
-
1759
- \`\`\`javascript
1760
- export class Echo extends Resource {
1761
- async *connect(incomingMessages) {
1762
- for await (let message of incomingMessages) {
1763
- yield message; // echo each message back
1764
- }
1765
- }
1766
- }
1767
- \`\`\`
1768
-
1769
- **Custom connect with timer and event-style access** — use \`super.connect()\` to get the outgoing stream, push periodic messages, echo incoming messages, and clean up on disconnect:
1770
-
1771
- \`\`\`javascript
1772
- export class Example extends Resource {
1773
- connect(incomingMessages) {
1774
- let outgoingMessages = super.connect();
1775
-
1776
- let timer = setInterval(() => {
1777
- outgoingMessages.send({ greeting: 'hi again!' });
1778
- }, 1000);
1779
-
1780
- incomingMessages.on('data', (message) => {
1781
- outgoingMessages.send(message); // echo incoming messages
1782
- });
1783
-
1784
- outgoingMessages.on('close', () => {
1785
- clearInterval(timer);
1786
- });
1787
-
1788
- return outgoingMessages;
1789
- }
1790
- }
1791
- \`\`\`
1792
-
1793
- ## Notes
1794
-
1795
- - WebSocket connections target a resource URL path. By default, connecting to a resource subscribes to changes for that resource.
1796
- - The \`connect(incomingMessages)\` method **must** return an async iterable or generator; returning a plain value will not work.
1797
- - \`super.connect()\` returns a streaming iterable with \`send(message)\` and a \`close\` event — use this when you need to push messages outside of the incoming message loop.
1798
- - For one-way real-time streaming without bidirectional communication, consider Server-Sent Events instead.
1799
- - For full pub/sub capabilities, Harper also supports MQTT; set \`Sec-WebSocket-Protocol: mqtt\` to use MQTT over WebSockets.
1800
- `,"schema-design-tooling":'---\nname: schema-design-tooling\ndescription: >-\n Best practices for Harper schema design, including core directives and GraphQL\n tooling configuration.\nmetadata:\n mode: generate\n sources:\n - reference/v5/database/schema.md#Overview\n - reference/v5/database/schema.md#Type Directives\n - reference/v5/database/schema.md#Field Directives\n sourceCommit: 3749d0c54be457a2a65d9a63c738a5dc88989ecd\n inputHash: ce22f3fefb660c6e\n---\n\n# Schema Design and GraphQL Tooling\n\nInstructions for the agent to follow when designing Harper schemas, applying core directives, and configuring GraphQL tooling.\n\n## When to Use\n\nApply this rule when creating or modifying Harper schema files (`.graphql`), configuring `graphqlSchema` in `config.yaml`, or deciding which directives to apply to types and fields. Use it any time you need to define tables, primary keys, indexes, or exported endpoints.\n\n## How It Works\n\n1. **Declare the schema file** in the component\'s `config.yaml` using the `graphqlSchema` plugin:\n\n ```yaml\n graphqlSchema:\n files: \'schema.graphql\'\n ```\n\n Both plugins and applications can specify schemas.\n\n2. **Mark types as tables** with `@table`. The type name becomes the table name by default:\n\n ```graphql\n type Dog @table {\n id: Long @primaryKey\n name: String\n breed: String\n age: Int\n }\n ```\n\n3. **Set a primary key** on every table using `@primaryKey`. Primary keys must be unique; duplicate-key inserts are rejected. If no primary key is provided on insert, Harper auto-generates one based on the field type:\n - `String` or `ID` → UUID string\n - `Int`, `Long`, or `Any` → auto-incrementing integer\n\n Use `Long` or `Any` for auto-generated numeric keys; `Int` is 32-bit and may be insufficient for large tables.\n\n4. **Index fields for querying** with `@indexed`. Required for filtering by an attribute in REST queries, SQL, or NoSQL operations:\n\n ```graphql\n type Breed @table {\n id: Long @primaryKey\n name: String @indexed\n }\n ```\n\n If the field value is an array, each element is individually indexed. Null values are indexed by default.\n\n5. **Expose a table as an external endpoint** with `@export`. Available via REST, MQTT, and other interfaces. The optional `name` parameter sets the URL path segment:\n\n ```graphql\n type MyTable @table @export(name: "my-table") {\n id: Long @primaryKey\n }\n ```\n\n Without `name`, the type name is used.\n\n6. **Configure `@table` arguments** as needed. All arguments are optional:\n\n | Argument | Type | Default | Description |\n | -------------- | --------- | ----------------------------- | ------------------------------------------------------------- |\n | `table` | `String` | type name | Override the table name |\n | `database` | `String` | `"data"` | Database to place the table in |\n | `expiration` | `Int` | — | Seconds until a record goes stale |\n | `eviction` | `Int` | `0` | Additional seconds after `expiration` before physical removal |\n | `scanInterval` | `Int` | `(expiration + eviction) / 4` | Seconds between eviction scans |\n | `replicate` | `Boolean` | `true` | Enable replication of this table |\n\n7. **Apply additional field directives** where needed:\n - `@createdTime` — auto-assigns creation timestamp (Unix epoch ms)\n - `@updatedTime` — auto-assigns update timestamp (Unix epoch ms)\n - `@expiresAt` — marks a field as the record\'s absolute expiration time (Unix epoch ms)\n - `@embed(source:, model:)` — computes an embedding vector when the source field is written; field type must be `[Float]`\n - `@hidden` — suppresses the field from MCP tool descriptors and OpenAPI document (not an access-control mechanism)\n\n8. **Use `@sealed`** on a type to prevent records from including properties beyond those declared in the schema:\n\n ```graphql\n type StrictRecord @table @sealed {\n id: Long @primaryKey\n name: String\n }\n ```\n\n9. **Use unique database names** in plugins or applications to avoid table naming collisions, since all tables default to the `data` database.\n\n## Examples\n\n**Minimal schema with two tables:**\n\n```graphql\ntype Dog @table {\n id: Long @primaryKey\n name: String\n breed: String\n age: Int\n}\n\ntype Breed @table {\n id: Long @primaryKey\n name: String @indexed\n}\n```\n\n**Table with expiration, eviction, and scan tuning:**\n\n```graphql\n# Expire after 5 minutes, evict after 1 hour, scan every 10 minutes\ntype WeatherCache @table(expiration: 300, eviction: 3300, scanInterval: 600) {\n id: ID @primaryKey\n temperature: Float\n}\n```\n\n**Table with multiple `@table` arguments combined:**\n\n```graphql\ntype Event @table(database: "analytics", expiration: 86400) {\n id: Long @primaryKey\n name: String @indexed\n}\n```\n\n**Exported table with overridden table name:**\n\n```graphql\ntype Product @table(table: "products") @export(name: "products") {\n id: Long @primaryKey\n category: String @indexed\n price: Float @indexed\n}\n```\n\n**Table with timestamps and per-record expiration:**\n\n```graphql\ntype Session @table {\n id: ID @primaryKey\n token: String\n createdAt: Long @createdTime\n updatedAt: Long @updatedTime\n expiresAt: Long @expiresAt\n}\n```\n\n**Table with a hidden internal field:**\n\n```graphql\ntype Customer @table {\n id: Long @primaryKey\n name: String\n\n """\n Internal — do not surface to external consumers.\n """\n creditScore: Int @hidden\n}\n```\n\n## Notes\n\n- `@table`, `@export`, `@sealed`, and `@hidden` are type-level directives; `@primaryKey`, `@indexed`, `@embed`, `@createdTime`, `@updatedTime`, `@expiresAt`, and `@hidden` are field-level directives.\n- `eviction` removes non-indexed record data but does **not** remove a record from its secondary indexes. Indexes remain functional for evicted records; Harper fetches the full record on demand when a query matches an evicted entry.\n- `scanInterval` is clock-aligned to the server\'s local timezone, not startup-aligned. The server\'s startup time does not affect when eviction runs.\n- Replication is enabled by default. If you disable replication on a table and re-enable it later, it will not catch up on writes made while replication was disabled.\n- `@hidden` is a metadata-visibility directive only. Use `attribute_permissions` on roles to enforce data access control.\n- A full-record `put` that omits an `@expiresAt` field clears it; a `patch` of other fields preserves it.\n',"serving-web-content":"---\nname: serving-web-content\ndescription: How to serve static files and integrated Vite/React applications in Harper.\nmetadata:\n mode: synthesized\n---\n\n# Serving Web Content\n\nInstructions for the agent to follow when serving web content from Harper.\n\n## When to Use\n\nUse this skill when you need to serve a frontend (HTML, CSS, JS, or a React/Vue app) directly from your Harper instance — either plain static files or an integrated Vite app with hot module replacement (HMR) in development and a real production build when deployed.\n\n## How It Works\n\nThere are two building blocks. Harper's built-in `static` plugin **serves** files; the `@harperfast/vite` plugin **builds** (and, for SSR, **renders**) a Vite app. For a Vite app they work **together** — the plugin builds into a directory and `static` serves that same directory.\n\n### Option A: Static plugin only (simple, pre-built assets)\n\nFor a plain static site or already-built assets, use `static` on its own:\n\n```yaml\nstatic:\n files: 'web/*'\n```\n\n- Place files in a `web/` folder in the project root; they are served from the root URL (e.g. `http://localhost:9926/index.html`).\n- Static files are matched first; if none matches, Harper falls through to your resource and table APIs.\n\n### Option B: Vite plugin + static plugin (integrated Vite app)\n\n> **Renamed in v1:** the plugin was previously `@harperfast/vite-plugin`. From `1.0.0` on it is **`@harperfast/vite`** (same key and `package`). It now pairs with the `static` plugin instead of building into `web/` itself.\n\n`@harperfast/vite` **builds** your app — in `harper dev` it runs Vite in middleware mode with HMR; in `harper run` it runs `vite build` and rebuilds when watched files change (and renders HTML for SSR). The `static` plugin **serves** the built output. Point both at the same directory (`output`, default `dist`) — that shared directory is the only contract between them.\n\n**SPA `config.yaml`** — list the plugin first so its dev server wins in `harper dev`; `notFound` + `fallthrough: false` makes client-side routing work:\n\n```yaml\n'@harperfast/vite':\n package: '@harperfast/vite'\n files: 'src/**/*'\n output: 'dist'\n\nstatic:\n files: 'dist/**'\n notFound:\n file: 'index.html'\n statusCode: 200\n fallthrough: false\n```\n\n**SSR `config.yaml`** — add an `ssr` entry so the plugin renders `index.html`, and set `index: false` on `static` so it serves assets only:\n\n```yaml\n'@harperfast/vite':\n package: '@harperfast/vite'\n files: 'src/**/*'\n output: 'dist'\n ssr: 'src/entry-server.tsx'\n\nstatic:\n files: 'dist/**'\n index: false\n```\n\n- Install dependencies: `npm install --save-dev vite @harperfast/vite @vitejs/plugin-react` (swap in your framework's Vite plugin, e.g. `@vitejs/plugin-vue`).\n- Then `harper dev .` runs the app with HMR and `harper run .` runs the production build. Vite does _not_ need to be executed separately.\n\n## Reading Harper Data During SSR\n\nThe render entry (`src/entry-server.tsx`) runs **inside Harper**, so it can read straight from the database and render the data into the HTML — no client-side fetch/XHR. `tables` is the same live, process-wide registry available everywhere (see [Programmatic Table Requests](programmatic-table-requests.md)); import it and query a table in an async `render`:\n\n```tsx\nimport { tables } from 'harper';\n\nexport async function render(url: string): Promise<string> {\n const product = await tables.Product.get(idFromUrl(url));\n return renderToString(\n <StrictMode>\n <App product={product} />\n </StrictMode>,\n );\n}\n```\n\nKeep `harper` external in `vite.config.ts` so this import resolves to Harper's running runtime instead of being bundled. `node_modules/harper` is symlinked to the running install, and symlinked deps aren't reliably auto-externalized for SSR:\n\n```typescript\nexport default defineConfig({\n ssr: { external: ['harper'] },\n // ...plugins, resolve, build\n});\n```\n\nTo hydrate on the client without re-fetching, embed the rendered data in the HTML (e.g. an inline `<script type=\"application/json\">`) and read it back before hydration — so the page needs no XHR at all.\n\n## Deploying to Production\n\nBecause `@harperfast/vite` builds on the node and `static` serves the output, deploy the component as-is — no manual build-and-move step is needed:\n\n```json\n{\n \"scripts\": {\n \"dev\": \"harper dev .\",\n \"start\": \"harper run .\",\n \"deploy\": \"harper deploy_component . restart=true replicated=true\"\n }\n}\n```\n\nOn deploy the plugin runs `vite build` at startup (and rebuilds when `files` change) while `static` serves the result. If you prefer to build in CI, commit the build output, point `static` at it, and omit `files` so the plugin stays idle while `static` serves the prebuilt assets. Either way, `npm create harper@latest` scaffolds a working setup for you.\n","typescript-type-stripping":`---
1801
- name: typescript-type-stripping
1802
- description: How to run TypeScript files directly in Harper without a build step.
1803
- metadata:
1804
- mode: generate
1805
- sources:
1806
- - reference/v5/components/javascript-environment.md#TypeScript Support
1807
- sourceCommit: b7fbddadd42eb4487190b650a9abc4bcfeef5819
1808
- inputHash: 4e6bd8b610edd595
1809
- ---
1810
-
1811
- # TypeScript Type Stripping in Harper
1812
-
1813
- Instructions for the agent to run \`.ts\` files directly in Harper without a build step using Node.js's built-in type stripping.
1814
-
1815
- ## When to Use
1816
-
1817
- Apply this rule when writing Harper resource files in TypeScript. Use it any time you need to reference \`.ts\` source files from \`config.yaml\` or import between local TypeScript modules in a Harper project.
1818
-
1819
- ## How It Works
1820
-
1821
- 1. **Ensure Node.js version**: Require Node.js 22.6 or later. Type stripping is unavailable on earlier versions.
1822
-
1823
- 2. **Point \`jsResource\` at \`.ts\` files**: The \`jsResource\` plugin loads both \`.js\` and \`.ts\` files. Set its \`files\` glob in \`config.yaml\` to target your \`.ts\` source files:
1824
-
1825
- \`\`\`yaml
1826
- jsResource:
1827
- files: 'resources/*.ts'
1828
- \`\`\`
1829
-
1830
- 3. **Use explicit \`.ts\` extensions in local imports**: Node's loader does not resolve \`'./helper'\` to \`'./helper.ts'\`, so always include the full extension:
1831
-
1832
- \`\`\`typescript
1833
- import { helper } from './helper.ts';
1834
- \`\`\`
1835
-
1836
- 4. **Stay within type-stripping limits**: Only type annotations and declarations are removed. Do not use enums with runtime values, namespaces with runtime semantics, or any other features that require code transformation beyond type stripping.
1837
-
1838
- ## Examples
1839
-
1840
- A complete Harper resource written in TypeScript, using imports from the \`harper\` package:
1841
-
1842
- \`\`\`typescript
1843
- import { type RequestTargetOrId, Resource, tables } from 'harper';
1844
-
1845
- export class MyResource extends Resource {
1846
- async get(target?: RequestTargetOrId): Promise<{ message: string }> {
1847
- return { message: 'Hello from TS' };
1848
- }
1849
- }
1850
- \`\`\`
1851
-
1852
- Paired \`config.yaml\` entry loading the file via \`jsResource\`:
1853
-
1854
- \`\`\`yaml
1855
- jsResource:
1856
- files: 'resources/*.ts'
1857
- \`\`\`
1858
-
1859
- ## Notes
1860
-
1861
- - No build step or transpiler is required — Harper runs \`.ts\` files directly.
1862
- - Type imports (e.g., \`import { type RequestTargetOrId }\`) from the \`harper\` package work as usual.
1863
- - Unsupported TypeScript features include: enums with runtime values, namespaces with runtime semantics, and anything requiring code transformation beyond simple type stripping.
1864
- `,"using-blob-datatype":"---\nname: using-blob-datatype\ndescription: How to use the Blob data type for efficient binary storage in Harper.\nmetadata:\n mode: generate\n sources:\n - reference/v5/database/schema.md#Blob Type\n - reference/v5/database/api.md#Streaming\n - reference/v5/database/api.md#`BlobOptions`\n - reference/v5/database/api.md#Blob Coercion\n sourceCommit: f37a8c4021e20d5c74c1d339a6b6c8c196b5603e\n inputHash: 92e03eb0b830f335\n---\n\n# Using the Blob Data Type\n\nInstructions for the agent to follow when storing and retrieving large binary content using the `Blob` data type in Harper.\n\n## When to Use\n\nApply this rule when a schema field needs to store large binary content such as images, video, audio, or large HTML — typically content larger than 20KB. Use `Blob` instead of `Bytes` when streaming support and out-of-record storage are required. See [handling-binary-data.md](handling-binary-data.md) for broader binary data guidance.\n\n## How It Works\n\n1. **Declare a `Blob` field in your schema**: Add a field typed as `Blob` to your `@table` type.\n\n ```graphql\n type MyTable @table {\n id: Any! @primaryKey\n data: Blob\n }\n ```\n\n2. **Create and store a blob with `createBlob()`**: Pass a buffer or stream to `createBlob()`, then `put` the record.\n\n ```javascript\n let blob = createBlob(largeBuffer);\n await MyTable.put({ id: 'my-record', data: blob });\n ```\n\n3. **Retrieve blob data using standard Web API methods**: The `Blob` type implements the Web API `Blob` interface. Use `.bytes()`, `.text()`, `.arrayBuffer()`, `.stream()`, or `.slice()` as needed.\n\n ```javascript\n let record = await MyTable.get('my-record');\n let buffer = await record.data.bytes(); // ArrayBuffer\n let text = await record.data.text(); // string\n let stream = record.data.stream(); // ReadableStream\n ```\n\n4. **Use `saveBeforeCommit` when full write must precede commit**: By default, `Blob` is not ACID-compliant — a record can reference a blob before it is fully written. Set `saveBeforeCommit: true` to block the transaction until the blob is fully saved.\n\n ```javascript\n let blob = createBlob(stream, { saveBeforeCommit: true });\n await MyTable.put({ id: 'my-record', data: blob });\n // put() resolves only after blob is fully written and record is committed\n ```\n\n5. **Register an error handler when returning a blob via REST**: Interrupted streams must be handled explicitly.\n\n ```javascript\n export class MyEndpoint extends MyTable {\n static async get(target) {\n const record = super.get(target);\n let blob = record.data;\n blob.on('error', () => {\n MyTable.invalidate(target);\n });\n return { status: 200, headers: {}, body: blob };\n }\n }\n ```\n\n6. **Rely on automatic coercion where applicable**: When a field is typed as `Blob` in the schema, any string or buffer assigned via `put`, `patch`, or `publish` is automatically coerced to a `Blob` — no manual `createBlob()` call is needed in those cases.\n\n### `BlobOptions` reference\n\nPass an options object as the second argument to `createBlob()`.\n\n| Option | Type | Default | Description |\n| ------------------ | --------- | ----------- | ------------------------------------------------------------------------------------------------------------------------ |\n| `type` | `string` | `undefined` | MIME type to associate with the blob (e.g., `image/jpeg`). Readable via `blob.type` and used when serving HTTP. |\n| `size` | `number` | `undefined` | Size of the data in bytes, if known ahead of time. Otherwise inferred from a buffer or determined as a stream completes. |\n| `saveBeforeCommit` | `boolean` | `false` | Wait until the blob is fully written before the transaction commits. |\n| `compress` | `boolean` | `false` | Compress the stored data with deflate. |\n| `flush` | `boolean` | `false` | Flush the file to disk after writing, before the `createBlob` promise chain resolves. |\n\n## Examples\n\n**Store an image with a MIME type:**\n\n```javascript\nlet blob = createBlob(imageBuffer, { type: 'image/jpeg' });\nawait Photo.put({ id, data: blob });\n```\n\n**Stream a blob in as it streams out (low-latency passthrough):**\n\n```javascript\nlet blob = createBlob(incomingStream);\n// blob exists, but data is still streaming to storage\nawait MyTable.put({ id: 'my-record', data: blob });\n\nlet record = await MyTable.get('my-record');\n// blob data is accessible as it arrives\nlet outgoingStream = record.data.stream();\n```\n\n**Guarantee full write before commit using `saveBeforeCommit`:**\n\n```javascript\nlet blob = createBlob(stream, { saveBeforeCommit: true });\nawait MyTable.put({ id: 'my-record', data: blob });\n```\n\n## Notes\n\n- `Blob` stores data separately from the record. If you need the binary data to be a true, ACID-committed part of the record, use a `Bytes` field instead.\n- All standard Web API `Blob` methods — `.text()`, `.arrayBuffer()`, `.stream()`, `.slice()`, and `.bytes()` — are available on retrieved blob fields.\n- Without `saveBeforeCommit: true`, blobs are **not** ACID-compliant by default; a record can reference a blob before it is fully written to storage.\n","v5-upgrade":"---\nname: v5-upgrade\ndescription: >-\n Breaking changes and recommended updates when migrating a Harper application\n to v5.\nmetadata:\n mode: generate\n sources:\n - release-notes/v5-lincoln/v5-migration.md\n sourceCommit: 3749d0c54be457a2a65d9a63c738a5dc88989ecd\n inputHash: 5ee6407370219136\n---\n\n# v5 Upgrade: Breaking Changes and Migration Guide\n\nInstructions for the agent to apply when migrating a Harper application to v5, covering all breaking changes and required code updates.\n\n## When to Use\n\nApply this rule when upgrading an existing Harper application to v5, when encountering runtime errors related to renamed packages, changed APIs, or security restrictions introduced in v5, or when reviewing application code for v5 compatibility before deployment.\n\n## How It Works\n\n1. **Update the package import from `harperdb` to `harper`**: All application code must import from `harper` instead of `harperdb`.\n\n ```javascript\n import { tables } from 'harper';\n ```\n\n2. **Enable `allowInstallScripts` if packages require install scripts**: Harper v5 uses `--ignore-scripts` by default when installing packages. If your application requires installation scripts (e.g., to install additional binaries), set the `allowInstallScripts` option when deploying.\n\n3. **Update `Table.get` usage — return value is now a frozen record object**: `Table.get` now returns a plain record object, not a table class instance. The record is frozen; you cannot mutate it directly.\n - Replace `wasLoadedFromSource()` with `target.loadedFromSource`:\n\n ```javascript\n // Old — remove this pattern:\n const record = await Table.get(id);\n if (record.wasLoadedFromSource()) { ... }\n\n // New — use loadedFromSource on the target:\n const target = new RequestTarget();\n target.id = id;\n const record = await Table.get(target);\n if (target.loadedFromSource) {\n // record was loaded from origin (not cache)\n }\n ```\n\n - Replace in-place mutation with object spread, since records are frozen:\n\n ```javascript\n // Old — throws in v5:\n const record = await Table.get(id);\n record.property = 'changed';\n\n // New — copy instead of mutate:\n let record = await Table.get(id);\n record = { ...record, property: 'changed' };\n ```\n\n - `getUpdatedTime` and `getExpiresAt` methods remain available on the record object.\n\n4. **Update transaction and context handling**: Harper v5 uses asynchronous context tracking. `Table.get` and other table calls now automatically inherit the current transaction context. Code that previously omitted context to bypass a transaction will no longer work as expected. Use `getContext` (imported from `harper`) to access and commit the current transaction explicitly when you need to see updated data.\n\n ```javascript\n import { setTimeout as delay } from 'node:timers/promises';\n import { getContext, transaction } from 'harper';\n\n class MyResource {\n static async get(target) {\n // Commit the current transaction to read latest data:\n await getContext().transaction.commit();\n // Optionally wrap each poll in a new transaction:\n while ((await transaction(() => Table.get(target))).status !== 'ready') {\n await delay(100);\n }\n return Table.get(target);\n }\n }\n ```\n\n5. **Register allowed spawn commands via `allowedSpawnCommands`**: Any use of `spawn`, `exec`, or `execFile` from `node:child_process` must reference executables listed in `applications.allowedSpawnCommands` in `harperdb-config.yaml`. Provide a `name` property in the options argument to ensure only a single named process is started across threads.\n\n6. **Replace `blob.save()` with `saveBeforeCommit`**: The `blob.save()` method has been removed. Use the `saveBeforeCommit` flag in the options passed to the `Blob` constructor instead.\n\n7. **Configure the `moduleLoader` and `lockdown` settings**: Harper v5 loads application modules through Node.js's VM module API. Control this behavior in `harperdb-config.yaml` under the `applications` key.\n\n | Setting | Default | Options |\n | ------------------ | -------------------- | --------------------------------------------------- |\n | `moduleLoader` | `vm-current-context` | `vm-current-context`, `vm`, `native`, `compartment` |\n | `lockdown` | `freeze-after-load` | `freeze-after-load`, `freeze`, `ses`, `none` |\n | `dependencyLoader` | `auto` | `auto`, `app`, `native` |\n | `allowedDirectory` | `app` | `app`, `any` |\n - Use `moduleLoader: native` to disable the VM loader entirely and restore pre-v5 behavior (application-specific context such as tagged logging and per-app `config` will not be available).\n - Use `lockdown: none` as a temporary workaround if a dependency modifies intrinsic prototypes at runtime and throws a `TypeError`.\n\n## Examples\n\n### Full `harperdb-config.yaml` `applications` block\n\n```yaml\napplications:\n lockdown: freeze-after-load\n moduleLoader: vm-current-context\n dependencyLoader: auto\n allowedDirectory: app\n allowedSpawnCommands:\n - npm\n - node\n```\n\n### Restricting allowed built-in modules\n\n```yaml\napplications:\n allowedBuiltinModules:\n - fs\n - path\n - http\n```\n\n### Disabling the VM loader for package compatibility\n\n```yaml\napplications:\n moduleLoader: native\n```\n\n### Accessing context and committing a transaction\n\n```javascript\nimport { getContext } from 'harper';\n\nawait getContext().transaction.commit();\n```\n\n## Notes\n\n- The `lockdown: freeze-after-load` default freezes `Object`, `Array`, `Promise`, `Map`, `Set`, and other intrinsics after all application code loads. Any code or dependency that mutates intrinsic prototypes after startup will throw a `TypeError`.\n- Under `lockdown: ses`, the constrained `fetch` (https-only) is applied only in `vm` mode. In `vm-current-context` and `native` modes, application code uses the standard global `fetch`.\n- In production, `allowedDirectory: app` prevents loading modules from outside the application's own directory tree. Set `allowedDirectory: any` only if your application legitimately requires it.\n- `dependencyLoader: native` is a narrower alternative to `moduleLoader: native` — it uses native loading only for npm packages while keeping the VM loader for first-party application source files.\n- Access Harper functions and APIs through the `harper` package rather than through global variables. Use `getContext` from `harper` to access request context without passing it explicitly through every call.\n","vector-indexing":`---
1865
- name: vector-indexing
1866
- description: How to enable and query vector indexes for similarity search in Harper.
1867
- metadata:
1868
- mode: generate
1869
- sources:
1870
- - reference/v5/database/schema.md#Vector Indexing
1871
- sourceCommit: d4cbc1a7dd400462e4a3243f944b3a75d89b29ca
1872
- inputHash: 1dae788bc850ea90
1873
- ---
1874
-
1875
- # Vector Indexing
1876
-
1877
- Instructions for the agent to enable HNSW vector indexes on table fields and query them for similarity search in Harper.
1878
-
1879
- ## When to Use
1880
-
1881
- Apply this rule when adding a vector similarity search capability to a Harper table — for example, storing text embeddings and querying for nearest neighbors, filtering by distance threshold, or combining vector search with record-level access control. See [adding-tables-with-schemas.md](adding-tables-with-schemas.md) for how to define the surrounding table schema.
1882
-
1883
- ## How It Works
1884
-
1885
- 1. **Declare the vector index** on a \`[Float]\` field using \`@indexed(type: "HNSW")\`:
1886
-
1887
- \`\`\`graphql
1888
- type Document @table {
1889
- id: Long @primaryKey
1890
- textEmbeddings: [Float] @indexed(type: "HNSW")
1891
- }
1892
- \`\`\`
1893
-
1894
- 2. **Query nearest neighbors** using \`Document.search()\` with the \`sort\` parameter. Set \`attribute\` to the indexed field and \`target\` to the query vector:
1895
-
1896
- \`\`\`javascript
1897
- let results = Document.search({
1898
- sort: { attribute: 'textEmbeddings', target: searchVector },
1899
- limit: 5,
1900
- });
1901
- \`\`\`
1902
-
1903
- 3. **Combine with filter conditions** to narrow results before or during graph traversal. Selective conditions are automatically diverted to an exact-scan strategy:
1904
-
1905
- \`\`\`javascript
1906
- let results = Document.search({
1907
- conditions: [{ attribute: 'price', comparator: 'lt', value: 50 }],
1908
- sort: { attribute: 'textEmbeddings', target: searchVector },
1909
- limit: 5,
1910
- });
1911
- \`\`\`
1912
-
1913
- 4. **Apply a function predicate during traversal** using \`vectorFilter\` (JavaScript API only). The function receives each candidate record and must return a synchronous boolean. It must be side-effect free and fast:
1914
-
1915
- \`\`\`javascript
1916
- let results = Document.search(
1917
- {
1918
- sort: { attribute: 'textEmbeddings', target: searchVector },
1919
- vectorFilter: (record) =>
1920
- record.tenantId === context.user.tenantId && record.status === 'published',
1921
- limit: 10,
1922
- },
1923
- context,
1924
- );
1925
- \`\`\`
1926
-
1927
- 5. **Filter by distance threshold** using \`target\` directly on a condition alongside \`comparator\` and \`value\`. This returns matches within the threshold without using \`sort\`:
1928
-
1929
- \`\`\`javascript
1930
- let results = Document.search({
1931
- conditions: {
1932
- attribute: 'textEmbeddings',
1933
- comparator: 'lt',
1934
- value: 0.1,
1935
- target: searchVector,
1936
- },
1937
- });
1938
- \`\`\`
1939
-
1940
- 6. **Include computed distance in results** by adding \`$distance\` to \`select\`. Works with both \`sort\`-based and threshold queries:
1941
-
1942
- \`\`\`javascript
1943
- let results = Document.search({
1944
- select: ['name', '$distance'],
1945
- sort: { attribute: 'textEmbeddings', target: searchVector },
1946
- limit: 5,
1947
- });
1948
- \`\`\`
1949
-
1950
- 7. **Tune per-query search options** on the \`sort\` descriptor using \`distance\` and \`ef\`:
1951
-
1952
- \`\`\`javascript
1953
- let results = Document.search({
1954
- sort: { attribute: 'textEmbeddings', target: searchVector, distance: 'dotProduct', ef: 200 },
1955
- limit: 5,
1956
- });
1957
- \`\`\`
1958
-
1959
- 8. **Tune filtered traversal** with \`ef\` and \`filterExpansion\` when a \`vectorFilter\` is very selective. The visit budget is \`ef * filterExpansion\` nodes (\`filterExpansion\` defaults to \`24\`):
1960
-
1961
- \`\`\`javascript
1962
- let results = Document.search(
1963
- {
1964
- sort: { attribute: 'textEmbeddings', target: searchVector, ef: 200, filterExpansion: 40 },
1965
- vectorFilter: (record) => record.category === 'rare',
1966
- limit: 10,
1967
- },
1968
- context,
1969
- );
1970
- \`\`\`
1971
-
1972
- 9. **Enforce row-level access control** using \`rowFilter\` on search and subscription targets (JavaScript API only). Attach it in an operation override. For vector queries, \`rowFilter\` participates in HNSW traversal so callers receive the k nearest _matching_ records:
1973
-
1974
- \`\`\`javascript
1975
- function canReadReport(record, context) {
1976
- const user = context.user;
1977
- if (user?.role?.permission?.super_user) return true;
1978
- return user?.username != null && record.ownerId != null && record.ownerId === user.username;
1979
- }
1980
-
1981
- export class Reports extends tables.Reports {
1982
- search(target) {
1983
- target.rowFilter = canReadReport;
1984
- return super.search(target);
1985
- }
1986
- }
1987
- \`\`\`
1988
-
1989
- ### HNSW Index Parameters
1990
-
1991
- Configure parameters directly on \`@indexed(type: "HNSW", ...)\`:
1992
-
1993
- | Parameter | Default | Description |
1994
- | ---------------------- | ----------------- | ------------------------------------------------------------------------------------------------ |
1995
- | \`distance\` | \`"cosine"\` | Distance function: \`"cosine"\`, \`"euclidean"\`, or \`"dotProduct"\` |
1996
- | \`efConstruction\` | \`100\` | Max nodes explored during index construction. Higher = better recall, lower = better performance |
1997
- | \`M\` | \`16\` | Preferred connections per graph layer |
1998
- | \`optimizeRouting\` | \`0.5\` | Heuristic aggressiveness for omitting redundant connections (0 = off, 1 = most aggressive) |
1999
- | \`mL\` | computed from \`M\` | Normalization factor for level generation |
2000
- | \`efConstructionSearch\` | auto-scaled | Max nodes explored during search. When unset, auto-scales with index size |
2001
- | \`quantization\` | — | \`"int8"\` stores vectors quantized to int8 |
2002
- | \`filterExpansion\` | \`24\` | Visit-budget multiplier for filtered search: visits at most \`ef * filterExpansion\` nodes |
2003
-
2004
- Per-query \`sort\` descriptor options:
2005
-
2006
- | Option | Values | Description |
2007
- | ---------- | ----------------------------------------- | ------------------------------------------------------ |
2008
- | \`distance\` | \`"cosine"\`, \`"euclidean"\`, \`"dotProduct"\` | Overrides the index's distance function for this query |
2009
- | \`ef\` | integer | Overrides the search exploration budget for this query |
2010
-
2011
- ## Examples
2012
-
2013
- **Index with custom HNSW parameters:**
2014
-
2015
- \`\`\`graphql
2016
- type Document @table {
2017
- id: Long @primaryKey
2018
- textEmbeddings: [Float]
2019
- @indexed(type: "HNSW", distance: "euclidean", optimizeRouting: 0, efConstructionSearch: 100)
2020
- }
2021
- \`\`\`
2022
-
2023
- **Index with int8 quantization:**
2024
-
2025
- \`\`\`graphql
2026
- type Document @table {
2027
- id: Long @primaryKey
2028
- textEmbeddings: [Float] @indexed(type: "HNSW", quantization: "int8")
2029
- }
2030
- \`\`\`
2031
-
2032
- **Nearest-neighbor search with distance included:**
2033
-
2034
- \`\`\`javascript
2035
- let results = Document.search({
2036
- select: ['name', '$distance'],
2037
- sort: { attribute: 'textEmbeddings', target: searchVector },
2038
- limit: 5,
2039
- });
2040
- \`\`\`
2041
-
2042
- **Filtered traversal with tuned budget:**
2043
-
2044
- \`\`\`javascript
2045
- let results = Document.search(
2046
- {
2047
- sort: { attribute: 'textEmbeddings', target: searchVector, ef: 200, filterExpansion: 40 },
2048
- vectorFilter: (record) => record.category === 'rare',
2049
- limit: 10,
2050
- },
2051
- context,
2052
- );
2053
- \`\`\`
2054
-
2055
- ## Notes
2056
-
2057
- - \`vectorFilter\` and \`rowFilter\` are available from the JavaScript API only; they cannot be set through REST or QUERY request data.
2058
- - \`vectorFilter\` functions must be synchronous, side-effect free, and fast — they can run once per candidate record visited during traversal; verdicts are memoized per query. Records passed to them are frozen.
2059
- - \`rowFilter\` does not apply to a direct primary-key \`get\`.
2060
- - Changing \`efConstructionSearch\` on an existing index does not trigger a rebuild. Structural parameters (\`distance\`, \`M\`, \`efConstruction\`, \`quantization\`) do rebuild the index when changed.
2061
- - With \`quantization: "int8"\`, nearest-neighbor \`sort\` queries re-rank results against full-precision vectors, restoring exact ordering and exact \`$distance\` values. Distance-threshold (\`lt\`/\`le\`) queries filter on the approximate distance.
2062
- - The correct parameter name is \`efConstruction\` (seeds the construction budget) and \`efConstructionSearch\` (controls search budget). The name \`efSearchConstruction\` is a previous documentation error.
2063
- - When no \`ef\` is passed and \`efConstructionSearch\` (or \`efConstruction\`) is not explicitly set, the search budget auto-scales with index size.
2064
- - \`cosine\` is the default distance function when \`distance\` is not specified.
2065
- `},ha={name:`readHarperSkill`,description:`Returns documentation for a Harper skill or best practice. Skills provide guidance on developing Harper applications.`,inputSchema:i({skill:p(pa)})};async function ga({input:{skill:e}}){return{success:!!ma[e],message:ma[e]||`No skill found with the name ${e}`}}var _a={...ha,icon:st,execute:ga},va={name:`readLogs`,description:`Returns the matching logs from the server.`,inputSchema:i({log_name:p([`hdb.log`,`system.log`]).default(`hdb.log`),limit:y().or(u()).optional(),level:p([`notify`,`error`,`warn`,`info`,`debug`,`trace`,`undefined`]).or(u()).optional(),from:y().or(u()).optional(),until:y().or(u()).optional()})};async function ya({input:e,instanceClientParams:t}){try{return{success:!0,data:await Be({...t,logFilters:e,replicated:t.entityType===`cluster`})}}catch(e){return{success:!1,message:`Error: ${e}`}}}var ba={...va,icon:dt,execute:ya},xa={name:`readTableRecords`,description:`Retrieves some or all table records from a database on the server.`,inputSchema:i({database:y().trim(),table:y().trim(),pageIndex:c().default(0),pageSize:c().default(10),primaryKey:y(),conditions:_(i({search_attribute:y(),search_type:p([`between`,`eq`,`equals`,`greater_than`,`greater_than_equal`,`less_than`,`less_than_equal`,`ne`,`not_equal`,`starts_with`]),search_value:m()})),sort:i({attribute:y(),descending:o()})})};async function Sa({input:{database:e,table:t,conditions:n,primaryKey:r,...i},instanceClientParams:a}){try{if(!n.length){let{data:n}=await Pe({...a,databaseName:e,tableName:t,onlyIfCached:!0,searchAttribute:r,...i});return{success:!0,data:n}}let{data:o}=await Ae({...a,databaseName:e,tableName:t,onlyIfCached:!0,conditions:n,...i});return{success:!0,data:o}}catch(e){return{success:!1,message:`Error: ${e}`}}}var Ca={...xa,icon:Ke,execute:Sa},wa={name:`restartHTTPService`,description:`Restarts the HTTP service on the server to allow schema and resource changes to be applied.`,inputSchema:i({})};async function Ta({instanceClientParams:e,baseURL:t}){let n=le.loading(`Restarting HTTP service...`,{description:`This may take a bit.`,duration:3e5});try{await tt({...e,operation:`restart_service`,replicated:e.entityType===`cluster`})}catch(e){return{success:!1,message:`Error: ${e}`}}return le.success(`Done!`,{description:`HTTP Service restarted!`,id:n,duration:5e3}),{success:!0,message:`HTTP Service restarted!`,webURL:t}}var Ea={...wa,icon:ze,execute:Ta,requiresApproval:!0},Da={name:`setComponentFile`,description:`Returns the contents of a component file by its full path (which was returned by getComponents)`,inputSchema:i({path:y().trim(),payload:y(),encoding:p([`utf8`,`ASCII`,`binary`,`hex`,`base64`,`utf16le`,`latin1`,`ucs2`])})};async function Oa({input:{path:e,encoding:t,payload:n},instanceClientParams:r}){try{let i=e.split(`/`),a=i.shift(),o=i.join(`/`),s=await Se({...r,file:o,project:a,payload:n,encoding:t});return await Xe.invalidateQueries({queryKey:[r.entityId,`get_component_file`,a,o]}),je(`ReloadApplicationRootEntries`,!0),{success:!0,data:s}}catch(e){return{success:!1,message:`Error: ${e}`}}}var ka={...Da,icon:ut,execute:Oa,requiresApproval:!0},Aa={name:`updateTableRecords`,description:`Updates records in a particular table in a particular database on the server.`,inputSchema:i({database:y().trim(),table:y().trim(),records:_(m())})};async function ja({input:{database:e,table:t,records:n},instanceClientParams:r,params:i}){try{let a=await He({...r,databaseName:e,tableName:t,records:n}),{databaseName:o,tableName:s}=i;return await Xe.invalidateQueries({queryKey:[r.entityId,o,s]}),{success:!0,data:a}}catch(e){return{success:!1,message:`Error: ${e}`}}}var Ma={readHarperSkill:_a,createApp:Fi,readLogs:ba,getAnalytics:Wi,listAnalyticsMetrics:fa,restartHTTPService:Ea,collectFeedback:Mi,getUserContext:aa,getComponentFile:qi,getComponents:Xi,setComponentFile:ka,dropComponentFile:Vi,getDescribeAll:$i,getDescribeTable:na,insertTableRecords:ca,readTableRecords:Ca,updateTableRecords:{...Aa,icon:ot,execute:ja,requiresApproval:!0},deleteTableRecords:Ri};function Na(e){return Ma[e]}function Pa(e){return e.state===`input-available`&&!!Na(ri(e))?.requiresApproval}function Fa(e){let t=[];for(let[n,r]of(e??[]).entries()){if(q(r)){if(Pa(r)){t.push({kind:`part`,part:r,index:n});continue}let e=t.at(-1);e?.kind===`tool-group`?e.parts.push(r):t.push({kind:`tool-group`,parts:[r],index:n});continue}$r(r)&&r.text.length>0&&t.push({kind:`part`,part:r,index:n})}return t}function Ia({part:e,onApprove:t,onDeny:n,onAlwaysApprove:r,isApproving:i}){let[a,o]=(0,C.useState)(!1),[s,c]=(0,C.useState)(!1),l=ri(e),u=Na(l),d=u?.icon||Fe,f=u?.requiresApproval,p=(0,C.useMemo)(()=>!e.input||typeof e.input==`object`&&Object.keys(e.input).length===0,[e.input]),m=(0,C.useMemo)(()=>{let t=JSON.stringify(e.input,null,` `);return{json:t,lines:t?t.split(`
2066
- `).length:0}},[e.input]),h=(0,C.useMemo)(()=>{let t=JSON.stringify(e.output,null,` `);return{json:t,lines:t?t.split(`
2067
- `).length:0}},[e.output]);return(0,w.jsxs)(`div`,{className:`tool-invocation ${e.state}`,children:[(0,w.jsxs)(`div`,{className:`tool-info`,children:[(0,w.jsxs)(`div`,{className:`tool-name`,children:[(0,w.jsx)(d,{size:14}),(0,w.jsx)(`span`,{children:l})]}),(0,w.jsxs)(`div`,{className:`tool-status`,children:[e.state===`input-streaming`&&(0,w.jsx)(`span`,{children:`Thinking...`}),e.state===`input-available`&&(0,w.jsx)(`span`,{children:i?`Executing...`:f?`Awaiting Approval...`:`Executing...`}),e.state===`output-available`&&(e.output?.error?(0,w.jsx)(lt,{size:14,className:`text-destructive`}):(0,w.jsx)(de,{size:14}))]})]}),e.state!==`input-streaming`&&(0,w.jsxs)(`div`,{className:`tool-io`,children:[!p&&(0,w.jsxs)(`div`,{className:`tool-args`,children:[(0,w.jsxs)(`div`,{className:`flex items-center justify-between gap-2 mb-1`,children:[(0,w.jsx)(`strong`,{children:`Input:`}),m.lines>3&&(0,w.jsx)(x,{type:`button`,variant:`ghost`,size:`sm`,className:`h-6 px-2 text-[10px] uppercase tracking-wider text-muted-foreground hover:text-foreground`,onClick:()=>o(!a),children:a?(0,w.jsxs)(w.Fragment,{children:[(0,w.jsx)(fe,{size:12}),`Hide`]}):(0,w.jsxs)(w.Fragment,{children:[(0,w.jsx)(ue,{size:12}),`Show`]})})]}),(0,w.jsx)(`div`,{className:a?`whitespace-pre-wrap`:`line-clamp-3 overflow-hidden whitespace-pre-wrap`,children:m.json})]}),e.state===`input-available`&&f&&(0,w.jsxs)(`div`,{className:`flex gap-2 mt-3 pt-3 border-t`,children:[(0,w.jsxs)(x,{size:`sm`,className:`h-8 text-xs bg-green-600 hover:bg-green-700 text-white`,onClick:()=>t?.(e.toolCallId),disabled:i,children:[i?(0,w.jsx)(ke,{className:`mr-2 h-3 w-3 animate-spin`}):null,`Approve`]}),(0,w.jsx)(x,{type:`button`,size:`sm`,variant:`outline`,className:`h-8 text-xs approval-outline`,onClick:()=>r?.(e.toolCallId),disabled:i,children:`Always Approve`}),(0,w.jsx)(x,{type:`button`,size:`sm`,variant:`outline`,className:`h-8 text-xs approval-outline`,onClick:()=>n?.(e.toolCallId),disabled:i,children:`Deny`})]}),e.state===`output-available`&&(0,w.jsx)(w.Fragment,{children:u?.render?u.render(e):(0,w.jsxs)(`div`,{className:`tool-result`,children:[(0,w.jsxs)(`div`,{className:`flex items-center justify-between gap-2 mb-1`,children:[(0,w.jsx)(`strong`,{children:`Result:`}),h.lines>3&&(0,w.jsx)(x,{type:`button`,variant:`ghost`,size:`sm`,className:`h-6 px-2 text-[10px] uppercase tracking-wider text-muted-foreground hover:text-foreground`,onClick:()=>c(!s),children:s?(0,w.jsxs)(w.Fragment,{children:[(0,w.jsx)(fe,{size:12}),`Hide`]}):(0,w.jsxs)(w.Fragment,{children:[(0,w.jsx)(ue,{size:12}),`Show`]})})]}),(0,w.jsx)(`div`,{className:s?`whitespace-pre-wrap`:`line-clamp-3 overflow-hidden whitespace-pre-wrap`,children:h.json})]})})]})]})}function La({parts:e,onApprove:t,onDeny:n,onAlwaysApprove:r,approvingToolCallIds:i}){let[a,o]=(0,C.useState)(!1),s=e.some(e=>e.state!==`output-available`&&e.state!==`output-error`),c=e.some(e=>e.state===`output-error`||e.state===`output-available`&&e.output?.error),l=e.length===1?ri(e[0]):void 0,u=l&&Na(l)?.icon||mt,d=l??`${e.length} tools`;return(0,w.jsxs)(`div`,{className:`tool-group`,children:[(0,w.jsxs)(`button`,{type:`button`,className:`tool-group-summary`,"aria-expanded":a,onClick:()=>o(!a),children:[a?(0,w.jsx)(ue,{size:14}):(0,w.jsx)(Ne,{size:14}),(0,w.jsx)(u,{size:14}),(0,w.jsx)(`span`,{children:s?`Using ${d}...`:`Used ${d}`}),(0,w.jsx)(`span`,{className:`tool-group-status`,children:s?(0,w.jsx)(ke,{size:14,className:`animate-spin`}):c?(0,w.jsx)(lt,{size:14,className:`text-destructive`}):(0,w.jsx)(de,{size:14})})]}),a&&e.map(e=>(0,w.jsx)(Ia,{part:e,onApprove:t,onDeny:n,onAlwaysApprove:r,isApproving:i?.has(e.toolCallId)},e.toolCallId))]})}function Ra({message:e,onApprove:t,onDeny:n,onAlwaysApprove:r,approvingToolCallIds:i}){return e.parts?.some(e=>$r(e)&&e.text.length>0||q(e))?(0,w.jsxs)(it.div,{initial:{opacity:0,y:10},animate:{opacity:1,y:0},className:`message-bubble ${e.role===`user`?`user`:`assistant`}`,children:[(0,w.jsx)(`div`,{className:`avatar`,children:e.role===`user`?(0,w.jsx)(Ve,{size:18}):(0,w.jsx)(rt,{size:18})}),(0,w.jsx)(`div`,{className:`content`,children:Fa(e.parts).map(e=>{if(e.kind===`tool-group`)return(0,w.jsx)(La,{parts:e.parts,onApprove:t,onDeny:n,onAlwaysApprove:r,approvingToolCallIds:i},e.parts[0].toolCallId);let{part:a,index:o}=e;return $r(a)?(0,w.jsx)(`div`,{className:`text-block`,children:a.text},o):q(a)?(0,w.jsx)(Ia,{part:a,onApprove:t,onDeny:n,onAlwaysApprove:r,isApproving:i?.has(a.toolCallId)},o):null})})]},e.id):null}function za(e,t){if(e!==`submitted`&&e!==`streaming`)return!1;if(t?.role!==`assistant`)return!0;let n=t.parts?.at(-1);return n?$r(n)?n.state!==`streaming`||n.text.length===0:!q(n)||n.state===`output-available`||n.state===`output-error`:!0}function Ba(){return(0,w.jsxs)(it.div,{initial:{opacity:0,y:10},animate:{opacity:1,y:0},transition:{delay:.2},className:`message-bubble assistant`,children:[(0,w.jsx)(`div`,{className:`avatar`,children:(0,w.jsx)(rt,{size:18})}),(0,w.jsxs)(`div`,{className:`content thinking-indicator`,role:`status`,"aria-label":`Harper Agent is thinking`,children:[(0,w.jsx)(`span`,{className:`thinking-dot`}),(0,w.jsx)(`span`,{className:`thinking-dot`}),(0,w.jsx)(`span`,{className:`thinking-dot`})]})]})}function Va(e){return re({queryKey:[`getMyUsage`,e],queryFn:async()=>{let{data:t}=await b.get(`/Chat/Usage/${e}`);return t}})}function Ha(){let{organizationId:e}=ie({strict:!1});return ae(Va(e))}function Ua(){let{data:e,isLoading:t,error:n}=Ha();if(t||n||!e)return null;let{usageUSD:r,monthlyLimitUSD:i,usageBarPercent:a}=e,o=e=>new Intl.NumberFormat(`en-US`,{style:`currency`,currency:`USD`}).format(e);return(0,w.jsxs)(`div`,{className:`usage-container`,children:[(0,w.jsxs)(`div`,{className:`usage-info`,children:[(0,w.jsx)(`span`,{children:`Monthly Org Usage`}),(0,w.jsxs)(`span`,{children:[o(r),` / `,o(i)]}),(0,w.jsxs)(`span`,{children:[Math.round(a),`%`]})]}),(0,w.jsx)(`div`,{className:`usage-bar-bg`,children:(0,w.jsx)(`div`,{className:`usage-bar-fill`,style:{width:`${a}%`}})})]})}function Wa({autoFocus:e,closeChat:t}){let n=ie({strict:!1}),{organizationId:r}=n,[i,a]=Ie(`ApplicationChat`,``),[o,s]=(0,C.useState)(!0),[c,l]=(0,C.useState)({}),[u,d]=(0,C.useState)(new Set),[f,p]=Ee(Te.ChatAlwaysApprovedTools,[]),m=new Set(f),h=nt(),g=De(),_=ne(),{messages:v,sendMessage:ee,status:te,addToolOutput:y,setMessages:b}=Di({transport:pi(r),generateId:O(),sendAutomaticallyWhen:fi,onFinish(){_.invalidateQueries({queryKey:[`getMyUsage`]})},async onToolCall({toolCall:e}){if(e.dynamic)return;let t=Na(e.toolName);if(t){if(t.requiresApproval&&!m.has(e.toolName)){let t={type:`tool-call`,toolCallId:e.toolCallId,toolName:e.toolName,input:e.input};l(n=>({...n,[e.toolCallId]:t}));return}let r=await t.execute({input:e.input,instanceClientParams:g,baseURL:h,params:n});y({tool:e.toolName,toolCallId:e.toolCallId,output:r})}}}),x=(0,C.useCallback)(async e=>{let t=c[e];if(t){d(t=>{let n=new Set(t);return n.add(e),n});try{let r=Na(t.toolName);if(r){let i=await r.execute({input:t.input,instanceClientParams:g,baseURL:h,params:n});y({tool:t.toolName,toolCallId:t.toolCallId,output:i}),l(t=>{let n={...t};return delete n[e],n})}}finally{d(t=>{let n=new Set(t);return n.delete(e),n})}}},[c,g,h,y,n]),re=(0,C.useCallback)(e=>{let t=c[e];t&&(y({tool:t.toolName,toolCallId:t.toolCallId,output:{error:`User denied the tool execution.`}}),l(t=>{let n={...t};return delete n[e],n}))},[c,y]),ae=(0,C.useCallback)(async e=>{let t=c[e];t&&(p(e=>Me([...e,t.toolName])),await x(e))},[c,p,x]);(0,C.useEffect)(()=>{(async()=>{try{let e=await _t();Array.isArray(e)&&b(e)}catch(e){console.error(`Failed to fetch initial messages:`,e)}finally{s(!1)}})()},[b]);let oe=te===`streaming`||te===`submitted`,se=(0,C.useRef)(null);return(0,C.useEffect)(()=>{se.current?.scrollIntoView({behavior:`smooth`})},[v]),(0,w.jsxs)(`div`,{className:`flex flex-col h-full`,children:[(0,w.jsxs)(`div`,{className:`flex items-start justify-between gap-6 px-4 py-2.5 border-b border-border bg-card`,children:[(0,w.jsxs)(`div`,{className:`flex flex-col gap-1 min-w-0 flex-1`,children:[(0,w.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,w.jsx)(rt,{className:`text-primary`,size:20}),(0,w.jsx)(`span`,{className:`font-semibold text-foreground`,children:`Harper Agent`})]}),(0,w.jsx)(Ua,{})]}),(0,w.jsxs)(`div`,{className:`flex items-center gap-2 shrink-0`,children:[(0,w.jsx)(gt,{setMessages:b}),(0,w.jsx)(`button`,{onClick:t,className:`p-1 hover:bg-accent rounded-md transition-colors text-muted-foreground hover:text-foreground`,title:`Close chat`,children:(0,w.jsx)(we,{size:20})})]})]}),(0,w.jsx)(`div`,{className:`flex-1 overflow-hidden`,children:(0,w.jsxs)(`div`,{className:`chat-interface h-full w-full`,children:[(0,w.jsxs)(`div`,{className:`messages-area`,children:[o&&(0,w.jsx)(ki,{}),!o&&v.length===0&&(0,w.jsxs)(`div`,{className:`empty-state`,children:[(0,w.jsx)(rt,{size:48}),(0,w.jsx)(`p`,{children:`Ask me to create a Harper app!`})]}),v.map(e=>(0,w.jsx)(Ra,{message:e,onApprove:x,onDeny:re,onAlwaysApprove:ae,approvingToolCallIds:u},e.id)),za(te,v.at(-1))&&(0,w.jsx)(Ba,{}),(0,w.jsx)(`div`,{ref:se})]}),(0,w.jsx)(Oi,{input:i,setInput:a,onSubmit:e=>{e.preventDefault(),i.trim()&&!oe&&!o&&(ee({text:i}),a(``))},disabled:o,autoFocus:e})]})})]})}export{Wa as Chat};