@xopcai/xopc 0.0.90 → 0.0.92

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 (365) hide show
  1. package/README.md +36 -12
  2. package/README.zh-CN.md +36 -12
  3. package/dist/browser-ext/manifest.json +1 -1
  4. package/dist/extensions/feishu/src/outbound/media-load.js +1 -1
  5. package/dist/extensions/feishu/src/workflow-progress.js +1 -1
  6. package/dist/extensions/telegram/src/plugin.js +1 -1
  7. package/dist/extensions/telegram/src/routing-integration.js +2 -2
  8. package/dist/extensions/telegram/src/workflow-progress.js +1 -1
  9. package/dist/extensions/telegram/xopc.extension.json +1 -1
  10. package/dist/extensions/weixin/src/api/api.js +2 -2
  11. package/dist/extensions/weixin/src/auth/accounts.js +1 -1
  12. package/dist/extensions/weixin/src/cdn/upload.js +1 -1
  13. package/dist/extensions/weixin/src/media/data-url.js +1 -1
  14. package/dist/extensions/weixin/src/messaging/debug-mode.js +1 -1
  15. package/dist/extensions/weixin/src/messaging/inbound.js +1 -1
  16. package/dist/extensions/weixin/src/messaging/process-message.js +1 -1
  17. package/dist/extensions/weixin/src/plugin.js +1 -1
  18. package/dist/extensions/weixin/src/storage/sync-buf.js +1 -1
  19. package/dist/extensions/weixin/src/workflow-progress.js +1 -1
  20. package/dist/gateway/static/root/assets/Combination-HAlzriaz.js +41 -0
  21. package/dist/gateway/static/root/assets/agents-uwPn7ZW9.js +222 -0
  22. package/dist/gateway/static/root/assets/apps-page-CWKdhSPU.js +1 -0
  23. package/dist/gateway/static/root/assets/{attachment-preview-renderer-CpyoFbs4.js → attachment-preview-renderer-DBAxQXb-.js} +2 -2
  24. package/dist/gateway/static/root/assets/{attachment-process-heavy-CqVriadb.js → attachment-process-heavy-Csq3TrrP.js} +4 -4
  25. package/dist/gateway/static/root/assets/channels-settings-hEhW7Mbk.js +1 -0
  26. package/dist/gateway/static/root/assets/{channels-status-swr-BrtH2VzC.js → channels-status-swr-XzddfJW2.js} +1 -1
  27. package/dist/gateway/static/root/assets/copy-Dv6d4Dvw.js +1 -0
  28. package/dist/gateway/static/root/assets/{cron-api-CyqbgfHM.js → cron-api--I8LJ44S.js} +1 -1
  29. package/dist/gateway/static/root/assets/cron-page-B0kvgZGR.js +1 -0
  30. package/dist/gateway/static/root/assets/dist-CYgHMQO0.js +1 -0
  31. package/dist/gateway/static/root/assets/{extension-debug-page-D6Ak0STa.js → extension-debug-page-6cRP0nA9.js} +1 -1
  32. package/dist/gateway/static/root/assets/{extension-page-Q0P3d6DW.js → extension-page-DpwIkspI.js} +1 -1
  33. package/dist/gateway/static/root/assets/{extension-settings-page-CL55LwU_.js → extension-settings-page-DYbnQUxH.js} +1 -1
  34. package/dist/gateway/static/root/assets/{fetch-Dqa9iTWl.js → fetch-DTN0w7rV.js} +1 -1
  35. package/dist/gateway/static/root/assets/{field-primitives-HUR6JElP.js → field-primitives-CslW6HwD.js} +1 -1
  36. package/dist/gateway/static/root/assets/heartbeat-config-api-2UiKevxG.js +1 -0
  37. package/dist/gateway/static/root/assets/index-BUKUv7QW.css +1 -0
  38. package/dist/gateway/static/root/assets/{index-BYcGfwcE.js → index-DnevRVa6.js} +63 -59
  39. package/dist/gateway/static/root/assets/logs-page-sOP4TXJ4.js +1 -0
  40. package/dist/gateway/static/root/assets/note-detail-page-B91pLkEI.css +1 -0
  41. package/dist/gateway/static/root/assets/note-detail-page-DvW2qg4i.js +179 -0
  42. package/dist/gateway/static/root/assets/note-time-BEiibLJv.js +1 -0
  43. package/dist/gateway/static/root/assets/notes-page-BFQaquHU.js +1 -0
  44. package/dist/gateway/static/root/assets/{pdf-BnEvgIXZ.js → pdf-epILhEOn.js} +1 -1
  45. package/dist/gateway/static/root/assets/preload-helper-zJ_50EbN.js +1 -0
  46. package/dist/gateway/static/root/assets/sessions-page-CptjDKAX.js +1 -0
  47. package/dist/gateway/static/root/assets/settings-advanced-gate-BctKqHcf.js +2 -0
  48. package/dist/gateway/static/root/assets/{settings-form-section-a0qGVOlr.js → settings-form-section-QJh5ruel.js} +1 -1
  49. package/dist/gateway/static/root/assets/settings-page-V3p-hISB.js +2 -0
  50. package/dist/gateway/static/root/assets/share-preview-page-DBsvvbmD.js +2 -0
  51. package/dist/gateway/static/root/assets/skills-page-q2zPUJAR.js +2 -0
  52. package/dist/gateway/static/root/assets/{theme-store-C0Ehmdo5.js → theme-store-ht5iswWS.js} +1 -1
  53. package/dist/gateway/static/root/assets/toast-z0toXu32.js +1 -0
  54. package/dist/gateway/static/root/assets/url-CWWpfkq1.js +3 -0
  55. package/dist/gateway/static/root/assets/{utils-DRQryzdn.js → utils-DhPv9xoB.js} +1 -1
  56. package/dist/gateway/static/root/assets/vendor-codemirror-DYoKfS8f.js +45 -0
  57. package/dist/gateway/static/root/assets/voice-api-key-field-DLSKUipa.js +1 -0
  58. package/dist/gateway/static/root/assets/{workflow-page.utils-DnG8JBhV.js → workflow-page.utils-CJqnPWkW.js} +1 -1
  59. package/dist/gateway/static/root/assets/workflows-page-DRRQ1A0l.js +27 -0
  60. package/dist/gateway/static/root/index.html +10 -8
  61. package/dist/package.js +1 -1
  62. package/dist/src/agent/agent-manager.js +7 -7
  63. package/dist/src/agent/agent-scope.js +1 -1
  64. package/dist/src/agent/bootstrap/load-bootstrap-files.js +1 -1
  65. package/dist/src/agent/context/workspace-seed.js +2 -2
  66. package/dist/src/agent/goals/goal-run-store.js +4 -4
  67. package/dist/src/agent/goals/persistent-goal-service.js +1 -1
  68. package/dist/src/agent/goals/post-turn.js +2 -2
  69. package/dist/src/agent/image/load-image-media.js +2 -2
  70. package/dist/src/agent/ipc/bus.js +1 -1
  71. package/dist/src/agent/ipc/inbox.js +2 -2
  72. package/dist/src/agent/ipc/socket.js +1 -1
  73. package/dist/src/agent/mcp/bundle-mcp-config.d.ts +2 -9
  74. package/dist/src/agent/mcp/bundle-mcp-config.js +10 -34
  75. package/dist/src/agent/mcp/bundle-mcp-config.js.map +1 -1
  76. package/dist/src/agent/mcp/bundle-mcp-materialize.js +1 -1
  77. package/dist/src/agent/mcp/bundle-mcp-policy.js +2 -2
  78. package/dist/src/agent/mcp/bundle-mcp-policy.js.map +1 -1
  79. package/dist/src/agent/mcp/bundle-mcp-runtime.js +5 -5
  80. package/dist/src/agent/mcp/bundle-mcp-runtime.js.map +1 -1
  81. package/dist/src/agent/mcp/index.js +2 -2
  82. package/dist/src/agent/mcp/mcp-transport-config.js +1 -1
  83. package/dist/src/agent/mcp/mcp-transport.js +1 -1
  84. package/dist/src/agent/memory/builtin-memory-store.js +1 -1
  85. package/dist/src/agent/memory/dreaming/deep-promotion.js +1 -1
  86. package/dist/src/agent/memory/dreaming/events.js +1 -1
  87. package/dist/src/agent/memory/dreaming/last-run.js +1 -1
  88. package/dist/src/agent/memory/dreaming/light-sweep.js +1 -1
  89. package/dist/src/agent/memory/dreaming/preview.js +1 -1
  90. package/dist/src/agent/memory/dreaming/rem-patterns.js +1 -1
  91. package/dist/src/agent/memory/dreaming/short-term-store.js +1 -1
  92. package/dist/src/agent/memory/dreaming/utils.js +1 -1
  93. package/dist/src/agent/memory/plugin-discovery.js +1 -1
  94. package/dist/src/agent/models/manager.js +1 -1
  95. package/dist/src/agent/prompt/service-prompt-builder.js +2 -2
  96. package/dist/src/agent/reply/post-compaction-context.js +1 -1
  97. package/dist/src/agent/reply/workspace-boundary-read.js +1 -1
  98. package/dist/src/agent/sandbox/path-policy.js +2 -2
  99. package/dist/src/agent/service/build-direct-message-content.js +1 -1
  100. package/dist/src/agent/service.js +4 -4
  101. package/dist/src/agent/session/session-inspector.js +1 -1
  102. package/dist/src/agent/skills/config.js +1 -1
  103. package/dist/src/agent/skills/hub-hash.js +2 -2
  104. package/dist/src/agent/skills/hub-lock.js +1 -1
  105. package/dist/src/agent/skills/hub-pull.js +2 -2
  106. package/dist/src/agent/skills/index.js +1 -1
  107. package/dist/src/agent/skills/managed-store.js +1 -1
  108. package/dist/src/agent/skills/scanner.js +1 -1
  109. package/dist/src/agent/skills/skill-manage-ops.js +1 -1
  110. package/dist/src/agent/skills/skill-manager.js +1 -1
  111. package/dist/src/agent/tools/dreaming-tool.js +1 -1
  112. package/dist/src/agent/tools/factory.js +1 -1
  113. package/dist/src/agent/tools/image-generate-tool.js +1 -1
  114. package/dist/src/agent/tools/send-media.js +1 -1
  115. package/dist/src/agent/tools/skill-manage-tool.js +1 -1
  116. package/dist/src/agent/tools/workflow-tool.js +1 -1
  117. package/dist/src/agent/tools/write.js +1 -1
  118. package/dist/src/agent/workflow/catalog.js +1 -1
  119. package/dist/src/auth/credentials.js +3 -3
  120. package/dist/src/auth/profiles/store.js +1 -1
  121. package/dist/src/auth/sync-provider-auth.js +1 -1
  122. package/dist/src/browser/cache-dir-policy.js +1 -1
  123. package/dist/src/browser/cdp-local-launcher.js +2 -2
  124. package/dist/src/browser/providers/browser-ext-install.js +3 -3
  125. package/dist/src/browser/providers/cloakbrowser.js +4 -4
  126. package/dist/src/browser/providers/playwright-doctor.js +1 -1
  127. package/dist/src/browser/stealth.js +1 -1
  128. package/dist/src/channels/attachments/inbound-persist.js +1 -1
  129. package/dist/src/channels/attachments/outbound-tts-persist.js +1 -1
  130. package/dist/src/channels/outbound/persist-store.js +1 -1
  131. package/dist/src/channels/pairing/allow-from-file.js +1 -1
  132. package/dist/src/channels/pairing/pairing-store.js +2 -2
  133. package/dist/src/chat-commands/agent-edit.js +2 -2
  134. package/dist/src/chat-commands/builtins/config.js +2 -2
  135. package/dist/src/chat-commands/context.js +1 -1
  136. package/dist/src/cli/command-catalog.js +0 -4
  137. package/dist/src/cli/command-catalog.js.map +1 -1
  138. package/dist/src/cli/command-loaders.js +1 -2
  139. package/dist/src/cli/command-loaders.js.map +1 -1
  140. package/dist/src/cli/command-manifest.js +0 -4
  141. package/dist/src/cli/command-manifest.js.map +1 -1
  142. package/dist/src/cli/commands/config.js +1 -1
  143. package/dist/src/cli/commands/doctor/checks/config-health.js +1 -1
  144. package/dist/src/cli/commands/doctor/checks/provider-auth.js +1 -1
  145. package/dist/src/cli/commands/doctor/checks/session-integrity.js +2 -2
  146. package/dist/src/cli/commands/doctor/checks/state-integrity.js +1 -1
  147. package/dist/src/cli/commands/doctor/checks/workspace-status.js +1 -1
  148. package/dist/src/cli/commands/extension-dev.js +1 -1
  149. package/dist/src/cli/commands/extension-marketplace.js +1 -1
  150. package/dist/src/cli/commands/extension-pack.js +1 -1
  151. package/dist/src/cli/commands/gateway/logs.js +1 -1
  152. package/dist/src/cli/commands/image.js +1 -1
  153. package/dist/src/cli/commands/init.js +4 -4
  154. package/dist/src/cli/commands/onboard.js +1 -1
  155. package/dist/src/cli/utils/init-workspace-core.js +2 -2
  156. package/dist/src/commands/agents.config.js +1 -1
  157. package/dist/src/config/agent-profile.js +1 -1
  158. package/dist/src/config/gateway-bind.js +1 -1
  159. package/dist/src/config/index.d.ts +0 -1
  160. package/dist/src/config/index.js +6 -7
  161. package/dist/src/config/index.js.map +1 -1
  162. package/dist/src/config/loader.js +2 -2
  163. package/dist/src/config/models-json.js +2 -2
  164. package/dist/src/config/paths-state.js +1 -1
  165. package/dist/src/config/profile.js +2 -2
  166. package/dist/src/config/schema.d.ts +36 -6
  167. package/dist/src/config/schema.js +13 -11
  168. package/dist/src/config/schema.js.map +1 -1
  169. package/dist/src/config/workspace-path.js +1 -1
  170. package/dist/src/connectors/builtin-catalog.d.ts +2 -0
  171. package/dist/src/connectors/builtin-catalog.js +152 -0
  172. package/dist/src/connectors/builtin-catalog.js.map +1 -0
  173. package/dist/src/connectors/catalog.d.ts +5 -0
  174. package/dist/src/connectors/catalog.js +13 -0
  175. package/dist/src/connectors/catalog.js.map +1 -0
  176. package/dist/src/connectors/health.d.ts +3 -0
  177. package/dist/src/connectors/health.js +61 -0
  178. package/dist/src/connectors/health.js.map +1 -0
  179. package/dist/src/connectors/install.d.ts +5 -0
  180. package/dist/src/connectors/install.js +46 -0
  181. package/dist/src/connectors/install.js.map +1 -0
  182. package/dist/src/connectors/instances.d.ts +4 -0
  183. package/dist/src/connectors/instances.js +43 -0
  184. package/dist/src/connectors/instances.js.map +1 -0
  185. package/dist/src/connectors/materialize.d.ts +9 -0
  186. package/dist/src/connectors/materialize.js +76 -0
  187. package/dist/src/connectors/materialize.js.map +1 -0
  188. package/dist/src/connectors/oauth.d.ts +22 -0
  189. package/dist/src/connectors/oauth.js +99 -0
  190. package/dist/src/connectors/oauth.js.map +1 -0
  191. package/dist/src/connectors/providers.d.ts +9 -0
  192. package/dist/src/connectors/providers.js +20 -0
  193. package/dist/src/connectors/providers.js.map +1 -0
  194. package/dist/src/connectors/secret-store.d.ts +7 -0
  195. package/dist/src/connectors/secret-store.js +47 -0
  196. package/dist/src/connectors/secret-store.js.map +1 -0
  197. package/dist/src/connectors/types.d.ts +102 -0
  198. package/dist/src/connectors/types.js +1 -0
  199. package/dist/src/connectors/usage.d.ts +6 -0
  200. package/dist/src/connectors/usage.js +63 -0
  201. package/dist/src/connectors/usage.js.map +1 -0
  202. package/dist/src/cron/executor.js +2 -2
  203. package/dist/src/cron/persistence.js +1 -1
  204. package/dist/src/cron/run-log-store.js +1 -1
  205. package/dist/src/daemon/constants.js +1 -1
  206. package/dist/src/daemon/install-plan.js +2 -2
  207. package/dist/src/daemon/launchd.js +2 -2
  208. package/dist/src/daemon/schtasks.js +2 -2
  209. package/dist/src/daemon/systemd.js +2 -2
  210. package/dist/src/extensions/bundle-mcp.js +1 -1
  211. package/dist/src/extensions/discover-extensions.js +1 -1
  212. package/dist/src/extensions/health.js +1 -1
  213. package/dist/src/extensions/loader.js +1 -1
  214. package/dist/src/extensions/lockfile.js +2 -2
  215. package/dist/src/extensions/update.js +1 -1
  216. package/dist/src/gateway/agents-admin.js +3 -3
  217. package/dist/src/gateway/file-path-classifier.js +2 -2
  218. package/dist/src/gateway/heartbeat/service.js +1 -1
  219. package/dist/src/gateway/hono/lib/config-payload.d.ts +1 -0
  220. package/dist/src/gateway/hono/lib/config-payload.js +2 -1
  221. package/dist/src/gateway/hono/lib/config-payload.js.map +1 -1
  222. package/dist/src/gateway/hono/lib/extension-store.js +2 -2
  223. package/dist/src/gateway/hono/lib/static-ui.js +2 -2
  224. package/dist/src/gateway/hono/middleware/auth.js +1 -2
  225. package/dist/src/gateway/hono/middleware/auth.js.map +1 -1
  226. package/dist/src/gateway/hono/oauth.js +1 -1
  227. package/dist/src/gateway/hono/routes/agents.js +1 -1
  228. package/dist/src/gateway/hono/routes/auth-registry-extensions.js +1 -1
  229. package/dist/src/gateway/hono/routes/config-patch/gateway.d.ts +2 -2
  230. package/dist/src/gateway/hono/routes/config-patch/gateway.js +12 -0
  231. package/dist/src/gateway/hono/routes/config-patch/gateway.js.map +1 -1
  232. package/dist/src/gateway/hono/routes/config-patch/misc.js +1 -1
  233. package/dist/src/gateway/hono/routes/connectors.d.ts +3 -0
  234. package/dist/src/gateway/hono/routes/connectors.js +177 -0
  235. package/dist/src/gateway/hono/routes/connectors.js.map +1 -0
  236. package/dist/src/gateway/hono/routes/dreaming.js +1 -1
  237. package/dist/src/gateway/hono/routes/home.d.ts +12 -0
  238. package/dist/src/gateway/hono/routes/home.js +50 -0
  239. package/dist/src/gateway/hono/routes/home.js.map +1 -0
  240. package/dist/src/gateway/hono/routes/host-fs.js +2 -2
  241. package/dist/src/gateway/hono/routes/lazy-bundles.js +20 -4
  242. package/dist/src/gateway/hono/routes/lazy-bundles.js.map +1 -1
  243. package/dist/src/gateway/hono/routes/models.js +1 -1
  244. package/dist/src/gateway/hono/routes/notes.d.ts +3 -0
  245. package/dist/src/gateway/hono/routes/notes.js +305 -0
  246. package/dist/src/gateway/hono/routes/notes.js.map +1 -0
  247. package/dist/src/gateway/hono/routes/sessions.js.map +1 -1
  248. package/dist/src/gateway/hono/routes/shares.js +1 -1
  249. package/dist/src/gateway/hono/routes/workspace.js +4 -4
  250. package/dist/src/gateway/lock.js +3 -3
  251. package/dist/src/gateway/ports.js +1 -1
  252. package/dist/src/gateway/service/agent-runner.js +2 -2
  253. package/dist/src/gateway/service/marketplace-service.js +2 -2
  254. package/dist/src/gateway/service.d.ts +3 -0
  255. package/dist/src/gateway/service.js +11 -1
  256. package/dist/src/gateway/service.js.map +1 -1
  257. package/dist/src/gateway/workspace-fs-file-list.js +1 -1
  258. package/dist/src/gateway/workspace-ripgrep.d.ts +6 -0
  259. package/dist/src/gateway/workspace-ripgrep.js +62 -11
  260. package/dist/src/gateway/workspace-ripgrep.js.map +1 -1
  261. package/dist/src/heartbeat/index.js +1 -1
  262. package/dist/src/infra/brew.js +1 -1
  263. package/dist/src/infra/package-json.js +1 -1
  264. package/dist/src/infra/package-update-steps.js +1 -1
  265. package/dist/src/infra/path-env.js +2 -2
  266. package/dist/src/infra/restart.js +2 -2
  267. package/dist/src/infra/stable-node-path.js +1 -1
  268. package/dist/src/infra/update-check.js +1 -1
  269. package/dist/src/infra/update-global.js +1 -1
  270. package/dist/src/infra/update-lock.js +3 -3
  271. package/dist/src/infra/update-runner.js +1 -1
  272. package/dist/src/infra/update-startup.js +2 -2
  273. package/dist/src/infra/write-file-atomic.js +2 -2
  274. package/dist/src/mcp/channel-bridge.js +1 -1
  275. package/dist/src/mcp/channel-bridge.js.map +1 -1
  276. package/dist/src/notes/attachment-ref.d.ts +9 -0
  277. package/dist/src/notes/attachment-ref.js +27 -0
  278. package/dist/src/notes/attachment-ref.js.map +1 -0
  279. package/dist/src/notes/index.d.ts +4 -0
  280. package/dist/src/notes/index.js +4 -0
  281. package/dist/src/notes/note-attachment-sync.d.ts +7 -0
  282. package/dist/src/notes/note-attachment-sync.js +46 -0
  283. package/dist/src/notes/note-attachment-sync.js.map +1 -0
  284. package/dist/src/notes/note-index-meta.d.ts +14 -0
  285. package/dist/src/notes/note-index-meta.js +87 -0
  286. package/dist/src/notes/note-index-meta.js.map +1 -0
  287. package/dist/src/notes/paths.d.ts +5 -0
  288. package/dist/src/notes/paths.js +23 -0
  289. package/dist/src/notes/paths.js.map +1 -0
  290. package/dist/src/notes/service.d.ts +53 -0
  291. package/dist/src/notes/service.js +373 -0
  292. package/dist/src/notes/service.js.map +1 -0
  293. package/dist/src/notes/store.d.ts +34 -0
  294. package/dist/src/notes/store.js +342 -0
  295. package/dist/src/notes/store.js.map +1 -0
  296. package/dist/src/notes/types.d.ts +199 -0
  297. package/dist/src/notes/types.js +1 -0
  298. package/dist/src/providers/auth-runtime/auth-profile-store.js +1 -1
  299. package/dist/src/providers/index.js +2 -2
  300. package/dist/src/providers/model-registry.js +1 -1
  301. package/dist/src/session/config-store.js +2 -2
  302. package/dist/src/session/init-session-turn.js +2 -2
  303. package/dist/src/session/parity/jsonl-transcript-io.js +2 -2
  304. package/dist/src/session/parity/sessions-json-file.js +1 -1
  305. package/dist/src/session/parity/transcript-file-lock.js +2 -2
  306. package/dist/src/session/parity/transcript-paths.js +1 -1
  307. package/dist/src/session/resolve-session.js +4 -4
  308. package/dist/src/session/search-index-cache.js +1 -1
  309. package/dist/src/session/search-index.js +1 -1
  310. package/dist/src/session/session-title.js +2 -2
  311. package/dist/src/session/store.d.ts +2 -0
  312. package/dist/src/session/store.js +27 -7
  313. package/dist/src/session/store.js.map +1 -1
  314. package/dist/src/share/share-auto.js +2 -2
  315. package/dist/src/share/share-store.js +3 -3
  316. package/dist/src/share/share-thumbnail.js +2 -2
  317. package/dist/src/share/share-zip.js +1 -1
  318. package/dist/src/share/site-share-store.js +3 -3
  319. package/dist/src/share/site-static-serve.js +1 -1
  320. package/dist/src/tui/clipboard-image.js +3 -3
  321. package/dist/src/tui/theme-manager.js +1 -1
  322. package/dist/src/tui/tui-keybindings-file.js +1 -1
  323. package/dist/src/tui/tui-scoped-models.js +2 -2
  324. package/dist/src/tui/tui-settings.js +1 -1
  325. package/dist/src/tui/tui.js +3 -3
  326. package/dist/src/tunnel/frpc-binary.js +3 -3
  327. package/dist/src/tunnel/frpc-config.js +1 -1
  328. package/dist/src/tunnel/frpc-extract.js +1 -1
  329. package/dist/src/tunnel/tunnel-state.js +1 -1
  330. package/dist/src/utils/logger/audit.js +1 -1
  331. package/dist/src/utils/logger/log-store.js +1 -1
  332. package/dist/src/utils/logger/rotation.js +1 -1
  333. package/dist/src/voice/tts/audio.js +1 -1
  334. package/dist/src/voice/tts/providers/edge-speech.js +2 -2
  335. package/dist/src/workflows/store/event-store.js +1 -1
  336. package/dist/src/workflows/store/run-store.js +1 -1
  337. package/package.json +1 -1
  338. package/dist/gateway/static/root/assets/agents-cPvvYLXo.js +0 -222
  339. package/dist/gateway/static/root/assets/apps-page-Bk1_P5FJ.js +0 -1
  340. package/dist/gateway/static/root/assets/channels-settings-CZoeQwHz.js +0 -1
  341. package/dist/gateway/static/root/assets/cron-dreaming-jobs-Ip703-qM.js +0 -2
  342. package/dist/gateway/static/root/assets/cron-page-BpLdiQN8.js +0 -1
  343. package/dist/gateway/static/root/assets/dist-BTWC-BTN.js +0 -45
  344. package/dist/gateway/static/root/assets/dist-BpAiK86n.js +0 -1
  345. package/dist/gateway/static/root/assets/eye-DAfL1U7M.js +0 -1
  346. package/dist/gateway/static/root/assets/heartbeat-config-api-DusckjUX.js +0 -1
  347. package/dist/gateway/static/root/assets/index-V7MQ7834.css +0 -1
  348. package/dist/gateway/static/root/assets/logs-page-_HcZ2fgK.js +0 -1
  349. package/dist/gateway/static/root/assets/sessions-page-iezSMjho.js +0 -1
  350. package/dist/gateway/static/root/assets/settings-page-C9_nYQwM.js +0 -3
  351. package/dist/gateway/static/root/assets/share-preview-page-DExl7CJy.js +0 -2
  352. package/dist/gateway/static/root/assets/skills-page-BlgGD93t.js +0 -2
  353. package/dist/gateway/static/root/assets/url-fxyYANfA.js +0 -3
  354. package/dist/gateway/static/root/assets/vendor-codemirror-D0yxdRpg.js +0 -58
  355. package/dist/gateway/static/root/assets/voice-api-key-field-D0viACE2.js +0 -1
  356. package/dist/gateway/static/root/assets/workflows-page-BvMobnJP.js +0 -27
  357. package/dist/src/cli/commands/mcp.d.ts +0 -4
  358. package/dist/src/cli/commands/mcp.js +0 -85
  359. package/dist/src/cli/commands/mcp.js.map +0 -1
  360. package/dist/src/config/mcp-config.d.ts +0 -34
  361. package/dist/src/config/mcp-config.js +0 -116
  362. package/dist/src/config/mcp-config.js.map +0 -1
  363. package/dist/src/gateway/hono/routes/mcp.d.ts +0 -3
  364. package/dist/src/gateway/hono/routes/mcp.js +0 -99
  365. package/dist/src/gateway/hono/routes/mcp.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"auth.js","names":[],"sources":["../../../../../src/gateway/hono/middleware/auth.ts"],"sourcesContent":["import { createMiddleware } from 'hono/factory';\nimport type { Context } from 'hono';\nimport { getConnInfo } from '@hono/node-server/conninfo';\n\nimport type { GatewayAuthConfig } from '../../../config/schema.js';\nimport type { ResolvedGatewayAuth } from '../../auth.js';\nimport { resolveClientIpFromRequest } from '../../client-ip.js';\nimport {\n authPolicyConfig,\n buckets,\n isAuthRateLimitGloballyDisabled,\n resolveAuthRateLimit,\n resolveAuthTracking,\n type ResolvedAuthRateLimitConfig,\n} from '../../rate-limit/index.js';\nimport { getClientIpFromHeaders } from '../../security/loopback.js';\nimport { safeEqualSecret } from '../../security/secret-equal.js';\nimport { authorizeTrustedProxy } from '../../trusted-proxy.js';\nimport { createLogger } from '../../../utils/logger.js';\n\nconst log = createLogger('Hono:Auth');\n\nexport interface AuthConfig {\n token?: string;\n /** Current gateway auth from config (for rate-limit settings); optional. */\n getGatewayAuth?: () => GatewayAuthConfig | undefined;\n getResolvedAuth?: () => ResolvedGatewayAuth;\n getTrustedProxyContext?: () => {\n trustedProxies?: string[];\n allowRealIpFallback?: boolean;\n };\n}\n\nfunction validateToken(providedToken: string | undefined, expectedToken: string): boolean {\n if (!providedToken) return false;\n return safeEqualSecret(providedToken, expectedToken);\n}\n\nfunction extractTokenFromHeader(authHeader: string | null): string | null {\n if (!authHeader) return null;\n const parts = authHeader.split(' ');\n if (parts.length === 2 && parts[0].toLowerCase() === 'bearer') return parts[1];\n return authHeader;\n}\n\n/**\n * SECURITY: query-string tokens leak into server logs, Referer headers, and\n * browser history. We accept them only where the `Authorization` header cannot\n * be set — SSE/WebSocket (`EventSource`) and `<img>` subresource loads for agent\n * avatars. For normal REST requests prefer the `Authorization: Bearer <token>`\n * header.\n */\nfunction extractTokenFromQuery(url: string): string | null {\n return new URL(url).searchParams.get('token');\n}\n\nconst QUERY_TOKEN_ALLOWED_PATHS = new Set(['/api/events', '/api/ws']);\n\nconst AGENT_AVATAR_GET_PATH = /^\\/api\\/agents\\/[^/]+\\/avatar$/;\n\n/** Exported for gateway security tests. */\nexport function isQueryTokenAllowedPath(path: string, method: string): boolean {\n if (QUERY_TOKEN_ALLOWED_PATHS.has(path) || path.startsWith('/api/events')) {\n return true;\n }\n // `<img src>` cannot send Bearer tokens; gateway console loads custom avatars here.\n if (method === 'GET' && AGENT_AVATAR_GET_PATH.test(path)) {\n return true;\n }\n return false;\n}\n\nfunction resolveRemoteAddress(c: Context): string | undefined {\n try {\n return getConnInfo(c).remote.address;\n } catch {\n return undefined;\n }\n}\n\nfunction resolveMiddlewareClientIp(\n c: Context,\n trustedProxies?: string[],\n allowRealIpFallback?: boolean,\n): string {\n if (trustedProxies?.length) {\n return resolveClientIpFromRequest({\n remoteAddress: resolveRemoteAddress(c),\n getHeader: (name) => c.req.header(name),\n trustedProxies,\n allowRealIpFallback,\n });\n }\n return getClientIpFromHeaders({\n get: (name: string) => c.req.header(name) ?? undefined,\n });\n}\n\ntype RateLimitContext = {\n active: boolean;\n cfg: ResolvedAuthRateLimitConfig;\n /** `undefined` when the client is exempted (loopback, disabled, etc.). */\n trackingKey: string | undefined;\n};\n\nfunction buildRateLimitContext(\n getGatewayAuth: AuthConfig['getGatewayAuth'],\n clientIp: string,\n origin: string | undefined,\n): RateLimitContext {\n const cfg = resolveAuthRateLimit(getGatewayAuth?.()?.rateLimit);\n const active = cfg.enabled && !isAuthRateLimitGloballyDisabled();\n if (!active) return { active: false, cfg, trackingKey: undefined };\n const tracking = resolveAuthTracking({ clientIp, origin, cfg: authPolicyConfig(cfg) });\n return {\n active: true,\n cfg,\n trackingKey: tracking.exempt ? undefined : tracking.key,\n };\n}\n\nfunction checkBlocked(rl: RateLimitContext): { blocked: false } | { blocked: true; retryAfterSec: number } {\n if (!rl.active || rl.trackingKey === undefined) return { blocked: false };\n return buckets.authFailure(rl.cfg).check(rl.trackingKey);\n}\n\nfunction recordFailure(rl: RateLimitContext): void {\n if (!rl.active || rl.trackingKey === undefined) return;\n buckets.authFailure(rl.cfg).fail(rl.trackingKey);\n}\n\nfunction recordSuccess(rl: RateLimitContext): void {\n if (!rl.active || rl.trackingKey === undefined) return;\n buckets.authFailure(rl.cfg).succeed(rl.trackingKey);\n}\n\nfunction blockedResponse(c: Context, retryAfterSec: number) {\n c.header('Retry-After', String(retryAfterSec));\n return c.json(\n {\n error: 'Too Many Requests',\n code: 'auth_blocked',\n message: 'Too many authentication attempts',\n retryAfter: retryAfterSec,\n },\n 429,\n );\n}\n\nexport function auth(config?: AuthConfig) {\n const { token, getGatewayAuth, getResolvedAuth, getTrustedProxyContext } = config || {};\n\n return createMiddleware(async (c, next) => {\n const resolvedAuth = getResolvedAuth?.();\n const authMode = resolvedAuth?.mode ?? (token ? 'token' : 'none');\n\n if (authMode === 'trusted-proxy') {\n const proxyContext = getTrustedProxyContext?.();\n const trustedProxies = proxyContext?.trustedProxies;\n const trustedProxyConfig = resolvedAuth?.trustedProxy;\n\n const clientIp = resolveMiddlewareClientIp(c, trustedProxies, proxyContext?.allowRealIpFallback);\n const origin = c.req.header('origin');\n const rl = buildRateLimitContext(getGatewayAuth, clientIp, origin);\n\n // Server misconfiguration — not an attack signal. Don't count.\n if (!trustedProxyConfig) {\n log.warn(\n { path: c.req.path, method: c.req.method, clientIp, reason: 'trusted_proxy_config_missing' },\n 'HTTP auth rejected: trusted-proxy config missing',\n );\n return c.json(\n { error: 'Unauthorized', code: 'auth_unconfigured', message: 'Trusted-proxy auth is not configured' },\n 401,\n );\n }\n\n const blocked = checkBlocked(rl);\n if (blocked.blocked) {\n log.warn(\n { clientIp, origin: origin ?? undefined, path: c.req.path, method: c.req.method, retryAfterSec: blocked.retryAfterSec, reason: 'auth_blocked' },\n 'Auth rate limit blocked',\n );\n return blockedResponse(c, blocked.retryAfterSec);\n }\n\n const result = authorizeTrustedProxy({\n remoteAddress: resolveRemoteAddress(c),\n getHeader: (name) => c.req.header(name),\n trustedProxies,\n trustedProxyConfig,\n });\n\n if (result.ok === false) {\n recordFailure(rl);\n log.warn(\n { path: c.req.path, method: c.req.method, clientIp, reason: result.reason },\n `HTTP auth rejected: trusted-proxy validation failed (${result.reason})`,\n );\n return c.json(\n { error: 'Unauthorized', code: 'invalid_proxy_credentials', message: 'Trusted-proxy authentication failed' },\n 401,\n );\n }\n\n recordSuccess(rl);\n await next();\n return;\n }\n\n if (authMode === 'none' || !token) {\n return next();\n }\n\n const proxyContext = getTrustedProxyContext?.();\n const clientIp = resolveMiddlewareClientIp(c, proxyContext?.trustedProxies, proxyContext?.allowRealIpFallback);\n const origin = c.req.header('origin');\n const rl = buildRateLimitContext(getGatewayAuth, clientIp, origin);\n\n const authHeader = extractTokenFromHeader(c.req.header('authorization'));\n const requestPath = new URL(c.req.url).pathname;\n const queryToken = isQueryTokenAllowedPath(requestPath, c.req.method)\n ? extractTokenFromQuery(c.req.url)\n : null;\n\n if (!authHeader && queryToken === null && new URL(c.req.url).searchParams.has('token')) {\n log.warn(\n { path: requestPath, method: c.req.method, clientIp },\n 'Token in query string rejected: use Authorization header for this endpoint',\n );\n }\n\n const providedToken = authHeader || queryToken;\n\n if (providedToken && validateToken(providedToken, token)) {\n recordSuccess(rl);\n await next();\n return;\n }\n\n const blocked = checkBlocked(rl);\n if (blocked.blocked) {\n log.warn(\n { clientIp, origin: origin ?? undefined, path: requestPath, method: c.req.method, retryAfterSec: blocked.retryAfterSec, reason: 'auth_blocked' },\n 'Auth rate limit blocked',\n );\n return blockedResponse(c, blocked.retryAfterSec);\n }\n\n // Missing token is an unauthenticated request, not a brute-force signal —\n // page reloads / SDK cold starts often hit endpoints before the token is\n // attached. Counting this would lock users out of the token-entry path.\n if (!providedToken) {\n log.warn(\n { path: c.req.path, method: c.req.method, clientIp, reason: 'missing_token' },\n 'HTTP auth rejected: no Bearer or ?token=',\n );\n return c.json(\n { error: 'Unauthorized', code: 'missing_token', message: 'Missing authentication token' },\n 401,\n );\n }\n\n recordFailure(rl);\n log.warn(\n { path: c.req.path, method: c.req.method, clientIp, reason: 'invalid_token' },\n 'HTTP auth rejected: token mismatch',\n );\n return c.json(\n { error: 'Unauthorized', code: 'invalid_token', message: 'Invalid authentication token' },\n 401,\n );\n });\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"auth.js","names":[],"sources":["../../../../../src/gateway/hono/middleware/auth.ts"],"sourcesContent":["import { createMiddleware } from 'hono/factory';\nimport type { Context } from 'hono';\nimport { getConnInfo } from '@hono/node-server/conninfo';\n\nimport type { GatewayAuthConfig } from '../../../config/schema.js';\nimport type { ResolvedGatewayAuth } from '../../auth.js';\nimport { resolveClientIpFromRequest } from '../../client-ip.js';\nimport {\n authPolicyConfig,\n buckets,\n isAuthRateLimitGloballyDisabled,\n resolveAuthRateLimit,\n resolveAuthTracking,\n type ResolvedAuthRateLimitConfig,\n} from '../../rate-limit/index.js';\nimport { getClientIpFromHeaders } from '../../security/loopback.js';\nimport { safeEqualSecret } from '../../security/secret-equal.js';\nimport { authorizeTrustedProxy } from '../../trusted-proxy.js';\nimport { createLogger } from '../../../utils/logger.js';\n\nconst log = createLogger('Hono:Auth');\n\nexport interface AuthConfig {\n token?: string;\n /** Current gateway auth from config (for rate-limit settings); optional. */\n getGatewayAuth?: () => GatewayAuthConfig | undefined;\n getResolvedAuth?: () => ResolvedGatewayAuth;\n getTrustedProxyContext?: () => {\n trustedProxies?: string[];\n allowRealIpFallback?: boolean;\n };\n}\n\nfunction validateToken(providedToken: string | undefined, expectedToken: string): boolean {\n if (!providedToken) return false;\n return safeEqualSecret(providedToken, expectedToken);\n}\n\nfunction extractTokenFromHeader(authHeader: string | null): string | null {\n if (!authHeader) return null;\n const parts = authHeader.split(' ');\n if (parts.length === 2 && parts[0].toLowerCase() === 'bearer') return parts[1];\n return authHeader;\n}\n\n/**\n * SECURITY: query-string tokens leak into server logs, Referer headers, and\n * browser history. We accept them only where the `Authorization` header cannot\n * be set — SSE/WebSocket (`EventSource`) and `<img>` subresource loads for agent\n * avatars. Note media uses Bearer-authenticated blob fetch in the gateway console.\n */\nfunction extractTokenFromQuery(url: string): string | null {\n return new URL(url).searchParams.get('token');\n}\n\nconst QUERY_TOKEN_ALLOWED_PATHS = new Set(['/api/events', '/api/ws']);\n\nconst AGENT_AVATAR_GET_PATH = /^\\/api\\/agents\\/[^/]+\\/avatar$/;\n\n/** Exported for gateway security tests. */\nexport function isQueryTokenAllowedPath(path: string, method: string): boolean {\n if (QUERY_TOKEN_ALLOWED_PATHS.has(path) || path.startsWith('/api/events')) {\n return true;\n }\n if (method === 'GET' && AGENT_AVATAR_GET_PATH.test(path)) {\n return true;\n }\n return false;\n}\n\nfunction resolveRemoteAddress(c: Context): string | undefined {\n try {\n return getConnInfo(c).remote.address;\n } catch {\n return undefined;\n }\n}\n\nfunction resolveMiddlewareClientIp(\n c: Context,\n trustedProxies?: string[],\n allowRealIpFallback?: boolean,\n): string {\n if (trustedProxies?.length) {\n return resolveClientIpFromRequest({\n remoteAddress: resolveRemoteAddress(c),\n getHeader: (name) => c.req.header(name),\n trustedProxies,\n allowRealIpFallback,\n });\n }\n return getClientIpFromHeaders({\n get: (name: string) => c.req.header(name) ?? undefined,\n });\n}\n\ntype RateLimitContext = {\n active: boolean;\n cfg: ResolvedAuthRateLimitConfig;\n /** `undefined` when the client is exempted (loopback, disabled, etc.). */\n trackingKey: string | undefined;\n};\n\nfunction buildRateLimitContext(\n getGatewayAuth: AuthConfig['getGatewayAuth'],\n clientIp: string,\n origin: string | undefined,\n): RateLimitContext {\n const cfg = resolveAuthRateLimit(getGatewayAuth?.()?.rateLimit);\n const active = cfg.enabled && !isAuthRateLimitGloballyDisabled();\n if (!active) return { active: false, cfg, trackingKey: undefined };\n const tracking = resolveAuthTracking({ clientIp, origin, cfg: authPolicyConfig(cfg) });\n return {\n active: true,\n cfg,\n trackingKey: tracking.exempt ? undefined : tracking.key,\n };\n}\n\nfunction checkBlocked(rl: RateLimitContext): { blocked: false } | { blocked: true; retryAfterSec: number } {\n if (!rl.active || rl.trackingKey === undefined) return { blocked: false };\n return buckets.authFailure(rl.cfg).check(rl.trackingKey);\n}\n\nfunction recordFailure(rl: RateLimitContext): void {\n if (!rl.active || rl.trackingKey === undefined) return;\n buckets.authFailure(rl.cfg).fail(rl.trackingKey);\n}\n\nfunction recordSuccess(rl: RateLimitContext): void {\n if (!rl.active || rl.trackingKey === undefined) return;\n buckets.authFailure(rl.cfg).succeed(rl.trackingKey);\n}\n\nfunction blockedResponse(c: Context, retryAfterSec: number) {\n c.header('Retry-After', String(retryAfterSec));\n return c.json(\n {\n error: 'Too Many Requests',\n code: 'auth_blocked',\n message: 'Too many authentication attempts',\n retryAfter: retryAfterSec,\n },\n 429,\n );\n}\n\nexport function auth(config?: AuthConfig) {\n const { token, getGatewayAuth, getResolvedAuth, getTrustedProxyContext } = config || {};\n\n return createMiddleware(async (c, next) => {\n const resolvedAuth = getResolvedAuth?.();\n const authMode = resolvedAuth?.mode ?? (token ? 'token' : 'none');\n\n if (authMode === 'trusted-proxy') {\n const proxyContext = getTrustedProxyContext?.();\n const trustedProxies = proxyContext?.trustedProxies;\n const trustedProxyConfig = resolvedAuth?.trustedProxy;\n\n const clientIp = resolveMiddlewareClientIp(c, trustedProxies, proxyContext?.allowRealIpFallback);\n const origin = c.req.header('origin');\n const rl = buildRateLimitContext(getGatewayAuth, clientIp, origin);\n\n // Server misconfiguration — not an attack signal. Don't count.\n if (!trustedProxyConfig) {\n log.warn(\n { path: c.req.path, method: c.req.method, clientIp, reason: 'trusted_proxy_config_missing' },\n 'HTTP auth rejected: trusted-proxy config missing',\n );\n return c.json(\n { error: 'Unauthorized', code: 'auth_unconfigured', message: 'Trusted-proxy auth is not configured' },\n 401,\n );\n }\n\n const blocked = checkBlocked(rl);\n if (blocked.blocked) {\n log.warn(\n { clientIp, origin: origin ?? undefined, path: c.req.path, method: c.req.method, retryAfterSec: blocked.retryAfterSec, reason: 'auth_blocked' },\n 'Auth rate limit blocked',\n );\n return blockedResponse(c, blocked.retryAfterSec);\n }\n\n const result = authorizeTrustedProxy({\n remoteAddress: resolveRemoteAddress(c),\n getHeader: (name) => c.req.header(name),\n trustedProxies,\n trustedProxyConfig,\n });\n\n if (result.ok === false) {\n recordFailure(rl);\n log.warn(\n { path: c.req.path, method: c.req.method, clientIp, reason: result.reason },\n `HTTP auth rejected: trusted-proxy validation failed (${result.reason})`,\n );\n return c.json(\n { error: 'Unauthorized', code: 'invalid_proxy_credentials', message: 'Trusted-proxy authentication failed' },\n 401,\n );\n }\n\n recordSuccess(rl);\n await next();\n return;\n }\n\n if (authMode === 'none' || !token) {\n return next();\n }\n\n const proxyContext = getTrustedProxyContext?.();\n const clientIp = resolveMiddlewareClientIp(c, proxyContext?.trustedProxies, proxyContext?.allowRealIpFallback);\n const origin = c.req.header('origin');\n const rl = buildRateLimitContext(getGatewayAuth, clientIp, origin);\n\n const authHeader = extractTokenFromHeader(c.req.header('authorization'));\n const requestPath = new URL(c.req.url).pathname;\n const queryToken = isQueryTokenAllowedPath(requestPath, c.req.method)\n ? extractTokenFromQuery(c.req.url)\n : null;\n\n if (!authHeader && queryToken === null && new URL(c.req.url).searchParams.has('token')) {\n log.warn(\n { path: requestPath, method: c.req.method, clientIp },\n 'Token in query string rejected: use Authorization header for this endpoint',\n );\n }\n\n const providedToken = authHeader || queryToken;\n\n if (providedToken && validateToken(providedToken, token)) {\n recordSuccess(rl);\n await next();\n return;\n }\n\n const blocked = checkBlocked(rl);\n if (blocked.blocked) {\n log.warn(\n { clientIp, origin: origin ?? undefined, path: requestPath, method: c.req.method, retryAfterSec: blocked.retryAfterSec, reason: 'auth_blocked' },\n 'Auth rate limit blocked',\n );\n return blockedResponse(c, blocked.retryAfterSec);\n }\n\n // Missing token is an unauthenticated request, not a brute-force signal —\n // page reloads / SDK cold starts often hit endpoints before the token is\n // attached. Counting this would lock users out of the token-entry path.\n if (!providedToken) {\n log.warn(\n { path: c.req.path, method: c.req.method, clientIp, reason: 'missing_token' },\n 'HTTP auth rejected: no Bearer or ?token=',\n );\n return c.json(\n { error: 'Unauthorized', code: 'missing_token', message: 'Missing authentication token' },\n 401,\n );\n }\n\n recordFailure(rl);\n log.warn(\n { path: c.req.path, method: c.req.method, clientIp, reason: 'invalid_token' },\n 'HTTP auth rejected: token mismatch',\n );\n return c.json(\n { error: 'Unauthorized', code: 'invalid_token', message: 'Invalid authentication token' },\n 401,\n );\n });\n}\n"],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  import { CredentialResolver, init_credentials } from "../../auth/credentials.js";
2
- import { anthropicOAuthProvider } from "../../auth/oauth/anthropic.js";
3
2
  import { getProviderAuthState, init_providers, isProviderConfigured } from "../../providers/index.js";
3
+ import { anthropicOAuthProvider } from "../../auth/oauth/anthropic.js";
4
4
  import { minimaxOAuthProvider } from "../../auth/oauth/minimax.js";
5
5
  import { minimaxCnOAuthProvider } from "../../auth/oauth/minimax-cn.js";
6
6
  import { kimiCodingOAuthProvider } from "../../auth/oauth/kimi-coding.js";
@@ -1,6 +1,6 @@
1
- import { init_agent_scope, normalizeAgentId } from "../../../agent/agent-scope.js";
2
1
  import { init_localized_text, normalizeLocalizedText } from "../../../config/localized-text.js";
3
2
  import { init_schema, parseModelRef } from "../../../config/schema.js";
3
+ import { init_agent_scope, normalizeAgentId } from "../../../agent/agent-scope.js";
4
4
  import { init_providers, isProviderConfigured, resolveModel } from "../../../providers/index.js";
5
5
  import { getVoiceModelsConfig } from "../../../config/voice.js";
6
6
  import { deleteAgentAvatarFile, finalizeCreateAgentDirs, listAgentProfileFiles, listGatewayAgents, prepareCreateAgent, prepareCreateAgentsBatch, prepareDeleteAgent, prepareUpdateAgent, readAgentAvatarFile, readAgentProfileFile, runAfterDeletePurge, writeAgentAvatarFromBase64, writeAgentProfileFile } from "../../agents-admin.js";
@@ -7,8 +7,8 @@ import { createOAuthHandler } from "../oauth.js";
7
7
  import { createOAuthAsyncHandler } from "../oauth-async.js";
8
8
  import { extensionAssetMimeType } from "../lib/extension-assets.js";
9
9
  import { loadExtensionStore, saveExtensionStore } from "../lib/extension-store.js";
10
- import { existsSync, readFileSync, statSync } from "node:fs";
11
10
  import { relative, resolve } from "node:path";
11
+ import { existsSync, readFileSync, statSync } from "node:fs";
12
12
  //#region src/gateway/hono/routes/auth-registry-extensions.ts
13
13
  init_providers();
14
14
  const EXTENSION_ASSET_CSP = "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob:; connect-src 'none'; frame-ancestors 'self'; frame-src 'none'; base-uri 'none'; object-src 'none'; form-action 'none'";
@@ -3,8 +3,8 @@
3
3
  *
4
4
  * Covers heartbeat, bind/customBindHost/port, tailscale, auth (mode + token +
5
5
  * password + rateLimit + trustedProxy), trustedProxies, allowRealIpFallback,
6
- * dangerouslyAllowHostHeaderOriginFallback, security, share, corsOrigins,
7
- * maxSseConnections, and channelConnectDefer{Mode,Ids,SkipIds}.
6
+ * dangerouslyAllowHostHeaderOriginFallback, security, share, publicUrl,
7
+ * corsOrigins, maxSseConnections, and channelConnectDefer{Mode,Ids,SkipIds}.
8
8
  *
9
9
  * Validation policy: each subsection that can reject rejects with a 400 and a
10
10
  * specific `message`. The dispatcher converts these into `c.json(...)`.
@@ -1,8 +1,10 @@
1
+ import { init_public_url, validatePublicUrl } from "../../../../config/public-url.js";
1
2
  import { isValidIPv4 } from "../../../../config/gateway-bind.js";
2
3
  import { mergeShareConfigPatch } from "../../../../share/share-config.js";
3
4
  import { isMaskedSecretPatchValue } from "../../lib/mask-secret-length.js";
4
5
  import { PATCH_OK, patchError } from "./result.js";
5
6
  //#region src/gateway/hono/routes/config-patch/gateway.ts
7
+ init_public_url();
6
8
  /**
7
9
  * Shared default for "user PATCH'd a gateway subsection but `config.gateway`
8
10
  * was never initialised". Identical to the inline literal repeated in the
@@ -219,6 +221,16 @@ function applyGatewayPatch(config, body) {
219
221
  const shareResult = mergeShareConfigPatch(config, body.gateway.share);
220
222
  if (shareResult.ok === false) return patchError(shareResult.message);
221
223
  }
224
+ if (body.gateway?.publicUrl !== void 0) {
225
+ const gw = ensureGateway(config);
226
+ if (body.gateway.publicUrl === null || body.gateway.publicUrl === "") delete gw.publicUrl;
227
+ else if (typeof body.gateway.publicUrl !== "string") return patchError("gateway.publicUrl must be a string or null");
228
+ else {
229
+ const validation = validatePublicUrl(body.gateway.publicUrl);
230
+ if (validation.ok === false) return patchError(`gateway.publicUrl: ${validation.message}`);
231
+ gw.publicUrl = validation.url;
232
+ }
233
+ }
222
234
  if (body.gateway?.corsOrigins !== void 0) {
223
235
  if (!Array.isArray(body.gateway.corsOrigins)) return patchError("gateway.corsOrigins must be an array");
224
236
  const gw = ensureGateway(config);
@@ -1 +1 @@
1
- {"version":3,"file":"gateway.js","names":[],"sources":["../../../../../../src/gateway/hono/routes/config-patch/gateway.ts"],"sourcesContent":["/**\n * `PATCH /api/config` — `body.gateway.*` section.\n *\n * Covers heartbeat, bind/customBindHost/port, tailscale, auth (mode + token +\n * password + rateLimit + trustedProxy), trustedProxies, allowRealIpFallback,\n * dangerouslyAllowHostHeaderOriginFallback, security, share, corsOrigins,\n * maxSseConnections, and channelConnectDefer{Mode,Ids,SkipIds}.\n *\n * Validation policy: each subsection that can reject rejects with a 400 and a\n * specific `message`. The dispatcher converts these into `c.json(...)`.\n *\n * Initial-state branches use the same literal defaults the inline code did\n * (loopback + port 18790 + 1800s heartbeat + 100 SSE conn + empty CORS) so\n * a brand-new install gets a working gateway after the first PATCH.\n */\nimport type { Config, GatewayBindMode } from '../../../../config/schema.js';\nimport { isValidIPv4 } from '../../../../config/gateway-bind.js';\nimport { mergeShareConfigPatch } from '../../../../share/share-config.js';\nimport { isMaskedSecretPatchValue } from '../../lib/mask-secret-length.js';\nimport { type PatchResult, PATCH_OK, patchError } from './result.js';\n\n/**\n * Shared default for \"user PATCH'd a gateway subsection but `config.gateway`\n * was never initialised\". Identical to the inline literal repeated in the\n * pre-extraction handler so this is behavior-preserving.\n */\nfunction ensureGateway(config: Config): NonNullable<Config['gateway']> {\n if (!config.gateway) {\n config.gateway = {\n bind: 'loopback',\n port: 18790,\n heartbeat: { enabled: true, intervalMs: 1_800_000, includeSystemPromptSection: false },\n maxSseConnections: 100,\n corsOrigins: [],\n };\n }\n return config.gateway;\n}\n\nfunction parseDeferIdList(raw: unknown): string[] | null {\n if (!Array.isArray(raw)) return null;\n const ids = raw\n .filter((x): x is string => typeof x === 'string' && x.trim().length > 0)\n .map((x) => x.trim());\n if (ids.length > 24) return null;\n return ids;\n}\n\nexport function applyGatewayPatch(config: Config, body: any): PatchResult {\n if (body.gateway?.heartbeat !== undefined && typeof body.gateway.heartbeat === 'object') {\n const gw = ensureGateway(config);\n if (!gw.heartbeat) {\n gw.heartbeat = { enabled: true, intervalMs: 1_800_000, includeSystemPromptSection: false };\n }\n const h = gw.heartbeat;\n const p = body.gateway.heartbeat as Record<string, unknown>;\n if (p.enabled !== undefined) h.enabled = Boolean(p.enabled);\n if (p.intervalMs !== undefined && typeof p.intervalMs === 'number' && Number.isFinite(p.intervalMs)) {\n h.intervalMs = p.intervalMs;\n }\n if (p.includeSystemPromptSection !== undefined) {\n h.includeSystemPromptSection = Boolean(p.includeSystemPromptSection);\n }\n if (p.target !== undefined) {\n if (p.target === null || p.target === '') delete (h as { target?: string }).target;\n else (h as { target?: string }).target = String(p.target);\n }\n if (p.targetChatId !== undefined) {\n if (p.targetChatId === null || p.targetChatId === '') delete (h as { targetChatId?: string }).targetChatId;\n else (h as { targetChatId?: string }).targetChatId = String(p.targetChatId);\n }\n if (p.prompt !== undefined) {\n if (p.prompt === null || p.prompt === '') delete (h as { prompt?: string }).prompt;\n else (h as { prompt?: string }).prompt = String(p.prompt);\n }\n if (p.ackMaxChars !== undefined) {\n if (p.ackMaxChars === null || p.ackMaxChars === '') delete (h as { ackMaxChars?: number }).ackMaxChars;\n else if (typeof p.ackMaxChars === 'number' && Number.isFinite(p.ackMaxChars)) {\n (h as { ackMaxChars?: number }).ackMaxChars = p.ackMaxChars;\n }\n }\n if (p.isolatedSession !== undefined) {\n if (p.isolatedSession === null || p.isolatedSession === false) {\n delete (h as { isolatedSession?: boolean }).isolatedSession;\n } else {\n (h as { isolatedSession?: boolean }).isolatedSession = Boolean(p.isolatedSession);\n }\n }\n if (p.activeHours !== undefined) {\n if (p.activeHours === null) {\n delete (h as { activeHours?: unknown }).activeHours;\n } else if (typeof p.activeHours === 'object' && p.activeHours !== null) {\n const ah = p.activeHours as Record<string, unknown>;\n const start = typeof ah.start === 'string' ? ah.start : '';\n const end = typeof ah.end === 'string' ? ah.end : '';\n if (start && end) {\n (h as { activeHours?: { start: string; end: string; timezone?: string } }).activeHours = {\n start,\n end,\n ...(typeof ah.timezone === 'string' && ah.timezone.trim() ? { timezone: ah.timezone } : {}),\n };\n } else {\n delete (h as { activeHours?: unknown }).activeHours;\n }\n }\n }\n }\n\n if (body.gateway?.bind !== undefined) {\n const bindModes = new Set(['auto', 'loopback', 'lan', 'tailnet', 'custom']);\n const bind = body.gateway.bind;\n if (typeof bind !== 'string' || !bindModes.has(bind)) {\n return patchError('gateway.bind must be one of: auto, loopback, lan, tailnet, custom');\n }\n if (!config.gateway) {\n config.gateway = {\n bind: bind as GatewayBindMode,\n port: 18790,\n heartbeat: { enabled: true, intervalMs: 1_800_000, includeSystemPromptSection: false },\n maxSseConnections: 100,\n corsOrigins: [],\n };\n } else {\n config.gateway.bind = bind as GatewayBindMode;\n }\n if (bind !== 'custom') {\n delete config.gateway.customBindHost;\n }\n }\n\n if (body.gateway?.customBindHost !== undefined) {\n if (body.gateway.customBindHost === null || body.gateway.customBindHost === '') {\n if (config.gateway) {\n delete config.gateway.customBindHost;\n }\n } else if (typeof body.gateway.customBindHost !== 'string' || !isValidIPv4(body.gateway.customBindHost.trim())) {\n return patchError('gateway.customBindHost must be a valid IPv4 address');\n } else if (config.gateway) {\n config.gateway.customBindHost = body.gateway.customBindHost.trim();\n config.gateway.bind = 'custom';\n }\n }\n\n if (body.gateway?.port !== undefined) {\n if (\n typeof body.gateway.port !== 'number' ||\n !Number.isFinite(body.gateway.port) ||\n body.gateway.port < 1 ||\n body.gateway.port > 65535\n ) {\n return patchError('gateway.port must be an integer from 1 to 65535');\n }\n if (!config.gateway) {\n config.gateway = {\n bind: 'loopback',\n port: Math.floor(body.gateway.port),\n heartbeat: { enabled: true, intervalMs: 1_800_000, includeSystemPromptSection: false },\n maxSseConnections: 100,\n corsOrigins: [],\n };\n } else {\n config.gateway.port = Math.floor(body.gateway.port);\n }\n }\n\n if (body.gateway?.tailscale !== undefined && typeof body.gateway.tailscale === 'object') {\n const ts = body.gateway.tailscale as Record<string, unknown>;\n if (!config.gateway) {\n config.gateway = {\n bind: 'loopback',\n port: 18790,\n auth: { mode: 'token' },\n heartbeat: { enabled: true, intervalMs: 1_800_000, includeSystemPromptSection: false },\n maxSseConnections: 100,\n corsOrigins: [],\n };\n }\n config.gateway.tailscale = {\n ...(config.gateway.tailscale ?? { mode: 'off', resetOnExit: true }),\n };\n if (ts.mode !== undefined) {\n if (ts.mode !== 'off' && ts.mode !== 'serve' && ts.mode !== 'funnel') {\n return patchError('gateway.tailscale.mode must be off, serve, or funnel');\n }\n config.gateway.tailscale.mode = ts.mode as 'off' | 'serve' | 'funnel';\n }\n if (ts.resetOnExit !== undefined) {\n config.gateway.tailscale.resetOnExit = ts.resetOnExit === true;\n }\n }\n\n if (body.gateway?.auth !== undefined) {\n const gw = ensureGateway(config);\n if (!gw.auth) gw.auth = { mode: 'token' };\n const a = body.gateway.auth;\n if (a.mode !== undefined) {\n if (\n a.mode !== 'none' &&\n a.mode !== 'token' &&\n a.mode !== 'password' &&\n a.mode !== 'trusted-proxy'\n ) {\n return patchError('gateway.auth.mode must be none, token, password, or trusted-proxy');\n }\n gw.auth.mode = a.mode;\n }\n if (a.token !== undefined) {\n if (a.token === null || (typeof a.token === 'string' && !a.token.trim())) {\n delete gw.auth.token;\n } else if (typeof a.token === 'string' && !isMaskedSecretPatchValue(a.token)) {\n gw.auth.token = a.token;\n }\n }\n if (a.password !== undefined) {\n if (a.password === null || (typeof a.password === 'string' && !a.password.trim())) {\n delete gw.auth.password;\n } else if (typeof a.password === 'string' && !isMaskedSecretPatchValue(a.password)) {\n gw.auth.password = a.password;\n }\n }\n if (a.rateLimit !== undefined && typeof a.rateLimit === 'object' && a.rateLimit !== null) {\n const rlIn = a.rateLimit as Record<string, unknown>;\n if (!gw.auth.rateLimit) {\n gw.auth.rateLimit = {\n enabled: true,\n maxAttempts: 5,\n windowMs: 900_000,\n blockDurationMs: 300_000,\n burstCoalesceMs: 1000,\n exemptLoopback: true,\n };\n }\n const rl = gw.auth.rateLimit!;\n if (rlIn.enabled !== undefined) rl.enabled = Boolean(rlIn.enabled);\n if (typeof rlIn.maxAttempts === 'number' && Number.isFinite(rlIn.maxAttempts)) {\n rl.maxAttempts = Math.max(1, Math.floor(rlIn.maxAttempts));\n }\n if (typeof rlIn.windowMs === 'number' && Number.isFinite(rlIn.windowMs) && rlIn.windowMs > 0) {\n rl.windowMs = Math.floor(rlIn.windowMs);\n }\n if (\n typeof rlIn.blockDurationMs === 'number' &&\n Number.isFinite(rlIn.blockDurationMs) &&\n rlIn.blockDurationMs > 0\n ) {\n rl.blockDurationMs = Math.floor(rlIn.blockDurationMs);\n }\n if (\n typeof rlIn.lockoutMs === 'number' &&\n Number.isFinite(rlIn.lockoutMs) &&\n rlIn.lockoutMs > 0\n ) {\n rl.blockDurationMs = Math.floor(rlIn.lockoutMs);\n }\n if (rlIn.exemptLoopback !== undefined) {\n rl.exemptLoopback = Boolean(rlIn.exemptLoopback);\n }\n }\n if (a.trustedProxy !== undefined) {\n if (a.trustedProxy === null) {\n delete gw.auth.trustedProxy;\n } else if (typeof a.trustedProxy === 'object' && a.trustedProxy !== null) {\n const tpIn = a.trustedProxy as Record<string, unknown>;\n const userHeader =\n typeof tpIn.userHeader === 'string' ? tpIn.userHeader.trim() : '';\n if (!userHeader) {\n return patchError('gateway.auth.trustedProxy.userHeader is required');\n }\n const trustedProxy: NonNullable<(typeof gw.auth)['trustedProxy']> = {\n userHeader,\n };\n if (tpIn.requiredHeaders !== undefined) {\n if (!Array.isArray(tpIn.requiredHeaders)) {\n return patchError('gateway.auth.trustedProxy.requiredHeaders must be an array');\n }\n trustedProxy.requiredHeaders = tpIn.requiredHeaders\n .filter((x): x is string => typeof x === 'string' && x.trim().length > 0)\n .map((x) => x.trim());\n }\n if (tpIn.allowUsers !== undefined) {\n if (!Array.isArray(tpIn.allowUsers)) {\n return patchError('gateway.auth.trustedProxy.allowUsers must be an array');\n }\n trustedProxy.allowUsers = tpIn.allowUsers\n .filter((x): x is string => typeof x === 'string' && x.trim().length > 0)\n .map((x) => x.trim());\n }\n if (tpIn.allowLoopback !== undefined) {\n trustedProxy.allowLoopback = Boolean(tpIn.allowLoopback);\n }\n gw.auth.trustedProxy = trustedProxy;\n }\n }\n }\n\n if (body.gateway?.trustedProxies !== undefined) {\n if (!Array.isArray(body.gateway.trustedProxies)) {\n return patchError('gateway.trustedProxies must be an array');\n }\n const gw = ensureGateway(config);\n gw.trustedProxies = body.gateway.trustedProxies\n .filter((x: unknown): x is string => typeof x === 'string' && x.trim().length > 0)\n .map((x: string) => x.trim());\n }\n\n if (body.gateway?.allowRealIpFallback !== undefined) {\n const gw = ensureGateway(config);\n gw.allowRealIpFallback = Boolean(body.gateway.allowRealIpFallback);\n }\n\n if (body.gateway?.dangerouslyAllowHostHeaderOriginFallback !== undefined) {\n const gw = ensureGateway(config);\n gw.dangerouslyAllowHostHeaderOriginFallback = Boolean(\n body.gateway.dangerouslyAllowHostHeaderOriginFallback,\n );\n }\n\n if (body.gateway?.security !== undefined) {\n if (typeof body.gateway.security !== 'object' || body.gateway.security === null) {\n return patchError('gateway.security must be an object');\n }\n const gw = ensureGateway(config);\n const secIn = body.gateway.security as Record<string, unknown>;\n if (!gw.security) {\n gw.security = {};\n }\n if (secIn.strict !== undefined) {\n gw.security.strict = Boolean(secIn.strict);\n }\n }\n\n if (body.gateway?.share !== undefined) {\n if (typeof body.gateway.share !== 'object' || body.gateway.share === null || Array.isArray(body.gateway.share)) {\n return patchError('gateway.share must be an object');\n }\n const shareResult = mergeShareConfigPatch(config, body.gateway.share as Record<string, unknown>);\n if (shareResult.ok === false) {\n return patchError(shareResult.message);\n }\n }\n\n if (body.gateway?.corsOrigins !== undefined) {\n if (!Array.isArray(body.gateway.corsOrigins)) {\n return patchError('gateway.corsOrigins must be an array');\n }\n const gw = ensureGateway(config);\n gw.corsOrigins = body.gateway.corsOrigins\n .filter((x: unknown): x is string => typeof x === 'string' && x.trim().length > 0)\n .map((x: string) => x.trim());\n }\n\n if (body.gateway?.maxSseConnections !== undefined) {\n if (\n typeof body.gateway.maxSseConnections !== 'number' ||\n !Number.isFinite(body.gateway.maxSseConnections) ||\n body.gateway.maxSseConnections < 1\n ) {\n return patchError('gateway.maxSseConnections must be a positive integer');\n }\n if (!config.gateway) {\n config.gateway = {\n bind: 'loopback',\n port: 18790,\n heartbeat: { enabled: true, intervalMs: 1_800_000, includeSystemPromptSection: false },\n maxSseConnections: Math.floor(body.gateway.maxSseConnections),\n corsOrigins: [],\n };\n } else {\n config.gateway.maxSseConnections = Math.floor(body.gateway.maxSseConnections);\n }\n }\n\n if (body.gateway?.channelConnectDeferMode !== undefined) {\n const mode = body.gateway.channelConnectDeferMode;\n if (mode !== 'auto' && mode !== 'off' && mode !== 'explicit') {\n return patchError('gateway.channelConnectDeferMode must be auto, off, or explicit');\n }\n const gw = ensureGateway(config);\n gw.channelConnectDeferMode = mode;\n }\n\n if (body.gateway?.channelConnectDeferIds !== undefined) {\n const ids = parseDeferIdList(body.gateway.channelConnectDeferIds);\n if (ids === null) {\n return patchError('gateway.channelConnectDeferIds must be an array of up to 24 strings');\n }\n const gw = ensureGateway(config);\n gw.channelConnectDeferIds = ids;\n }\n\n if (body.gateway?.channelConnectDeferSkipIds !== undefined) {\n const ids = parseDeferIdList(body.gateway.channelConnectDeferSkipIds);\n if (ids === null) {\n return patchError('gateway.channelConnectDeferSkipIds must be an array of up to 24 strings');\n }\n const gw = ensureGateway(config);\n gw.channelConnectDeferSkipIds = ids;\n }\n\n return PATCH_OK;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"gateway.js","names":[],"sources":["../../../../../../src/gateway/hono/routes/config-patch/gateway.ts"],"sourcesContent":["/**\n * `PATCH /api/config` — `body.gateway.*` section.\n *\n * Covers heartbeat, bind/customBindHost/port, tailscale, auth (mode + token +\n * password + rateLimit + trustedProxy), trustedProxies, allowRealIpFallback,\n * dangerouslyAllowHostHeaderOriginFallback, security, share, publicUrl,\n * corsOrigins, maxSseConnections, and channelConnectDefer{Mode,Ids,SkipIds}.\n *\n * Validation policy: each subsection that can reject rejects with a 400 and a\n * specific `message`. The dispatcher converts these into `c.json(...)`.\n *\n * Initial-state branches use the same literal defaults the inline code did\n * (loopback + port 18790 + 1800s heartbeat + 100 SSE conn + empty CORS) so\n * a brand-new install gets a working gateway after the first PATCH.\n */\nimport type { Config, GatewayBindMode } from '../../../../config/schema.js';\nimport { isValidIPv4 } from '../../../../config/gateway-bind.js';\nimport { validatePublicUrl } from '../../../../config/public-url.js';\nimport { mergeShareConfigPatch } from '../../../../share/share-config.js';\nimport { isMaskedSecretPatchValue } from '../../lib/mask-secret-length.js';\nimport { type PatchResult, PATCH_OK, patchError } from './result.js';\n\n/**\n * Shared default for \"user PATCH'd a gateway subsection but `config.gateway`\n * was never initialised\". Identical to the inline literal repeated in the\n * pre-extraction handler so this is behavior-preserving.\n */\nfunction ensureGateway(config: Config): NonNullable<Config['gateway']> {\n if (!config.gateway) {\n config.gateway = {\n bind: 'loopback',\n port: 18790,\n heartbeat: { enabled: true, intervalMs: 1_800_000, includeSystemPromptSection: false },\n maxSseConnections: 100,\n corsOrigins: [],\n };\n }\n return config.gateway;\n}\n\nfunction parseDeferIdList(raw: unknown): string[] | null {\n if (!Array.isArray(raw)) return null;\n const ids = raw\n .filter((x): x is string => typeof x === 'string' && x.trim().length > 0)\n .map((x) => x.trim());\n if (ids.length > 24) return null;\n return ids;\n}\n\nexport function applyGatewayPatch(config: Config, body: any): PatchResult {\n if (body.gateway?.heartbeat !== undefined && typeof body.gateway.heartbeat === 'object') {\n const gw = ensureGateway(config);\n if (!gw.heartbeat) {\n gw.heartbeat = { enabled: true, intervalMs: 1_800_000, includeSystemPromptSection: false };\n }\n const h = gw.heartbeat;\n const p = body.gateway.heartbeat as Record<string, unknown>;\n if (p.enabled !== undefined) h.enabled = Boolean(p.enabled);\n if (p.intervalMs !== undefined && typeof p.intervalMs === 'number' && Number.isFinite(p.intervalMs)) {\n h.intervalMs = p.intervalMs;\n }\n if (p.includeSystemPromptSection !== undefined) {\n h.includeSystemPromptSection = Boolean(p.includeSystemPromptSection);\n }\n if (p.target !== undefined) {\n if (p.target === null || p.target === '') delete (h as { target?: string }).target;\n else (h as { target?: string }).target = String(p.target);\n }\n if (p.targetChatId !== undefined) {\n if (p.targetChatId === null || p.targetChatId === '') delete (h as { targetChatId?: string }).targetChatId;\n else (h as { targetChatId?: string }).targetChatId = String(p.targetChatId);\n }\n if (p.prompt !== undefined) {\n if (p.prompt === null || p.prompt === '') delete (h as { prompt?: string }).prompt;\n else (h as { prompt?: string }).prompt = String(p.prompt);\n }\n if (p.ackMaxChars !== undefined) {\n if (p.ackMaxChars === null || p.ackMaxChars === '') delete (h as { ackMaxChars?: number }).ackMaxChars;\n else if (typeof p.ackMaxChars === 'number' && Number.isFinite(p.ackMaxChars)) {\n (h as { ackMaxChars?: number }).ackMaxChars = p.ackMaxChars;\n }\n }\n if (p.isolatedSession !== undefined) {\n if (p.isolatedSession === null || p.isolatedSession === false) {\n delete (h as { isolatedSession?: boolean }).isolatedSession;\n } else {\n (h as { isolatedSession?: boolean }).isolatedSession = Boolean(p.isolatedSession);\n }\n }\n if (p.activeHours !== undefined) {\n if (p.activeHours === null) {\n delete (h as { activeHours?: unknown }).activeHours;\n } else if (typeof p.activeHours === 'object' && p.activeHours !== null) {\n const ah = p.activeHours as Record<string, unknown>;\n const start = typeof ah.start === 'string' ? ah.start : '';\n const end = typeof ah.end === 'string' ? ah.end : '';\n if (start && end) {\n (h as { activeHours?: { start: string; end: string; timezone?: string } }).activeHours = {\n start,\n end,\n ...(typeof ah.timezone === 'string' && ah.timezone.trim() ? { timezone: ah.timezone } : {}),\n };\n } else {\n delete (h as { activeHours?: unknown }).activeHours;\n }\n }\n }\n }\n\n if (body.gateway?.bind !== undefined) {\n const bindModes = new Set(['auto', 'loopback', 'lan', 'tailnet', 'custom']);\n const bind = body.gateway.bind;\n if (typeof bind !== 'string' || !bindModes.has(bind)) {\n return patchError('gateway.bind must be one of: auto, loopback, lan, tailnet, custom');\n }\n if (!config.gateway) {\n config.gateway = {\n bind: bind as GatewayBindMode,\n port: 18790,\n heartbeat: { enabled: true, intervalMs: 1_800_000, includeSystemPromptSection: false },\n maxSseConnections: 100,\n corsOrigins: [],\n };\n } else {\n config.gateway.bind = bind as GatewayBindMode;\n }\n if (bind !== 'custom') {\n delete config.gateway.customBindHost;\n }\n }\n\n if (body.gateway?.customBindHost !== undefined) {\n if (body.gateway.customBindHost === null || body.gateway.customBindHost === '') {\n if (config.gateway) {\n delete config.gateway.customBindHost;\n }\n } else if (typeof body.gateway.customBindHost !== 'string' || !isValidIPv4(body.gateway.customBindHost.trim())) {\n return patchError('gateway.customBindHost must be a valid IPv4 address');\n } else if (config.gateway) {\n config.gateway.customBindHost = body.gateway.customBindHost.trim();\n config.gateway.bind = 'custom';\n }\n }\n\n if (body.gateway?.port !== undefined) {\n if (\n typeof body.gateway.port !== 'number' ||\n !Number.isFinite(body.gateway.port) ||\n body.gateway.port < 1 ||\n body.gateway.port > 65535\n ) {\n return patchError('gateway.port must be an integer from 1 to 65535');\n }\n if (!config.gateway) {\n config.gateway = {\n bind: 'loopback',\n port: Math.floor(body.gateway.port),\n heartbeat: { enabled: true, intervalMs: 1_800_000, includeSystemPromptSection: false },\n maxSseConnections: 100,\n corsOrigins: [],\n };\n } else {\n config.gateway.port = Math.floor(body.gateway.port);\n }\n }\n\n if (body.gateway?.tailscale !== undefined && typeof body.gateway.tailscale === 'object') {\n const ts = body.gateway.tailscale as Record<string, unknown>;\n if (!config.gateway) {\n config.gateway = {\n bind: 'loopback',\n port: 18790,\n auth: { mode: 'token' },\n heartbeat: { enabled: true, intervalMs: 1_800_000, includeSystemPromptSection: false },\n maxSseConnections: 100,\n corsOrigins: [],\n };\n }\n config.gateway.tailscale = {\n ...(config.gateway.tailscale ?? { mode: 'off', resetOnExit: true }),\n };\n if (ts.mode !== undefined) {\n if (ts.mode !== 'off' && ts.mode !== 'serve' && ts.mode !== 'funnel') {\n return patchError('gateway.tailscale.mode must be off, serve, or funnel');\n }\n config.gateway.tailscale.mode = ts.mode as 'off' | 'serve' | 'funnel';\n }\n if (ts.resetOnExit !== undefined) {\n config.gateway.tailscale.resetOnExit = ts.resetOnExit === true;\n }\n }\n\n if (body.gateway?.auth !== undefined) {\n const gw = ensureGateway(config);\n if (!gw.auth) gw.auth = { mode: 'token' };\n const a = body.gateway.auth;\n if (a.mode !== undefined) {\n if (\n a.mode !== 'none' &&\n a.mode !== 'token' &&\n a.mode !== 'password' &&\n a.mode !== 'trusted-proxy'\n ) {\n return patchError('gateway.auth.mode must be none, token, password, or trusted-proxy');\n }\n gw.auth.mode = a.mode;\n }\n if (a.token !== undefined) {\n if (a.token === null || (typeof a.token === 'string' && !a.token.trim())) {\n delete gw.auth.token;\n } else if (typeof a.token === 'string' && !isMaskedSecretPatchValue(a.token)) {\n gw.auth.token = a.token;\n }\n }\n if (a.password !== undefined) {\n if (a.password === null || (typeof a.password === 'string' && !a.password.trim())) {\n delete gw.auth.password;\n } else if (typeof a.password === 'string' && !isMaskedSecretPatchValue(a.password)) {\n gw.auth.password = a.password;\n }\n }\n if (a.rateLimit !== undefined && typeof a.rateLimit === 'object' && a.rateLimit !== null) {\n const rlIn = a.rateLimit as Record<string, unknown>;\n if (!gw.auth.rateLimit) {\n gw.auth.rateLimit = {\n enabled: true,\n maxAttempts: 5,\n windowMs: 900_000,\n blockDurationMs: 300_000,\n burstCoalesceMs: 1000,\n exemptLoopback: true,\n };\n }\n const rl = gw.auth.rateLimit!;\n if (rlIn.enabled !== undefined) rl.enabled = Boolean(rlIn.enabled);\n if (typeof rlIn.maxAttempts === 'number' && Number.isFinite(rlIn.maxAttempts)) {\n rl.maxAttempts = Math.max(1, Math.floor(rlIn.maxAttempts));\n }\n if (typeof rlIn.windowMs === 'number' && Number.isFinite(rlIn.windowMs) && rlIn.windowMs > 0) {\n rl.windowMs = Math.floor(rlIn.windowMs);\n }\n if (\n typeof rlIn.blockDurationMs === 'number' &&\n Number.isFinite(rlIn.blockDurationMs) &&\n rlIn.blockDurationMs > 0\n ) {\n rl.blockDurationMs = Math.floor(rlIn.blockDurationMs);\n }\n if (\n typeof rlIn.lockoutMs === 'number' &&\n Number.isFinite(rlIn.lockoutMs) &&\n rlIn.lockoutMs > 0\n ) {\n rl.blockDurationMs = Math.floor(rlIn.lockoutMs);\n }\n if (rlIn.exemptLoopback !== undefined) {\n rl.exemptLoopback = Boolean(rlIn.exemptLoopback);\n }\n }\n if (a.trustedProxy !== undefined) {\n if (a.trustedProxy === null) {\n delete gw.auth.trustedProxy;\n } else if (typeof a.trustedProxy === 'object' && a.trustedProxy !== null) {\n const tpIn = a.trustedProxy as Record<string, unknown>;\n const userHeader =\n typeof tpIn.userHeader === 'string' ? tpIn.userHeader.trim() : '';\n if (!userHeader) {\n return patchError('gateway.auth.trustedProxy.userHeader is required');\n }\n const trustedProxy: NonNullable<(typeof gw.auth)['trustedProxy']> = {\n userHeader,\n };\n if (tpIn.requiredHeaders !== undefined) {\n if (!Array.isArray(tpIn.requiredHeaders)) {\n return patchError('gateway.auth.trustedProxy.requiredHeaders must be an array');\n }\n trustedProxy.requiredHeaders = tpIn.requiredHeaders\n .filter((x): x is string => typeof x === 'string' && x.trim().length > 0)\n .map((x) => x.trim());\n }\n if (tpIn.allowUsers !== undefined) {\n if (!Array.isArray(tpIn.allowUsers)) {\n return patchError('gateway.auth.trustedProxy.allowUsers must be an array');\n }\n trustedProxy.allowUsers = tpIn.allowUsers\n .filter((x): x is string => typeof x === 'string' && x.trim().length > 0)\n .map((x) => x.trim());\n }\n if (tpIn.allowLoopback !== undefined) {\n trustedProxy.allowLoopback = Boolean(tpIn.allowLoopback);\n }\n gw.auth.trustedProxy = trustedProxy;\n }\n }\n }\n\n if (body.gateway?.trustedProxies !== undefined) {\n if (!Array.isArray(body.gateway.trustedProxies)) {\n return patchError('gateway.trustedProxies must be an array');\n }\n const gw = ensureGateway(config);\n gw.trustedProxies = body.gateway.trustedProxies\n .filter((x: unknown): x is string => typeof x === 'string' && x.trim().length > 0)\n .map((x: string) => x.trim());\n }\n\n if (body.gateway?.allowRealIpFallback !== undefined) {\n const gw = ensureGateway(config);\n gw.allowRealIpFallback = Boolean(body.gateway.allowRealIpFallback);\n }\n\n if (body.gateway?.dangerouslyAllowHostHeaderOriginFallback !== undefined) {\n const gw = ensureGateway(config);\n gw.dangerouslyAllowHostHeaderOriginFallback = Boolean(\n body.gateway.dangerouslyAllowHostHeaderOriginFallback,\n );\n }\n\n if (body.gateway?.security !== undefined) {\n if (typeof body.gateway.security !== 'object' || body.gateway.security === null) {\n return patchError('gateway.security must be an object');\n }\n const gw = ensureGateway(config);\n const secIn = body.gateway.security as Record<string, unknown>;\n if (!gw.security) {\n gw.security = {};\n }\n if (secIn.strict !== undefined) {\n gw.security.strict = Boolean(secIn.strict);\n }\n }\n\n if (body.gateway?.share !== undefined) {\n if (typeof body.gateway.share !== 'object' || body.gateway.share === null || Array.isArray(body.gateway.share)) {\n return patchError('gateway.share must be an object');\n }\n const shareResult = mergeShareConfigPatch(config, body.gateway.share as Record<string, unknown>);\n if (shareResult.ok === false) {\n return patchError(shareResult.message);\n }\n }\n\n if (body.gateway?.publicUrl !== undefined) {\n const gw = ensureGateway(config);\n if (body.gateway.publicUrl === null || body.gateway.publicUrl === '') {\n delete gw.publicUrl;\n } else if (typeof body.gateway.publicUrl !== 'string') {\n return patchError('gateway.publicUrl must be a string or null');\n } else {\n const validation = validatePublicUrl(body.gateway.publicUrl);\n if (validation.ok === false) {\n return patchError(`gateway.publicUrl: ${validation.message}`);\n }\n gw.publicUrl = validation.url;\n }\n }\n\n if (body.gateway?.corsOrigins !== undefined) {\n if (!Array.isArray(body.gateway.corsOrigins)) {\n return patchError('gateway.corsOrigins must be an array');\n }\n const gw = ensureGateway(config);\n gw.corsOrigins = body.gateway.corsOrigins\n .filter((x: unknown): x is string => typeof x === 'string' && x.trim().length > 0)\n .map((x: string) => x.trim());\n }\n\n if (body.gateway?.maxSseConnections !== undefined) {\n if (\n typeof body.gateway.maxSseConnections !== 'number' ||\n !Number.isFinite(body.gateway.maxSseConnections) ||\n body.gateway.maxSseConnections < 1\n ) {\n return patchError('gateway.maxSseConnections must be a positive integer');\n }\n if (!config.gateway) {\n config.gateway = {\n bind: 'loopback',\n port: 18790,\n heartbeat: { enabled: true, intervalMs: 1_800_000, includeSystemPromptSection: false },\n maxSseConnections: Math.floor(body.gateway.maxSseConnections),\n corsOrigins: [],\n };\n } else {\n config.gateway.maxSseConnections = Math.floor(body.gateway.maxSseConnections);\n }\n }\n\n if (body.gateway?.channelConnectDeferMode !== undefined) {\n const mode = body.gateway.channelConnectDeferMode;\n if (mode !== 'auto' && mode !== 'off' && mode !== 'explicit') {\n return patchError('gateway.channelConnectDeferMode must be auto, off, or explicit');\n }\n const gw = ensureGateway(config);\n gw.channelConnectDeferMode = mode;\n }\n\n if (body.gateway?.channelConnectDeferIds !== undefined) {\n const ids = parseDeferIdList(body.gateway.channelConnectDeferIds);\n if (ids === null) {\n return patchError('gateway.channelConnectDeferIds must be an array of up to 24 strings');\n }\n const gw = ensureGateway(config);\n gw.channelConnectDeferIds = ids;\n }\n\n if (body.gateway?.channelConnectDeferSkipIds !== undefined) {\n const ids = parseDeferIdList(body.gateway.channelConnectDeferSkipIds);\n if (ids === null) {\n return patchError('gateway.channelConnectDeferSkipIds must be an array of up to 24 strings');\n }\n const gw = ensureGateway(config);\n gw.channelConnectDeferSkipIds = ids;\n }\n\n return PATCH_OK;\n}\n"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
- import { CredentialResolver, init_credentials } from "../../../../auth/credentials.js";
2
1
  import { BindingsConfigSchema, McpConfigSchema, init_schema } from "../../../../config/schema.js";
2
+ import { CredentialResolver, init_credentials } from "../../../../auth/credentials.js";
3
3
  import { canonicalizeConfiguredMcpServer } from "../../../../config/mcp-config-normalize.js";
4
4
  import { mergeCronConfigPatch, mergeGatewaySkillsMarketplacePatch, mergeGoalsConfigPatch, mergeSessionConfigPatch, mergeUpdateConfigPatch } from "../../../../config/web-patch.js";
5
5
  import { assertGatewayAuthConfigured, resolveGatewayAuth } from "../../../auth.js";
@@ -0,0 +1,3 @@
1
+ import type { Hono } from 'hono';
2
+ import type { AuthenticatedRouteDeps } from './deps.js';
3
+ export declare function registerConnectorRoutes(authenticated: Hono, deps: AuthenticatedRouteDeps): void;
@@ -0,0 +1,177 @@
1
+ import { listConnectorProviders } from "../../../connectors/providers.js";
2
+ import { getConnectorDefinition, listConnectorCatalog } from "../../../connectors/catalog.js";
3
+ import { recordConnectorHealthUsage } from "../../../connectors/usage.js";
4
+ import { getConnectorInstance, listConnectorInstances } from "../../../connectors/instances.js";
5
+ import { testConnectorInstance } from "../../../connectors/health.js";
6
+ import { completeConnectorOAuth, startConnectorOAuth } from "../../../connectors/oauth.js";
7
+ import { installConnector, uninstallConnector } from "../../../connectors/install.js";
8
+ //#region src/gateway/hono/routes/connectors.ts
9
+ function errorMessage(error) {
10
+ return error instanceof Error ? error.message : String(error);
11
+ }
12
+ function registerConnectorRoutes(authenticated, deps) {
13
+ const { service, strictRateLimitMiddleware } = deps;
14
+ authenticated.get("/api/connectors/catalog", (c) => {
15
+ return c.json({
16
+ ok: true,
17
+ payload: {
18
+ connectors: listConnectorCatalog(),
19
+ providers: listConnectorProviders().map((provider) => ({
20
+ id: provider.id,
21
+ displayName: provider.displayName
22
+ }))
23
+ }
24
+ });
25
+ });
26
+ authenticated.get("/api/connectors/installed", (c) => {
27
+ const config = service.currentConfig;
28
+ return c.json({
29
+ ok: true,
30
+ payload: { instances: listConnectorInstances(config) }
31
+ });
32
+ });
33
+ authenticated.get("/api/connectors/:id", (c) => {
34
+ const connectorId = c.req.param("id");
35
+ const connector = getConnectorDefinition(connectorId);
36
+ if (!connector) return c.json({
37
+ ok: false,
38
+ error: `Unknown connector: ${connectorId}`
39
+ }, 404);
40
+ const config = service.currentConfig;
41
+ const instances = listConnectorInstances(config).filter((instance) => instance.connectorId === connectorId);
42
+ return c.json({
43
+ ok: true,
44
+ payload: {
45
+ connector,
46
+ instances
47
+ }
48
+ });
49
+ });
50
+ authenticated.post("/api/connectors/approvals/respond", async (c) => {
51
+ const body = await c.req.json().catch(() => ({}));
52
+ return c.json({
53
+ ok: true,
54
+ payload: {
55
+ acknowledged: true,
56
+ body
57
+ }
58
+ });
59
+ });
60
+ authenticated.post("/api/connectors/:id/oauth/start", strictRateLimitMiddleware, async (c) => {
61
+ const connectorId = c.req.param("id");
62
+ const connector = getConnectorDefinition(connectorId);
63
+ if (!connector) return c.json({
64
+ ok: false,
65
+ error: `Unknown connector: ${connectorId}`
66
+ }, 404);
67
+ try {
68
+ const oauth = await startConnectorOAuth(connector);
69
+ return c.json({
70
+ ok: true,
71
+ payload: { oauth }
72
+ });
73
+ } catch (error) {
74
+ return c.json({
75
+ ok: false,
76
+ error: errorMessage(error)
77
+ }, 400);
78
+ }
79
+ });
80
+ authenticated.post("/api/connectors/:id/oauth/complete", strictRateLimitMiddleware, async (c) => {
81
+ const connectorId = c.req.param("id");
82
+ const connector = getConnectorDefinition(connectorId);
83
+ if (!connector) return c.json({
84
+ ok: false,
85
+ error: `Unknown connector: ${connectorId}`
86
+ }, 404);
87
+ const body = await c.req.json().catch(() => ({}));
88
+ const deviceCode = body && typeof body === "object" && !Array.isArray(body) && typeof body.deviceCode === "string" ? body.deviceCode : "";
89
+ try {
90
+ const oauth = await completeConnectorOAuth(connector, { deviceCode });
91
+ return c.json({
92
+ ok: true,
93
+ payload: { oauth }
94
+ });
95
+ } catch (error) {
96
+ return c.json({
97
+ ok: false,
98
+ error: errorMessage(error)
99
+ }, 400);
100
+ }
101
+ });
102
+ authenticated.post("/api/connectors/:id/install", strictRateLimitMiddleware, async (c) => {
103
+ const connectorId = c.req.param("id");
104
+ const body = await c.req.json().catch(() => ({}));
105
+ const input = body && typeof body === "object" && !Array.isArray(body) ? body : {};
106
+ const config = service.currentConfig;
107
+ try {
108
+ const instance = await installConnector(config, connectorId, input);
109
+ const saved = await service.saveConfig(config);
110
+ if (!saved.saved) return c.json({
111
+ ok: false,
112
+ error: saved.error
113
+ }, 500);
114
+ return c.json({
115
+ ok: true,
116
+ payload: { instance }
117
+ });
118
+ } catch (error) {
119
+ return c.json({
120
+ ok: false,
121
+ error: errorMessage(error)
122
+ }, 400);
123
+ }
124
+ });
125
+ authenticated.post("/api/connectors/:id/test", async (c) => {
126
+ const instanceId = c.req.param("id");
127
+ const config = service.currentConfig;
128
+ const instance = getConnectorInstance(config, instanceId);
129
+ if (!instance) return c.json({
130
+ ok: false,
131
+ error: `Connector instance not found: ${instanceId}`
132
+ }, 404);
133
+ try {
134
+ const result = await testConnectorInstance(config, instance.materialized.serverId);
135
+ recordConnectorHealthUsage(config, instance.instanceId, result);
136
+ const saved = await service.saveConfig(config);
137
+ if (!saved.saved) return c.json({
138
+ ok: false,
139
+ error: saved.error
140
+ }, 500);
141
+ return c.json({
142
+ ok: true,
143
+ payload: result
144
+ });
145
+ } catch (error) {
146
+ return c.json({
147
+ ok: false,
148
+ error: errorMessage(error)
149
+ }, 500);
150
+ }
151
+ });
152
+ authenticated.delete("/api/connectors/:id", strictRateLimitMiddleware, async (c) => {
153
+ const instanceId = c.req.param("id");
154
+ const config = service.currentConfig;
155
+ try {
156
+ const instance = uninstallConnector(config, instanceId);
157
+ const saved = await service.saveConfig(config);
158
+ if (!saved.saved) return c.json({
159
+ ok: false,
160
+ error: saved.error
161
+ }, 500);
162
+ return c.json({
163
+ ok: true,
164
+ payload: { instance }
165
+ });
166
+ } catch (error) {
167
+ return c.json({
168
+ ok: false,
169
+ error: errorMessage(error)
170
+ }, 400);
171
+ }
172
+ });
173
+ }
174
+ //#endregion
175
+ export { registerConnectorRoutes };
176
+
177
+ //# sourceMappingURL=connectors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"connectors.js","names":[],"sources":["../../../../../src/gateway/hono/routes/connectors.ts"],"sourcesContent":["import type { Hono } from 'hono';\n\nimport type { Config } from '../../../config/schema.js';\nimport { getConnectorDefinition, listConnectorCatalog, listConnectorProviders } from '../../../connectors/catalog.js';\nimport { testConnectorInstance } from '../../../connectors/health.js';\nimport { installConnector, uninstallConnector } from '../../../connectors/install.js';\nimport { getConnectorInstance, listConnectorInstances } from '../../../connectors/instances.js';\nimport { startConnectorOAuth, completeConnectorOAuth } from '../../../connectors/oauth.js';\nimport { recordConnectorHealthUsage } from '../../../connectors/usage.js';\nimport type { ConnectorInstallInput } from '../../../connectors/types.js';\nimport type { AuthenticatedRouteDeps } from './deps.js';\n\nfunction errorMessage(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n\nexport function registerConnectorRoutes(authenticated: Hono, deps: AuthenticatedRouteDeps): void {\n const { service, strictRateLimitMiddleware } = deps;\n\n authenticated.get('/api/connectors/catalog', (c) => {\n return c.json({\n ok: true,\n payload: {\n connectors: listConnectorCatalog(),\n providers: listConnectorProviders().map((provider) => ({\n id: provider.id,\n displayName: provider.displayName,\n })),\n },\n });\n });\n\n authenticated.get('/api/connectors/installed', (c) => {\n const config = service.currentConfig as Config;\n return c.json({ ok: true, payload: { instances: listConnectorInstances(config) } });\n });\n\n authenticated.get('/api/connectors/:id', (c) => {\n const connectorId = c.req.param('id');\n const connector = getConnectorDefinition(connectorId);\n if (!connector) {\n return c.json({ ok: false, error: `Unknown connector: ${connectorId}` }, 404);\n }\n const config = service.currentConfig as Config;\n const instances = listConnectorInstances(config).filter((instance) => instance.connectorId === connectorId);\n return c.json({ ok: true, payload: { connector, instances } });\n });\n\n authenticated.post('/api/connectors/approvals/respond', async (c) => {\n const body = await c.req.json().catch(() => ({}));\n return c.json({ ok: true, payload: { acknowledged: true, body } });\n });\n\n authenticated.post('/api/connectors/:id/oauth/start', strictRateLimitMiddleware, async (c) => {\n const connectorId = c.req.param('id');\n const connector = getConnectorDefinition(connectorId);\n if (!connector) {\n return c.json({ ok: false, error: `Unknown connector: ${connectorId}` }, 404);\n }\n try {\n const oauth = await startConnectorOAuth(connector);\n return c.json({ ok: true, payload: { oauth } });\n } catch (error) {\n return c.json({ ok: false, error: errorMessage(error) }, 400);\n }\n });\n\n authenticated.post('/api/connectors/:id/oauth/complete', strictRateLimitMiddleware, async (c) => {\n const connectorId = c.req.param('id');\n const connector = getConnectorDefinition(connectorId);\n if (!connector) {\n return c.json({ ok: false, error: `Unknown connector: ${connectorId}` }, 404);\n }\n const body = await c.req.json().catch(() => ({}));\n const deviceCode = body && typeof body === 'object' && !Array.isArray(body) && typeof body.deviceCode === 'string'\n ? body.deviceCode\n : '';\n try {\n const oauth = await completeConnectorOAuth(connector, { deviceCode });\n return c.json({ ok: true, payload: { oauth } });\n } catch (error) {\n return c.json({ ok: false, error: errorMessage(error) }, 400);\n }\n });\n\n authenticated.post('/api/connectors/:id/install', strictRateLimitMiddleware, async (c) => {\n const connectorId = c.req.param('id');\n const body = await c.req.json().catch(() => ({}));\n const input: ConnectorInstallInput = body && typeof body === 'object' && !Array.isArray(body) ? body : {};\n const config = service.currentConfig as Config;\n try {\n const instance = await installConnector(config, connectorId, input);\n const saved = await service.saveConfig(config);\n if (!saved.saved) {\n return c.json({ ok: false, error: saved.error }, 500);\n }\n return c.json({ ok: true, payload: { instance } });\n } catch (error) {\n return c.json({ ok: false, error: errorMessage(error) }, 400);\n }\n });\n\n authenticated.post('/api/connectors/:id/test', async (c) => {\n const instanceId = c.req.param('id');\n const config = service.currentConfig as Config;\n const instance = getConnectorInstance(config, instanceId);\n if (!instance) {\n return c.json({ ok: false, error: `Connector instance not found: ${instanceId}` }, 404);\n }\n try {\n const result = await testConnectorInstance(config, instance.materialized.serverId);\n recordConnectorHealthUsage(config, instance.instanceId, result);\n const saved = await service.saveConfig(config);\n if (!saved.saved) {\n return c.json({ ok: false, error: saved.error }, 500);\n }\n return c.json({ ok: true, payload: result });\n } catch (error) {\n return c.json({ ok: false, error: errorMessage(error) }, 500);\n }\n });\n\n authenticated.delete('/api/connectors/:id', strictRateLimitMiddleware, async (c) => {\n const instanceId = c.req.param('id');\n const config = service.currentConfig as Config;\n try {\n const instance = uninstallConnector(config, instanceId);\n const saved = await service.saveConfig(config);\n if (!saved.saved) {\n return c.json({ ok: false, error: saved.error }, 500);\n }\n return c.json({ ok: true, payload: { instance } });\n } catch (error) {\n return c.json({ ok: false, error: errorMessage(error) }, 400);\n }\n });\n}\n"],"mappings":"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"}
@@ -5,8 +5,8 @@ import { getWorkspacePath } from "../../../config/workspace-path-helpers.js";
5
5
  import { parseDreamingLastRunFile } from "../../../agent/memory/dreaming/last-run.js";
6
6
  import { readDreamingEvents } from "../../../agent/memory/dreaming/events.js";
7
7
  import { previewDreamingDeepPromotion } from "../../../agent/memory/dreaming/preview.js";
8
- import fs from "node:fs/promises";
9
8
  import path from "node:path";
9
+ import fs from "node:fs/promises";
10
10
  //#region src/gateway/hono/routes/dreaming.ts
11
11
  function isRecord(v) {
12
12
  return v !== null && typeof v === "object" && !Array.isArray(v);
@@ -0,0 +1,12 @@
1
+ import type { Hono } from 'hono';
2
+ import type { AuthenticatedRouteDeps } from './deps.js';
3
+ /**
4
+ * GET /api/home — Aggregated home screen data for the mobile app.
5
+ *
6
+ * Returns:
7
+ * - recentlyOpened: notes sorted by lastOpenedAt (continue rail)
8
+ * - inboxCount: number of notes with status === 'inbox'
9
+ * - pendingTasks: task notes where done === false
10
+ * - recentSessions: last 5 active AI sessions (threads)
11
+ */
12
+ export declare function registerHomeRoutes(authenticated: Hono, deps: AuthenticatedRouteDeps): void;
@@ -0,0 +1,50 @@
1
+ //#region src/gateway/hono/routes/home.ts
2
+ /**
3
+ * GET /api/home — Aggregated home screen data for the mobile app.
4
+ *
5
+ * Returns:
6
+ * - recentlyOpened: notes sorted by lastOpenedAt (continue rail)
7
+ * - inboxCount: number of notes with status === 'inbox'
8
+ * - pendingTasks: task notes where done === false
9
+ * - recentSessions: last 5 active AI sessions (threads)
10
+ */
11
+ function registerHomeRoutes(authenticated, deps) {
12
+ const { service } = deps;
13
+ authenticated.get("/api/home", async (c) => {
14
+ const notes = service.notesServiceInstance;
15
+ const sessions = service.sessions;
16
+ const [recentlyOpened, inbox, pendingTasks, recentSessions] = await Promise.all([
17
+ notes.listNotes({
18
+ sortBy: "lastOpenedAt",
19
+ sortOrder: "desc",
20
+ limit: 10
21
+ }),
22
+ notes.listNotes({
23
+ status: "inbox",
24
+ limit: 0
25
+ }),
26
+ notes.listNotes({
27
+ pendingTasksOnly: true,
28
+ sortBy: "createdAt",
29
+ sortOrder: "desc",
30
+ limit: 10
31
+ }),
32
+ sessions.listSessions({
33
+ sortBy: "updatedAt",
34
+ sortOrder: "desc",
35
+ limit: 5
36
+ })
37
+ ]);
38
+ return c.json({
39
+ recentlyOpened: recentlyOpened.items.filter((n) => n.lastOpenedAt),
40
+ inboxCount: inbox.total,
41
+ pendingTasks: pendingTasks.items,
42
+ pendingTaskCount: pendingTasks.total,
43
+ recentSessions: recentSessions.items
44
+ });
45
+ });
46
+ }
47
+ //#endregion
48
+ export { registerHomeRoutes };
49
+
50
+ //# sourceMappingURL=home.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"home.js","names":[],"sources":["../../../../../src/gateway/hono/routes/home.ts"],"sourcesContent":["import type { Hono } from 'hono';\n\nimport type { AuthenticatedRouteDeps } from './deps.js';\n\n/**\n * GET /api/home — Aggregated home screen data for the mobile app.\n *\n * Returns:\n * - recentlyOpened: notes sorted by lastOpenedAt (continue rail)\n * - inboxCount: number of notes with status === 'inbox'\n * - pendingTasks: task notes where done === false\n * - recentSessions: last 5 active AI sessions (threads)\n */\nexport function registerHomeRoutes(authenticated: Hono, deps: AuthenticatedRouteDeps): void {\n const { service } = deps;\n\n authenticated.get('/api/home', async (c) => {\n const notes = service.notesServiceInstance;\n const sessions = service.sessions;\n\n const [recentlyOpened, inbox, pendingTasks, recentSessions] = await Promise.all([\n notes.listNotes({ sortBy: 'lastOpenedAt', sortOrder: 'desc', limit: 10 }),\n notes.listNotes({ status: 'inbox', limit: 0 }),\n notes.listNotes({ pendingTasksOnly: true, sortBy: 'createdAt', sortOrder: 'desc', limit: 10 }),\n sessions.listSessions({ sortBy: 'updatedAt', sortOrder: 'desc', limit: 5 }),\n ]);\n\n return c.json({\n recentlyOpened: recentlyOpened.items.filter((n) => n.lastOpenedAt),\n inboxCount: inbox.total,\n pendingTasks: pendingTasks.items,\n pendingTaskCount: pendingTasks.total,\n recentSessions: recentSessions.items,\n });\n });\n}\n"],"mappings":";;;;;;;;;;AAaA,SAAgB,mBAAmB,eAAqB,MAAoC;CAC1F,MAAM,EAAE,YAAY;AAEpB,eAAc,IAAI,aAAa,OAAO,MAAM;EAC1C,MAAM,QAAQ,QAAQ;EACtB,MAAM,WAAW,QAAQ;EAEzB,MAAM,CAAC,gBAAgB,OAAO,cAAc,kBAAkB,MAAM,QAAQ,IAAI;GAC9E,MAAM,UAAU;IAAE,QAAQ;IAAgB,WAAW;IAAQ,OAAO;IAAI,CAAC;GACzE,MAAM,UAAU;IAAE,QAAQ;IAAS,OAAO;IAAG,CAAC;GAC9C,MAAM,UAAU;IAAE,kBAAkB;IAAM,QAAQ;IAAa,WAAW;IAAQ,OAAO;IAAI,CAAC;GAC9F,SAAS,aAAa;IAAE,QAAQ;IAAa,WAAW;IAAQ,OAAO;IAAG,CAAC;GAC5E,CAAC;AAEF,SAAO,EAAE,KAAK;GACZ,gBAAgB,eAAe,MAAM,QAAQ,MAAM,EAAE,aAAa;GAClE,YAAY,MAAM;GAClB,cAAc,aAAa;GAC3B,kBAAkB,aAAa;GAC/B,gBAAgB,eAAe;GAChC,CAAC;GACF"}
@@ -1,8 +1,8 @@
1
1
  import { createLogger } from "../../../utils/logger/index.js";
2
2
  import { init_logger } from "../../../utils/logger.js";
3
- import { readdir, realpath, stat } from "node:fs/promises";
4
- import * as path$1 from "node:path";
5
3
  import * as os$1 from "node:os";
4
+ import * as path$1 from "node:path";
5
+ import { readdir, realpath, stat } from "node:fs/promises";
6
6
  //#region src/gateway/hono/routes/host-fs.ts
7
7
  init_logger();
8
8
  const log = createLogger("HostFs");
@@ -126,6 +126,22 @@ const AUTHENTICATED_LAZY_ROUTE_BUNDLES = [
126
126
  return { register: registerGoalsRoutes };
127
127
  }
128
128
  },
129
+ {
130
+ id: "notes",
131
+ match: (path) => startsWithAny(path, ["/api/notes"]),
132
+ load: async () => {
133
+ const { registerNotesRoutes } = await import("./notes.js");
134
+ return { register: registerNotesRoutes };
135
+ }
136
+ },
137
+ {
138
+ id: "home",
139
+ match: (path) => startsWithAny(path, ["/api/home"]),
140
+ load: async () => {
141
+ const { registerHomeRoutes } = await import("./home.js");
142
+ return { register: registerHomeRoutes };
143
+ }
144
+ },
129
145
  {
130
146
  id: "workflows",
131
147
  match: (path) => startsWithAny(path, ["/api/workflows"]),
@@ -199,11 +215,11 @@ const AUTHENTICATED_LAZY_ROUTE_BUNDLES = [
199
215
  }
200
216
  },
201
217
  {
202
- id: "mcp",
203
- match: (path) => startsWithAny(path, ["/api/mcp"]),
218
+ id: "connectors",
219
+ match: (path) => startsWithAny(path, ["/api/connectors"]),
204
220
  load: async () => {
205
- const { registerMcpRoutes } = await import("./mcp.js");
206
- return { register: registerMcpRoutes };
221
+ const { registerConnectorRoutes } = await import("./connectors.js");
222
+ return { register: registerConnectorRoutes };
207
223
  }
208
224
  }
209
225
  ];