@vantran-se/openchamber-web 1.23.1 → 1.24.4

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 (313) hide show
  1. package/bin/cli.test.js +29 -6
  2. package/bin/lib/cli-http.js +5 -1
  3. package/bin/lib/commands-status.js +5 -0
  4. package/dist/assets/{CodeMirrorCommentWidgets-BOpqXpFU.js → CodeMirrorCommentWidgets-B4a0JkUz.js} +1 -1
  5. package/dist/assets/DiffView-B2CD9wC8.js +4 -0
  6. package/dist/assets/FilesView-C4vMFclc.js +13 -0
  7. package/dist/assets/GitView-Byu2DY7s.js +6 -0
  8. package/dist/assets/GuestAttachDialog-B808E0-d.js +1 -0
  9. package/dist/assets/{JsonTreeView-nd_E8eVM.js → JsonTreeView-VW_7czo3.js} +1 -1
  10. package/dist/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
  11. package/dist/assets/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
  12. package/dist/assets/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
  13. package/dist/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
  14. package/dist/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
  15. package/dist/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
  16. package/dist/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
  17. package/dist/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
  18. package/dist/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
  19. package/dist/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
  20. package/dist/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
  21. package/dist/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
  22. package/dist/assets/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
  23. package/dist/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
  24. package/dist/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
  25. package/dist/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
  26. package/dist/assets/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
  27. package/dist/assets/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
  28. package/dist/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
  29. package/dist/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
  30. package/dist/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
  31. package/dist/assets/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
  32. package/dist/assets/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
  33. package/dist/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
  34. package/dist/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
  35. package/dist/assets/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
  36. package/dist/assets/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
  37. package/dist/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
  38. package/dist/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
  39. package/dist/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
  40. package/dist/assets/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
  41. package/dist/assets/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
  42. package/dist/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
  43. package/dist/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
  44. package/dist/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
  45. package/dist/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
  46. package/dist/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
  47. package/dist/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
  48. package/dist/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
  49. package/dist/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
  50. package/dist/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
  51. package/dist/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
  52. package/dist/assets/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
  53. package/dist/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
  54. package/dist/assets/KaTeX_Script-Regular-D5yQViql.woff +0 -0
  55. package/dist/assets/KaTeX_Size1-Regular-C195tn64.woff +0 -0
  56. package/dist/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
  57. package/dist/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
  58. package/dist/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
  59. package/dist/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
  60. package/dist/assets/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
  61. package/dist/assets/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
  62. package/dist/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
  63. package/dist/assets/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
  64. package/dist/assets/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
  65. package/dist/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
  66. package/dist/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
  67. package/dist/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
  68. package/dist/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
  69. package/dist/assets/LinearIssuesView-EzGNCGrd.js +1 -0
  70. package/dist/assets/{MarkdownImageGallery-CVYds3sQ.js → MarkdownImageGallery-B2YUDFaB.js} +1 -1
  71. package/dist/assets/MarkdownRendererImpl-B4ikIzR3.js +12 -0
  72. package/dist/assets/{OnboardingScreen-Dd2IbPTn.js → OnboardingScreen-CQHBSTEi.js} +1 -1
  73. package/dist/assets/{PatchDiff-nUu5i4bG.js → PatchDiff-DCjGhlYV.js} +1 -1
  74. package/dist/assets/PierreDiffViewer-CEDZNkU2.js +210 -0
  75. package/dist/assets/PlanView-D3x-pTkZ.js +5 -0
  76. package/dist/assets/PluginPane-DEcgDQ9h.js +3 -0
  77. package/dist/assets/SettingsView-CSinuH-1.js +29 -0
  78. package/dist/assets/{SettingsWindow-BccxY81J.js → SettingsWindow-B5CHoJFZ.js} +1 -1
  79. package/dist/assets/SubmoduleDiffSummary-oxeACCWs.js +1 -0
  80. package/dist/assets/ToolOutputDialog-tLNWmfcW.js +15 -0
  81. package/dist/assets/{ToolPartDiffPreview-BFVgk0UK.js → ToolPartDiffPreview-CflzmK-x.js} +2 -2
  82. package/dist/assets/{VirtualizedFileDiff-z3_H74UR.js → VirtualizedFileDiff-NU0FHFhT.js} +3 -3
  83. package/dist/assets/{WalkthroughView-BqM9GFbJ.js → WalkthroughView-BZyjhqHv.js} +2 -2
  84. package/dist/assets/appThemeRegistry-DLicw4dH.js +1 -0
  85. package/dist/assets/commitAndPush-BDftrjr6.js +1 -0
  86. package/dist/assets/{computeVirtualFileMetrics-Bdazp9Qo.js → computeVirtualFileMetrics-DlWlEM3x.js} +1 -1
  87. package/dist/assets/de-Bro6_zyl.js +10 -0
  88. package/dist/assets/es-Bb9XQZvd.js +16 -0
  89. package/dist/assets/fr-Dgfzn-IL.js +14 -0
  90. package/dist/assets/{index-eo1-D_7z.js → index-CtQNmqUL.js} +1 -1
  91. package/dist/assets/index-DqaMWNrC.css +1 -0
  92. package/dist/assets/index-Dqc6USl3.js +40 -0
  93. package/dist/assets/{isDiffPlainText-BvKH712-.js → isDiffPlainText-CO4e5J_S.js} +1 -1
  94. package/dist/assets/{isFilePlainText-BdVVPukf.js → isFilePlainText-ue6kCou7.js} +1 -1
  95. package/dist/assets/ja-BYsakGFh.js +16 -0
  96. package/dist/assets/ko-BSaQz9aN.js +16 -0
  97. package/dist/assets/main-B62_pjL5.js +2 -0
  98. package/dist/assets/main-BEdcOI2P.js +896 -0
  99. package/dist/assets/{markdown-shiki.worker-D5fBU-lw.js → markdown-shiki.worker-CahLvHIq.js} +5 -5
  100. package/dist/assets/markdownCore-CK48LG0z.js +5 -0
  101. package/dist/assets/miniChat-LT8Rqofr.js +2 -0
  102. package/dist/assets/mobile-CqarEynh.js +2 -0
  103. package/dist/assets/{patchFileDiff-B7LjppSS.js → patchFileDiff-D7QVlovD.js} +3 -3
  104. package/dist/assets/pl-OIviPdoj.js +16 -0
  105. package/dist/assets/pt-BR-Cltg-E6s.js +16 -0
  106. package/dist/assets/renderElectronMiniChatApp-COyLTtZx.js +2 -0
  107. package/dist/assets/renderMobileApp-BC1MHg6g.js +25 -0
  108. package/dist/assets/runtimeEndpointReset-DdrazOVH.js +25 -0
  109. package/dist/assets/{scheduledTasksApi-hceovDei.js → scheduledTasksApi-B2SWMGEU.js} +1 -1
  110. package/dist/assets/shikiHighlight-BPu3JiQs.js +1 -0
  111. package/dist/assets/textMateThemeFromAppTheme-DWqRPo9A.js +1 -0
  112. package/dist/assets/tr-CQI-KPre.js +7 -0
  113. package/dist/assets/uk-CqW7R4DA.js +16 -0
  114. package/dist/assets/useAppFontEffects-ne84JBVL.js +7333 -0
  115. package/dist/assets/useInlineCommentController-CgS0fnw_.js +2 -0
  116. package/dist/assets/useRootScrollLock-Cpf1qoGp.js +2 -0
  117. package/dist/assets/{vendor-base-ui-BY_5qla_.js → vendor-base-ui-CsXYnR5c.js} +1 -1
  118. package/dist/assets/{vendor-codemirror-language-data-DWA1bm1F.js → vendor-codemirror-language-data-Bx2EHc1O.js} +2 -2
  119. package/dist/assets/vendor-framer-motion-Bq3iTZ6r.js +1 -0
  120. package/dist/assets/vendor-katex-Cp579UoJ.css +1 -0
  121. package/dist/assets/{vendor-motion-dom-D_o3BTI3.js → vendor-motion-dom-DcCgeG69.js} +1 -1
  122. package/dist/assets/{vendor-remixicon-react-Dil0zKKT.js → vendor-remixicon-react-BDmGmFCA.js} +1 -1
  123. package/dist/assets/vendor-strip-json-comments-5dJlOkP1.js +4 -0
  124. package/dist/assets/{vendor-tanstack-react-virtual-g05Cx3z9.js → vendor-tanstack-react-virtual-ClYN8CzB.js} +1 -1
  125. package/dist/assets/{vendor-tanstack-virtual-core-Dubg10g5.js → vendor-tanstack-virtual-core-BewVQryB.js} +1 -1
  126. package/dist/assets/{vendor-zod-B6551dwG.js → vendor-zod-CgAdXWZO.js} +4 -4
  127. package/dist/assets/{web-components-B_Z64So5.js → web-components-DxX8bZ1o.js} +2 -2
  128. package/dist/assets/zh-CN-CVZG_o_J.js +16 -0
  129. package/dist/assets/zh-TW-D5ZxzCZp.js +16 -0
  130. package/dist/index.html +6 -4
  131. package/dist/mini-chat.html +6 -4
  132. package/dist/mobile.html +6 -4
  133. package/package.json +12 -9
  134. package/server/built-in-extensions/registry.json +4 -0
  135. package/server/index.d.ts +2 -0
  136. package/server/index.js +44 -10
  137. package/server/lib/agent-tool/DOCUMENTATION.md +17 -4
  138. package/server/lib/agent-tool/runtime.js +62 -15
  139. package/server/lib/agent-tool/runtime.test.js +88 -2
  140. package/server/lib/changelog/update-notes.js +2 -1
  141. package/server/lib/changelog/update-notes.test.js +19 -0
  142. package/server/lib/event-stream/DOCUMENTATION.md +23 -0
  143. package/server/lib/event-stream/delta-coalescer.js +0 -0
  144. package/server/lib/event-stream/delta-coalescer.test.js +292 -0
  145. package/server/lib/event-stream/global-hub.js +53 -23
  146. package/server/lib/event-stream/global-hub.test.js +160 -0
  147. package/server/lib/event-stream/global-ws-bridge.js +1 -0
  148. package/server/lib/event-stream/index.js +4 -0
  149. package/server/lib/fs/DOCUMENTATION.md +10 -1
  150. package/server/lib/fs/git-process.test.js +77 -0
  151. package/server/lib/fs/routes.js +58 -5
  152. package/server/lib/fs/routes.test.js +116 -0
  153. package/server/lib/fs/search.js +2 -1
  154. package/server/lib/git/DOCUMENTATION.md +20 -5
  155. package/server/lib/git/routes.js +16 -3
  156. package/server/lib/git/serial-refresh.js +93 -0
  157. package/server/lib/git/serial-refresh.test.js +112 -0
  158. package/server/lib/git/service.js +429 -70
  159. package/server/lib/git/service.test.js +418 -0
  160. package/server/lib/github/pr-status.js +5 -5
  161. package/server/lib/github/pr-status.test.js +1 -1
  162. package/server/lib/github/routes.js +4 -4
  163. package/server/lib/guests/DOCUMENTATION.md +68 -0
  164. package/server/lib/guests/auth-store.js +184 -0
  165. package/server/lib/guests/auth-store.test.js +112 -0
  166. package/server/lib/guests/background.test.js +83 -0
  167. package/server/lib/guests/builtins.js +34 -0
  168. package/server/lib/guests/builtins.test.js +174 -0
  169. package/server/lib/guests/catalog.js +477 -0
  170. package/server/lib/guests/catalog.test.js +390 -0
  171. package/server/lib/guests/clone.js +297 -0
  172. package/server/lib/guests/extract-zip.js +136 -0
  173. package/server/lib/guests/extract-zip.test.js +109 -0
  174. package/server/lib/guests/files.js +308 -0
  175. package/server/lib/guests/files.test.js +262 -0
  176. package/server/lib/guests/grant-scope.js +81 -0
  177. package/server/lib/guests/grant-scope.test.js +75 -0
  178. package/server/lib/guests/host-session.js +73 -0
  179. package/server/lib/guests/host-session.test.js +30 -0
  180. package/server/lib/guests/html-styles.js +6 -0
  181. package/server/lib/guests/html-styles.test.js +45 -0
  182. package/server/lib/guests/html-tokens.js +73 -0
  183. package/server/lib/guests/html-tokens.test.js +53 -0
  184. package/server/lib/guests/install.js +406 -0
  185. package/server/lib/guests/install.test.js +338 -0
  186. package/server/lib/guests/oauth.js +501 -0
  187. package/server/lib/guests/oauth.test.js +481 -0
  188. package/server/lib/guests/persist.js +336 -0
  189. package/server/lib/guests/persist.test.js +288 -0
  190. package/server/lib/guests/request.js +112 -0
  191. package/server/lib/guests/request.test.js +206 -0
  192. package/server/lib/guests/routes.js +838 -0
  193. package/server/lib/guests/service.js +538 -0
  194. package/server/lib/guests/service.test.js +277 -0
  195. package/server/lib/guests/sockets.js +129 -0
  196. package/server/lib/guests/sockets.test.js +110 -0
  197. package/server/lib/guests/ssh-install.test.js +188 -0
  198. package/server/lib/guests/storage.js +68 -0
  199. package/server/lib/guests/storage.test.js +59 -0
  200. package/server/lib/guests/updates.js +294 -0
  201. package/server/lib/guests/updates.test.js +334 -0
  202. package/server/lib/guests/upload.js +50 -0
  203. package/server/lib/guests/upload.test.js +131 -0
  204. package/server/lib/linear/DOCUMENTATION.md +1 -1
  205. package/server/lib/message-queue/DOCUMENTATION.md +10 -1
  206. package/server/lib/message-queue/runtime.js +21 -1
  207. package/server/lib/message-queue/runtime.test.js +52 -5
  208. package/server/lib/notifications/routes.js +5 -0
  209. package/server/lib/openchamber-control/DOCUMENTATION.md +6 -0
  210. package/server/lib/openchamber-sessions/routes.js +62 -29
  211. package/server/lib/openchamber-sessions/routes.test.js +96 -0
  212. package/server/lib/opencode/DOCUMENTATION.md +55 -1
  213. package/server/lib/opencode/bootstrap-runtime.js +1 -0
  214. package/server/lib/opencode/core-routes.js +39 -1
  215. package/server/lib/opencode/feature-routes-runtime.js +15 -0
  216. package/server/lib/opencode/lifecycle-process.test.js +84 -0
  217. package/server/lib/opencode/lifecycle.js +54 -67
  218. package/server/lib/opencode/openchamber-routes.js +72 -14
  219. package/server/lib/opencode/openchamber-routes.test.js +71 -3
  220. package/server/lib/opencode/session-runtime.js +68 -0
  221. package/server/lib/opencode/session-runtime.test.js +43 -0
  222. package/server/lib/opencode/settings-helpers.js +8 -0
  223. package/server/lib/opencode/settings-helpers.test.js +13 -1
  224. package/server/lib/opencode/settings-normalization-runtime.js +2 -0
  225. package/server/lib/opencode/settings-normalization-runtime.test.js +13 -0
  226. package/server/lib/opencode/settings-registry.json +15 -0
  227. package/server/lib/opencode/shutdown-runtime.js +3 -0
  228. package/server/lib/opencode/shutdown-runtime.test.js +24 -0
  229. package/server/lib/opencode/theme-archive.js +53 -0
  230. package/server/lib/opencode/theme-catalog.js +171 -0
  231. package/server/lib/opencode/theme-catalog.test.js +125 -0
  232. package/server/lib/opencode/theme-import.test.js +144 -0
  233. package/server/lib/opencode/theme-runtime.js +100 -28
  234. package/server/lib/opencode/theme-runtime.test.js +15 -0
  235. package/server/lib/permission-auto-accept/DOCUMENTATION.md +8 -0
  236. package/server/lib/permission-auto-accept/runtime.js +13 -0
  237. package/server/lib/permission-auto-accept/runtime.test.js +37 -1
  238. package/server/lib/projects/project-config.js +2 -2
  239. package/server/lib/quota/DOCUMENTATION.md +0 -1
  240. package/server/lib/quota/providers/index.js +0 -7
  241. package/server/lib/realtime-proxy-terminal.test.js +150 -0
  242. package/server/lib/realtime-proxy.js +2 -0
  243. package/server/lib/routing/DOCUMENTATION.md +83 -0
  244. package/server/lib/routing/defaults.js +98 -0
  245. package/server/lib/routing/feature-flag.js +11 -0
  246. package/server/lib/routing/history.js +34 -0
  247. package/server/lib/routing/jev.js +98 -0
  248. package/server/lib/routing/routes.http.test.js +100 -0
  249. package/server/lib/routing/routes.js +81 -0
  250. package/server/lib/routing/runtime.js +217 -0
  251. package/server/lib/routing/runtime.test.js +188 -0
  252. package/server/lib/routing/store.js +249 -0
  253. package/server/lib/routing/store.test.js +96 -0
  254. package/server/lib/scheduled-tasks/runtime.js +2 -2
  255. package/server/lib/scheduled-tasks/runtime.test.js +14 -0
  256. package/server/lib/security/request-security.js +9 -5
  257. package/server/lib/security/request-security.test.js +37 -0
  258. package/server/lib/small-model/DOCUMENTATION.md +14 -2
  259. package/server/lib/small-model/call.js +37 -6
  260. package/server/lib/small-model/call.test.js +182 -0
  261. package/server/lib/terminal/DOCUMENTATION.md +23 -2
  262. package/server/lib/terminal/runtime.js +27 -5
  263. package/server/lib/terminal/runtime.test.js +67 -0
  264. package/server/lib/terminal/shutdown.js +106 -0
  265. package/server/lib/terminal/shutdown.test.js +84 -0
  266. package/server/lib/tts/service.test.js +78 -0
  267. package/server/lib/ui-auth/DOCUMENTATION.md +8 -0
  268. package/server/lib/ui-auth/session-cookie.js +51 -0
  269. package/server/lib/ui-auth/session-cookie.test.js +46 -0
  270. package/server/lib/ui-auth/ui-auth.js +56 -17
  271. package/server/lib/ui-auth/ui-auth.test.js +96 -0
  272. package/dist/assets/DiffView-CyLmb-wF.js +0 -4
  273. package/dist/assets/DirtyBranchSwitchDialog-pu5kcoir.js +0 -1
  274. package/dist/assets/FilesView-WtJB0y_l.js +0 -13
  275. package/dist/assets/GitView-DkNrV0BK.js +0 -6
  276. package/dist/assets/LinearIssuesView-B0H0Otii.js +0 -1
  277. package/dist/assets/MarkdownRendererImpl-DSqVN2d8.js +0 -12
  278. package/dist/assets/PierreDiffViewer-Bsq9z-sw.js +0 -161
  279. package/dist/assets/PlanView-CAFziKH5.js +0 -5
  280. package/dist/assets/SettingsView-BRittavZ.js +0 -28
  281. package/dist/assets/ToolOutputDialog-B0uYaJio.js +0 -15
  282. package/dist/assets/appThemeRegistry-BK0dHKa6.js +0 -1
  283. package/dist/assets/de-c7CYLCAW.js +0 -10
  284. package/dist/assets/es-BKAVPQmQ.js +0 -16
  285. package/dist/assets/fr-Bj1glqfV.js +0 -14
  286. package/dist/assets/index-BYFyOu_D.css +0 -1
  287. package/dist/assets/index-BfwRClDe.js +0 -40
  288. package/dist/assets/ja-5jwSIbK0.js +0 -16
  289. package/dist/assets/ko-BaDbg-Eb.js +0 -16
  290. package/dist/assets/main-CGG2_uHq.js +0 -2
  291. package/dist/assets/main-CcrSaL4J.js +0 -930
  292. package/dist/assets/markdownCore-DsmQr3bt.js +0 -5
  293. package/dist/assets/miniChat-DEaAhP4b.js +0 -2
  294. package/dist/assets/mobile-BC3rsvv0.js +0 -2
  295. package/dist/assets/pl-BFKVBDFu.js +0 -16
  296. package/dist/assets/pt-BR-qKfHvkDL.js +0 -16
  297. package/dist/assets/registerCustomTheme-BBXUCRnG.js +0 -1
  298. package/dist/assets/renderElectronMiniChatApp-CR9d1Mr0.js +0 -2
  299. package/dist/assets/renderMobileApp-Da5dwobZ.js +0 -25
  300. package/dist/assets/runtimeEndpointReset-CLYVRw2H.js +0 -41
  301. package/dist/assets/shikiHighlight-D1Z9G58W.js +0 -1
  302. package/dist/assets/tr-DYXPoEDG.js +0 -7
  303. package/dist/assets/uk-CwAoloR8.js +0 -16
  304. package/dist/assets/useAppFontEffects-DeStGcUT.js +0 -7282
  305. package/dist/assets/useGitComparison-CpxioduU.js +0 -1
  306. package/dist/assets/useInlineCommentController-gmUnJtrb.js +0 -2
  307. package/dist/assets/useRootScrollLock--a3cPz8s.js +0 -1
  308. package/dist/assets/vendor-framer-motion-livSKyyV.js +0 -1
  309. package/dist/assets/zh-CN-D9MG0lqF.js +0 -16
  310. package/dist/assets/zh-TW-1HNK7shh.js +0 -16
  311. package/server/lib/quota/providers/crof.js +0 -96
  312. package/server/lib/quota/providers/crof.test.js +0 -98
  313. /package/dist/assets/{vendor-katex-k3Ppq1Ha.js → vendor-katex-CHD9BdDO.js} +0 -0
