@mavea/mavea 1.0.7

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 (557) hide show
  1. package/CHANGELOG.md +159 -0
  2. package/DISCLAIMER.md +16 -0
  3. package/LICENSE +75 -0
  4. package/PRIVACY.md +127 -0
  5. package/README.md +248 -0
  6. package/SECURITY.md +72 -0
  7. package/SUPPORT.md +13 -0
  8. package/TERMS.md +122 -0
  9. package/THIRD-PARTY.txt +639 -0
  10. package/TRADEMARKS.md +15 -0
  11. package/bin/mavea.mjs +1079 -0
  12. package/dist/.vite/manifest.json +4261 -0
  13. package/dist/_headers +52 -0
  14. package/dist/assets/AppCommandPalette-DUMSp3rd.js +1 -0
  15. package/dist/assets/AtlasView-B5fkQhO6.css +1 -0
  16. package/dist/assets/AtlasView-Dl2fssaG.js +1 -0
  17. package/dist/assets/BlockEmpty-CLtVQf6c.js +1 -0
  18. package/dist/assets/BriefingPlayer-DO205Qkh.js +1 -0
  19. package/dist/assets/BriefingPlayer-TpFZB77N.css +1 -0
  20. package/dist/assets/CanvasSkeleton-BZZPCuRZ.js +2 -0
  21. package/dist/assets/CanvasSkeleton-iy6DBvde.css +1 -0
  22. package/dist/assets/CardEditor-BY1bZiV6.css +1 -0
  23. package/dist/assets/CardEditor-DzJXb0G7.js +1 -0
  24. package/dist/assets/CheckLogRail-F4AlgAcc.css +1 -0
  25. package/dist/assets/CheckLogRail-wUfby67Z.js +1 -0
  26. package/dist/assets/CodeOutput-Kh6ldxQz.js +97 -0
  27. package/dist/assets/CommandPalette-Bb-eErih.css +1 -0
  28. package/dist/assets/CommandPalette-Kl00mMZm.js +1 -0
  29. package/dist/assets/CourseLessonReader-COmTQdSK.css +1 -0
  30. package/dist/assets/CourseLessonReader-MBHoknUz.js +2 -0
  31. package/dist/assets/CourseRail-CUa7uIGG.css +1 -0
  32. package/dist/assets/CourseRail-q6x5cCpW.js +1 -0
  33. package/dist/assets/CoursesApp-v89OVJvg.js +2 -0
  34. package/dist/assets/CrossExamPanel-CZ0ShGma.css +1 -0
  35. package/dist/assets/CrossExamPanel-DH04p6VS.js +1 -0
  36. package/dist/assets/DashPresent-BYXbPuGj.js +1 -0
  37. package/dist/assets/DashPresent-DQYcgp-W.css +1 -0
  38. package/dist/assets/DashboardDetail-B50ZkeVK.js +2 -0
  39. package/dist/assets/DashboardLoopRuntime-CFXPx3v_.js +1 -0
  40. package/dist/assets/DashboardOverview-C-FdGWM5.js +1 -0
  41. package/dist/assets/DashboardSettings-Dmw6JTbI.js +1 -0
  42. package/dist/assets/DashboardsApp-Dx-EsaPW.css +1 -0
  43. package/dist/assets/DashboardsApp-JSY_bVfi.js +2 -0
  44. package/dist/assets/DeepZoomApp-BFNwli7l.js +37 -0
  45. package/dist/assets/DeepZoomApp-fRXCJHHZ.css +1 -0
  46. package/dist/assets/DelegatePanel-BK7rEhIc.js +26 -0
  47. package/dist/assets/DelegatePanel-_9RZiLHM.css +1 -0
  48. package/dist/assets/DemoGallery-BPtVG7_y.js +1 -0
  49. package/dist/assets/DropSelect-DUhdQSta.js +1 -0
  50. package/dist/assets/ExportModal-D4WpAg2c.css +1 -0
  51. package/dist/assets/ExportModal-D65cGyj_.js +2 -0
  52. package/dist/assets/ExtractionPreview-Iwfg2Ogl.js +18 -0
  53. package/dist/assets/FallbackCard-B489rTd9.js +1 -0
  54. package/dist/assets/FallbackCard-D_6ps1xA.css +1 -0
  55. package/dist/assets/FeatureUseNotice-CWt7gOwS.css +1 -0
  56. package/dist/assets/FeatureUseNotice-DPtQ0OGb.js +1 -0
  57. package/dist/assets/FlagshipCTA-BXntKhxb.js +1 -0
  58. package/dist/assets/FlagshipCommandPalette-BDJfasI-.js +1 -0
  59. package/dist/assets/FlagshipShowcase-DJ8Gxk_G.js +1 -0
  60. package/dist/assets/FlashcardsApp-CLNo4WX7.js +1 -0
  61. package/dist/assets/ForecastPanel-Da2ZBUrE.css +1 -0
  62. package/dist/assets/ForecastPanel-PBO2-dgS.js +1 -0
  63. package/dist/assets/GalleryApp-B1CB3_81.css +1 -0
  64. package/dist/assets/GalleryApp-DM03CMRy.js +1 -0
  65. package/dist/assets/HonestByDesign-Dqyth6nW.js +1 -0
  66. package/dist/assets/HowItWorks-C0zosIvq.js +1 -0
  67. package/dist/assets/LegalApp-DZBdExTy.js +1 -0
  68. package/dist/assets/LegalMarkdownDocument-CSZhRG5r.js +3 -0
  69. package/dist/assets/LegalPageShell-C_HottbD.css +1 -0
  70. package/dist/assets/LegalPageShell-DTeXqWyc.js +1 -0
  71. package/dist/assets/LeverPanel-DhpJY76O.css +1 -0
  72. package/dist/assets/LeverPanel-aZfhtVJX.js +1 -0
  73. package/dist/assets/Library-D2XGNXz7.js +1 -0
  74. package/dist/assets/Library-DmrtHjUf.css +1 -0
  75. package/dist/assets/LibraryOverlay-B2WQSgwr.js +1 -0
  76. package/dist/assets/LibraryOverlay-CnKWDMG_.css +1 -0
  77. package/dist/assets/LiveApp-B9zwXlGC.js +61 -0
  78. package/dist/assets/LiveApp-BVZGpJ1S.css +1 -0
  79. package/dist/assets/LiveSettings-CmgrMqvK.css +1 -0
  80. package/dist/assets/LiveSettings-D9OcWlm6.js +6 -0
  81. package/dist/assets/MindMapViewerDrawer-YYyZqmAd.js +1 -0
  82. package/dist/assets/MindShape-Ca3MXEgK.css +1 -0
  83. package/dist/assets/MindShape-mTlN5mPZ.js +1 -0
  84. package/dist/assets/Orb-B0NEVfqL.js +1 -0
  85. package/dist/assets/PinToDashboard-_kIOHs0k.js +1 -0
  86. package/dist/assets/PlanReview-33V8GTNB.js +1 -0
  87. package/dist/assets/Presence-CzLJIeSD.js +1 -0
  88. package/dist/assets/PresentationDeck-BDoGecxr.js +1 -0
  89. package/dist/assets/PrismApp-PfBTFhMF.js +2 -0
  90. package/dist/assets/PrismAskController-DBoxQSJR.css +1 -0
  91. package/dist/assets/PrismAskController-DbQDrlU9.js +37 -0
  92. package/dist/assets/PrismBriefingPlayer-1fvlfLR8.js +2 -0
  93. package/dist/assets/PrismOverlay-B7lEspdu.js +131 -0
  94. package/dist/assets/PrismOverlay-BTfAicBt.css +1 -0
  95. package/dist/assets/PrivacyApp-CR4lRs0L.js +128 -0
  96. package/dist/assets/Quiz-CUwtekfu.js +1 -0
  97. package/dist/assets/Recap-DCiiWNiV.css +1 -0
  98. package/dist/assets/Recap-H5fhj5Tc.js +1 -0
  99. package/dist/assets/ReelJelly-3jSVsJsy.js +1 -0
  100. package/dist/assets/RehearsalPanel-BCU615wg.css +1 -0
  101. package/dist/assets/RehearsalPanel-BVgjrOPg.js +6 -0
  102. package/dist/assets/ReplayCard-BpYO5vX-.js +2 -0
  103. package/dist/assets/ReplayOverlay-DXmVdeIr.js +1 -0
  104. package/dist/assets/RewindOverlay-BusfWeFq.js +1 -0
  105. package/dist/assets/RewindOverlay-C92qgvmi.css +1 -0
  106. package/dist/assets/RippleApp-9KrJPYgN.js +2 -0
  107. package/dist/assets/RippleAskController-BNAUoIW0.css +1 -0
  108. package/dist/assets/RippleAskController-CO9wE7hU.js +34 -0
  109. package/dist/assets/RippleOverlay-DMHLbfh8.js +6 -0
  110. package/dist/assets/RippleOverlay-_iiZsQVZ.css +1 -0
  111. package/dist/assets/SeeDontRead-C389viue.js +1 -0
  112. package/dist/assets/ShareModal-C8S7ySls.css +1 -0
  113. package/dist/assets/ShareModal-ClnEkudw.js +32 -0
  114. package/dist/assets/ShipCascade-BUtwvQoW.js +1 -0
  115. package/dist/assets/ShipCascade-CyFnrlET.css +1 -0
  116. package/dist/assets/ShipCourse-B7lG6DYW.js +1 -0
  117. package/dist/assets/ShipCourse-DcT7PUSm.css +1 -0
  118. package/dist/assets/ShipGate-BVZfCllb.css +1 -0
  119. package/dist/assets/ShipGate-BYYu9WVq.js +2 -0
  120. package/dist/assets/ShipHotspots-Bj2CovtT.js +1 -0
  121. package/dist/assets/ShipHotspots-CLOMutPv.css +1 -0
  122. package/dist/assets/ShipIncident-BUHvFFiC.css +1 -0
  123. package/dist/assets/ShipIncident-DcmindmE.js +2 -0
  124. package/dist/assets/ShipMigration-BznCskNg.css +1 -0
  125. package/dist/assets/ShipMigration-s0hVjDQl.js +1 -0
  126. package/dist/assets/ShipOnboarding-BC9Vxkpa.css +1 -0
  127. package/dist/assets/ShipOnboarding-ekbHL7OH.js +1 -0
  128. package/dist/assets/ShipRead-BVNgQT6L.js +1 -0
  129. package/dist/assets/ShipRollout-BdUQzMyP.js +1 -0
  130. package/dist/assets/ShipRollout-CqeObx5b.css +1 -0
  131. package/dist/assets/ShipSuggestions-B6fKYh8L.js +1 -0
  132. package/dist/assets/ShipSuggestions-BKRvk5Mj.css +1 -0
  133. package/dist/assets/ShipWorkspace-3D3Rrs1p.js +2 -0
  134. package/dist/assets/ShipWorkspace-D6XQpGEN.css +1 -0
  135. package/dist/assets/SignatureLoop-C60r8Wm5.js +1 -0
  136. package/dist/assets/SrsReview-BoaYb6XN.js +1 -0
  137. package/dist/assets/SrsReview-DmGdGxT0.css +1 -0
  138. package/dist/assets/SynthesisApp-vJ2Jq0Qe.js +2 -0
  139. package/dist/assets/SynthesisOverlay-CkERphvG.js +66 -0
  140. package/dist/assets/TermsApp-C70tW6m6.js +123 -0
  141. package/dist/assets/TopicCanvas-CT0eSj2M.js +2 -0
  142. package/dist/assets/TopicCanvas-D2Nax9II.css +1 -0
  143. package/dist/assets/TourPrism-BvucSkcs.js +1 -0
  144. package/dist/assets/TrackerTile-CasZNmt4.js +2 -0
  145. package/dist/assets/TwoSurfaces-C90X7Aj5.js +1 -0
  146. package/dist/assets/UnderstoodPanel-CHPD2Ttj.js +1 -0
  147. package/dist/assets/UnderstoodPanel-Q6GX1TFq.css +1 -0
  148. package/dist/assets/WhyMachineOverlay-BZk3PVTl.css +1 -0
  149. package/dist/assets/WhyMachineOverlay-CB0_n6Sy.js +1 -0
  150. package/dist/assets/WowFeatures-Ci_H5QYX.js +1 -0
  151. package/dist/assets/ZoomDeck-B2SjNwY7.css +1 -0
  152. package/dist/assets/ZoomDeck-BQHO79ZU.js +1 -0
  153. package/dist/assets/__vite-browser-external-BufR4LQa.js +1 -0
  154. package/dist/assets/ai-Ba4lZJ9Y.js +12 -0
  155. package/dist/assets/alternateFinishes-DZ-rkpkX.js +494 -0
  156. package/dist/assets/annotationAuto-B0nihA4F.js +1 -0
  157. package/dist/assets/annotationReel-BcU9Q0Sw.js +1 -0
  158. package/dist/assets/annotations-D2K9A5GB.js +1 -0
  159. package/dist/assets/backup-c-Btapzp.js +1 -0
  160. package/dist/assets/blockLabel-DAqaHKy3.js +1 -0
  161. package/dist/assets/c-DWGmR78Y.js +1 -0
  162. package/dist/assets/c-SSSlmE39.js +1 -0
  163. package/dist/assets/cache-BumECILO.js +1 -0
  164. package/dist/assets/canvas-QTEIiK23.js +1 -0
  165. package/dist/assets/catalog-BHjl-1uH.js +2 -0
  166. package/dist/assets/catalog-Dqaq2YFd.js +1 -0
  167. package/dist/assets/cfo.generated-Bjl5OGay.js +1 -0
  168. package/dist/assets/chapters-BiUsDClQ.js +1 -0
  169. package/dist/assets/charts1-EOoxU_K3.js +1 -0
  170. package/dist/assets/charts2-tyUiQPff.js +1 -0
  171. package/dist/assets/chunk-BVpWp9h4.js +1 -0
  172. package/dist/assets/citation-BcvmjKS8.js +1 -0
  173. package/dist/assets/code-CpjYCNS8.js +8 -0
  174. package/dist/assets/codeContext-0UMRSGRr.js +5 -0
  175. package/dist/assets/colors-D49Req-e.js +1 -0
  176. package/dist/assets/compose-BJ9EfcQS.js +3 -0
  177. package/dist/assets/contentVault-DzTYWcbD.js +1 -0
  178. package/dist/assets/core-DEFyprhs.js +1 -0
  179. package/dist/assets/corpus.generated-oX9uU93S.js +11 -0
  180. package/dist/assets/courseSeed-CZdNBTTs.js +1 -0
  181. package/dist/assets/courseStore-DfafnL-9.js +1 -0
  182. package/dist/assets/courses-BkH1ntDL.css +1 -0
  183. package/dist/assets/cpp-BGdv8dzs.js +1 -0
  184. package/dist/assets/cpp-CNAAXZl-.js +1 -0
  185. package/dist/assets/csharp-oqKa8noW.js +1 -0
  186. package/dist/assets/css-CdtkT07m.js +1 -0
  187. package/dist/assets/css-LbU1hoFO.js +1 -0
  188. package/dist/assets/dag-C3Xx8pOD.js +2 -0
  189. package/dist/assets/dashboardEvents-DR9d_c74.js +2 -0
  190. package/dist/assets/dashboards-rcWxdoXI.css +1 -0
  191. package/dist/assets/deckLine-NBd3MyGT.js +1 -0
  192. package/dist/assets/demoPaletteItems-NPCSaSU6.js +1 -0
  193. package/dist/assets/dev.generated-DYgVxL_4.js +73 -0
  194. package/dist/assets/diagrams-CaSfjT4I.js +1 -0
  195. package/dist/assets/diff-woXpYk--.js +1 -0
  196. package/dist/assets/display-OvC57CMc.js +9 -0
  197. package/dist/assets/dist-BFx3nZg4.js +2785 -0
  198. package/dist/assets/dist-xRGLOZwv.js +14 -0
  199. package/dist/assets/docs-B2aDtm5K.js +1 -0
  200. package/dist/assets/everyday-CoZa4kDZ.js +1 -0
  201. package/dist/assets/explode-WBykfhqW.js +13 -0
  202. package/dist/assets/extractNumbers-CuhagRkd.js +1 -0
  203. package/dist/assets/facts-BBTt3ImG.js +1 -0
  204. package/dist/assets/finance-Bxn_Q1p0.js +1 -0
  205. package/dist/assets/fit-0HxU-rtB.js +1 -0
  206. package/dist/assets/fitText-CDFmCQzl.js +1 -0
  207. package/dist/assets/flows-BL81J7yN.js +1 -0
  208. package/dist/assets/format-DlZTyeMy.js +1 -0
  209. package/dist/assets/format-hc2QOoIu.js +1 -0
  210. package/dist/assets/forms-DeoXOxdD.js +1 -0
  211. package/dist/assets/generate-8odaTyr4.js +17 -0
  212. package/dist/assets/generateBeats-b64CL54v.js +1 -0
  213. package/dist/assets/generateCourse-Cj_-vDWu.js +28 -0
  214. package/dist/assets/generateLive-D4B30fnF.js +52 -0
  215. package/dist/assets/geometry-DXAbnb0J.js +1 -0
  216. package/dist/assets/gesture-DabMpPcq.js +2 -0
  217. package/dist/assets/github-dark-C-LZuMrd.js +1 -0
  218. package/dist/assets/github-light-EUqPIrTm.js +1 -0
  219. package/dist/assets/githubBrowser-DywfDeYx.js +1 -0
  220. package/dist/assets/githubToken-DtcLYqwm.js +11 -0
  221. package/dist/assets/go-rLFTqkRN.js +1 -0
  222. package/dist/assets/homeTarget-BgWKI_E1.js +1 -0
  223. package/dist/assets/html-BcACZWSP.js +1 -0
  224. package/dist/assets/html-DDNsd9lV.js +1 -0
  225. package/dist/assets/http-CJCtjYpA.js +2 -0
  226. package/dist/assets/icons-CHVz6kv_.js +1 -0
  227. package/dist/assets/index-CepQEz75.css +1 -0
  228. package/dist/assets/index-y8GL67bB.js +22 -0
  229. package/dist/assets/index.es-CRLiWwiA.js +5 -0
  230. package/dist/assets/info-CiqHR5cs.js +1 -0
  231. package/dist/assets/java-BtIQNnN0.js +1 -0
  232. package/dist/assets/java-DxlWrXwe.js +1 -0
  233. package/dist/assets/javascript-BzbQS41l.js +1 -0
  234. package/dist/assets/javascript-Yelw-5ZN.js +1 -0
  235. package/dist/assets/json-B0N3XRZU.js +1 -0
  236. package/dist/assets/json-B88Oqtu5.js +1 -0
  237. package/dist/assets/json-CaljABEy.js +1 -0
  238. package/dist/assets/jspdf.es.min-C-Pf79px.js +79 -0
  239. package/dist/assets/jsx-D3KKoC5L.js +1 -0
  240. package/dist/assets/jsx-hEbJ82HF.js +1 -0
  241. package/dist/assets/jsx-runtime-DaSxXjOY.js +1 -0
  242. package/dist/assets/katex-BMCG0xok.js +257 -0
  243. package/dist/assets/keyVault-DEsNh9FR.js +1 -0
  244. package/dist/assets/kokoro-D4GKpSL0.js +1 -0
  245. package/dist/assets/kotlin-DhhofPvG.js +1 -0
  246. package/dist/assets/layout-BFQOzXtG.js +1 -0
  247. package/dist/assets/layout-CkO0Psde.js +1 -0
  248. package/dist/assets/lazyRetry-D50B1UMY.js +1 -0
  249. package/dist/assets/leaflet-src-C_xhOQY7.js +1 -0
  250. package/dist/assets/learn-DVfqN-nf.js +1 -0
  251. package/dist/assets/lib-DMAxsZKm.css +1 -0
  252. package/dist/assets/lib-VFqp6Y3w.js +1 -0
  253. package/dist/assets/links--u_phi0x.js +1 -0
  254. package/dist/assets/liveSchema-CJ49PX5R.js +98 -0
  255. package/dist/assets/markdown-BYOwaDjH.js +1 -0
  256. package/dist/assets/mastery-BPjxP0fN.js +4 -0
  257. package/dist/assets/media-CsrUl279.js +43 -0
  258. package/dist/assets/model-BE0UHu1w.js +27 -0
  259. package/dist/assets/motion-S0NRruNj.js +1 -0
  260. package/dist/assets/nav-Czm-NzPV.js +1 -0
  261. package/dist/assets/neighborhoods-C-1Tjr1r.js +1 -0
  262. package/dist/assets/notes-A9t4jdfx.css +1 -0
  263. package/dist/assets/notes-lROPCorS.js +1 -0
  264. package/dist/assets/notify-Bz4wuE4T.js +1 -0
  265. package/dist/assets/now-C9-UAzTC.js +1 -0
  266. package/dist/assets/number-DXgzss0v.js +1 -0
  267. package/dist/assets/officeDoc-B6nEhNp4.js +3 -0
  268. package/dist/assets/openchemlib-nMLMmg26.js +23 -0
  269. package/dist/assets/overlays-JxbHtA2o.js +1 -0
  270. package/dist/assets/owners-FXDGInVq.js +2 -0
  271. package/dist/assets/pageVisibility-BxUVsw7Z.js +1 -0
  272. package/dist/assets/pdf-Df7PCH7q.js +11 -0
  273. package/dist/assets/pdf.worker.min-yatZIOMy.mjs +21 -0
  274. package/dist/assets/penStrokes-9Q_l7NTt.js +1 -0
  275. package/dist/assets/perfProbe-COAp9PAa.js +1 -0
  276. package/dist/assets/php-CYrBA5iX.js +1 -0
  277. package/dist/assets/pickers-B4-3HOR8.js +1 -0
  278. package/dist/assets/pin-Bya3BL_a.css +1 -0
  279. package/dist/assets/pin-CXSuPJYL.js +1 -0
  280. package/dist/assets/planTracker-7AMCQPNx.js +1 -0
  281. package/dist/assets/portal-DMw7C32j.js +1 -0
  282. package/dist/assets/pptxgen.es-CvTILmV9.js +115 -0
  283. package/dist/assets/predictions-CYS7Vo39.js +1 -0
  284. package/dist/assets/prewarm--whjQhWJ.js +1 -0
  285. package/dist/assets/prism-app-CXYElq8-.css +1 -0
  286. package/dist/assets/prism.generated-BhbHDHR6.js +41 -0
  287. package/dist/assets/prismExtract.worker-Cws9K1NG.js +13 -0
  288. package/dist/assets/prismGround.worker-CIvKqxm2.js +1 -0
  289. package/dist/assets/prismLayout.worker-CZO2CY7B.js +1 -0
  290. package/dist/assets/providers-wzm7E8Pa.js +1 -0
  291. package/dist/assets/purify.es-adlwq8Pz.js +3 -0
  292. package/dist/assets/python-gzcpVVnB.js +1 -0
  293. package/dist/assets/queue-DHeyJ32F.css +1 -0
  294. package/dist/assets/queue-J4h7E3uc.js +1 -0
  295. package/dist/assets/quietHours-BvcsBKKK.js +1 -0
  296. package/dist/assets/react-BQSORdFI.js +1 -0
  297. package/dist/assets/reference-sJzyMiL4.js +1 -0
  298. package/dist/assets/registry-1GuPBfQK.js +1 -0
  299. package/dist/assets/registry-2GJZ46M8.css +1 -0
  300. package/dist/assets/registry-2v0jlh5Q.js +2 -0
  301. package/dist/assets/registry-B8DStMJk.js +1 -0
  302. package/dist/assets/registry-B940W2j5.js +1 -0
  303. package/dist/assets/registry-BAoRB8rd.css +1 -0
  304. package/dist/assets/registry-BPvIPLke.js +1 -0
  305. package/dist/assets/registry-BVHiKEwE.css +1 -0
  306. package/dist/assets/registry-BcZXBr3y.css +1 -0
  307. package/dist/assets/registry-BffpZK5w.js +1 -0
  308. package/dist/assets/registry-BgGeRiDA.js +2 -0
  309. package/dist/assets/registry-Buq5uuCv.js +1 -0
  310. package/dist/assets/registry-BzNLfje1.css +1 -0
  311. package/dist/assets/registry-C3ezxLR3.css +1 -0
  312. package/dist/assets/registry-CAusoyBh.js +1 -0
  313. package/dist/assets/registry-CEVrY72Z.js +1 -0
  314. package/dist/assets/registry-CKjKq6ct.js +1 -0
  315. package/dist/assets/registry-CNgybLQv.css +1 -0
  316. package/dist/assets/registry-CRM7y8QT.css +1 -0
  317. package/dist/assets/registry-CRisz4Ca.css +1 -0
  318. package/dist/assets/registry-Cg7qUZPS.js +1 -0
  319. package/dist/assets/registry-Cix-yqch.js +1 -0
  320. package/dist/assets/registry-CtbuZWYz.css +1 -0
  321. package/dist/assets/registry-DCI_BeFJ.js +5 -0
  322. package/dist/assets/registry-DDLSYDVA.js +1 -0
  323. package/dist/assets/registry-DI1wSG1Y.js +1 -0
  324. package/dist/assets/registry-DJinB5ye.js +2 -0
  325. package/dist/assets/registry-DUvXX_d0.js +1 -0
  326. package/dist/assets/registry-DVzLacl_.css +1 -0
  327. package/dist/assets/registry-DWcNVyI2.css +1 -0
  328. package/dist/assets/registry-D_URPoL4.js +1 -0
  329. package/dist/assets/registry-Dkc7hN5T.js +1 -0
  330. package/dist/assets/registry-DmQlNN3y.js +1 -0
  331. package/dist/assets/registry-DpaaVbmL.css +1 -0
  332. package/dist/assets/registry-Dpb8EXHn.js +49 -0
  333. package/dist/assets/registry-Dru0JcTa.css +1 -0
  334. package/dist/assets/registry-DujBAgn_.js +1 -0
  335. package/dist/assets/registry-Dye5m3qt.css +1 -0
  336. package/dist/assets/registry-GeSy4i7R.css +1 -0
  337. package/dist/assets/registry-QcULZpdE.js +4 -0
  338. package/dist/assets/registry-T3i2Q9SI.css +1 -0
  339. package/dist/assets/registry-UFIuwh3i.css +1 -0
  340. package/dist/assets/registry-Xzq_Rpmm.css +1 -0
  341. package/dist/assets/registry-ZOWzhOHk.css +1 -0
  342. package/dist/assets/registry-aIH-Im5Y.css +1 -0
  343. package/dist/assets/registry-aazwkBJp.js +1 -0
  344. package/dist/assets/registry-ei6fIgBT.css +1 -0
  345. package/dist/assets/registry-types-DMuK0vJ6.js +1 -0
  346. package/dist/assets/registry-upbw6pyj.css +1 -0
  347. package/dist/assets/registry-zRPjWNl5.js +1 -0
  348. package/dist/assets/relate-A9ZeaaAI.js +1 -0
  349. package/dist/assets/richText-BkxJhl9N.js +1 -0
  350. package/dist/assets/ruby-BhrksQMt.js +1 -0
  351. package/dist/assets/run-BYP2YlZT.js +23 -0
  352. package/dist/assets/run-C_0B_41W.js +21 -0
  353. package/dist/assets/run-DSVvshaB.js +21 -0
  354. package/dist/assets/rust-Cfkwpbl8.js +1 -0
  355. package/dist/assets/safeCssColor-di93BXgG.js +1 -0
  356. package/dist/assets/safeImageUrl-CUkucDUu.js +1 -0
  357. package/dist/assets/scale-Bcgfo6Hp.js +1 -0
  358. package/dist/assets/screen-DLR7p_yP.js +1 -0
  359. package/dist/assets/search-DnjHupRf.js +1 -0
  360. package/dist/assets/seed-b1xc0dj2.js +1 -0
  361. package/dist/assets/shapes-RqjqC0ay.js +1 -0
  362. package/dist/assets/shard000-DM_rqD7W.js +1 -0
  363. package/dist/assets/shard001-gQEQs7_F.js +1 -0
  364. package/dist/assets/shard002-DbDas-W-.js +1 -0
  365. package/dist/assets/shard003-DxMszG4_.js +1 -0
  366. package/dist/assets/shard004-DZMpLBw1.js +1 -0
  367. package/dist/assets/shard005-DLVkh9IH.js +1 -0
  368. package/dist/assets/shard006-B6efKHov.js +1 -0
  369. package/dist/assets/shard007-AFdZLe38.js +1 -0
  370. package/dist/assets/shard008-LbSBzwRx.js +1 -0
  371. package/dist/assets/shard009-D_6-SUDb.js +1 -0
  372. package/dist/assets/shard010-DbOj-uZW.js +1 -0
  373. package/dist/assets/shard011-BYSz7EEW.js +1 -0
  374. package/dist/assets/shard012-B5Ypj7OV.js +1 -0
  375. package/dist/assets/shard013-BtsliNIe.js +1 -0
  376. package/dist/assets/shard014-15sjmk68.js +1 -0
  377. package/dist/assets/shard015-nnXrqru_.js +1 -0
  378. package/dist/assets/shard016-BayXFE13.js +1 -0
  379. package/dist/assets/shard017-Cy4cGexs.js +1 -0
  380. package/dist/assets/shard018-aO-BYJ8H.js +1 -0
  381. package/dist/assets/shard019-gxaTeA3I.js +1 -0
  382. package/dist/assets/shard020-BibJdMI0.js +1 -0
  383. package/dist/assets/shard021-2FE-tze4.js +1 -0
  384. package/dist/assets/shard022-IXiyG-JK.js +1 -0
  385. package/dist/assets/shard023-314F6NJS.js +1 -0
  386. package/dist/assets/shard024-cN5rpQ_X.js +1 -0
  387. package/dist/assets/shard025-KKTaXOGE.js +1 -0
  388. package/dist/assets/shard026-C2Dkd1t6.js +1 -0
  389. package/dist/assets/shard027-Xy-8x9As.js +1 -0
  390. package/dist/assets/shard028-Bul-klUj.js +1 -0
  391. package/dist/assets/shard029-BbRSUcUZ.js +1 -0
  392. package/dist/assets/shard030-GYllsFVC.js +1 -0
  393. package/dist/assets/shard031-DMigeiyn.js +1 -0
  394. package/dist/assets/shard032-CcvmzK0l.js +1 -0
  395. package/dist/assets/shard033-11AU702M.js +1 -0
  396. package/dist/assets/shard034-Bx3urxjM.js +1 -0
  397. package/dist/assets/shard035-DBdEeyCt.js +1 -0
  398. package/dist/assets/shard036-vYgoRBqS.js +1 -0
  399. package/dist/assets/shard037-DP4MMw91.js +1 -0
  400. package/dist/assets/shard038-ffxsv7d6.js +1 -0
  401. package/dist/assets/shard039-C1JHHNp9.js +1 -0
  402. package/dist/assets/shard040-JbVvCSO_.js +1 -0
  403. package/dist/assets/shard041-5L_eFwGx.js +1 -0
  404. package/dist/assets/shard042-C9nsGL79.js +1 -0
  405. package/dist/assets/shard043-Dx_9HSKI.js +1 -0
  406. package/dist/assets/shard044-B3QQNC4A.js +1 -0
  407. package/dist/assets/shard045-B7z0WHO6.js +1 -0
  408. package/dist/assets/shard046-D1yDablJ.js +1 -0
  409. package/dist/assets/shard047-DJi3AgeT.js +1 -0
  410. package/dist/assets/shard048-D_2ipfUr.js +1 -0
  411. package/dist/assets/shard049-1aGgWZdd.js +1 -0
  412. package/dist/assets/shard050-Bjwa0Og4.js +1 -0
  413. package/dist/assets/shard051-Cx_GAk3v.js +1 -0
  414. package/dist/assets/shard052-LaeOD3V5.js +1 -0
  415. package/dist/assets/shard053-D-da7Foj.js +1 -0
  416. package/dist/assets/shard054-CM8eSRQk.js +1 -0
  417. package/dist/assets/shard055-QRpDl4Vs.js +1 -0
  418. package/dist/assets/shard056-DkY7CQm3.js +1 -0
  419. package/dist/assets/shard057-BVCgf7o0.js +1 -0
  420. package/dist/assets/shard058-93aGtdrX.js +1 -0
  421. package/dist/assets/shard059-rJE9X1_I.js +1 -0
  422. package/dist/assets/shard060-Lu_hfl1r.js +1 -0
  423. package/dist/assets/shard061-C9A8iNiq.js +1 -0
  424. package/dist/assets/shard062-BBIpEYZO.js +1 -0
  425. package/dist/assets/shard063-C_uen3Ub.js +1 -0
  426. package/dist/assets/shard064-DAHUsHST.js +1 -0
  427. package/dist/assets/shard065-C2edvdvh.js +1 -0
  428. package/dist/assets/shard066-DFcuVhZm.js +1 -0
  429. package/dist/assets/shard067-BN8DM8JZ.js +1 -0
  430. package/dist/assets/shard068-i464K77p.js +1 -0
  431. package/dist/assets/shard069-Dm9m2a5U.js +1 -0
  432. package/dist/assets/shard070-BPVvR8GH.js +1 -0
  433. package/dist/assets/shard071-Bal_0d9L.js +1 -0
  434. package/dist/assets/shard072-CBQu62kt.js +1 -0
  435. package/dist/assets/shard073-D5BRae0w.js +1 -0
  436. package/dist/assets/shard074-DtFvcBnZ.js +1 -0
  437. package/dist/assets/share-QHGHNDhQ.js +1 -0
  438. package/dist/assets/shellscript-BiGZg9Om.js +1 -0
  439. package/dist/assets/shellscript-CqHdAlCp.js +1 -0
  440. package/dist/assets/shikiHighlight-DUCYbsJ2.js +153 -0
  441. package/dist/assets/sourceHost-BV3t2XDb.js +1 -0
  442. package/dist/assets/speed-DwPw9KSv.js +1 -0
  443. package/dist/assets/spokenText-D4zPX9JY.js +1 -0
  444. package/dist/assets/sql-0Qcw9ht3.js +1 -0
  445. package/dist/assets/sql-CP0rg-5b.js +1 -0
  446. package/dist/assets/src-DbgF7cRH.js +2 -0
  447. package/dist/assets/stats-BeP5Bws0.js +1 -0
  448. package/dist/assets/status-BY02LIJt.js +1 -0
  449. package/dist/assets/stepDriver-DwjFet6U.js +1 -0
  450. package/dist/assets/store-4JNNn732.js +1 -0
  451. package/dist/assets/store-BFC7DZcg.js +1 -0
  452. package/dist/assets/store-BFrJaSxJ.js +1 -0
  453. package/dist/assets/store-DXmC_fP2.js +0 -0
  454. package/dist/assets/store-DgG0C1Qx.js +1 -0
  455. package/dist/assets/streamParse-DRgMHWye.js +2 -0
  456. package/dist/assets/student.generated-DS_acPaJ.js +1 -0
  457. package/dist/assets/swift-DonLKvLd.js +1 -0
  458. package/dist/assets/tables-Dzd3rTqG.js +1 -0
  459. package/dist/assets/time-BHTmJR1s.js +1 -0
  460. package/dist/assets/toast-BBNs2h3L.js +1 -0
  461. package/dist/assets/toml-CcmNWLt0.js +1 -0
  462. package/dist/assets/traveler.generated-Beun9X7y.js +1 -0
  463. package/dist/assets/tsx-5f3ulCja.js +1 -0
  464. package/dist/assets/tsx-BOvsFOI6.js +1 -0
  465. package/dist/assets/typeof-B5XbjTb1.js +1 -0
  466. package/dist/assets/typescript-Utq2Cl8c.js +1 -0
  467. package/dist/assets/typescript-j_1H8WHN.js +1 -0
  468. package/dist/assets/useDashboardLoop-B6ByHWoE.js +5 -0
  469. package/dist/assets/useFocusTrap-DbfG6zbM.js +1 -0
  470. package/dist/assets/useLiveConfig-X9Wxh90k.js +1 -0
  471. package/dist/assets/useSpatialCanvas-DogK9457.js +1 -0
  472. package/dist/assets/useSpotlightWalk-rMbmNBKK.js +1 -0
  473. package/dist/assets/useSrsCards-CagZefwX.js +1 -0
  474. package/dist/assets/useStudy-Bflreq2a.js +1 -0
  475. package/dist/assets/useTimeout-BRYvu2jQ.js +1 -0
  476. package/dist/assets/useValidatedImage-D2fhA198.js +1 -0
  477. package/dist/assets/useZoomGesture-CYc3tf2z.js +1 -0
  478. package/dist/assets/verbatim-CBMzUDlf.js +1 -0
  479. package/dist/assets/worker-BbLKfGzm.js +2 -0
  480. package/dist/assets/xml-WY0zc4PG.js +1 -0
  481. package/dist/assets/yaml-CxbubiML.js +1 -0
  482. package/dist/assets/yaml-DijMHRDA.js +1 -0
  483. package/dist/demo-assets/CREDITS.md +40 -0
  484. package/dist/demo-assets/images/basalt-cliffs.jpg +0 -0
  485. package/dist/demo-assets/images/capelinhos.jpg +0 -0
  486. package/dist/demo-assets/images/cliff-fields.jpg +0 -0
  487. package/dist/demo-assets/images/crater-panorama.jpg +0 -0
  488. package/dist/demo-assets/images/furnas-lake.jpg +0 -0
  489. package/dist/demo-assets/images/green-coast.jpg +0 -0
  490. package/dist/demo-assets/images/overcast-coast.jpg +0 -0
  491. package/dist/demo-assets/images/patchwork-fields.jpg +0 -0
  492. package/dist/demo-assets/images/ponta-delgada.jpg +0 -0
  493. package/dist/demo-assets/images/sete-cidades.jpg +0 -0
  494. package/dist/demo-assets/images/slide-placeholder-light.svg +9 -0
  495. package/dist/demo-assets/images/slide-placeholder.svg +9 -0
  496. package/dist/demo-assets/images/village-street.jpg +0 -0
  497. package/dist/demo-assets/pdf/cfd-primer.pdf +0 -0
  498. package/dist/demo-assets/video/azores-film.mp4 +0 -0
  499. package/dist/favicon.svg +19 -0
  500. package/dist/fonts/LICENSE.txt +34 -0
  501. package/dist/fonts/archivo-var-latin.woff2 +0 -0
  502. package/dist/fonts/bodoni-moda-400-italic-latin.woff2 +0 -0
  503. package/dist/fonts/bodoni-moda-var-latin.woff2 +0 -0
  504. package/dist/fonts/eb-garamond-var-italic-latin.woff2 +0 -0
  505. package/dist/fonts/eb-garamond-var-latin.woff2 +0 -0
  506. package/dist/fonts/export/families/archivo.css +12 -0
  507. package/dist/fonts/export/families/bodoni-moda.css +23 -0
  508. package/dist/fonts/export/families/eb-garamond.css +22 -0
  509. package/dist/fonts/export/families/ibm-plex-sans.css +12 -0
  510. package/dist/fonts/export/families/instrument-serif.css +22 -0
  511. package/dist/fonts/export/families/jetbrains-mono.css +12 -0
  512. package/dist/fonts/export/families/libre-franklin.css +12 -0
  513. package/dist/fonts/export/families/lora.css +22 -0
  514. package/dist/fonts/export/families/source-serif-4.css +12 -0
  515. package/dist/fonts/export/families/space-grotesk.css +12 -0
  516. package/dist/fonts/export/families/spectral.css +52 -0
  517. package/dist/fonts/fonts.css +141 -0
  518. package/dist/fonts/hanken-grotesk-var-latin.woff2 +0 -0
  519. package/dist/fonts/ibm-plex-sans-var-latin.woff2 +0 -0
  520. package/dist/fonts/instrument-serif-400-italic-latin.woff2 +0 -0
  521. package/dist/fonts/instrument-serif-400-latin.woff2 +0 -0
  522. package/dist/fonts/jetbrains-mono-var-latin.woff2 +0 -0
  523. package/dist/fonts/libre-franklin-var-latin.woff2 +0 -0
  524. package/dist/fonts/lora-var-italic-latin.woff2 +0 -0
  525. package/dist/fonts/lora-var-latin.woff2 +0 -0
  526. package/dist/fonts/newsreader-var-italic-latin.woff2 +0 -0
  527. package/dist/fonts/newsreader-var-latin.woff2 +0 -0
  528. package/dist/fonts/plex-mono-400-latin.woff2 +0 -0
  529. package/dist/fonts/plex-mono-500-latin.woff2 +0 -0
  530. package/dist/fonts/plex-mono-600-latin.woff2 +0 -0
  531. package/dist/fonts/source-serif-4-var-latin.woff2 +0 -0
  532. package/dist/fonts/space-grotesk-var-latin.woff2 +0 -0
  533. package/dist/fonts/spectral-400-italic-latin.woff2 +0 -0
  534. package/dist/fonts/spectral-400-latin.woff2 +0 -0
  535. package/dist/fonts/spectral-500-italic-latin.woff2 +0 -0
  536. package/dist/fonts/spectral-500-latin.woff2 +0 -0
  537. package/dist/fonts/spectral-600-latin.woff2 +0 -0
  538. package/dist/index.html +117 -0
  539. package/dist/legal/DISCLAIMER.md +16 -0
  540. package/dist/legal/LICENSE.txt +75 -0
  541. package/dist/legal/PRIVACY.md +127 -0
  542. package/dist/legal/SECURITY.md +72 -0
  543. package/dist/legal/SUPPORT.md +13 -0
  544. package/dist/legal/TERMS.md +122 -0
  545. package/dist/legal/THIRD-PARTY.txt +639 -0
  546. package/dist/legal/TRADEMARKS.md +15 -0
  547. package/dist/ort-wasm-simd-threaded.mjs +59 -0
  548. package/dist/sw.js +30 -0
  549. package/dist/vad.worklet.bundle.min.js +1 -0
  550. package/docker-compose.yml +33 -0
  551. package/gateway/README.md +99 -0
  552. package/gateway/actions-gateway.mjs +537 -0
  553. package/gateway/connectors.d.mts +27 -0
  554. package/gateway/connectors.mjs +463 -0
  555. package/gateway/guard.mjs +110 -0
  556. package/gateway/tokenStore.mjs +134 -0
  557. package/package.json +143 -0
