@xopcai/xopc 0.0.270 → 0.0.273

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 (255) hide show
  1. package/README.md +1 -5
  2. package/README.zh-CN.md +1 -5
  3. package/dist/browser-ext/dist/assets/{auth-cwEj8rFb.js → auth-DkwOUI6_.js} +132 -33
  4. package/dist/browser-ext/dist/background.js +2 -2
  5. package/dist/browser-ext/dist/sidepanel.html +1 -1
  6. package/dist/browser-ext/dist/sidepanel.js +46 -32
  7. package/dist/browser-ext/manifest.json +1 -1
  8. package/dist/extensions/telegram/xopc.extension.json +1 -1
  9. package/dist/gateway/static/root/assets/{activity-store-D_0FmdRj.js → activity-store-cF7IX2RP.js} +1 -1
  10. package/dist/gateway/static/root/assets/{agent-avatar-dicebear-IZvEXak_.js → agent-avatar-dicebear-BrgxX8nG.js} +1 -1
  11. package/dist/gateway/static/root/assets/agent-defaults-settings-panel-DvhuRCLA.js +1 -0
  12. package/dist/gateway/static/root/assets/agents-C0By2FIo.js +1 -0
  13. package/dist/gateway/static/root/assets/{api-O3TTQ4qN.js → api-CYkdUpkx.js} +1 -1
  14. package/dist/gateway/static/root/assets/app-link-BiBXVEvp.js +1 -0
  15. package/dist/gateway/static/root/assets/{app-management-settings-panel-Cqqsbzri.js → app-management-settings-panel-DfoNzWIa.js} +1 -1
  16. package/dist/gateway/static/root/assets/{appearance-settings-DaJyf32s.js → appearance-settings-czbLdCqj.js} +1 -1
  17. package/dist/gateway/static/root/assets/apps-page-BSJXKWcE.js +1 -0
  18. package/dist/gateway/static/root/assets/{archive-plugin-kDPnDTJI.js → archive-plugin-D14P13mX.js} +1 -1
  19. package/dist/gateway/static/root/assets/{attachment-load-CJ3VceKS.js → attachment-load-Dok_B1Gv.js} +1 -1
  20. package/dist/gateway/static/root/assets/{automations-page-JwMtU8XB.js → automations-page-DM7ZEewI.js} +1 -1
  21. package/dist/gateway/static/root/assets/automations-workspace--1TsZf3O.js +6 -0
  22. package/dist/gateway/static/root/assets/{binary-plugins-DzyZXLBX.js → binary-plugins-CxNg6InF.js} +1 -1
  23. package/dist/gateway/static/root/assets/{block-editor-kTt3gYIJ.js → block-editor-D22VcYnC.js} +3 -3
  24. package/dist/gateway/static/root/assets/{browser-automation-inputs-BKohPYR4.js → browser-automation-inputs-6NWTLEpd.js} +1 -1
  25. package/dist/gateway/static/root/assets/{browser-automations-page-ktQfFPk-.js → browser-automations-page-BrqySdbW.js} +2 -2
  26. package/dist/gateway/static/root/assets/browser-settings-page-DOHgQer_.js +8 -0
  27. package/dist/gateway/static/root/assets/capabilities-settings-panel-Bpse_5K-.js +8 -0
  28. package/dist/gateway/static/root/assets/channels-settings-yHsY174W.js +1 -0
  29. package/dist/gateway/static/root/assets/{channels-status-swr-DrqzYmDr.js → channels-status-swr-BUZimNmp.js} +1 -1
  30. package/dist/gateway/static/root/assets/{chat-terminal-dock-CIFGGLGa.js → chat-terminal-dock-CZPBNpMI.js} +2 -2
  31. package/dist/gateway/static/root/assets/clock-3-DnrAnuyZ.js +1 -0
  32. package/dist/gateway/static/root/assets/connectors-page-B_wLKGnH.js +2 -0
  33. package/dist/gateway/static/root/assets/cron-expression-C26e13YU.js +2 -0
  34. package/dist/gateway/static/root/assets/date-picker-Da_0QyLe.js +1 -0
  35. package/dist/gateway/static/root/assets/{dependency-picker-D3vNIjRI.js → dependency-picker-D_djqzy7.js} +1 -1
  36. package/dist/gateway/static/root/assets/{desktop-pet-fQwRb_3p.js → desktop-pet-Celmbw-T.js} +1 -1
  37. package/dist/gateway/static/root/assets/{desktop-pet-settings-DfOJ-GvT.js → desktop-pet-settings-CqNNgF45.js} +1 -1
  38. package/dist/gateway/static/root/assets/device-pairing-wizard-B5_w9qlm.js +1 -0
  39. package/dist/gateway/static/root/assets/{extension-debug-page-Cn53jB5-.js → extension-debug-page-ku3kCjvH.js} +1 -1
  40. package/dist/gateway/static/root/assets/{extension-page-IDpLCxpC.js → extension-page-C7FpHwL4.js} +1 -1
  41. package/dist/gateway/static/root/assets/extension-settings-page-OMj2tU2_.js +1 -0
  42. package/dist/gateway/static/root/assets/{gateway-config-swr-B7dcmP7Q.js → gateway-config-swr-6eb1vKE1.js} +1 -1
  43. package/dist/gateway/static/root/assets/gateway-settings-CH-6vkgN.js +1 -0
  44. package/dist/gateway/static/root/assets/{gateway-startup-retry-JGhGMhVZ.js → gateway-startup-retry-DUFFCU8H.js} +1 -1
  45. package/dist/gateway/static/root/assets/git-branch-Dh9uxTot.js +1 -0
  46. package/dist/gateway/static/root/assets/heartbeat-settings-CSFzOACM.js +1 -0
  47. package/dist/gateway/static/root/assets/home-page-BJebAKB-.js +1 -0
  48. package/dist/gateway/static/root/assets/{image-generation-api-BJLX7Qrh.js → image-generation-api-C1cHRBRp.js} +1 -1
  49. package/dist/gateway/static/root/assets/index-C6OWYFtQ.js +74 -0
  50. package/dist/gateway/static/root/assets/index-DKy1Qn1_.css +2 -0
  51. package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings-CBvMTFFx.js → keyboard-shortcuts-settings-BuvD3iv8.js} +1 -1
  52. package/dist/gateway/static/root/assets/local-app-workbench-page-CaC4-THD.js +2 -0
  53. package/dist/gateway/static/root/assets/{local-apps-page-APCMNDvU.js → local-apps-page-DdJ8zwBp.js} +1 -1
  54. package/dist/gateway/static/root/assets/locale-store-BBSCIl4I.js +1 -0
  55. package/dist/gateway/static/root/assets/logs-page-BaR2he0K.js +2 -0
  56. package/dist/gateway/static/root/assets/management-settings-r-iYWZFY.js +1 -0
  57. package/dist/gateway/static/root/assets/markdown-view-c5vtnYe8.js +201 -0
  58. package/dist/gateway/static/root/assets/{media-plugins-C10byeaa.js → media-plugins-D_a6GDY6.js} +1 -1
  59. package/dist/gateway/static/root/assets/message-circle-Badhj-4D.js +1 -0
  60. package/dist/gateway/static/root/assets/message-square-fVE7Ghj1.js +1 -0
  61. package/dist/gateway/static/root/assets/{messages-D0V_bgRP.js → messages-DjuBdDCn.js} +3 -3
  62. package/dist/gateway/static/root/assets/note-detail-panel-BV6nbgac.js +5 -0
  63. package/dist/gateway/static/root/assets/notes-page-BmLKoWwi.js +8 -0
  64. package/dist/gateway/static/root/assets/{page-tabs-qQ36zncF.js → page-tabs-C7Le9bSI.js} +1 -1
  65. package/dist/gateway/static/root/assets/popover-select-Dz_Qis2R.js +1 -0
  66. package/dist/gateway/static/root/assets/{preview-open-alternatives-BiAJvvCo.js → preview-open-alternatives-B2pOxJBK.js} +1 -1
  67. package/dist/gateway/static/root/assets/{proactive-card-CcNBqHoH.js → proactive-card-BlQ1vCtV.js} +1 -1
  68. package/dist/gateway/static/root/assets/{proactive-page-C3K61jve.js → proactive-page-CghKTfYa.js} +1 -1
  69. package/dist/gateway/static/root/assets/{product-open-page-CunnDP4w.js → product-open-page-DpjiHgwu.js} +1 -1
  70. package/dist/gateway/static/root/assets/project-detail-page-CV8Lh296.js +1 -0
  71. package/dist/gateway/static/root/assets/projects-page-COweOaJP.js +1 -0
  72. package/dist/gateway/static/root/assets/{registry-api-0JSegbNl.js → registry-api-CyQ4k1Ux.js} +1 -1
  73. package/dist/gateway/static/root/assets/remote-access-hub-ChPPGVU5.js +1 -0
  74. package/dist/gateway/static/root/assets/{runtime-tools-settings-panel-bu_mwBTr.js → runtime-tools-settings-panel-Bl4ArLHf.js} +2 -2
  75. package/dist/gateway/static/root/assets/{schema-form-BE0sgZyz.js → schema-form-KQFmfWd4.js} +1 -1
  76. package/dist/gateway/static/root/assets/sessions-page-DgmHibOK.js +1 -0
  77. package/dist/gateway/static/root/assets/settings-advanced-gate-DV7kMco2.js +1 -0
  78. package/dist/gateway/static/root/assets/{settings-form-section-CBo517lV.js → settings-form-section-Dbnls9ty.js} +1 -1
  79. package/dist/gateway/static/root/assets/{settings-page-DBPimx93.js → settings-page-CDKirYRG.js} +1 -1
  80. package/dist/gateway/static/root/assets/setup-status-panel-SQmtWoOs.js +1 -0
  81. package/dist/gateway/static/root/assets/{share-preview-page-DdV75VTe.js → share-preview-page-DwgLjS1m.js} +1 -1
  82. package/dist/gateway/static/root/assets/shares-settings-Cs5bUrYw.js +1 -0
  83. package/dist/gateway/static/root/assets/skill-reload-api-DyKrjq7F.js +1 -0
  84. package/dist/gateway/static/root/assets/{skills-page-Cn_-nvRo.js → skills-page-Bd0_ED_p.js} +1 -1
  85. package/dist/gateway/static/root/assets/skills-page.utils-rA-XT-YG.js +1 -0
  86. package/dist/gateway/static/root/assets/system-settings-panel-CSkMrHLz.js +1 -0
  87. package/dist/gateway/static/root/assets/task-detail-page-CEQU-L_G.js +1 -0
  88. package/dist/gateway/static/root/assets/{theme-store-1wryLgBQ.js → theme-store-DWpIEWen.js} +1 -1
  89. package/dist/gateway/static/root/assets/tunnel-api-COJcGnEi.js +1 -0
  90. package/dist/gateway/static/root/assets/{use-autosave-N_lm4FdD.js → use-autosave-DkQAIAuB.js} +1 -1
  91. package/dist/gateway/static/root/assets/user-model-page-BQAU55lf.js +2 -0
  92. package/dist/gateway/static/root/assets/{voice-api-key-field-DMsyVfri.js → voice-api-key-field-BrqcH0P-.js} +1 -1
  93. package/dist/gateway/static/root/assets/{voice-config-api-QWVmiAp3.js → voice-config-api-BJ95Z3pT.js} +1 -1
  94. package/dist/gateway/static/root/assets/{work-discovery-overlay-BC0vAxp1.js → work-discovery-overlay-vfTWKm13.js} +1 -1
  95. package/dist/gateway/static/root/assets/{workflow-run-setup-panel-Cz9jQIlP.js → workflow-run-setup-panel-CHdr_ng9.js} +2 -2
  96. package/dist/gateway/static/root/assets/workflows-page-hwRJD7vR.js +6 -0
  97. package/dist/gateway/static/root/index.html +16 -11
  98. package/dist/package.js +1 -1
  99. package/dist/packages/gateway-contract/src/device-pairing.js +2 -1
  100. package/dist/packages/gateway-contract/src/session-identity.js +37 -0
  101. package/dist/src/agent/memory/compaction-chunks.d.ts +18 -0
  102. package/dist/src/agent/memory/compaction-chunks.js +53 -0
  103. package/dist/src/agent/memory/compaction-request.d.ts +12 -0
  104. package/dist/src/agent/memory/compaction-request.js +72 -0
  105. package/dist/src/agent/memory/compaction.d.ts +3 -0
  106. package/dist/src/agent/memory/compaction.js +166 -118
  107. package/dist/src/agent/service.js +1 -0
  108. package/dist/src/browser/native-messaging-host.js +3 -1
  109. package/dist/src/browser/providers/browser-ext-install.d.ts +6 -0
  110. package/dist/src/browser/providers/browser-ext-install.js +16 -1
  111. package/dist/src/cli/bin.js +2 -2
  112. package/dist/src/cli/commands/agent.js +2 -2
  113. package/dist/src/cli/commands/auth.js +1 -1
  114. package/dist/src/cli/commands/doctor/checks/database-schema.js +1 -1
  115. package/dist/src/cli/commands/extension-dev.js +1 -1
  116. package/dist/src/cli/commands/extension-marketplace.js +1 -1
  117. package/dist/src/cli/commands/extension.js +1 -1
  118. package/dist/src/cli/commands/gateway/lifecycle.js +1 -1
  119. package/dist/src/cli/commands/gateway/run-foreground.js +8 -5
  120. package/dist/src/cli/commands/gateway/service.js +4 -3
  121. package/dist/src/cli/commands/gateway/token.js +28 -1
  122. package/dist/src/cli/commands/gateway-ssh-tunnel.js +1 -1
  123. package/dist/src/cli/commands/models.js +2 -2
  124. package/dist/src/cli/commands/onboard.js +1 -1
  125. package/dist/src/cli/commands/platform.js +1 -1
  126. package/dist/src/cli/commands/profile.js +1 -1
  127. package/dist/src/cli/commands/tunnel.js +6 -1
  128. package/dist/src/cli/commands/update.js +1 -1
  129. package/dist/src/cli/extension-cli-register.js +1 -1
  130. package/dist/src/config/index.js +1 -1
  131. package/dist/src/gateway/device-routes.js +4 -3
  132. package/dist/src/gateway/heartbeat/service.js +1 -1
  133. package/dist/src/gateway/hono/app.js +1 -0
  134. package/dist/src/gateway/hono/middleware/auth.d.ts +1 -2
  135. package/dist/src/gateway/hono/middleware/auth.js +49 -31
  136. package/dist/src/gateway/hono/middleware/strict-rate-limit.js +11 -15
  137. package/dist/src/gateway/hono/routes/browser-session.d.ts +3 -0
  138. package/dist/src/gateway/hono/routes/browser-session.js +43 -0
  139. package/dist/src/gateway/hono/routes/browser.js +26 -0
  140. package/dist/src/gateway/hono/routes/devices.js +61 -96
  141. package/dist/src/gateway/hono/routes/exposure.js +3 -7
  142. package/dist/src/gateway/hono/routes/lazy-bundles.js +8 -0
  143. package/dist/src/gateway/hono/routes/models.js +60 -1
  144. package/dist/src/gateway/hono/routes/notes.js +3 -7
  145. package/dist/src/gateway/hono/routes/sessions.js +11 -0
  146. package/dist/src/gateway/hono/routes/shares.js +8 -20
  147. package/dist/src/gateway/hono/routes/site-shares.js +4 -8
  148. package/dist/src/gateway/hono/routes/tunnel.js +13 -13
  149. package/dist/src/gateway/image-generation-setup.d.ts +17 -0
  150. package/dist/src/gateway/image-generation-setup.js +30 -21
  151. package/dist/src/gateway/rate-limit/buckets.d.ts +3 -0
  152. package/dist/src/gateway/rate-limit/buckets.js +10 -0
  153. package/dist/src/gateway/run-loop.js +1 -1
  154. package/dist/src/gateway/runtime-config.js +2 -0
  155. package/dist/src/gateway/security/browser-session.d.ts +5 -0
  156. package/dist/src/gateway/security/browser-session.js +45 -0
  157. package/dist/src/gateway/security/gateway-principal.d.ts +1 -0
  158. package/dist/src/gateway/server.js +1 -1
  159. package/dist/src/gateway/service.d.ts +1 -0
  160. package/dist/src/gateway/service.js +11 -1
  161. package/dist/src/heartbeat/index.js +1 -1
  162. package/dist/src/infra/rate-limit/keyed-store.d.ts +3 -0
  163. package/dist/src/infra/rate-limit/keyed-store.js +9 -2
  164. package/dist/src/proactive/policy/service.d.ts +1 -1
  165. package/dist/src/realtime/runtime.d.ts +2 -1
  166. package/dist/src/realtime/runtime.js +9 -3
  167. package/dist/src/realtime/tickets.d.ts +1 -0
  168. package/dist/src/realtime/tickets.js +3 -0
  169. package/dist/src/session/store.d.ts +2 -0
  170. package/dist/src/session/store.js +17 -2
  171. package/dist/src/session/types.d.ts +2 -1
  172. package/dist/src/storage/sqlite/browser-session-repository.d.ts +17 -0
  173. package/dist/src/storage/sqlite/browser-session-repository.js +54 -0
  174. package/dist/src/storage/sqlite/device-pairing-approval.js +3 -4
  175. package/dist/src/storage/sqlite/device-pairing-repository.d.ts +4 -10
  176. package/dist/src/storage/sqlite/device-pairing-repository.js +10 -62
  177. package/dist/src/storage/sqlite/index.d.ts +1 -1
  178. package/dist/src/storage/sqlite/index.js +2 -2
  179. package/dist/src/storage/sqlite/migrations/164_browser_sessions.sql +8 -0
  180. package/dist/src/storage/sqlite/migrations/165_device_pairing_target.sql +40 -0
  181. package/dist/src/storage/sqlite/migrations/runner.d.ts +1 -1
  182. package/dist/src/storage/sqlite/migrations/runner.js +3 -3
  183. package/dist/src/storage/sqlite/migrations/runner.ts +1 -1
  184. package/dist/src/storage/sqlite/schema.js +1 -1
  185. package/dist/src/storage/sqlite/session-identity-sql.d.ts +2 -0
  186. package/dist/src/storage/sqlite/session-identity-sql.js +18 -0
  187. package/dist/src/storage/sqlite/session-repository.js +26 -22
  188. package/dist/src/tunnel/auth-policy.d.ts +3 -0
  189. package/dist/src/tunnel/auth-policy.js +8 -0
  190. package/dist/src/tunnel/broker-client.d.ts +5 -15
  191. package/dist/src/tunnel/broker-client.js +37 -49
  192. package/dist/src/tunnel/frpc-binary.d.ts +8 -6
  193. package/dist/src/tunnel/frpc-binary.js +76 -88
  194. package/dist/src/tunnel/frpc-config.d.ts +2 -1
  195. package/dist/src/tunnel/frpc-config.js +29 -12
  196. package/dist/src/tunnel/frpc-release.d.ts +27 -0
  197. package/dist/src/tunnel/frpc-release.js +30 -0
  198. package/dist/src/tunnel/gateway-lifecycle.js +8 -2
  199. package/dist/src/tunnel/index.js +2 -1
  200. package/dist/src/tunnel/registration-proof.d.ts +19 -0
  201. package/dist/src/tunnel/registration-proof.js +37 -0
  202. package/dist/src/tunnel/tunnel-persist.js +3 -1
  203. package/dist/src/tunnel/tunnel-service.d.ts +1 -0
  204. package/dist/src/tunnel/tunnel-service.js +35 -8
  205. package/dist/src/tunnel/tunnel-state.js +11 -5
  206. package/dist/src/tunnel/tunnel-types.d.ts +2 -0
  207. package/dist/src/tunnel/well-known.js +5 -1
  208. package/dist/src/user-context/config.js +2 -2
  209. package/dist/src/utils/logger/redact.js +4 -0
  210. package/dist/src/voice/realtime/runtime.d.ts +1 -0
  211. package/dist/src/voice/realtime/runtime.js +17 -1
  212. package/dist/src/voice/realtime/runtime.types.d.ts +1 -0
  213. package/dist/src/workflows/service/workflow-run-service.js +2 -0
  214. package/dist/src/workflows/service/workflow-session-bridge.d.ts +1 -0
  215. package/dist/src/workflows/service/workflow-session-bridge.js +1 -0
  216. package/package.json +3 -3
  217. package/dist/gateway/static/root/assets/agent-defaults-settings-panel-CE3ygr3l.js +0 -1
  218. package/dist/gateway/static/root/assets/agents-DzG2qw-c.js +0 -1
  219. package/dist/gateway/static/root/assets/apps-page-B4lX6yoT.js +0 -1
  220. package/dist/gateway/static/root/assets/automations-workspace-BiNBewg0.js +0 -6
  221. package/dist/gateway/static/root/assets/browser-settings-page-Dgdt5uVL.js +0 -8
  222. package/dist/gateway/static/root/assets/capabilities-settings-panel-BpDW-R9f.js +0 -7
  223. package/dist/gateway/static/root/assets/channels-settings-DU4EQnR0.js +0 -1
  224. package/dist/gateway/static/root/assets/connectors-page-CfJqy284.js +0 -2
  225. package/dist/gateway/static/root/assets/cron-expression-BNwbnrEb.js +0 -2
  226. package/dist/gateway/static/root/assets/date-picker-DKyirU4K.js +0 -1
  227. package/dist/gateway/static/root/assets/extension-settings-page-B1dds2bP.js +0 -1
  228. package/dist/gateway/static/root/assets/gateway-settings-pp9jN0wl.js +0 -1
  229. package/dist/gateway/static/root/assets/heartbeat-settings-B8_zTyev.js +0 -1
  230. package/dist/gateway/static/root/assets/home-page-g1KdAdLb.js +0 -1
  231. package/dist/gateway/static/root/assets/index-1zRt56Zt.css +0 -2
  232. package/dist/gateway/static/root/assets/index-OMnem2nr.js +0 -74
  233. package/dist/gateway/static/root/assets/local-app-workbench-page-bj75v2ZE.js +0 -2
  234. package/dist/gateway/static/root/assets/locale-store-BThkG0W5.js +0 -1
  235. package/dist/gateway/static/root/assets/logs-page-BX7n39zV.js +0 -2
  236. package/dist/gateway/static/root/assets/management-settings-CM62j8ZX.js +0 -1
  237. package/dist/gateway/static/root/assets/markdown-view-BwjpJVPs.js +0 -201
  238. package/dist/gateway/static/root/assets/mobile-pairing-wizard-BCWfwVx3.js +0 -1
  239. package/dist/gateway/static/root/assets/note-detail-panel-koOqb0gX.js +0 -5
  240. package/dist/gateway/static/root/assets/notes-page-BH54rY3B.js +0 -8
  241. package/dist/gateway/static/root/assets/popover-select-CKBYnT3c.js +0 -1
  242. package/dist/gateway/static/root/assets/project-detail-page-SL2g8MZY.js +0 -1
  243. package/dist/gateway/static/root/assets/projects-page-BtxazT5J.js +0 -1
  244. package/dist/gateway/static/root/assets/remote-access-hub-BSb7b67A.js +0 -1
  245. package/dist/gateway/static/root/assets/sessions-page-ljcS2KVz.js +0 -1
  246. package/dist/gateway/static/root/assets/settings-advanced-gate-CR9Y9LQm.js +0 -1
  247. package/dist/gateway/static/root/assets/setup-status-panel-J3AnooPW.js +0 -1
  248. package/dist/gateway/static/root/assets/shares-settings-AAm4Iwcp.js +0 -1
  249. package/dist/gateway/static/root/assets/skill-reload-api-pRCjP5sm.js +0 -1
  250. package/dist/gateway/static/root/assets/skills-page.utils-CfVAc_lu.js +0 -1
  251. package/dist/gateway/static/root/assets/system-settings-panel-B-pzalp-.js +0 -1
  252. package/dist/gateway/static/root/assets/task-detail-page-CmrLy3PO.js +0 -1
  253. package/dist/gateway/static/root/assets/tunnel-api-Cgpnm2fL.js +0 -1
  254. package/dist/gateway/static/root/assets/user-model-page-u3QLDX6L.js +0 -2
  255. package/dist/gateway/static/root/assets/workflows-page-DA6OOK6X.js +0 -6