@@ -0,0 +1,501 @@
1
+ import crypto from 'node:crypto';
2
+
3
+ import {
4
+ GUEST_ACCOUNT_MAX,
5
+ GUEST_REQUEST_TIMEOUT_MS,
6
+ isGuestRequestPath,
7
+ resolveIntegrationApi,
8
+ resolveIntegrationAuth,
9
+ } from '@openchamber/sdk';
10
+
11
+ import { dropGuestTokens, getGuestAuth, patchGuestAuth } from './auth-store.js';
12
+
13
+ export const PENDING_AUTHORIZATION_TTL_MS = 10 * 60_000;
14
+
15
+ const pendingByState = new Map();
16
+ const pendingByGuestId = new Map();
17
+
18
+ export class GuestOAuthError extends Error {
19
+ constructor(message, code = 'GUEST_OAUTH_FAILED') {
20
+ super(message);
21
+ this.name = 'GuestOAuthError';
22
+ this.code = code;
23
+ }
24
+ }
25
+
26
+ export const createPkcePair = () => {
27
+ const verifier = crypto.randomBytes(32).toString('base64url');
28
+ const challenge = crypto.createHash('sha256').update(verifier).digest('base64url');
29
+ return { verifier, challenge };
30
+ };
31
+
32
+ const pruneExpiredPending = (now = Date.now()) => {
33
+ for (const [state, entry] of pendingByState.entries()) {
34
+ if (!entry || entry.expiresAt <= now) {
35
+ pendingByState.delete(state);
36
+ if (entry?.guestId) {
37
+ const current = pendingByGuestId.get(entry.guestId);
38
+ if (current?.state === state) {
39
+ pendingByGuestId.delete(entry.guestId);
40
+ }
41
+ }
42
+ }
43
+ }
44
+ };
45
+
46
+ const dropPendingForGuest = (guestId) => {
47
+ const current = pendingByGuestId.get(guestId);
48
+ if (current?.state) {
49
+ pendingByState.delete(current.state);
50
+ }
51
+ pendingByGuestId.delete(guestId);
52
+ };
53
+
54
+ const rememberPending = (state, entry) => {
55
+ dropPendingForGuest(entry.guestId);
56
+ pendingByState.set(state, entry);
57
+ pendingByGuestId.set(entry.guestId, { ...entry, state });
58
+ };
59
+
60
+ // `state` is the only thing that ties a callback to the click that started
61
+ // it. Accepting a callback without it would let any link visited during the
62
+ // pending window attach a stranger's account, so a missing state is a refusal.
63
+ const takePending = (guestId, state) => {
64
+ const trimmed = readTrimmedString(state);
65
+ if (!trimmed) {
66
+ return null;
67
+ }
68
+ const pending = pendingByState.get(trimmed);
69
+ if (!pending || pending.guestId !== guestId) {
70
+ return null;
71
+ }
72
+ pendingByState.delete(trimmed);
73
+ if (pendingByGuestId.get(guestId)?.state === trimmed) {
74
+ pendingByGuestId.delete(guestId);
75
+ }
76
+ return pending;
77
+ };
78
+
79
+ const isPlainObject = (value) => Boolean(value) && typeof value === 'object' && !Array.isArray(value);
80
+
81
+ const readTrimmedString = (value) => (typeof value === 'string' ? value.trim() : '');
82
+
83
+ const readExpiresAt = (expiresIn, now = Date.now()) => {
84
+ const seconds = typeof expiresIn === 'number' && Number.isFinite(expiresIn) ? expiresIn : Number(expiresIn);
85
+ if (!Number.isFinite(seconds) || seconds <= 0) {
86
+ return now + 24 * 60 * 60 * 1000;
87
+ }
88
+ return now + Math.floor(seconds) * 1000;
89
+ };
90
+
91
+ const parseTokenPayload = (payload) => {
92
+ if (!isPlainObject(payload)) {
93
+ throw new GuestOAuthError('Token response was empty');
94
+ }
95
+ if (readTrimmedString(payload.error)) {
96
+ throw new GuestOAuthError(
97
+ readTrimmedString(payload.error_description) || readTrimmedString(payload.error),
98
+ readTrimmedString(payload.error).toUpperCase() || 'GUEST_OAUTH_FAILED',
99
+ );
100
+ }
101
+ const accessToken = readTrimmedString(payload.access_token);
102
+ if (!accessToken) {
103
+ throw new GuestOAuthError('Token response was missing access_token');
104
+ }
105
+ return {
106
+ accessToken,
107
+ refreshToken: readTrimmedString(payload.refresh_token) || null,
108
+ tokenType: readTrimmedString(payload.token_type) || 'bearer',
109
+ expiresAt: readExpiresAt(payload.expires_in),
110
+ };
111
+ };
112
+
113
+ const readTokenError = (payload, status) => {
114
+ const description = isPlainObject(payload)
115
+ ? (readTrimmedString(payload.error_description) || readTrimmedString(payload.error))
116
+ : '';
117
+ return description || `Token request failed (${status})`;
118
+ };
119
+
120
+ const postForm = async (url, body) => {
121
+ const response = await fetch(url, {
122
+ method: 'POST',
123
+ headers: {
124
+ Accept: 'application/json',
125
+ 'Content-Type': 'application/x-www-form-urlencoded',
126
+ },
127
+ body: new URLSearchParams(body).toString(),
128
+ signal: AbortSignal.timeout(GUEST_REQUEST_TIMEOUT_MS),
129
+ });
130
+ const payload = await response.json().catch(() => null);
131
+ if (!response.ok) {
132
+ throw new GuestOAuthError(readTokenError(payload, response.status));
133
+ }
134
+ return parseTokenPayload(payload);
135
+ };
136
+
137
+ const postJson = async (url, body) => {
138
+ const response = await fetch(url, {
139
+ method: 'POST',
140
+ headers: {
141
+ Accept: 'application/json',
142
+ 'Content-Type': 'application/json',
143
+ },
144
+ body: JSON.stringify(body),
145
+ signal: AbortSignal.timeout(GUEST_REQUEST_TIMEOUT_MS),
146
+ });
147
+ const payload = await response.json().catch(() => null);
148
+ if (!response.ok) {
149
+ throw new GuestOAuthError(readTokenError(payload, response.status));
150
+ }
151
+ return parseTokenPayload(payload);
152
+ };
153
+
154
+ const exchangeAuthorizationCode = async (tokenUrl, formBody, jsonBody) => {
155
+ try {
156
+ return await postForm(tokenUrl, formBody);
157
+ } catch (first) {
158
+ try {
159
+ return await postJson(tokenUrl, jsonBody);
160
+ } catch {
161
+ throw first;
162
+ }
163
+ }
164
+ };
165
+
166
+ export const guestAuthorizationHeader = (token, authorization) => {
167
+ if (authorization === 'bearer') {
168
+ return `Bearer ${token}`;
169
+ }
170
+ if (authorization === 'basic') {
171
+ // `basic` stores the already-encoded `username:token` pair; see saveGuestAccessToken.
172
+ return `Basic ${token}`;
173
+ }
174
+ return token;
175
+ };
176
+
177
+ /** Encodes `username:token` for a `basic` integration. Stored as the access token so requests need no username. */
178
+ export const encodeBasicCredential = (username, token) => Buffer.from(`${username}:${token}`, 'utf8').toString('base64');
179
+
180
+ export const guestRedirectUri = (origin, guestId) => `${origin.replace(/\/+$/, '')}/api/guests/${guestId}/oauth/callback`;
181
+
182
+ /** With `integration`, `hasClient` is false for a client entered for endpoints the package no longer names. */
183
+ export const toPublicGuestAuth = (entry, integration) => ({
184
+ connected: Boolean(entry?.accessToken),
185
+ account: typeof entry?.account === 'string' ? entry.account : '',
186
+ hasClient: integration ? Boolean(usableClientCredentials(entry, integration).clientId) : Boolean(entry?.clientId),
187
+ settings: entry?.settings && typeof entry.settings === 'object' ? { ...entry.settings } : {},
188
+ });
189
+
190
+ const readAccountLabel = (payload, name) => {
191
+ if (!isPlainObject(payload) || typeof name !== 'string' || name === '') {
192
+ return '';
193
+ }
194
+ let current = payload;
195
+ for (const part of name.split('.')) {
196
+ if (!isPlainObject(current) || !(part in current)) {
197
+ return '';
198
+ }
199
+ current = current[part];
200
+ }
201
+ return typeof current === 'string' ? current.trim().slice(0, GUEST_ACCOUNT_MAX) : '';
202
+ };
203
+
204
+ const fetchAccountLabel = async (api, accessToken) => {
205
+ if (!api.account) {
206
+ return { ok: true, account: '' };
207
+ }
208
+ if (!isGuestRequestPath(api.account.path)) {
209
+ return { ok: false, account: '' };
210
+ }
211
+ const url = new URL(api.account.path, `${api.apiOrigin}/`);
212
+ if (url.origin !== api.apiOrigin) {
213
+ return { ok: false, account: '' };
214
+ }
215
+ const response = await fetch(url, {
216
+ headers: {
217
+ Accept: 'application/json',
218
+ Authorization: guestAuthorizationHeader(accessToken, api.authorization),
219
+ },
220
+ signal: AbortSignal.timeout(GUEST_REQUEST_TIMEOUT_MS),
221
+ });
222
+ if (!response.ok) {
223
+ return { ok: false, account: '' };
224
+ }
225
+ const payload = await response.json().catch(() => null);
226
+ return { ok: true, account: readAccountLabel(payload, api.account.name) };
227
+ };
228
+
229
+ /**
230
+ * The addresses credentials for this integration go to: the API origin and,
231
+ * for OAuth, the authorize and token endpoints.
232
+ * @returns {{ apiOrigin: string, authorizeUrl?: string, tokenUrl?: string } | null}
233
+ */
234
+ export const credentialTarget = (integration) => {
235
+ const api = resolveIntegrationApi(integration ?? {});
236
+ if (!api) {
237
+ return null;
238
+ }
239
+ const target = { apiOrigin: api.apiOrigin };
240
+ if (integration?.oauth) {
241
+ target.authorizeUrl = integration.oauth.authorizeUrl;
242
+ target.tokenUrl = integration.oauth.tokenUrl;
243
+ }
244
+ return target;
245
+ };
246
+
247
+ const sameTarget = (a, b) => Boolean(a && b)
248
+ && a.apiOrigin === b.apiOrigin
249
+ && (a.authorizeUrl ?? null) === (b.authorizeUrl ?? null)
250
+ && (a.tokenUrl ?? null) === (b.tokenUrl ?? null);
251
+
252
+ /**
253
+ * Whether the stored tokens were minted for the integration as it is now.
254
+ * Tokens without a recorded target never count.
255
+ */
256
+ export const storedTokensUsable = (stored, integration) => (
257
+ Boolean(stored?.accessToken) && sameTarget(stored.target, credentialTarget(integration))
258
+ );
259
+
260
+ /**
261
+ * The client id and secret, only when they were entered for the endpoints
262
+ * the package names now. Anything else is treated as missing.
263
+ * @returns {{ clientId: string, clientSecret: string }}
264
+ */
265
+ export const usableClientCredentials = (stored, integration) => {
266
+ if (!sameTarget(stored?.clientTarget, credentialTarget(integration))) {
267
+ return { clientId: '', clientSecret: '' };
268
+ }
269
+ return {
270
+ clientId: readTrimmedString(stored?.clientId),
271
+ clientSecret: readTrimmedString(stored?.clientSecret),
272
+ };
273
+ };
274
+
275
+ /**
276
+ * Tokens that no longer match the package's addresses are dropped, so the
277
+ * card shows disconnected and nothing is sent to the new addresses.
278
+ * @returns {Promise<object | null>} the stored entry when its tokens are usable
279
+ */
280
+ export const takeUsableGuestAuth = async (guest, persistPath) => {
281
+ const stored = await getGuestAuth(guest.id, persistPath);
282
+ if (!stored?.accessToken) {
283
+ return stored;
284
+ }
285
+ if (storedTokensUsable(stored, guest.integration)) {
286
+ return stored;
287
+ }
288
+ await dropGuestTokens(guest.id, persistPath);
289
+ return getGuestAuth(guest.id, persistPath);
290
+ };
291
+
292
+ /**
293
+ * Save the OAuth client the user entered on the Integrations card. The
294
+ * client is bound to the endpoints the package names now. An empty secret
295
+ * keeps the stored one only for the same client id and the same endpoints;
296
+ * a new id or moved endpoints drop the old secret instead of carrying it
297
+ * over. Decided under the store lock against the entry as it is then.
298
+ */
299
+ export const saveGuestOAuthClient = async ({ guest, persistPath, clientId, clientSecret }) => {
300
+ if (resolveIntegrationAuth(guest.integration ?? {}) !== 'oauth') {
301
+ throw new GuestOAuthError('This guest does not declare OAuth.', 'NO_INTEGRATION');
302
+ }
303
+ const id = readTrimmedString(clientId);
304
+ const secret = readTrimmedString(clientSecret);
305
+ if (!id) {
306
+ throw new GuestOAuthError('Client id is missing.', 'CLIENT_MISSING');
307
+ }
308
+ const clientTarget = credentialTarget(guest.integration);
309
+ return patchGuestAuth(guest.id, (current) => {
310
+ const next = { clientId: id, clientTarget };
311
+ if (secret) {
312
+ next.clientSecret = secret;
313
+ } else if (readTrimmedString(current?.clientId) !== id || !sameTarget(current?.clientTarget, clientTarget)) {
314
+ next.clientSecret = undefined;
315
+ }
316
+ return next;
317
+ }, persistPath);
318
+ };
319
+
320
+ export const saveGuestAccessToken = async ({ guest, persistPath, token, username }) => {
321
+ if (resolveIntegrationAuth(guest.integration ?? {}) !== 'token') {
322
+ throw new GuestOAuthError('This guest does not accept a pasted token.', 'NO_TOKEN_AUTH');
323
+ }
324
+ const api = resolveIntegrationApi(guest.integration);
325
+ const pastedToken = readTrimmedString(token);
326
+ if (!api || !pastedToken) {
327
+ throw new GuestOAuthError('API token is missing.', 'TOKEN_MISSING');
328
+ }
329
+ const pastedUsername = readTrimmedString(username);
330
+ if (api.authorization === 'basic' && !pastedUsername) {
331
+ throw new GuestOAuthError('Username is missing.', 'USERNAME_MISSING');
332
+ }
333
+ const accessToken = api.authorization === 'basic'
334
+ ? encodeBasicCredential(pastedUsername, pastedToken)
335
+ : pastedToken;
336
+ const probed = await fetchAccountLabel(api, accessToken);
337
+ if (api.account && !probed.ok) {
338
+ throw new GuestOAuthError('That API token was refused.', 'TOKEN_INVALID');
339
+ }
340
+ const account = probed.account || (api.authorization === 'basic' ? pastedUsername.slice(0, GUEST_ACCOUNT_MAX) : '');
341
+ await patchGuestAuth(guest.id, {
342
+ accessToken,
343
+ refreshToken: null,
344
+ tokenType: api.authorization,
345
+ expiresAt: null,
346
+ account,
347
+ authorizedAt: Date.now(),
348
+ target: credentialTarget(guest.integration),
349
+ }, persistPath);
350
+ return { connected: true, account };
351
+ };
352
+
353
+ export const startGuestAuthorization = async ({ guest, persistPath, origin }) => {
354
+ const oauth = guest.integration?.oauth;
355
+ if (resolveIntegrationAuth(guest.integration ?? {}) !== 'oauth' || !oauth) {
356
+ throw new GuestOAuthError('This guest does not declare OAuth.', 'NO_INTEGRATION');
357
+ }
358
+ const stored = await getGuestAuth(guest.id, persistPath);
359
+ const { clientId } = usableClientCredentials(stored, guest.integration);
360
+ if (!clientId) {
361
+ throw new GuestOAuthError('Client id is missing. Save it in Integrations first.', 'CLIENT_MISSING');
362
+ }
363
+ pruneExpiredPending();
364
+ const { verifier, challenge } = createPkcePair();
365
+ const state = crypto.randomBytes(32).toString('base64url');
366
+ const redirectUri = guestRedirectUri(origin, guest.id);
367
+ rememberPending(state, {
368
+ guestId: guest.id,
369
+ codeVerifier: verifier,
370
+ redirectUri,
371
+ // The exchange goes to the endpoints the user saw when they clicked
372
+ // Connect, and only if the package still names the same ones.
373
+ target: credentialTarget(guest.integration),
374
+ expiresAt: Date.now() + PENDING_AUTHORIZATION_TTL_MS,
375
+ });
376
+
377
+ const url = new URL(oauth.authorizeUrl);
378
+ url.searchParams.set('response_type', 'code');
379
+ url.searchParams.set('client_id', clientId);
380
+ url.searchParams.set('redirect_uri', redirectUri);
381
+ url.searchParams.set('state', state);
382
+ url.searchParams.set('code_challenge', challenge);
383
+ url.searchParams.set('code_challenge_method', 'S256');
384
+ if (oauth.scopes && oauth.scopes.length > 0) {
385
+ url.searchParams.set('scope', oauth.scopes.join(' '));
386
+ }
387
+
388
+ return {
389
+ authorizationUrl: url.toString(),
390
+ expiresIn: Math.floor(PENDING_AUTHORIZATION_TTL_MS / 1000),
391
+ };
392
+ };
393
+
394
+ export const consumeGuestAuthorization = async ({ guest, persistPath, code, state, error, errorDescription }) => {
395
+ pruneExpiredPending();
396
+ if (readTrimmedString(error)) {
397
+ dropPendingForGuest(guest.id);
398
+ throw new GuestOAuthError(readTrimmedString(errorDescription) || readTrimmedString(error));
399
+ }
400
+ const pending = takePending(guest.id, state);
401
+ if (!pending) {
402
+ throw new GuestOAuthError('Authorization state was missing or expired.', 'STATE_MISMATCH');
403
+ }
404
+ if (!sameTarget(pending.target, credentialTarget(guest.integration))) {
405
+ throw new GuestOAuthError('The extension changed its endpoints while you were signing in. Review it in Settings → Extensions and connect again.', 'TARGET_CHANGED');
406
+ }
407
+ const stored = await getGuestAuth(guest.id, persistPath);
408
+ const { clientId, clientSecret } = usableClientCredentials(stored, guest.integration);
409
+ if (!clientId || !code) {
410
+ throw new GuestOAuthError('Authorization code or client credentials were missing.');
411
+ }
412
+ const tokens = await exchangeAuthorizationCode(
413
+ pending.target.tokenUrl,
414
+ {
415
+ grant_type: 'authorization_code',
416
+ code,
417
+ redirect_uri: pending.redirectUri,
418
+ client_id: clientId,
419
+ client_secret: clientSecret,
420
+ code_verifier: pending.codeVerifier,
421
+ },
422
+ {
423
+ client_id: clientId,
424
+ client_secret: clientSecret,
425
+ code,
426
+ },
427
+ );
428
+ let account = '';
429
+ try {
430
+ const api = resolveIntegrationApi(guest.integration);
431
+ if (api) {
432
+ const probed = await fetchAccountLabel(api, tokens.accessToken);
433
+ account = probed.account;
434
+ }
435
+ } catch {
436
+ account = '';
437
+ }
438
+ // The client that made this exchange must still be the one on file, for
439
+ // the same endpoints, when the tokens land.
440
+ const saved = await patchGuestAuth(guest.id, {
441
+ accessToken: tokens.accessToken,
442
+ refreshToken: tokens.refreshToken,
443
+ tokenType: tokens.tokenType,
444
+ expiresAt: tokens.expiresAt,
445
+ account,
446
+ authorizedAt: Date.now(),
447
+ target: pending.target,
448
+ }, persistPath, (current) => (
449
+ readTrimmedString(current?.clientId) === clientId && sameTarget(current?.clientTarget, pending.target)
450
+ ));
451
+ if (!saved || saved.accessToken !== tokens.accessToken) {
452
+ throw new GuestOAuthError('The client credentials changed while you were signing in. Connect again.', 'TARGET_CHANGED');
453
+ }
454
+ return { connected: true, account };
455
+ };
456
+
457
+ export const refreshGuestAccessToken = async ({ guest, persistPath }) => {
458
+ if (resolveIntegrationAuth(guest.integration ?? {}) !== 'oauth' || !guest.integration?.oauth) {
459
+ return null;
460
+ }
461
+ const stored = await takeUsableGuestAuth(guest, persistPath);
462
+ const refreshToken = readTrimmedString(stored?.refreshToken);
463
+ const { clientId, clientSecret } = usableClientCredentials(stored, guest.integration);
464
+ if (!refreshToken || !clientId) {
465
+ return null;
466
+ }
467
+ const target = stored.target;
468
+ const previousAccessToken = stored.accessToken;
469
+ const tokens = await postForm(target.tokenUrl, {
470
+ grant_type: 'refresh_token',
471
+ refresh_token: refreshToken,
472
+ client_id: clientId,
473
+ client_secret: clientSecret,
474
+ });
475
+ // The round trip took time. If the entry moved on meanwhile (a new
476
+ // Connect for other endpoints, a disconnect), this answer belongs to the
477
+ // old entry and is dropped rather than written under the new target.
478
+ const saved = await patchGuestAuth(guest.id, {
479
+ accessToken: tokens.accessToken,
480
+ refreshToken: tokens.refreshToken ?? refreshToken,
481
+ tokenType: tokens.tokenType,
482
+ expiresAt: tokens.expiresAt,
483
+ }, persistPath, (current) => (
484
+ current?.accessToken === previousAccessToken
485
+ && readTrimmedString(current?.refreshToken) === refreshToken
486
+ && sameTarget(current?.target, target)
487
+ ));
488
+ if (!saved || saved.accessToken !== tokens.accessToken) {
489
+ return null;
490
+ }
491
+ return tokens.accessToken;
492
+ };
493
+
494
+ export const disconnectGuestAuth = async (guestId, persistPath) => {
495
+ await dropGuestTokens(guestId, persistPath);
496
+ };
497
+
498
+ export const clearGuestPendingForTests = () => {
499
+ pendingByState.clear();
500
+ pendingByGuestId.clear();
501
+ };