@@ -0,0 +1,463 @@
1
+ // connectors.mjs — the action connectors, kept pure so they're testable.
2
+ //
3
+ // One connector per action id from the app's catalog (src/live/actions/catalog.ts).
4
+ // Each takes the args the user confirmed and the gateway's environment (which holds the
5
+ // credentials), performs the real call, and returns a plain { ok, status, detail }. No
6
+ // HTTP server, no process globals: env and fetch are passed in, so a test can drive every
7
+ // path — unconfigured, bad input, upstream success, upstream failure — without a socket.
8
+ //
9
+ // Credentials live ONLY here, in the deployment's environment — never in the browser. This
10
+ // is the single shared gateway model: the self-hoster connects their own accounts once
11
+ // (one Google OAuth token, one GitHub token) and everyone using that deployment acts
12
+ // through them. Per-visitor OAuth would need a stateful backend; that's deliberately out
13
+ // of scope.
14
+ import { augmentEnv, freshGoogleToken } from './tokenStore.mjs';
15
+
16
+ /** A connector failed because the deployment hasn't supplied its credentials yet. */
17
+ function unconfigured(detail) {
18
+ return { ok: false, status: 503, detail };
19
+ }
20
+
21
+ /** The user (or model) sent something the connector can't use. */
22
+ function badRequest(detail) {
23
+ return { ok: false, status: 400, detail };
24
+ }
25
+
26
+ /** The upstream service rejected the call. */
27
+ function upstreamFailed(service, status, detail) {
28
+ return {
29
+ ok: false,
30
+ status: 502,
31
+ detail: detail || `${service} rejected the request (${status}).`,
32
+ };
33
+ }
34
+
35
+ // --- input hygiene ---------------------------------------------------------------------
36
+ // Args originate from model output the user confirmed — trusted to a point, but a confirmed
37
+ // string can still carry control characters or be unbounded. Cap length (abuse / cost) and,
38
+ // for anything interpolated into an API path or request, collapse CR/LF so a crafted value
39
+ // can't smuggle in structure the connector didn't intend.
40
+ const MAX = {
41
+ title: 200,
42
+ body: 16000,
43
+ notes: 4000,
44
+ diff: 200000,
45
+ file: 24000,
46
+ };
47
+
48
+ /** GitHub's own name charset — owners/repos are interpolated into the API path, so a crafted value
49
+ * (slashes, .., query chars) must not be able to retarget the request. */
50
+ const GH_NAME = /^[A-Za-z0-9._-]+$/;
51
+
52
+ const clip = (s, n) => (s.length > n ? s.slice(0, n) : s);
53
+ const oneLine = (s) => s.replace(/[\r\n]+/g, ' ').trim();
54
+
55
+ // --- Google Calendar -------------------------------------------------------------------
56
+ async function calendarAddEvent(args, env, fetchImpl) {
57
+ const token = (await freshGoogleToken(fetchImpl)) ?? env.GOOGLE_OAUTH_TOKEN;
58
+ if (!token) {
59
+ return unconfigured('Google Calendar isn’t set up — connect Google in the Actions settings.');
60
+ }
61
+ const title = clip(oneLine(args.title ?? ''), MAX.title);
62
+ const start = (args.start ?? '').trim();
63
+ if (!title || !start)
64
+ return badRequest('A calendar event needs at least a title and a start time.');
65
+
66
+ const startMs = Date.parse(start);
67
+ if (Number.isNaN(startMs)) return badRequest(`Couldn’t read the start time: “${start}”.`);
68
+ const durationMin = Number(args.durationMin) > 0 ? Number(args.durationMin) : 60;
69
+ const endIso = new Date(startMs + durationMin * 60_000).toISOString();
70
+
71
+ const res = await fetchImpl('https://www.googleapis.com/calendar/v3/calendars/primary/events', {
72
+ method: 'POST',
73
+ headers: { authorization: `Bearer ${token}`, 'content-type': 'application/json' },
74
+ body: JSON.stringify({
75
+ summary: title,
76
+ description: clip(String(args.notes ?? ''), MAX.notes),
77
+ start: { dateTime: new Date(startMs).toISOString() },
78
+ end: { dateTime: endIso },
79
+ }),
80
+ });
81
+ if (!res.ok) return upstreamFailed('Google Calendar', res.status);
82
+ return { ok: true, status: 200, detail: `Added “${title}” to your calendar.` };
83
+ }
84
+
85
+ // --- GitHub ----------------------------------------------------------------------------
86
+ // Opens a DRAFT pull request only — draft PRs can't be merged until the user explicitly
87
+ // marks them ready. The connector has no delete or merge path; it can only create.
88
+ async function githubOpenDraftPr(args, env, fetchImpl) {
89
+ const token = env.GITHUB_OAUTH_TOKEN;
90
+ if (!token) {
91
+ return unconfigured("GitHub isn't set up — connect GitHub in the Actions settings.");
92
+ }
93
+
94
+ const [owner, repo] = (env.GITHUB_DEFAULT_REPO || '').split('/');
95
+ if (!owner || !repo) {
96
+ return unconfigured(
97
+ 'Set a default repo in the Actions settings (owner/repo format) before opening a PR.',
98
+ );
99
+ }
100
+ // owner/repo are interpolated straight into the API path — restrict to GitHub's own name
101
+ // charset so a crafted value (slashes, .., query chars) can't retarget the request.
102
+ const GH_NAME = /^[A-Za-z0-9._-]+$/;
103
+ if (!GH_NAME.test(owner) || !GH_NAME.test(repo)) {
104
+ return badRequest('Repo must be owner/name using letters, numbers, “.”, “_” or “-” only.');
105
+ }
106
+
107
+ const title = clip(oneLine(args.title ?? ''), MAX.title);
108
+ const head = oneLine(args.head ?? '').trim();
109
+ const base = oneLine(args.base ?? 'main').trim();
110
+ if (!title || !head) return badRequest('A PR needs a title and a branch name.');
111
+
112
+ const res = await fetchImpl(`https://api.github.com/repos/${owner}/${repo}/pulls`, {
113
+ method: 'POST',
114
+ headers: {
115
+ authorization: `Bearer ${token}`,
116
+ 'content-type': 'application/json',
117
+ 'user-agent': 'mavea-gateway/1',
118
+ accept: 'application/vnd.github+json',
119
+ },
120
+ body: JSON.stringify({
121
+ title,
122
+ head,
123
+ base,
124
+ body: clip(String(args.body ?? ''), MAX.body),
125
+ draft: true,
126
+ }),
127
+ });
128
+ if (!res.ok) return upstreamFailed('GitHub', res.status);
129
+ const data = await res.json();
130
+ return { ok: true, status: 200, detail: `Draft PR opened: ${data.html_url}` };
131
+ }
132
+
133
+ // Resolve and validate an owner/repo from the arg (or the configured default). Returns
134
+ // { owner, repo } or an error result the caller returns as-is.
135
+ function resolveRepo(args, env) {
136
+ const repoArg = oneLine(args.repo ?? '') || env.GITHUB_DEFAULT_REPO || '';
137
+ const [owner, repo] = repoArg.split('/');
138
+ if (!owner || !repo) {
139
+ return {
140
+ err: unconfigured(
141
+ 'Provide a repo (owner/name), or set a default repo in the Actions settings.',
142
+ ),
143
+ };
144
+ }
145
+ if (!GH_NAME.test(owner) || !GH_NAME.test(repo)) {
146
+ return {
147
+ err: badRequest('Repo must be owner/name using letters, numbers, “.”, “_” or “-” only.'),
148
+ };
149
+ }
150
+ return { owner, repo };
151
+ }
152
+
153
+ // READ-ONLY. Fetch a pull request's metadata + unified diff. There is no merge/comment/approve
154
+ // path here — Ripple only ever READS through this connector.
155
+ async function githubGetPrDiff(args, env, fetchImpl) {
156
+ const token = env.GITHUB_OAUTH_TOKEN;
157
+ if (!token) return unconfigured("GitHub isn't set up — connect GitHub in the Actions settings.");
158
+ const r = resolveRepo(args, env);
159
+ if (r.err) return r.err;
160
+ const { owner, repo } = r;
161
+ const num = oneLine(args.prNumber ?? '').trim();
162
+ if (!/^\d+$/.test(num)) return badRequest('PR number must be a number, e.g. 4821.');
163
+
164
+ const url = `https://api.github.com/repos/${owner}/${repo}/pulls/${num}`;
165
+ const auth = { authorization: `Bearer ${token}`, 'user-agent': 'mavea-gateway/1' };
166
+
167
+ const metaRes = await fetchImpl(url, {
168
+ method: 'GET',
169
+ headers: { ...auth, accept: 'application/vnd.github+json' },
170
+ });
171
+ if (!metaRes.ok) {
172
+ return upstreamFailed(
173
+ 'GitHub',
174
+ metaRes.status,
175
+ metaRes.status === 404 ? `PR #${num} not found in ${owner}/${repo}.` : undefined,
176
+ );
177
+ }
178
+ const pr = await metaRes.json();
179
+
180
+ const diffRes = await fetchImpl(url, {
181
+ method: 'GET',
182
+ headers: { ...auth, accept: 'application/vnd.github.v3.diff' },
183
+ });
184
+ if (!diffRes.ok) return upstreamFailed('GitHub', diffRes.status);
185
+ const diff = clip(await diffRes.text(), MAX.diff);
186
+
187
+ return {
188
+ ok: true,
189
+ status: 200,
190
+ detail: `Loaded PR #${num}: ${pr.title ?? ''}`.trim(),
191
+ payload: {
192
+ kind: 'diff',
193
+ diff,
194
+ label: `${owner}/${repo} #${num}`,
195
+ title: pr.title ?? '',
196
+ branch: pr.head?.ref ?? '',
197
+ base: pr.base?.ref ?? '',
198
+ },
199
+ };
200
+ }
201
+
202
+ // READ-ONLY. The unified diff between two refs (base...head) — a branch, tag, or commit SHA — so you
203
+ // can run Ripple on a branch's changes, not just an open PR. Reads only; never writes.
204
+ async function githubCompareRefs(args, env, fetchImpl) {
205
+ const token = env.GITHUB_OAUTH_TOKEN;
206
+ if (!token) return unconfigured("GitHub isn't set up — connect GitHub in the Actions settings.");
207
+ const r = resolveRepo(args, env);
208
+ if (r.err) return r.err;
209
+ const { owner, repo } = r;
210
+ const baseRef = oneLine(args.base ?? '').trim();
211
+ const headRef = oneLine(args.head ?? '').trim();
212
+ if (!baseRef || !headRef)
213
+ return badRequest('Provide a base and a head ref (branch, tag, or SHA).');
214
+
215
+ // Refs can contain "/" and ".", so encode each side; owner/repo are already charset-validated.
216
+ const range = `${encodeURIComponent(baseRef)}...${encodeURIComponent(headRef)}`;
217
+ const url = `https://api.github.com/repos/${owner}/${repo}/compare/${range}`;
218
+ const diffRes = await fetchImpl(url, {
219
+ method: 'GET',
220
+ headers: {
221
+ authorization: `Bearer ${token}`,
222
+ 'user-agent': 'mavea-gateway/1',
223
+ accept: 'application/vnd.github.v3.diff',
224
+ },
225
+ });
226
+ if (!diffRes.ok) return upstreamFailed('GitHub', diffRes.status);
227
+ const diff = clip(await diffRes.text(), MAX.diff);
228
+
229
+ return {
230
+ ok: true,
231
+ status: 200,
232
+ detail: `Compared ${baseRef}...${headRef} in ${owner}/${repo}`,
233
+ payload: { kind: 'diff', diff, label: `${owner}/${repo} ${baseRef}...${headRef}` },
234
+ };
235
+ }
236
+
237
+ // READ-ONLY. The file tree of a repo at a ref (default HEAD) — so Ripple can explore a whole repo or
238
+ // a folder with no change at all (the onboarding view). Returns just the blob paths; reads only.
239
+ // Resolves `ref` to its concrete commit FIRST: a branch/tag name is a moving target, so two calls made
240
+ // moments apart could otherwise silently see different code, and there'd be nothing stable to cache
241
+ // against. The commit's own tree SHA is then an immutable snapshot to read.
242
+ async function githubGetRepoTree(args, env, fetchImpl) {
243
+ const token = env.GITHUB_OAUTH_TOKEN;
244
+ if (!token) return unconfigured("GitHub isn't set up — connect GitHub in the Actions settings.");
245
+ const r = resolveRepo(args, env);
246
+ if (r.err) return r.err;
247
+ const { owner, repo } = r;
248
+ const ref = oneLine(args.ref ?? '') || 'HEAD';
249
+ const auth = {
250
+ authorization: `Bearer ${token}`,
251
+ 'user-agent': 'mavea-gateway/1',
252
+ accept: 'application/vnd.github+json',
253
+ };
254
+
255
+ const commitRes = await fetchImpl(
256
+ `https://api.github.com/repos/${owner}/${repo}/commits/${encodeURIComponent(ref)}`,
257
+ { method: 'GET', headers: auth },
258
+ );
259
+ if (!commitRes.ok) {
260
+ return upstreamFailed(
261
+ 'GitHub',
262
+ commitRes.status,
263
+ commitRes.status === 404 ? `Couldn’t find ${owner}/${repo} @ ${ref}.` : undefined,
264
+ );
265
+ }
266
+ const commit = await commitRes.json();
267
+ const commitSha = typeof commit.sha === 'string' ? commit.sha : ref;
268
+ const treeSha = commit.commit?.tree?.sha || commitSha;
269
+
270
+ const url = `https://api.github.com/repos/${owner}/${repo}/git/trees/${encodeURIComponent(treeSha)}?recursive=1`;
271
+ const res = await fetchImpl(url, { method: 'GET', headers: auth });
272
+ if (!res.ok) {
273
+ return upstreamFailed(
274
+ 'GitHub',
275
+ res.status,
276
+ res.status === 404 ? `Couldn’t find ${owner}/${repo} @ ${ref}.` : undefined,
277
+ );
278
+ }
279
+ const data = await res.json();
280
+ // Cap the path count so a giant monorepo can't balloon the response; flag if GitHub truncated it.
281
+ const paths = Array.isArray(data.tree)
282
+ ? data.tree
283
+ .filter((t) => t && t.type === 'blob' && typeof t.path === 'string')
284
+ .map((t) => t.path)
285
+ .slice(0, 4000)
286
+ : [];
287
+
288
+ return {
289
+ ok: true,
290
+ status: 200,
291
+ detail: `Loaded ${paths.length} files from ${owner}/${repo}`,
292
+ payload: {
293
+ kind: 'tree',
294
+ paths,
295
+ label: `${owner}/${repo}`,
296
+ truncated: Boolean(data.truncated) || paths.length >= 4000,
297
+ // The exact commit `ref` resolved to — a stable identity to cache against, even when `ref`
298
+ // itself is a branch name that can move.
299
+ sha: commitSha,
300
+ },
301
+ };
302
+ }
303
+
304
+ // READ-ONLY. The contents of one file at a ref — so Ripple can read the actual code a change touches,
305
+ // not just the diff. Decodes GitHub's base64 blob to text. Reads only.
306
+ async function githubGetFileContents(args, env, fetchImpl) {
307
+ const token = env.GITHUB_OAUTH_TOKEN;
308
+ if (!token) return unconfigured("GitHub isn't set up — connect GitHub in the Actions settings.");
309
+ const r = resolveRepo(args, env);
310
+ if (r.err) return r.err;
311
+ const { owner, repo } = r;
312
+ const path = (args.path ?? '').trim();
313
+ if (!path || path.includes('..')) return badRequest('Provide a file path inside the repo.');
314
+ const ref = oneLine(args.ref ?? '') || 'HEAD';
315
+
316
+ const segs = path
317
+ .split('/')
318
+ .map((s) => encodeURIComponent(s))
319
+ .join('/');
320
+ const url = `https://api.github.com/repos/${owner}/${repo}/contents/${segs}?ref=${encodeURIComponent(ref)}`;
321
+ const res = await fetchImpl(url, {
322
+ method: 'GET',
323
+ headers: {
324
+ authorization: `Bearer ${token}`,
325
+ 'user-agent': 'mavea-gateway/1',
326
+ accept: 'application/vnd.github+json',
327
+ },
328
+ });
329
+ if (!res.ok) {
330
+ return upstreamFailed(
331
+ 'GitHub',
332
+ res.status,
333
+ res.status === 404 ? `${path} not found.` : undefined,
334
+ );
335
+ }
336
+ const data = await res.json();
337
+ if (data.type !== 'file' || typeof data.content !== 'string') {
338
+ return badRequest('That path is not a file.');
339
+ }
340
+ const text = clip(Buffer.from(data.content, 'base64').toString('utf8'), MAX.file);
341
+ return {
342
+ ok: true,
343
+ status: 200,
344
+ detail: `Read ${path}`,
345
+ payload: { kind: 'file', path, content: text },
346
+ };
347
+ }
348
+
349
+ // READ-ONLY. Find where a symbol is used across the repo (GitHub code search). Grounds the real blast
350
+ // radius a diff can't see — the actual callers. Reads only; returns the file paths that match.
351
+ async function githubSearchCode(args, env, fetchImpl) {
352
+ const token = env.GITHUB_OAUTH_TOKEN;
353
+ if (!token) return unconfigured("GitHub isn't set up — connect GitHub in the Actions settings.");
354
+ const r = resolveRepo(args, env);
355
+ if (r.err) return r.err;
356
+ const { owner, repo } = r;
357
+ const term = (args.query ?? '').trim();
358
+ if (!/^[A-Za-z_$][\w$]*$/.test(term))
359
+ return badRequest('Search term must be a single identifier.');
360
+
361
+ const q = encodeURIComponent(`${term} repo:${owner}/${repo}`);
362
+ const url = `https://api.github.com/search/code?q=${q}&per_page=20`;
363
+ const res = await fetchImpl(url, {
364
+ method: 'GET',
365
+ headers: {
366
+ authorization: `Bearer ${token}`,
367
+ 'user-agent': 'mavea-gateway/1',
368
+ accept: 'application/vnd.github+json',
369
+ },
370
+ });
371
+ if (!res.ok) return upstreamFailed('GitHub', res.status);
372
+ const data = await res.json();
373
+ const files = Array.isArray(data.items)
374
+ ? data.items
375
+ .map((i) => i && i.path)
376
+ .filter((p) => typeof p === 'string')
377
+ .slice(0, 20)
378
+ : [];
379
+ return {
380
+ ok: true,
381
+ status: 200,
382
+ detail: `${files.length} file(s) reference ${term}`,
383
+ payload: { kind: 'search', term, files },
384
+ };
385
+ }
386
+
387
+ // READ-ONLY. The recent committers to a path — a real "who to ask / who to wake" signal when a repo
388
+ // has no CODEOWNERS (the REST API has no line-level blame; recent committers is the closest read-only
389
+ // proxy). Reads only; returns logins with their commit counts, most active first.
390
+ async function githubGetFileCommits(args, env, fetchImpl) {
391
+ const token = env.GITHUB_OAUTH_TOKEN;
392
+ if (!token) return unconfigured("GitHub isn't set up — connect GitHub in the Actions settings.");
393
+ const r = resolveRepo(args, env);
394
+ if (r.err) return r.err;
395
+ const { owner, repo } = r;
396
+ const path = (args.path ?? '').trim();
397
+ if (!path || path.includes('..')) {
398
+ return badRequest('Provide a file or folder path inside the repo.');
399
+ }
400
+ const ref = oneLine(args.ref ?? '');
401
+ const q = new URLSearchParams({ path, per_page: '10' });
402
+ if (ref) q.set('sha', ref);
403
+ const url = `https://api.github.com/repos/${owner}/${repo}/commits?${q.toString()}`;
404
+ const res = await fetchImpl(url, {
405
+ method: 'GET',
406
+ headers: {
407
+ authorization: `Bearer ${token}`,
408
+ 'user-agent': 'mavea-gateway/1',
409
+ accept: 'application/vnd.github+json',
410
+ },
411
+ });
412
+ if (!res.ok) return upstreamFailed('GitHub', res.status);
413
+ const data = await res.json();
414
+ const counts = new Map();
415
+ if (Array.isArray(data)) {
416
+ for (const c of data) {
417
+ const login = c?.author?.login || c?.commit?.author?.name;
418
+ if (typeof login === 'string' && login) counts.set(login, (counts.get(login) ?? 0) + 1);
419
+ }
420
+ }
421
+ const committers = [...counts.entries()]
422
+ .map(([login, count]) => ({ login, count }))
423
+ .sort((a, b) => b.count - a.count)
424
+ .slice(0, 6);
425
+ return {
426
+ ok: true,
427
+ status: 200,
428
+ detail: `${committers.length} recent committer(s) to ${path}`,
429
+ payload: { kind: 'commits', path, committers },
430
+ };
431
+ }
432
+
433
+ /** action id → connector. The id is also the proxy route the app POSTs to. */
434
+ const CONNECTORS = {
435
+ 'calendar.addEvent': calendarAddEvent,
436
+ 'github.openDraftPr': githubOpenDraftPr,
437
+ // Read-only — Ripple fetches diffs / trees / files / code-search / committers to analyze; never writes.
438
+ 'github.getPrDiff': githubGetPrDiff,
439
+ 'github.compareRefs': githubCompareRefs,
440
+ 'github.getRepoTree': githubGetRepoTree,
441
+ 'github.getFileContents': githubGetFileContents,
442
+ 'github.searchCode': githubSearchCode,
443
+ 'github.getFileCommits': githubGetFileCommits,
444
+ };
445
+
446
+ /** The action ids this gateway knows how to run. */
447
+ export const SUPPORTED_ACTIONS = Object.keys(CONNECTORS);
448
+
449
+ /**
450
+ * Run a confirmed action. Pure: pass the env that holds the credentials and a fetch
451
+ * implementation (defaults to the global). Never throws — a network error becomes an
452
+ * honest { ok:false } the surface can show.
453
+ */
454
+ export async function runConnector(id, args, env = process.env, fetchImpl = fetch) {
455
+ const connector = CONNECTORS[id];
456
+ if (!connector) return { ok: false, status: 404, detail: `No connector for “${id}”.` };
457
+ try {
458
+ const augmented = augmentEnv(env);
459
+ return await connector(args && typeof args === 'object' ? args : {}, augmented, fetchImpl);
460
+ } catch {
461
+ return { ok: false, status: 502, detail: `Couldn’t reach the connector for “${id}”.` };
462
+ }
463
+ }
@@ -0,0 +1,110 @@
1
+ // Pure CSRF/auth checks for the actions gateway, kept separate so they can be unit-tested without
2
+ // starting the HTTP server. See actions-gateway.mjs for why the gateway must reject foreign-origin
3
+ // state-changing requests: it holds the deployer's OAuth credentials and fires real actions.
4
+ import { createHash, randomBytes, timingSafeEqual } from 'node:crypto';
5
+
6
+ /**
7
+ * True when a state-changing request may proceed on origin grounds. A browser always attaches an
8
+ * `Origin` header to a cross-origin POST/DELETE (even a no-preflight "simple" request), so an
9
+ * allowlist on Origin blocks CSRF. A request with neither Origin nor Referer is NOT silently
10
+ * trusted: the HTTP layer must authenticate it as a non-browser API call.
11
+ */
12
+ export function originAllowed(headers, allowedOrigins) {
13
+ const origin = headers.origin;
14
+ if (origin) return allowedOrigins.has(origin);
15
+ const referer = headers.referer;
16
+ if (referer) return [...allowedOrigins].some((o) => referer === o || referer.startsWith(o + '/'));
17
+ return false;
18
+ }
19
+
20
+ /** True when the shared secret is satisfied. An empty configured secret is valid only for a
21
+ * loopback-only server; startup validation prevents it on any remote bind. */
22
+ export function secretOk(headers, secret) {
23
+ if (!secret) return true;
24
+ const supplied = headers['x-gateway-secret'];
25
+ if (typeof supplied !== 'string') return false;
26
+ const expectedBytes = Buffer.from(secret);
27
+ const suppliedBytes = Buffer.from(supplied);
28
+ return (
29
+ expectedBytes.byteLength === suppliedBytes.byteLength &&
30
+ timingSafeEqual(expectedBytes, suppliedBytes)
31
+ );
32
+ }
33
+
34
+ /** The only unauthenticated bind targets the gateway permits. */
35
+ export function isLoopbackHost(host) {
36
+ return host === '127.0.0.1' || host === '::1' || host === 'localhost';
37
+ }
38
+
39
+ /** Refuse a remotely reachable gateway unless it has a strong shared secret. */
40
+ export function assertGatewayConfig(host, secret) {
41
+ if (typeof host !== 'string' || !host.trim()) throw new Error('ACTIONS_HOST must not be empty');
42
+ if (!isLoopbackHost(host) && (typeof secret !== 'string' || secret.length < 32)) {
43
+ throw new Error(
44
+ 'GATEWAY_SECRET must be at least 32 characters when ACTIONS_HOST is not loopback',
45
+ );
46
+ }
47
+ return { host, remote: !isLoopbackHost(host) };
48
+ }
49
+
50
+ function canonicalJson(value) {
51
+ if (value === null || typeof value !== 'object') return JSON.stringify(value);
52
+ if (Array.isArray(value)) return `[${value.map(canonicalJson).join(',')}]`;
53
+ return `{${Object.keys(value)
54
+ .sort()
55
+ .map((key) => `${JSON.stringify(key)}:${canonicalJson(value[key])}`)
56
+ .join(',')}}`;
57
+ }
58
+
59
+ function actionDigest(id, args) {
60
+ return createHash('sha256').update(canonicalJson({ id, args })).digest();
61
+ }
62
+
63
+ /** Single-use action confirmations. The token is random; its stored digest is bound to the exact
64
+ * action id and arguments the user saw. `consume` always burns a known token, even on mismatch, so
65
+ * a captured token cannot be probed or replayed with altered arguments. */
66
+ export function createActionConfirmationStore(ttlMs, now = () => Date.now()) {
67
+ const pending = new Map();
68
+ return {
69
+ issue(id, args) {
70
+ const t = now();
71
+ for (const [token, entry] of pending) if (entry.expiresAt <= t) pending.delete(token);
72
+ const token = randomBytes(32).toString('base64url');
73
+ pending.set(token, { digest: actionDigest(id, args), expiresAt: t + ttlMs });
74
+ return token;
75
+ },
76
+ consume(token, id, args) {
77
+ if (typeof token !== 'string' || !token) return false;
78
+ const entry = pending.get(token);
79
+ if (!entry) return false;
80
+ pending.delete(token);
81
+ if (entry.expiresAt <= now()) return false;
82
+ return timingSafeEqual(entry.digest, actionDigest(id, args));
83
+ },
84
+ };
85
+ }
86
+
87
+ /**
88
+ * A single-use, TTL'd OAuth `state` store (CSRF protection for the GET redirect callback). `issue()`
89
+ * mints a nonce included in the auth URL; `consume()` validates + burns it on the callback, so a
90
+ * forged callback with no/expired/reused state is rejected. `now` is injectable for tests.
91
+ */
92
+ export function createOAuthStateStore(ttlMs, now = () => Date.now()) {
93
+ const pending = new Map();
94
+ return {
95
+ issue() {
96
+ const t = now();
97
+ for (const [k, exp] of pending) if (exp <= t) pending.delete(k);
98
+ const state = randomBytes(16).toString('hex');
99
+ pending.set(state, t + ttlMs);
100
+ return state;
101
+ },
102
+ consume(state) {
103
+ if (!state) return false;
104
+ const exp = pending.get(state);
105
+ if (exp === undefined) return false;
106
+ pending.delete(state); // single-use
107
+ return exp > now();
108
+ },
109
+ };
110
+ }