@@ -2,8 +2,8 @@ import { createLogger } from "../../utils/logger/index.js";
2
2
  import { init_logger } from "../../utils/logger.js";
3
3
  import { CredentialResolver, init_credentials } from "../../auth/credentials.js";
4
4
  import { getAllProviders, init_providers } from "../../providers/index.js";
5
- import { disconnectProvider } from "../../providers/provider-disconnect.js";
6
5
  import { formatExamples, register } from "../registry.js";
6
+ import { disconnectProvider } from "../../providers/provider-disconnect.js";
7
7
  import { colorizeStatus, colors } from "../utils/colors.js";
8
8
  import { listAllProfiles, listProfilesForProvider, removeAuthProfile, upsertAuthProfile } from "../../auth/profiles/profiles.js";
9
9
  import { getOAuthProvider, getSupportedOAuthProviders } from "../utils/oauth-providers.js";
@@ -52,7 +52,7 @@ async function checkDatabaseSchema(ctx) {
52
52
  id: "database-schema",
53
53
  label: "Database schema",
54
54
  status: "pass",
55
- message: `SQLite schema v${status.dbVersion} (current release v163).`,
55
+ message: `SQLite schema v${status.dbVersion} (current release v165).`,
56
56
  hints: []
57
57
  };
58
58
  }
@@ -5,10 +5,10 @@ import { init_paths, resolveConfigPath, resolveExtensionsDir } from "../../confi
5
5
  import { init_normalize_manifest, normalizeExtensionManifest } from "../../extensions/normalize-manifest.js";
6
6
  import { init_loader, loadConfig } from "../../config/loader.js";
7
7
  import { checkEngineCompatibility } from "../../extensions/engine-check.js";
8
+ import { getContextWithOpts } from "../context.js";
8
9
  import { GatewayServer } from "../../gateway/server.js";
9
10
  import { runGatewayLoop } from "../../gateway/run-loop.js";
10
11
  import "../../gateway/index.js";
11
- import { getContextWithOpts } from "../context.js";
12
12
  import { colors } from "../utils/colors.js";
13
13
  import { initWorkspace } from "../utils/init-workspace.js";
14
14
  import { join, resolve } from "node:path";
@@ -1,11 +1,11 @@
1
1
  import { init_paths, resolveExtensionsDir } from "../../config/paths.js";
2
2
  import { init_loader, loadConfig } from "../../config/loader.js";
3
3
  import { downloadExtensionStoreZipBuffer, resolveExtensionZipDownloadUrl, resolveExtensionsStoreBaseUrl, verifyStoreArtifactSha256 } from "../../agent/skills/marketplace/adapters/store/store-api-client.js";
4
+ import { getContextWithOpts } from "../context.js";
4
5
  import { getExtensionLockfileManager } from "../../extensions/lockfile.js";
5
6
  import { installFromLocal, installFromNpm, peekExtensionManifestFromStoreZip } from "../../extensions/install.js";
6
7
  import { commitStagedExtensionInstall, finalizeStagedExtensionInstall, rollbackStagedExtensionInstall, stageExtensionStoreZip } from "../../extensions/install-transaction.js";
7
8
  import { fetchRegistry, findExtension, getExtensionMarketplaceStoreBaseUrl, listExtensions, searchExtensions } from "../../extensions/marketplace.js";
8
- import { getContextWithOpts } from "../context.js";
9
9
  import { colors } from "../utils/colors.js";
10
10
  import { validateExtensionPackageDirectory } from "./extension-pack.js";
11
11
  import { join, resolve } from "node:path";
@@ -5,10 +5,10 @@ import { init_paths, resolveExtensionsDir } from "../../config/paths.js";
5
5
  import { init_loader, loadConfig, saveConfig } from "../../config/loader.js";
6
6
  import { checkEngineCompatibility } from "../../extensions/engine-check.js";
7
7
  import { ExtensionLoader } from "../../extensions/loader.js";
8
+ import { getContextWithOpts } from "../context.js";
8
9
  import { getExtensionLockfileManager } from "../../extensions/lockfile.js";
9
10
  import { checkAllExtensionsHealth, getExtensionHealthChecker } from "../../extensions/health.js";
10
11
  import { collectExtensionPackageDependencyIssues } from "../../extensions/package-contract.js";
11
- import { getContextWithOpts } from "../context.js";
12
12
  import { colors } from "../utils/colors.js";
13
13
  import { createExtensionCreateCommand } from "./extension-create.js";
14
14
  import { createExtensionDevCommand } from "./extension-dev.js";
@@ -1,7 +1,7 @@
1
1
  import { init_paths, resolveConfigPath } from "../../../config/paths.js";
2
2
  import { loadConfig } from "../../../config/loader.js";
3
- import { isRestartEnabled } from "../../../config/commands.flags.js";
4
3
  import "../../../config/index.js";
4
+ import { isRestartEnabled } from "../../../config/commands.flags.js";
5
5
  import { resolveGatewayService } from "../../../daemon/service.js";
6
6
  import { authorizeGatewaySigusr1Restart, writeGatewayRestartIntentSync } from "../../../infra/restart.js";
7
7
  import { findVerifiedGatewayListenerPidsOnPortSync, formatGatewayPidList, signalVerifiedGatewayPidSync } from "../../../infra/gateway-processes.js";
@@ -69,10 +69,13 @@ async function runGatewayFromCliOptions(options, ctx) {
69
69
  const { resolveGatewayAuth, assertGatewayAuthConfigured } = await import("../../../gateway/auth.js");
70
70
  const { assertGatewayRuntimeConfig } = await import("../../../gateway/runtime-config.js");
71
71
  let auth = resolveGatewayAuth({ authConfig: effectiveConfig.gateway?.auth });
72
- if (typeof options.token === "string" && options.token.trim().length > 0) auth = {
73
- mode: "token",
74
- token: options.token.trim()
75
- };
72
+ if (typeof options.token === "string" && options.token.trim().length > 0) {
73
+ auth = {
74
+ mode: "token",
75
+ token: options.token.trim()
76
+ };
77
+ process.env.XOPC_GATEWAY_TOKEN = auth.token;
78
+ }
76
79
  try {
77
80
  assertGatewayAuthConfigured(auth);
78
81
  assertGatewayRuntimeConfig({
@@ -126,7 +129,7 @@ async function runGatewayFromCliOptions(options, ctx) {
126
129
  });
127
130
  await server.start();
128
131
  const displayHost = bindHost === "0.0.0.0" ? "localhost" : bindHost;
129
- const token = options.token || config?.gateway?.auth?.token;
132
+ const token = auth.mode === "token" ? auth.token : void 0;
130
133
  console.log("✅ Gateway started");
131
134
  console.log(` URL: http://${displayHost}:${port}`);
132
135
  if (token) console.log(` Token: ${token.slice(0, 8)}...${token.slice(-8)}`);
@@ -9,8 +9,9 @@ init_paths();
9
9
  * Create service install subcommand - actually installs the OS service
10
10
  */
11
11
  function createInstallCommand() {
12
- return new Command("install").description("Install gateway as OS service (LaunchAgent / systemd / Task)").option("--port <port>", "Gateway port").option("--token <token>", "Gateway auth token").option("--force", "Force reinstall if already installed").option("--json", "Output JSON").action(async (options) => {
12
+ return new Command("install").description("Install gateway as OS service (LaunchAgent / systemd / Task)").option("--port <port>", "Gateway port").option("--token <token>", "Gateway auth token").option("--force", "Force reinstall if already installed").option("--json", "Output JSON").action(async (options, command) => {
13
13
  const configPath = getContextWithOpts().configPath || resolveConfigPath();
14
+ const force = options.force === true || command.optsWithGlobals().force === true;
14
15
  const [{ loadConfig }, { resolveGatewayService, isDaemonAvailableAsync, getPlatformName }, { buildGatewayInstallArgs }] = await Promise.all([
15
16
  import("../../../config/index.js"),
16
17
  import("../../../daemon/service.js"),
@@ -30,7 +31,7 @@ function createInstallCommand() {
30
31
  }
31
32
  const service = await resolveGatewayService();
32
33
  const loaded = await service.isLoaded({ env: process.env });
33
- if (loaded && !options.force) {
34
+ if (loaded && !force) {
34
35
  if (options.json) console.log(JSON.stringify({
35
36
  ok: true,
36
37
  result: "already-installed"
@@ -38,7 +39,7 @@ function createInstallCommand() {
38
39
  else console.log("ℹ️ Service already installed. Use --force to reinstall.");
39
40
  return;
40
41
  }
41
- if (loaded && options.force) try {
42
+ if (loaded && force) try {
42
43
  await service.uninstall({ env: process.env });
43
44
  } catch {}
44
45
  const installArgs = buildGatewayInstallArgs({
@@ -4,6 +4,17 @@ import crypto from "crypto";
4
4
  import { Command } from "commander";
5
5
  //#region src/cli/commands/gateway/token.ts
6
6
  init_paths();
7
+ async function readInstalledServiceToken() {
8
+ try {
9
+ const { isDaemonAvailableAsync, resolveGatewayService } = await import("../../../daemon/service.js");
10
+ if (!await isDaemonAvailableAsync()) return void 0;
11
+ const service = await resolveGatewayService();
12
+ if (!await service.isLoaded({ env: process.env })) return void 0;
13
+ return (await service.readCommand(process.env))?.environment?.XOPC_GATEWAY_TOKEN?.trim() || void 0;
14
+ } catch {
15
+ return;
16
+ }
17
+ }
7
18
  /**
8
19
  * Create the token subcommand for managing gateway authentication token.
9
20
  */
@@ -14,6 +25,7 @@ function createTokenCommand() {
14
25
  const log = createLogger("GatewayTokenCommand");
15
26
  try {
16
27
  const config = loadConfig(configPath);
28
+ const installedServiceToken = await readInstalledServiceToken();
17
29
  if (options.generate) {
18
30
  const newToken = crypto.randomBytes(24).toString("hex");
19
31
  config.gateway = config.gateway || {};
@@ -31,9 +43,16 @@ function createTokenCommand() {
31
43
  console.log("");
32
44
  console.log("Or set environment variable:");
33
45
  console.log(` export XOPC_GATEWAY_TOKEN=${newToken}`);
46
+ if (installedServiceToken && installedServiceToken !== newToken) {
47
+ console.log("");
48
+ console.log("⚠️ The installed gateway service still uses its previous token.");
49
+ console.log(" Run `xopc gateway service install --force`, then restart the service.");
50
+ }
34
51
  process.exit(0);
35
52
  } else {
36
- const currentToken = config.gateway?.auth?.token;
53
+ const configToken = config.gateway?.auth?.token?.trim();
54
+ const environmentToken = process.env.XOPC_GATEWAY_TOKEN?.trim();
55
+ const currentToken = installedServiceToken || environmentToken || configToken;
37
56
  if ((config.gateway?.auth?.mode || "token") === "none") {
38
57
  console.log("⚠️ Gateway authentication is disabled (mode: none)");
39
58
  console.log("");
@@ -46,6 +65,14 @@ function createTokenCommand() {
46
65
  console.log(` ${currentToken}`);
47
66
  console.log("");
48
67
  console.log(`Preview: ${tokenPreview}`);
68
+ if (installedServiceToken) console.log("Source: installed gateway service");
69
+ else if (environmentToken) console.log("Source: XOPC_GATEWAY_TOKEN");
70
+ else console.log(`Source: ${configPath}`);
71
+ if (installedServiceToken && configToken && installedServiceToken !== configToken) {
72
+ console.log("");
73
+ console.log("⚠️ Token drift detected: the installed service token overrides the config token.");
74
+ console.log(" Run `xopc gateway service install --force`, then restart the service to sync.");
75
+ }
49
76
  console.log("");
50
77
  console.log("Usage:");
51
78
  console.log(` xopc gateway --token ${currentToken}`);
@@ -1,5 +1,5 @@
1
- import { startSshPortForward } from "../../infra/ssh-tunnel.js";
2
1
  import { formatExamples } from "../registry.js";
2
+ import { startSshPortForward } from "../../infra/ssh-tunnel.js";
3
3
  import { Command } from "commander";
4
4
  //#region src/cli/commands/gateway-ssh-tunnel.ts
5
5
  function registerGatewaySshTunnelCommand(parent, ctx) {
@@ -2,11 +2,11 @@ import { getAgentDefaultModelRef, init_schema } from "../../config/schema.js";
2
2
  import { loadConfig, saveConfig } from "../../config/loader.js";
3
3
  import { CredentialResolver, init_credentials } from "../../auth/credentials.js";
4
4
  import { getAllModels, getAvailableModels, getConfiguredProviders, getProviderAuthState, getProviderDisplayName, init_providers, isProviderConfigured, providerSupportsApiKey, providerSupportsOAuth, resolveModel } from "../../providers/index.js";
5
+ import { formatExamples, register } from "../registry.js";
6
+ import { getContextWithOpts } from "../context.js";
5
7
  import "../../config/index.js";
6
8
  import { prepareUpdateGlobalDefaults } from "../../gateway/global-defaults-admin.js";
7
9
  import { disconnectProvider } from "../../providers/provider-disconnect.js";
8
- import { formatExamples, register } from "../registry.js";
9
- import { getContextWithOpts } from "../context.js";
10
10
  import { colors } from "../utils/colors.js";
11
11
  import { runCliOAuthLogin } from "../utils/oauth-login.js";
12
12
  import { input } from "@inquirer/prompts";
@@ -2,8 +2,8 @@ import { init_paths_state, resolveStateDir } from "../../config/paths-state.js";
2
2
  import { ConfigSchema, init_schema } from "../../config/schema.js";
3
3
  import { saveConfig } from "../../config/loader.js";
4
4
  import { resolveGatewayLocalClientHost } from "../../config/gateway-bind.js";
5
- import "../../config/index.js";
6
5
  import { formatExamples, register } from "../registry.js";
6
+ import "../../config/index.js";
7
7
  import { provisionEagerRuntimes } from "../../runtime-tools/bootstrap.js";
8
8
  import { colors } from "../utils/colors.js";
9
9
  import { initWorkspace } from "../utils/init-workspace.js";
@@ -1,6 +1,6 @@
1
1
  import { loadConfig, saveConfig } from "../../config/loader.js";
2
- import "../../config/index.js";
3
2
  import { formatExamples, register } from "../registry.js";
3
+ import "../../config/index.js";
4
4
  import { PLATFORM_RUNTIME_PROFILE, PLATFORM_RUNTIME_PROVIDER, PlatformRuntimeClient, discoverPlatform } from "../../platform/client.js";
5
5
  import "../../platform/index.js";
6
6
  import { getProfile, upsertAuthProfile } from "../../auth/profiles/profiles.js";
@@ -1,7 +1,7 @@
1
1
  import { createLogger } from "../../utils/logger/index.js";
2
2
  import { init_logger } from "../../utils/logger.js";
3
- import { createProfile, deleteProfile, getCurrentProfile, getSwitchCommand, listProfiles, resolveProfileStateDir } from "../../config/profile.js";
4
3
  import { formatExamples, register } from "../registry.js";
4
+ import { createProfile, deleteProfile, getCurrentProfile, getSwitchCommand, listProfiles, resolveProfileStateDir } from "../../config/profile.js";
5
5
  import { colors } from "../utils/colors.js";
6
6
  import { Command } from "commander";
7
7
  import Table from "cli-table3";
@@ -1,16 +1,19 @@
1
1
  import { createLogger } from "../../utils/logger/index.js";
2
2
  import { init_logger } from "../../utils/logger.js";
3
+ import { isXopcDatabaseOpen, openXopcDatabase } from "../../storage/sqlite/connection.js";
3
4
  import { loadConfig, saveConfig } from "../../config/loader.js";
4
5
  import { resolveGatewayEffectiveHost } from "../../config/gateway-bind.js";
5
6
  import { ensureFrpcBinary } from "../../tunnel/frpc-binary.js";
6
7
  import { resolveTunnelBrokerUrl, resolveTunnelRegistrationSecret } from "../../tunnel/env.js";
7
8
  import { loadTunnelState } from "../../tunnel/tunnel-state.js";
8
9
  import { getTunnelService } from "../../tunnel/tunnel-service.js";
10
+ import { formatExamples, register } from "../registry.js";
9
11
  import "../../config/index.js";
12
+ import { resolveGatewayAuth } from "../../gateway/auth.js";
13
+ import { requireTunnelGatewayToken } from "../../tunnel/auth-policy.js";
10
14
  import { TUNNEL_RISK_SUMMARY_LINES, TunnelConsentError, assertTunnelMayStart, hasValidTunnelConsent } from "../../tunnel/consent.js";
11
15
  import { resolveFrpSubdomainHost } from "../../tunnel/frp-subdomain-host.js";
12
16
  import { applyTunnelConsentToConfig, mergeTunnelConfigPatch, setTunnelEnabledInConfig } from "../../tunnel/tunnel-config.js";
13
- import { formatExamples, register } from "../registry.js";
14
17
  import "../../tunnel/index.js";
15
18
  import { Command } from "commander";
16
19
  //#region src/cli/commands/tunnel.ts
@@ -26,6 +29,7 @@ function resolveGatewayPortHost(config) {
26
29
  };
27
30
  }
28
31
  function resolveGatewayToken(config) {
32
+ requireTunnelGatewayToken(resolveGatewayAuth({ authConfig: config.gateway.auth }));
29
33
  const fromEnv = process.env.XOPC_GATEWAY_TOKEN?.trim();
30
34
  if (fromEnv) return fromEnv;
31
35
  const token = config.gateway.auth?.token?.trim();
@@ -155,6 +159,7 @@ function createTunnelCommand(ctx) {
155
159
  });
156
160
  const config = loadConfig(ctx.configPath);
157
161
  assertTunnelMayStart(config);
162
+ if (!isXopcDatabaseOpen()) openXopcDatabase();
158
163
  const { port, host } = resolveGatewayPortHost(config);
159
164
  const token = resolveGatewayToken(config);
160
165
  const tunnel = getTunnelService();
@@ -1,11 +1,11 @@
1
1
  import { PACKAGE_VERSION, init_package_version } from "../../package-version.js";
2
2
  import { loadConfig } from "../../config/loader.js";
3
+ import { formatExamples, register } from "../registry.js";
3
4
  import "../../config/index.js";
4
5
  import { acquireUpdateLock } from "../../infra/update-lock.js";
5
6
  import { normalizeUpdateChannel } from "../../infra/update-channels.js";
6
7
  import { compareSemver, resolveNpmChannelTag } from "../../infra/update-check.js";
7
8
  import { formatUpdateApiResult, resolveUpdateInstallSurface, runGatewayUpdateWithPostSteps } from "../../infra/update-runner.js";
8
- import { formatExamples, register } from "../registry.js";
9
9
  import { Command } from "commander";
10
10
  //#region src/cli/commands/update.ts
11
11
  init_package_version();
@@ -4,9 +4,9 @@ import { ExtensionLoader } from "../extensions/loader.js";
4
4
  import "../extensions/index.js";
5
5
  import { MessageBus } from "../infra/bus/queue.js";
6
6
  import "../infra/bus/index.js";
7
+ import { createDefaultContext } from "./registry.js";
7
8
  import { getWorkspacePath } from "../config/workspace-path-helpers.js";
8
9
  import "../config/index.js";
9
- import { createDefaultContext } from "./registry.js";
10
10
  import { registerExtensionCliProgram } from "../extensions/sdk/channel-helpers.js";
11
11
  import { join } from "path";
12
12
  //#region src/cli/extension-cli-register.ts
@@ -13,10 +13,10 @@ import { clearConfigValueCache, getAllowedCommands, getCacheStats, init_resolve_
13
13
  import { CustomModelSchema, ImageGenerationCapabilitiesSchema, ImageGenerationModelSchema, ImageGenerationProviderSchema, ModelOverrideSchema, ModelsJsonSchema, OpenAICompatSchema, OpenAICompletionsCompatSchema, OpenAIResponsesCompatSchema, OpenRouterRoutingSchema, ProviderConfigSchema, VercelGatewayRoutingSchema, getDefaultModelValues, init_models_json, loadModelsJson, modelsJsonExists, saveModelsJson, validateModelsConfig } from "./models-json.js";
14
14
  import { canonicalizeConfiguredMcpServer, isKnownCliMcpTypeAlias, normalizeConfiguredMcpServers, resolveXopcMcpTransportAlias } from "./mcp-config-normalize.js";
15
15
  import { formatThinkingLevels, listThinkingLevels, normalizeElevatedMode, normalizeReasoningLevel, normalizeThinkLevel, normalizeVerboseLevel, thinkLevelToNumber } from "../agent/transcript/thinking-types.js";
16
- import { diffConfigPaths } from "./diff.js";
17
16
  import { getWorkspacePath } from "./workspace-path-helpers.js";
18
17
  import { listAgentProfileMarkdownDirs, listAgentWorkspaceDirs } from "./workspace-dirs.js";
19
18
  import { ProfileManager, createProfile, deleteProfile, getCurrentProfile, getProfileManager, getProfileNameFromDir, getSwitchCommand, listProfiles, resolveProfileStateDir } from "./profile.js";
19
+ import { diffConfigPaths } from "./diff.js";
20
20
  import { BASE_RELOAD_RULES, buildReloadPlan, matchReloadRule } from "./rules.js";
21
21
  import { ConfigHotReloader } from "./reload.js";
22
22
  //#region src/config/index.ts
@@ -19,9 +19,6 @@ function routeId(kind, url) {
19
19
  function resolveSecureDeviceRoutes(config) {
20
20
  const tunnelStatus = getTunnelService().getStatus();
21
21
  const candidates = [{
22
- kind: "custom-https",
23
- url: secureUrl(resolveReverseProxyPublicUrl(config))
24
- }, {
25
22
  kind: "xopc-secure-link",
26
23
  url: tunnelStatus.state === "connected" ? secureUrl(tunnelStatus.publicUrl) : null
27
24
  }];
@@ -30,6 +27,10 @@ function resolveSecureDeviceRoutes(config) {
30
27
  kind: "tailscale",
31
28
  url: secureUrl(`https://${tailscale.hostname}`)
32
29
  });
30
+ candidates.push({
31
+ kind: "custom-https",
32
+ url: secureUrl(resolveReverseProxyPublicUrl(config))
33
+ });
33
34
  const seen = /* @__PURE__ */ new Set();
34
35
  const routes = [];
35
36
  for (const candidate of candidates) {
@@ -1,9 +1,9 @@
1
1
  import { createLogger } from "../../utils/logger/index.js";
2
2
  import { init_logger } from "../../utils/logger.js";
3
3
  import { shouldSilence, stripHeartbeatToken } from "../../heartbeat/tokens.js";
4
+ import { appendCronEventLines } from "../../heartbeat/event-prompt.js";
4
5
  import { isWithinActiveHours } from "../../heartbeat/active-hours.js";
5
6
  import { isHeartbeatContentEmpty } from "../../heartbeat/content-check.js";
6
- import { appendCronEventLines } from "../../heartbeat/event-prompt.js";
7
7
  import { createHeartbeatWake } from "../../heartbeat/wake.js";
8
8
  import { resolveHeartbeatMdPath } from "../workspace-heartbeat-path.js";
9
9
  import { readFile } from "fs/promises";
@@ -225,6 +225,7 @@ function createHonoApp(config) {
225
225
  authenticated.use(auth({
226
226
  getGatewayAuth: () => service.currentConfig.gateway?.auth,
227
227
  getResolvedAuth: () => service.getResolvedAuth(),
228
+ isPublicTunnelEnabled: () => service.currentConfig.tunnel?.enabled === true,
228
229
  getTrustedProxyContext: () => ({
229
230
  trustedProxies: service.currentConfig.gateway?.trustedProxies,
230
231
  allowRealIpFallback: service.currentConfig.gateway?.allowRealIpFallback === true
@@ -4,13 +4,12 @@ export interface AuthConfig {
4
4
  /** Current gateway auth from config (for rate-limit settings); optional. */
5
5
  getGatewayAuth?: () => GatewayAuthConfig | undefined;
6
6
  getResolvedAuth?: () => ResolvedGatewayAuth;
7
+ isPublicTunnelEnabled?: () => boolean;
7
8
  getTrustedProxyContext?: () => {
8
9
  trustedProxies?: string[];
9
10
  allowRealIpFallback?: boolean;
10
11
  };
11
12
  }
12
- /** Exported for gateway security tests. */
13
- export declare function isQueryTokenAllowedPath(path: string, method: string): boolean;
14
13
  export declare function auth(config?: AuthConfig): import("hono").MiddlewareHandler<any, string, {}, (Response & import("hono").TypedResponse<{
15
14
  error: string;
16
15
  code: string;
@@ -5,11 +5,12 @@ import { authenticateDeviceAccessToken, getDevice } from "../../../storage/sqlit
5
5
  import { safeEqualSecret } from "../../security/secret-equal.js";
6
6
  import { resolveClientIpFromRequest } from "../../client-ip.js";
7
7
  import { authPolicyConfig, buckets, resolveAuthRateLimit } from "../../rate-limit/buckets.js";
8
- import { getClientIpFromHeaders } from "../../security/loopback.js";
9
8
  import { resolveAuthTracking } from "../../rate-limit/auth-policy.js";
10
9
  import { isAuthRateLimitGloballyDisabled } from "../../rate-limit/env-flags.js";
11
10
  import "../../rate-limit/index.js";
11
+ import { authenticateBrowserSession } from "../../../storage/sqlite/browser-session-repository.js";
12
12
  import { isChromeExtensionOrigin } from "../../security/origin-check.js";
13
+ import { browserCookieRequestAllowed, readBrowserSessionCookie, writeBrowserSessionCookie } from "../../security/browser-session.js";
13
14
  import { authorizeTrustedProxy } from "../../trusted-proxy.js";
14
15
  import { setGatewayPrincipal } from "../../security/gateway-principal.js";
15
16
  import { createMiddleware } from "hono/factory";
@@ -30,21 +31,6 @@ function extractTokenFromHeader(authHeader) {
30
31
  if (parts.length === 2 && parts[0].toLowerCase() === "bearer") return parts[1];
31
32
  return authHeader;
32
33
  }
33
- /**
34
- * SECURITY: query-string tokens leak into server logs, Referer headers, and
35
- * browser history. We accept them only for avatar `<img>` loads, where an
36
- * Authorization header cannot be set. Realtime WebSocket authentication uses a
37
- * one-time ticket acquired over authenticated HTTP.
38
- */
39
- function extractTokenFromQuery(url) {
40
- return new URL(url).searchParams.get("token");
41
- }
42
- const AGENT_AVATAR_GET_PATH = /^\/api\/agents\/[^/]+\/avatar$/;
43
- /** Exported for gateway security tests. */
44
- function isQueryTokenAllowedPath(path, method) {
45
- if (method === "GET" && AGENT_AVATAR_GET_PATH.test(path)) return true;
46
- return false;
47
- }
48
34
  function resolveRemoteAddress(c) {
49
35
  try {
50
36
  return getConnInfo(c).remote.address;
@@ -53,17 +39,16 @@ function resolveRemoteAddress(c) {
53
39
  }
54
40
  }
55
41
  function resolveMiddlewareClientIp(c, trustedProxies, allowRealIpFallback) {
56
- if (trustedProxies?.length) return resolveClientIpFromRequest({
42
+ return resolveClientIpFromRequest({
57
43
  remoteAddress: resolveRemoteAddress(c),
58
44
  getHeader: (name) => c.req.header(name),
59
45
  trustedProxies,
60
46
  allowRealIpFallback
61
47
  });
62
- return getClientIpFromHeaders({ get: (name) => c.req.header(name) ?? void 0 });
63
48
  }
64
- function buildRateLimitContext(getGatewayAuth, clientIp, origin) {
49
+ function buildRateLimitContext(getGatewayAuth, clientIp, origin, enforce = false) {
65
50
  const cfg = resolveAuthRateLimit(getGatewayAuth?.()?.rateLimit);
66
- if (!(cfg.enabled && !isAuthRateLimitGloballyDisabled())) return {
51
+ if (!(cfg.enabled && (enforce || !isAuthRateLimitGloballyDisabled()))) return {
67
52
  active: false,
68
53
  cfg,
69
54
  trackingKey: void 0
@@ -101,7 +86,18 @@ function blockedResponse(c, retryAfterSec) {
101
86
  }, 429);
102
87
  }
103
88
  function auth(config) {
104
- const { getGatewayAuth, getResolvedAuth, getTrustedProxyContext } = config || {};
89
+ const { getGatewayAuth: readGatewayAuth, getResolvedAuth, getTrustedProxyContext, isPublicTunnelEnabled } = config || {};
90
+ const getGatewayAuth = () => {
91
+ const current = readGatewayAuth?.();
92
+ return isPublicTunnelEnabled?.() ? {
93
+ ...current,
94
+ rateLimit: {
95
+ ...current?.rateLimit,
96
+ enabled: true,
97
+ exemptLoopback: false
98
+ }
99
+ } : current;
100
+ };
105
101
  return createMiddleware(async (c, next) => {
106
102
  const resolvedAuth = getResolvedAuth?.();
107
103
  if (!resolvedAuth) {
@@ -115,13 +111,17 @@ function auth(config) {
115
111
  }, 401);
116
112
  }
117
113
  const authMode = resolvedAuth.mode;
114
+ if (isPublicTunnelEnabled?.() && authMode !== "token") return c.json({
115
+ error: "Unauthorized",
116
+ code: "unsafe_tunnel_auth"
117
+ }, 401);
118
118
  if (authMode === "trusted-proxy") {
119
119
  const proxyContext = getTrustedProxyContext?.();
120
120
  const trustedProxies = proxyContext?.trustedProxies;
121
121
  const trustedProxyConfig = resolvedAuth?.trustedProxy;
122
122
  const clientIp = resolveMiddlewareClientIp(c, trustedProxies, proxyContext?.allowRealIpFallback);
123
123
  const origin = c.req.header("origin");
124
- const rl = buildRateLimitContext(getGatewayAuth, clientIp, origin);
124
+ const rl = buildRateLimitContext(getGatewayAuth, clientIp, origin, isPublicTunnelEnabled?.());
125
125
  if (!trustedProxyConfig) {
126
126
  log.warn({
127
127
  path: c.req.path,
@@ -199,16 +199,34 @@ function auth(config) {
199
199
  const proxyContext = getTrustedProxyContext?.();
200
200
  const clientIp = resolveMiddlewareClientIp(c, proxyContext?.trustedProxies, proxyContext?.allowRealIpFallback);
201
201
  const origin = c.req.header("origin");
202
- const rl = buildRateLimitContext(getGatewayAuth, clientIp, origin);
202
+ const rl = buildRateLimitContext(getGatewayAuth, clientIp, origin, isPublicTunnelEnabled?.());
203
203
  const authHeader = extractTokenFromHeader(c.req.header("authorization"));
204
+ const browserCookie = readBrowserSessionCookie(c);
205
+ if (!authHeader && browserCookie) {
206
+ if (!browserCookieRequestAllowed(c)) return c.json({
207
+ error: "Forbidden",
208
+ code: "csrf_rejected"
209
+ }, 403);
210
+ const session = authenticateBrowserSession(browserCookie, resolvedAuth);
211
+ if (!session) {
212
+ recordFailure(rl);
213
+ return c.json({
214
+ error: "Unauthorized",
215
+ code: "browser_session_expired"
216
+ }, 401);
217
+ }
218
+ if (session.renewed) writeBrowserSessionCookie(c, browserCookie, session.expiresAt);
219
+ setGatewayPrincipal(c, {
220
+ kind: "owner",
221
+ principalId: `browser:${session.sessionId}`,
222
+ browserSessionId: session.sessionId,
223
+ scopes: ["gateway.admin"]
224
+ });
225
+ recordSuccess(rl);
226
+ return next();
227
+ }
204
228
  const requestPath = new URL(c.req.url).pathname;
205
- const queryToken = authMode === "token" && isQueryTokenAllowedPath(requestPath, c.req.method) ? extractTokenFromQuery(c.req.url) : null;
206
- if (!authHeader && queryToken === null && new URL(c.req.url).searchParams.has("token")) log.warn({
207
- path: requestPath,
208
- method: c.req.method,
209
- clientIp
210
- }, "Credential in query string rejected: use Authorization header for this endpoint");
211
- const providedCredential = authHeader || queryToken;
229
+ const providedCredential = authHeader;
212
230
  const browserExtensionOrigin = isChromeExtensionOrigin(origin) ? origin.toLowerCase() : void 0;
213
231
  if (providedCredential && validateCredential(providedCredential, expectedCredential)) {
214
232
  if (browserExtensionOrigin) return c.json({
@@ -294,4 +312,4 @@ function auth(config) {
294
312
  });
295
313
  }
296
314
  //#endregion
297
- export { auth, isQueryTokenAllowedPath };
315
+ export { auth };
@@ -2,7 +2,6 @@ import { createLogger } from "../../../utils/logger/index.js";
2
2
  import { init_logger } from "../../../utils/logger.js";
3
3
  import { resolveClientIpFromRequest } from "../../client-ip.js";
4
4
  import { buckets } from "../../rate-limit/buckets.js";
5
- import { getClientIpFromHeaders } from "../../security/loopback.js";
6
5
  import "../../rate-limit/index.js";
7
6
  import { createMiddleware } from "hono/factory";
8
7
  import { getConnInfo } from "@hono/node-server/conninfo";
@@ -15,21 +14,18 @@ init_logger();
15
14
  const log = createLogger("Hono:StrictRateLimit");
16
15
  function resolveClientIp(c, deps) {
17
16
  const { trustedProxies, allowRealIpFallback } = deps.getTrustedProxyContext();
18
- if (trustedProxies?.length) {
19
- let remoteAddress;
20
- try {
21
- remoteAddress = getConnInfo(c).remote.address;
22
- } catch {
23
- remoteAddress = void 0;
24
- }
25
- return resolveClientIpFromRequest({
26
- remoteAddress,
27
- getHeader: (name) => c.req.header(name),
28
- trustedProxies,
29
- allowRealIpFallback
30
- });
17
+ let remoteAddress;
18
+ try {
19
+ remoteAddress = getConnInfo(c).remote.address;
20
+ } catch {
21
+ remoteAddress = void 0;
31
22
  }
32
- return getClientIpFromHeaders({ get: (name) => c.req.header(name) ?? void 0 });
23
+ return resolveClientIpFromRequest({
24
+ remoteAddress,
25
+ getHeader: (name) => c.req.header(name),
26
+ trustedProxies,
27
+ allowRealIpFallback
28
+ });
33
29
  }
34
30
  function createClientRateLimitMiddleware(deps, options) {
35
31
  return createMiddleware(async (c, next) => {
@@ -0,0 +1,3 @@
1
+ import type { Hono } from 'hono';
2
+ import type { AuthenticatedRouteDeps } from './deps.js';
3
+ export declare function registerBrowserSessionRoutes(app: Hono, deps: AuthenticatedRouteDeps): void;
@@ -0,0 +1,43 @@
1
+ import { BrowserSessionLimitError, createBrowserSession, deleteBrowserSession } from "../../../storage/sqlite/browser-session-repository.js";
2
+ import { browserCookieRequestAllowed, clearBrowserSessionCookie, writeBrowserSessionCookie } from "../../security/browser-session.js";
3
+ import { getGatewayPrincipal } from "../../security/gateway-principal.js";
4
+ //#region src/gateway/hono/routes/browser-session.ts
5
+ function registerBrowserSessionRoutes(app, deps) {
6
+ app.get("/api/browser-session", (c) => {
7
+ c.header("Cache-Control", "no-store");
8
+ const principal = getGatewayPrincipal(c);
9
+ return c.json({ sessionKey: principal.principalId });
10
+ });
11
+ app.post("/api/browser-session", deps.strictRateLimitMiddleware, (c) => {
12
+ const principal = getGatewayPrincipal(c);
13
+ if (principal.kind !== "owner" || !browserCookieRequestAllowed(c)) return c.json({ error: "Forbidden" }, 403);
14
+ let session;
15
+ try {
16
+ session = createBrowserSession(deps.service.getResolvedAuth(), principal.browserSessionId);
17
+ } catch (error) {
18
+ if (error instanceof BrowserSessionLimitError) return c.json({ error: "Browser session limit reached" }, 409);
19
+ throw error;
20
+ }
21
+ if (principal.browserSessionId) {
22
+ deps.service.realtime.disconnectPrincipal(principal.principalId);
23
+ deps.service.voiceRealtime.disconnectPrincipal(principal.principalId);
24
+ }
25
+ writeBrowserSessionCookie(c, session.token, session.expiresAt);
26
+ c.header("Cache-Control", "no-store");
27
+ return c.json({ sessionKey: `browser:${session.sessionId}` });
28
+ });
29
+ app.delete("/api/browser-session", (c) => {
30
+ if (!browserCookieRequestAllowed(c)) return c.json({ error: "Forbidden" }, 403);
31
+ const principal = getGatewayPrincipal(c);
32
+ if (principal.browserSessionId) {
33
+ deleteBrowserSession(principal.browserSessionId);
34
+ deps.service.realtime.disconnectPrincipal(principal.principalId);
35
+ deps.service.voiceRealtime.disconnectPrincipal(principal.principalId);
36
+ }
37
+ clearBrowserSessionCookie(c);
38
+ c.header("Cache-Control", "no-store");
39
+ return c.json({ ok: true });
40
+ });
41
+ }
42
+ //#endregion
43
+ export { registerBrowserSessionRoutes };