@xopcai/xopc 0.0.270 → 0.0.273

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (255) hide show
  1. package/README.md +1 -5
  2. package/README.zh-CN.md +1 -5
  3. package/dist/browser-ext/dist/assets/{auth-cwEj8rFb.js → auth-DkwOUI6_.js} +132 -33
  4. package/dist/browser-ext/dist/background.js +2 -2
  5. package/dist/browser-ext/dist/sidepanel.html +1 -1
  6. package/dist/browser-ext/dist/sidepanel.js +46 -32
  7. package/dist/browser-ext/manifest.json +1 -1
  8. package/dist/extensions/telegram/xopc.extension.json +1 -1
  9. package/dist/gateway/static/root/assets/{activity-store-D_0FmdRj.js → activity-store-cF7IX2RP.js} +1 -1
  10. package/dist/gateway/static/root/assets/{agent-avatar-dicebear-IZvEXak_.js → agent-avatar-dicebear-BrgxX8nG.js} +1 -1
  11. package/dist/gateway/static/root/assets/agent-defaults-settings-panel-DvhuRCLA.js +1 -0
  12. package/dist/gateway/static/root/assets/agents-C0By2FIo.js +1 -0
  13. package/dist/gateway/static/root/assets/{api-O3TTQ4qN.js → api-CYkdUpkx.js} +1 -1
  14. package/dist/gateway/static/root/assets/app-link-BiBXVEvp.js +1 -0
  15. package/dist/gateway/static/root/assets/{app-management-settings-panel-Cqqsbzri.js → app-management-settings-panel-DfoNzWIa.js} +1 -1
  16. package/dist/gateway/static/root/assets/{appearance-settings-DaJyf32s.js → appearance-settings-czbLdCqj.js} +1 -1
  17. package/dist/gateway/static/root/assets/apps-page-BSJXKWcE.js +1 -0
  18. package/dist/gateway/static/root/assets/{archive-plugin-kDPnDTJI.js → archive-plugin-D14P13mX.js} +1 -1
  19. package/dist/gateway/static/root/assets/{attachment-load-CJ3VceKS.js → attachment-load-Dok_B1Gv.js} +1 -1
  20. package/dist/gateway/static/root/assets/{automations-page-JwMtU8XB.js → automations-page-DM7ZEewI.js} +1 -1
  21. package/dist/gateway/static/root/assets/automations-workspace--1TsZf3O.js +6 -0
  22. package/dist/gateway/static/root/assets/{binary-plugins-DzyZXLBX.js → binary-plugins-CxNg6InF.js} +1 -1
  23. package/dist/gateway/static/root/assets/{block-editor-kTt3gYIJ.js → block-editor-D22VcYnC.js} +3 -3
  24. package/dist/gateway/static/root/assets/{browser-automation-inputs-BKohPYR4.js → browser-automation-inputs-6NWTLEpd.js} +1 -1
  25. package/dist/gateway/static/root/assets/{browser-automations-page-ktQfFPk-.js → browser-automations-page-BrqySdbW.js} +2 -2
  26. package/dist/gateway/static/root/assets/browser-settings-page-DOHgQer_.js +8 -0
  27. package/dist/gateway/static/root/assets/capabilities-settings-panel-Bpse_5K-.js +8 -0
  28. package/dist/gateway/static/root/assets/channels-settings-yHsY174W.js +1 -0
  29. package/dist/gateway/static/root/assets/{channels-status-swr-DrqzYmDr.js → channels-status-swr-BUZimNmp.js} +1 -1
  30. package/dist/gateway/static/root/assets/{chat-terminal-dock-CIFGGLGa.js → chat-terminal-dock-CZPBNpMI.js} +2 -2
  31. package/dist/gateway/static/root/assets/clock-3-DnrAnuyZ.js +1 -0
  32. package/dist/gateway/static/root/assets/connectors-page-B_wLKGnH.js +2 -0
  33. package/dist/gateway/static/root/assets/cron-expression-C26e13YU.js +2 -0
  34. package/dist/gateway/static/root/assets/date-picker-Da_0QyLe.js +1 -0
  35. package/dist/gateway/static/root/assets/{dependency-picker-D3vNIjRI.js → dependency-picker-D_djqzy7.js} +1 -1
  36. package/dist/gateway/static/root/assets/{desktop-pet-fQwRb_3p.js → desktop-pet-Celmbw-T.js} +1 -1
  37. package/dist/gateway/static/root/assets/{desktop-pet-settings-DfOJ-GvT.js → desktop-pet-settings-CqNNgF45.js} +1 -1
  38. package/dist/gateway/static/root/assets/device-pairing-wizard-B5_w9qlm.js +1 -0
  39. package/dist/gateway/static/root/assets/{extension-debug-page-Cn53jB5-.js → extension-debug-page-ku3kCjvH.js} +1 -1
  40. package/dist/gateway/static/root/assets/{extension-page-IDpLCxpC.js → extension-page-C7FpHwL4.js} +1 -1
  41. package/dist/gateway/static/root/assets/extension-settings-page-OMj2tU2_.js +1 -0
  42. package/dist/gateway/static/root/assets/{gateway-config-swr-B7dcmP7Q.js → gateway-config-swr-6eb1vKE1.js} +1 -1
  43. package/dist/gateway/static/root/assets/gateway-settings-CH-6vkgN.js +1 -0
  44. package/dist/gateway/static/root/assets/{gateway-startup-retry-JGhGMhVZ.js → gateway-startup-retry-DUFFCU8H.js} +1 -1
  45. package/dist/gateway/static/root/assets/git-branch-Dh9uxTot.js +1 -0
  46. package/dist/gateway/static/root/assets/heartbeat-settings-CSFzOACM.js +1 -0
  47. package/dist/gateway/static/root/assets/home-page-BJebAKB-.js +1 -0
  48. package/dist/gateway/static/root/assets/{image-generation-api-BJLX7Qrh.js → image-generation-api-C1cHRBRp.js} +1 -1
  49. package/dist/gateway/static/root/assets/index-C6OWYFtQ.js +74 -0
  50. package/dist/gateway/static/root/assets/index-DKy1Qn1_.css +2 -0
  51. package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings-CBvMTFFx.js → keyboard-shortcuts-settings-BuvD3iv8.js} +1 -1
  52. package/dist/gateway/static/root/assets/local-app-workbench-page-CaC4-THD.js +2 -0
  53. package/dist/gateway/static/root/assets/{local-apps-page-APCMNDvU.js → local-apps-page-DdJ8zwBp.js} +1 -1
  54. package/dist/gateway/static/root/assets/locale-store-BBSCIl4I.js +1 -0
  55. package/dist/gateway/static/root/assets/logs-page-BaR2he0K.js +2 -0
  56. package/dist/gateway/static/root/assets/management-settings-r-iYWZFY.js +1 -0
  57. package/dist/gateway/static/root/assets/markdown-view-c5vtnYe8.js +201 -0
  58. package/dist/gateway/static/root/assets/{media-plugins-C10byeaa.js → media-plugins-D_a6GDY6.js} +1 -1
  59. package/dist/gateway/static/root/assets/message-circle-Badhj-4D.js +1 -0
  60. package/dist/gateway/static/root/assets/message-square-fVE7Ghj1.js +1 -0
  61. package/dist/gateway/static/root/assets/{messages-D0V_bgRP.js → messages-DjuBdDCn.js} +3 -3
  62. package/dist/gateway/static/root/assets/note-detail-panel-BV6nbgac.js +5 -0
  63. package/dist/gateway/static/root/assets/notes-page-BmLKoWwi.js +8 -0
  64. package/dist/gateway/static/root/assets/{page-tabs-qQ36zncF.js → page-tabs-C7Le9bSI.js} +1 -1
  65. package/dist/gateway/static/root/assets/popover-select-Dz_Qis2R.js +1 -0
  66. package/dist/gateway/static/root/assets/{preview-open-alternatives-BiAJvvCo.js → preview-open-alternatives-B2pOxJBK.js} +1 -1
  67. package/dist/gateway/static/root/assets/{proactive-card-CcNBqHoH.js → proactive-card-BlQ1vCtV.js} +1 -1
  68. package/dist/gateway/static/root/assets/{proactive-page-C3K61jve.js → proactive-page-CghKTfYa.js} +1 -1
  69. package/dist/gateway/static/root/assets/{product-open-page-CunnDP4w.js → product-open-page-DpjiHgwu.js} +1 -1
  70. package/dist/gateway/static/root/assets/project-detail-page-CV8Lh296.js +1 -0
  71. package/dist/gateway/static/root/assets/projects-page-COweOaJP.js +1 -0
  72. package/dist/gateway/static/root/assets/{registry-api-0JSegbNl.js → registry-api-CyQ4k1Ux.js} +1 -1
  73. package/dist/gateway/static/root/assets/remote-access-hub-ChPPGVU5.js +1 -0
  74. package/dist/gateway/static/root/assets/{runtime-tools-settings-panel-bu_mwBTr.js → runtime-tools-settings-panel-Bl4ArLHf.js} +2 -2
  75. package/dist/gateway/static/root/assets/{schema-form-BE0sgZyz.js → schema-form-KQFmfWd4.js} +1 -1
  76. package/dist/gateway/static/root/assets/sessions-page-DgmHibOK.js +1 -0
  77. package/dist/gateway/static/root/assets/settings-advanced-gate-DV7kMco2.js +1 -0
  78. package/dist/gateway/static/root/assets/{settings-form-section-CBo517lV.js → settings-form-section-Dbnls9ty.js} +1 -1
  79. package/dist/gateway/static/root/assets/{settings-page-DBPimx93.js → settings-page-CDKirYRG.js} +1 -1
  80. package/dist/gateway/static/root/assets/setup-status-panel-SQmtWoOs.js +1 -0
  81. package/dist/gateway/static/root/assets/{share-preview-page-DdV75VTe.js → share-preview-page-DwgLjS1m.js} +1 -1
  82. package/dist/gateway/static/root/assets/shares-settings-Cs5bUrYw.js +1 -0
  83. package/dist/gateway/static/root/assets/skill-reload-api-DyKrjq7F.js +1 -0
  84. package/dist/gateway/static/root/assets/{skills-page-Cn_-nvRo.js → skills-page-Bd0_ED_p.js} +1 -1
  85. package/dist/gateway/static/root/assets/skills-page.utils-rA-XT-YG.js +1 -0
  86. package/dist/gateway/static/root/assets/system-settings-panel-CSkMrHLz.js +1 -0
  87. package/dist/gateway/static/root/assets/task-detail-page-CEQU-L_G.js +1 -0
  88. package/dist/gateway/static/root/assets/{theme-store-1wryLgBQ.js → theme-store-DWpIEWen.js} +1 -1
  89. package/dist/gateway/static/root/assets/tunnel-api-COJcGnEi.js +1 -0
  90. package/dist/gateway/static/root/assets/{use-autosave-N_lm4FdD.js → use-autosave-DkQAIAuB.js} +1 -1
  91. package/dist/gateway/static/root/assets/user-model-page-BQAU55lf.js +2 -0
  92. package/dist/gateway/static/root/assets/{voice-api-key-field-DMsyVfri.js → voice-api-key-field-BrqcH0P-.js} +1 -1
  93. package/dist/gateway/static/root/assets/{voice-config-api-QWVmiAp3.js → voice-config-api-BJ95Z3pT.js} +1 -1
  94. package/dist/gateway/static/root/assets/{work-discovery-overlay-BC0vAxp1.js → work-discovery-overlay-vfTWKm13.js} +1 -1
  95. package/dist/gateway/static/root/assets/{workflow-run-setup-panel-Cz9jQIlP.js → workflow-run-setup-panel-CHdr_ng9.js} +2 -2
  96. package/dist/gateway/static/root/assets/workflows-page-hwRJD7vR.js +6 -0
  97. package/dist/gateway/static/root/index.html +16 -11
  98. package/dist/package.js +1 -1
  99. package/dist/packages/gateway-contract/src/device-pairing.js +2 -1
  100. package/dist/packages/gateway-contract/src/session-identity.js +37 -0
  101. package/dist/src/agent/memory/compaction-chunks.d.ts +18 -0
  102. package/dist/src/agent/memory/compaction-chunks.js +53 -0
  103. package/dist/src/agent/memory/compaction-request.d.ts +12 -0
  104. package/dist/src/agent/memory/compaction-request.js +72 -0
  105. package/dist/src/agent/memory/compaction.d.ts +3 -0
  106. package/dist/src/agent/memory/compaction.js +166 -118
  107. package/dist/src/agent/service.js +1 -0
  108. package/dist/src/browser/native-messaging-host.js +3 -1
  109. package/dist/src/browser/providers/browser-ext-install.d.ts +6 -0
  110. package/dist/src/browser/providers/browser-ext-install.js +16 -1
  111. package/dist/src/cli/bin.js +2 -2
  112. package/dist/src/cli/commands/agent.js +2 -2
  113. package/dist/src/cli/commands/auth.js +1 -1
  114. package/dist/src/cli/commands/doctor/checks/database-schema.js +1 -1
  115. package/dist/src/cli/commands/extension-dev.js +1 -1
  116. package/dist/src/cli/commands/extension-marketplace.js +1 -1
  117. package/dist/src/cli/commands/extension.js +1 -1
  118. package/dist/src/cli/commands/gateway/lifecycle.js +1 -1
  119. package/dist/src/cli/commands/gateway/run-foreground.js +8 -5
  120. package/dist/src/cli/commands/gateway/service.js +4 -3
  121. package/dist/src/cli/commands/gateway/token.js +28 -1
  122. package/dist/src/cli/commands/gateway-ssh-tunnel.js +1 -1
  123. package/dist/src/cli/commands/models.js +2 -2
  124. package/dist/src/cli/commands/onboard.js +1 -1
  125. package/dist/src/cli/commands/platform.js +1 -1
  126. package/dist/src/cli/commands/profile.js +1 -1
  127. package/dist/src/cli/commands/tunnel.js +6 -1
  128. package/dist/src/cli/commands/update.js +1 -1
  129. package/dist/src/cli/extension-cli-register.js +1 -1
  130. package/dist/src/config/index.js +1 -1
  131. package/dist/src/gateway/device-routes.js +4 -3
  132. package/dist/src/gateway/heartbeat/service.js +1 -1
  133. package/dist/src/gateway/hono/app.js +1 -0
  134. package/dist/src/gateway/hono/middleware/auth.d.ts +1 -2
  135. package/dist/src/gateway/hono/middleware/auth.js +49 -31
  136. package/dist/src/gateway/hono/middleware/strict-rate-limit.js +11 -15
  137. package/dist/src/gateway/hono/routes/browser-session.d.ts +3 -0
  138. package/dist/src/gateway/hono/routes/browser-session.js +43 -0
  139. package/dist/src/gateway/hono/routes/browser.js +26 -0
  140. package/dist/src/gateway/hono/routes/devices.js +61 -96
  141. package/dist/src/gateway/hono/routes/exposure.js +3 -7
  142. package/dist/src/gateway/hono/routes/lazy-bundles.js +8 -0
  143. package/dist/src/gateway/hono/routes/models.js +60 -1
  144. package/dist/src/gateway/hono/routes/notes.js +3 -7
  145. package/dist/src/gateway/hono/routes/sessions.js +11 -0
  146. package/dist/src/gateway/hono/routes/shares.js +8 -20
  147. package/dist/src/gateway/hono/routes/site-shares.js +4 -8
  148. package/dist/src/gateway/hono/routes/tunnel.js +13 -13
  149. package/dist/src/gateway/image-generation-setup.d.ts +17 -0
  150. package/dist/src/gateway/image-generation-setup.js +30 -21
  151. package/dist/src/gateway/rate-limit/buckets.d.ts +3 -0
  152. package/dist/src/gateway/rate-limit/buckets.js +10 -0
  153. package/dist/src/gateway/run-loop.js +1 -1
  154. package/dist/src/gateway/runtime-config.js +2 -0
  155. package/dist/src/gateway/security/browser-session.d.ts +5 -0
  156. package/dist/src/gateway/security/browser-session.js +45 -0
  157. package/dist/src/gateway/security/gateway-principal.d.ts +1 -0
  158. package/dist/src/gateway/server.js +1 -1
  159. package/dist/src/gateway/service.d.ts +1 -0
  160. package/dist/src/gateway/service.js +11 -1
  161. package/dist/src/heartbeat/index.js +1 -1
  162. package/dist/src/infra/rate-limit/keyed-store.d.ts +3 -0
  163. package/dist/src/infra/rate-limit/keyed-store.js +9 -2
  164. package/dist/src/proactive/policy/service.d.ts +1 -1
  165. package/dist/src/realtime/runtime.d.ts +2 -1
  166. package/dist/src/realtime/runtime.js +9 -3
  167. package/dist/src/realtime/tickets.d.ts +1 -0
  168. package/dist/src/realtime/tickets.js +3 -0
  169. package/dist/src/session/store.d.ts +2 -0
  170. package/dist/src/session/store.js +17 -2
  171. package/dist/src/session/types.d.ts +2 -1
  172. package/dist/src/storage/sqlite/browser-session-repository.d.ts +17 -0
  173. package/dist/src/storage/sqlite/browser-session-repository.js +54 -0
  174. package/dist/src/storage/sqlite/device-pairing-approval.js +3 -4
  175. package/dist/src/storage/sqlite/device-pairing-repository.d.ts +4 -10
  176. package/dist/src/storage/sqlite/device-pairing-repository.js +10 -62
  177. package/dist/src/storage/sqlite/index.d.ts +1 -1
  178. package/dist/src/storage/sqlite/index.js +2 -2
  179. package/dist/src/storage/sqlite/migrations/164_browser_sessions.sql +8 -0
  180. package/dist/src/storage/sqlite/migrations/165_device_pairing_target.sql +40 -0
  181. package/dist/src/storage/sqlite/migrations/runner.d.ts +1 -1
  182. package/dist/src/storage/sqlite/migrations/runner.js +3 -3
  183. package/dist/src/storage/sqlite/migrations/runner.ts +1 -1
  184. package/dist/src/storage/sqlite/schema.js +1 -1
  185. package/dist/src/storage/sqlite/session-identity-sql.d.ts +2 -0
  186. package/dist/src/storage/sqlite/session-identity-sql.js +18 -0
  187. package/dist/src/storage/sqlite/session-repository.js +26 -22
  188. package/dist/src/tunnel/auth-policy.d.ts +3 -0
  189. package/dist/src/tunnel/auth-policy.js +8 -0
  190. package/dist/src/tunnel/broker-client.d.ts +5 -15
  191. package/dist/src/tunnel/broker-client.js +37 -49
  192. package/dist/src/tunnel/frpc-binary.d.ts +8 -6
  193. package/dist/src/tunnel/frpc-binary.js +76 -88
  194. package/dist/src/tunnel/frpc-config.d.ts +2 -1
  195. package/dist/src/tunnel/frpc-config.js +29 -12
  196. package/dist/src/tunnel/frpc-release.d.ts +27 -0
  197. package/dist/src/tunnel/frpc-release.js +30 -0
  198. package/dist/src/tunnel/gateway-lifecycle.js +8 -2
  199. package/dist/src/tunnel/index.js +2 -1
  200. package/dist/src/tunnel/registration-proof.d.ts +19 -0
  201. package/dist/src/tunnel/registration-proof.js +37 -0
  202. package/dist/src/tunnel/tunnel-persist.js +3 -1
  203. package/dist/src/tunnel/tunnel-service.d.ts +1 -0
  204. package/dist/src/tunnel/tunnel-service.js +35 -8
  205. package/dist/src/tunnel/tunnel-state.js +11 -5
  206. package/dist/src/tunnel/tunnel-types.d.ts +2 -0
  207. package/dist/src/tunnel/well-known.js +5 -1
  208. package/dist/src/user-context/config.js +2 -2
  209. package/dist/src/utils/logger/redact.js +4 -0
  210. package/dist/src/voice/realtime/runtime.d.ts +1 -0
  211. package/dist/src/voice/realtime/runtime.js +17 -1
  212. package/dist/src/voice/realtime/runtime.types.d.ts +1 -0
  213. package/dist/src/workflows/service/workflow-run-service.js +2 -0
  214. package/dist/src/workflows/service/workflow-session-bridge.d.ts +1 -0
  215. package/dist/src/workflows/service/workflow-session-bridge.js +1 -0
  216. package/package.json +3 -3
  217. package/dist/gateway/static/root/assets/agent-defaults-settings-panel-CE3ygr3l.js +0 -1
  218. package/dist/gateway/static/root/assets/agents-DzG2qw-c.js +0 -1
  219. package/dist/gateway/static/root/assets/apps-page-B4lX6yoT.js +0 -1
  220. package/dist/gateway/static/root/assets/automations-workspace-BiNBewg0.js +0 -6
  221. package/dist/gateway/static/root/assets/browser-settings-page-Dgdt5uVL.js +0 -8
  222. package/dist/gateway/static/root/assets/capabilities-settings-panel-BpDW-R9f.js +0 -7
  223. package/dist/gateway/static/root/assets/channels-settings-DU4EQnR0.js +0 -1
  224. package/dist/gateway/static/root/assets/connectors-page-CfJqy284.js +0 -2
  225. package/dist/gateway/static/root/assets/cron-expression-BNwbnrEb.js +0 -2
  226. package/dist/gateway/static/root/assets/date-picker-DKyirU4K.js +0 -1
  227. package/dist/gateway/static/root/assets/extension-settings-page-B1dds2bP.js +0 -1
  228. package/dist/gateway/static/root/assets/gateway-settings-pp9jN0wl.js +0 -1
  229. package/dist/gateway/static/root/assets/heartbeat-settings-B8_zTyev.js +0 -1
  230. package/dist/gateway/static/root/assets/home-page-g1KdAdLb.js +0 -1
  231. package/dist/gateway/static/root/assets/index-1zRt56Zt.css +0 -2
  232. package/dist/gateway/static/root/assets/index-OMnem2nr.js +0 -74
  233. package/dist/gateway/static/root/assets/local-app-workbench-page-bj75v2ZE.js +0 -2
  234. package/dist/gateway/static/root/assets/locale-store-BThkG0W5.js +0 -1
  235. package/dist/gateway/static/root/assets/logs-page-BX7n39zV.js +0 -2
  236. package/dist/gateway/static/root/assets/management-settings-CM62j8ZX.js +0 -1
  237. package/dist/gateway/static/root/assets/markdown-view-BwjpJVPs.js +0 -201
  238. package/dist/gateway/static/root/assets/mobile-pairing-wizard-BCWfwVx3.js +0 -1
  239. package/dist/gateway/static/root/assets/note-detail-panel-koOqb0gX.js +0 -5
  240. package/dist/gateway/static/root/assets/notes-page-BH54rY3B.js +0 -8
  241. package/dist/gateway/static/root/assets/popover-select-CKBYnT3c.js +0 -1
  242. package/dist/gateway/static/root/assets/project-detail-page-SL2g8MZY.js +0 -1
  243. package/dist/gateway/static/root/assets/projects-page-BtxazT5J.js +0 -1
  244. package/dist/gateway/static/root/assets/remote-access-hub-BSb7b67A.js +0 -1
  245. package/dist/gateway/static/root/assets/sessions-page-ljcS2KVz.js +0 -1
  246. package/dist/gateway/static/root/assets/settings-advanced-gate-CR9Y9LQm.js +0 -1
  247. package/dist/gateway/static/root/assets/setup-status-panel-J3AnooPW.js +0 -1
  248. package/dist/gateway/static/root/assets/shares-settings-AAm4Iwcp.js +0 -1
  249. package/dist/gateway/static/root/assets/skill-reload-api-pRCjP5sm.js +0 -1
  250. package/dist/gateway/static/root/assets/skills-page.utils-CfVAc_lu.js +0 -1
  251. package/dist/gateway/static/root/assets/system-settings-panel-B-pzalp-.js +0 -1
  252. package/dist/gateway/static/root/assets/task-detail-page-CmrLy3PO.js +0 -1
  253. package/dist/gateway/static/root/assets/tunnel-api-Cgpnm2fL.js +0 -1
  254. package/dist/gateway/static/root/assets/user-model-page-u3QLDX6L.js +0 -2
  255. package/dist/gateway/static/root/assets/workflows-page-DA6OOK6X.js +0 -6
@@ -7,82 +7,30 @@ const PAIRING_ATTEMPTS = 5;
7
7
  function hashToken(token) {
8
8
  return crypto.createHash("sha256").update(token).digest("hex");
9
9
  }
10
- function hashesMatch(left, right) {
11
- return crypto.timingSafeEqual(Buffer.from(left, "hex"), Buffer.from(right, "hex"));
12
- }
13
- function tokenId(token) {
14
- if (!token.startsWith(PAIRING_TOKEN_PREFIX)) return void 0;
15
- const separator = token.indexOf("_", 10);
16
- if (separator <= 10 || separator === token.length - 1) return void 0;
17
- return token.slice(10, separator);
18
- }
19
- function createDevicePairingSetup(routes, now = Date.now(), protocolVersion = 2, options) {
20
- if (routes.length === 0) throw new Error("No secure mobile route is available");
10
+ function createDevicePairingSetup(routes, now = Date.now(), options) {
11
+ if (routes.length === 0) throw new Error("No secure device route is available");
21
12
  const id = crypto.randomUUID();
22
13
  const token = `${PAIRING_TOKEN_PREFIX}${id}_${crypto.randomBytes(32).toString("base64url")}`;
23
14
  const expiresAt = now + (options?.ttlMs ?? PAIRING_TTL_MS);
24
15
  runSqliteWriteTransaction((db) => {
25
- db.prepare(`DELETE FROM device_pairing_sessions WHERE
26
- (protocol_version = 2 AND (expires_at <= ? OR consumed_at IS NOT NULL)) OR
27
- (protocol_version = 3 AND expires_at < ?)`).run(now, now - 1440 * 6e4);
16
+ db.prepare(`DELETE FROM device_pairing_sessions
17
+ WHERE expires_at < ?`).run(now - 1440 * 6e4);
28
18
  db.prepare(`
29
19
  INSERT INTO device_pairing_sessions (
30
20
  pairing_id, secret_hash, routes_json, expires_at, attempts_remaining, created_at
31
- , protocol_version, enrollment_issuer, enrollment_extension_id,
32
- enrollment_public_key_thumbprint, enrollment_nonce
21
+ , enrollment_issuer, enrollment_extension_id,
22
+ enrollment_public_key_thumbprint, enrollment_nonce, target_kind
33
23
  ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
34
- `).run(id, hashToken(token), JSON.stringify(routes), expiresAt, PAIRING_ATTEMPTS, now, protocolVersion, options?.enrollment?.issuer ?? null, options?.enrollment?.extensionId ?? null, options?.enrollment?.publicKeyThumbprint ?? null, options?.enrollment?.nonce ?? null);
24
+ `).run(id, hashToken(token), JSON.stringify(routes), expiresAt, PAIRING_ATTEMPTS, now, options?.enrollment?.issuer ?? null, options?.enrollment?.extensionId ?? null, options?.enrollment?.publicKeyThumbprint ?? null, options?.enrollment?.nonce ?? null, options.targetKind);
35
25
  });
36
26
  return {
37
27
  id,
38
28
  token,
39
29
  routes: [...routes],
40
- expiresAt
30
+ expiresAt,
31
+ targetKind: options.targetKind
41
32
  };
42
33
  }
43
- function consumeDevicePairingToken(token, now = Date.now()) {
44
- const id = tokenId(token);
45
- if (!id) return {
46
- ok: false,
47
- reason: "invalid"
48
- };
49
- return runSqliteWriteTransaction((db) => {
50
- const row = db.prepare("SELECT * FROM device_pairing_sessions WHERE pairing_id = ?").get(id);
51
- if (!row || row.attempts_remaining <= 0) return {
52
- ok: false,
53
- reason: "invalid"
54
- };
55
- if (row.protocol_version !== 2) return {
56
- ok: false,
57
- reason: "invalid"
58
- };
59
- if (row.consumed_at !== null) return {
60
- ok: false,
61
- reason: "consumed"
62
- };
63
- if (row.expires_at <= now) return {
64
- ok: false,
65
- reason: "expired"
66
- };
67
- if (!hashesMatch(row.secret_hash, hashToken(token))) {
68
- db.prepare(`
69
- UPDATE device_pairing_sessions
70
- SET attempts_remaining = attempts_remaining - 1
71
- WHERE pairing_id = ? AND attempts_remaining > 0
72
- `).run(id);
73
- return {
74
- ok: false,
75
- reason: "invalid"
76
- };
77
- }
78
- db.prepare("UPDATE device_pairing_sessions SET consumed_at = ? WHERE pairing_id = ?").run(now, id);
79
- return {
80
- ok: true,
81
- pairingId: id,
82
- routes: JSON.parse(row.routes_json)
83
- };
84
- });
85
- }
86
34
  function isDevicePairingSetupActive(pairingId, now = Date.now()) {
87
35
  const row = getSqliteDatabase().prepare(`
88
36
  SELECT 1 FROM device_pairing_sessions
@@ -91,4 +39,4 @@ function isDevicePairingSetupActive(pairingId, now = Date.now()) {
91
39
  return Boolean(row);
92
40
  }
93
41
  //#endregion
94
- export { consumeDevicePairingToken, createDevicePairingSetup, isDevicePairingSetupActive };
42
+ export { createDevicePairingSetup, isDevicePairingSetupActive };
@@ -9,7 +9,7 @@ export { deleteEndpointSessionBinding, getEndpointSessionBinding, setEndpointSes
9
9
  export { deleteBrowserTabBinding, deleteBrowserTabBindingsByEndpoint, deleteBrowserTabBindingsByPrincipal, getBrowserTabBinding, getBrowserTabBindingById, setBrowserTabBinding, } from './browser-tab-binding-repository.js';
10
10
  export { authenticateDeviceAccessToken, buildRefreshProofMessage, createDevice, getDevice, issueDeviceTokenPair, listDevices, revokeDevice, rotateDeviceRefreshToken, type DeviceAccessIdentity, type DevicePlatform, type DevicePublicKeyJwk, type DeviceRecord, type DeviceTokenPair, } from './device-access-repository.js';
11
11
  export { clearGatewayIdentityForTest, getOrCreateGatewayIdentity, signGatewayPayload, type GatewayIdentity, } from './gateway-identity-repository.js';
12
- export { consumeDevicePairingToken, createDevicePairingSetup, isDevicePairingSetupActive, type DevicePairingSetup, type DeviceRoute, type PairingConsumeResult, } from './device-pairing-repository.js';
12
+ export { createDevicePairingSetup, isDevicePairingSetupActive, type DevicePairingSetup, type DeviceRoute, } from './device-pairing-repository.js';
13
13
  export { claimContextExtractionRun, finishContextExtractionRun, getContextExtractionRun, hasIndependentExtractionOutput, listContextExtractionOutputs, listContextExtractionRuns, type ContextExtractionOutput, type ContextExtractionRun, type ContextExtractionStatus, type ContextObjectType, } from './context-extraction-repository.js';
14
14
  export { closeTemporalAssertions, createTemporalAssertion, linkContextObjects, listContextObjectRelations, listTemporalAssertions, type ContextObjectRelation, type ContextTemporalAssertion, } from './context-relation-repository.js';
15
15
  export { createCollaborationRule, getCollaborationRule, listCollaborationRules, setCollaborationRuleStatus, type CollaborationRule, } from './collaboration-rule-repository.js';
@@ -10,7 +10,7 @@ import { deleteEndpointSessionBinding, getEndpointSessionBinding, setEndpointSes
10
10
  import { deleteBrowserTabBinding, deleteBrowserTabBindingsByEndpoint, deleteBrowserTabBindingsByPrincipal, getBrowserTabBinding, getBrowserTabBindingById, setBrowserTabBinding } from "./browser-tab-binding-repository.js";
11
11
  import { authenticateDeviceAccessToken, buildRefreshProofMessage, createDevice, getDevice, issueDeviceTokenPair, listDevices, revokeDevice, rotateDeviceRefreshToken } from "./device-access-repository.js";
12
12
  import { clearGatewayIdentityForTest, getOrCreateGatewayIdentity, signGatewayPayload } from "./gateway-identity-repository.js";
13
- import { consumeDevicePairingToken, createDevicePairingSetup, isDevicePairingSetupActive } from "./device-pairing-repository.js";
13
+ import { createDevicePairingSetup, isDevicePairingSetupActive } from "./device-pairing-repository.js";
14
14
  import { claimContextExtractionRun, finishContextExtractionRun, getContextExtractionRun, hasIndependentExtractionOutput, listContextExtractionOutputs, listContextExtractionRuns } from "./context-extraction-repository.js";
15
15
  import { closeTemporalAssertions, createTemporalAssertion, linkContextObjects, listContextObjectRelations, listTemporalAssertions } from "./context-relation-repository.js";
16
16
  import { createCollaborationRule, getCollaborationRule, listCollaborationRules, setCollaborationRuleStatus } from "./collaboration-rule-repository.js";
@@ -40,4 +40,4 @@ import { appendConnectorExecutionAudit, claimConnectorWebhookDelivery, completeC
40
40
  import { getConnectorAccount, listConnectorAccounts, reconcileConnectorAccount, refreshConnectorAccountCurrent } from "./connector-account-repository.js";
41
41
  import { getConnectorSyncPolicy, getConnectorSyncPolicyForConnection, listConnectorSyncPolicies, upsertConnectorSyncPolicy } from "./connector-sync-policy-repository.js";
42
42
  import { getUserTrustPolicy, setUserTrustPolicy } from "./user-trust-repository.js";
43
- export { COMPOSER_INPUT_HISTORY_LIMIT, DatabaseSchemaMigrationGapError, DatabaseSchemaTooNewError, SCHEMA_META_SCHEMA_VERSION_KEY, XOPC_DB_BASELINE_SCHEMA_VERSION, XOPC_DB_FILENAME, XOPC_DB_SCHEMA_VERSION, acknowledgeHomeAttention, appendCompactionBoundaryIfUnchanged, appendComposerInputHistory, appendConnectorExecutionAudit, appendTranscriptEntry, applyPendingMigrations, authenticateDeviceAccessToken, bindEndpointPrincipal, buildDefaultSessionMetadata, buildGlobalSessionStats, buildRefreshProofMessage, buildRelationshipPrompt, cancelQueuedSessionInput, claimConnectorWebhookDelivery, claimContextExtractionRun, claimKnowledgeSourceItems, claimNextConnectorLearningJob, claimNextSessionInput, classifyStoredRow, clearComposerInputHistory, clearGatewayIdentityForTest, closeTemporalAssertions, closeXopcDatabase, completeConnectorWebhookDelivery, completeKnowledgeSourceItemSynthesis, consumeClarificationApproval, consumeClarificationResume, consumeConnectorApproval, consumeDevicePairingToken, countKnowledgeSourceItems, createClarificationWait, createCollaborationRule, createConnectorApproval, createContextEvidence, createDevice, createDevicePairingSetup, createEndpointPrincipal, createObjectLinkRecord, createTemporalAssertion, decideConnectorApproval, deleteBrowserTabBinding, deleteBrowserTabBindingsByEndpoint, deleteBrowserTabBindingsByPrincipal, deleteConnectorConnection, deleteConnectorInstallation, deleteEndpointSessionBinding, deleteKnowledgeSourceItems, deleteNoteAgentContextRecord, deleteNoteRecord, deleteObjectLinkRecord, deleteSessionConfig, deleteSessionRecord, discoverSqlMigrations, enqueueConnectorLearningJob, ensureSessionRecord, ensureXopcDatabaseSchema, estimateTokensFromMessages, extractFtsContent, findSessionInput, findSessionKeyBySessionId, finishContextExtractionRun, finishEndpointToolInvocationAudit, finishKnowledgeSyncRun, finishSessionInputRun, getActiveClarification, getActivityEventRecord, getBrowserTabBinding, getBrowserTabBindingById, getCachedConnectorCatalogEntry, getClarification, getClarificationResumeInput, getClarificationSnapshot, getCollaborationRule, getConnectorAccount, getConnectorApproval, getConnectorConnection, getConnectorInstallation, getConnectorSyncPolicy, getConnectorSyncPolicyForConnection, getContextExtractionRun, getCurrentSessionId, getDevice, getEndpointPrincipal, getEndpointSessionBinding, getGlobalSessionStats, getInteractionState, getKnowledgeConsumerWatermark, getKnowledgeSourceCursor, getKnowledgeSourceItem, getNoteAgentContextRecord, getNoteRecord, getOrCreateGatewayIdentity, getRelationshipSettings, getSessionConfig, getSessionInputById, getSessionInputState, getSessionMetadata, getSessionPersistedLevels, getSessionTaskPlan, getSqliteDatabase, getUserPeopleIndexState, getUserPerson, getUserTrustPolicy, getXopcDatabase, hasIndependentExtractionOutput, hasSessionConfig, incrementSessionStatsOnAppend, insertSessionInput, inspectSchemaMigrationStatus, isClarificationSuspended, isDevicePairingSetupActive, isHomeAttentionAcknowledged, isProactiveSupportAllowed, isXopcDatabaseOpen, issueDeviceTokenPair, linkContextObjects, listActiveSessionInputRuns, listActivityRecords, listCachedConnectorCatalogEntries, listCollaborationRules, listCompactionBoundaries, listComposerInputHistory, listConnectorAccounts, listConnectorActionMetadata, listConnectorApprovals, listConnectorConnections, listConnectorExecutionAudit, listConnectorInstallations, listConnectorLearningJobs, listConnectorSyncPolicies, listContextExtractionOutputs, listContextExtractionRuns, listContextObjectRelations, listDevices, listEndpointPrincipals, listEndpointToolInvocationAudits, listKnowledgeSourceChanges, listKnowledgeSourceItems, listKnowledgeSyncRuns, listNoteRecords, listObjectActivityRecords, listObjectLinkRecords, listProjectActivityRecords, listRegisteredMigrationTargets, listSessionMetadata, listSessionsByAgent, listTemporalAssertions, listUserPeople, loadCompactionSourceSnapshot, loadLlmMessagesForSession, loadTranscriptHistoryRowsForSession, loadTranscriptRows, loadTranscriptRowsForSession, mergeUserPeople, metadataToSessionInsert, mutateQueuedSessionInput, openXopcDatabase, paginateTranscriptMessages, patchSessionMetadata, pruneBoundedKnowledgeSourceItems, readSchemaVersion, readSchemaVersionForTest, reconcileConnectorAccount, recordActivityEvent, recoverSessionInputState, recoverStaleConnectorLearningJobs, refreshConnectorAccountCurrent, releaseConnectorWebhookDelivery, replaceConnectorCatalogEntries, replaceLatestSessionTurnAndQueueInput, replaceTranscriptRows, replaceUserPeopleIndex, requireXopcDatabase, resetSessionRecord, resetXopcDatabaseSingletonForTest, resolveClarification, resolveMigrationsDir, resolveSessionAgentId, resolveXopcDatabasePath, restoreBeforeCompactionBoundary, revokeDevice, revokeEndpointPrincipal, rotateDeviceRefreshToken, runSqliteWriteTransaction, searchSessionTranscript, sessionConfigRowToConfig, sessionRowToMetadata, setBrowserTabBinding, setCollaborationRuleStatus, setConnectorLearningPaused, setEndpointSessionBinding, setInteractionState, setKnowledgeConsumerWatermark, setKnowledgeSourceCursor, setKnowledgeSourceItemSynthesisStatus, setSessionConfig, setSessionInputStatus, setSessionTaskPlan, setUserTrustPolicy, signGatewayPayload, startEndpointToolInvocationAudit, startKnowledgeSyncRun, summarizeUserPeople, supersedeActiveClarification, touchEndpointPrincipal, transcriptEntryRowToStoredRow, updateConnectorLearningJob, updateInteractionStateFromMessage, updateRelationshipSettings, updateSessionConfig, updateSessionStats, updateUserPerson, upsertConnectorActionMetadata, upsertConnectorCatalogEntry, upsertConnectorConnection, upsertConnectorInstallation, upsertConnectorSyncPolicy, upsertKnowledgeSourceItems, upsertNoteAgentContextRecord, upsertNoteRecord, validateLatestSessionTurnTarget };
43
+ export { COMPOSER_INPUT_HISTORY_LIMIT, DatabaseSchemaMigrationGapError, DatabaseSchemaTooNewError, SCHEMA_META_SCHEMA_VERSION_KEY, XOPC_DB_BASELINE_SCHEMA_VERSION, XOPC_DB_FILENAME, XOPC_DB_SCHEMA_VERSION, acknowledgeHomeAttention, appendCompactionBoundaryIfUnchanged, appendComposerInputHistory, appendConnectorExecutionAudit, appendTranscriptEntry, applyPendingMigrations, authenticateDeviceAccessToken, bindEndpointPrincipal, buildDefaultSessionMetadata, buildGlobalSessionStats, buildRefreshProofMessage, buildRelationshipPrompt, cancelQueuedSessionInput, claimConnectorWebhookDelivery, claimContextExtractionRun, claimKnowledgeSourceItems, claimNextConnectorLearningJob, claimNextSessionInput, classifyStoredRow, clearComposerInputHistory, clearGatewayIdentityForTest, closeTemporalAssertions, closeXopcDatabase, completeConnectorWebhookDelivery, completeKnowledgeSourceItemSynthesis, consumeClarificationApproval, consumeClarificationResume, consumeConnectorApproval, countKnowledgeSourceItems, createClarificationWait, createCollaborationRule, createConnectorApproval, createContextEvidence, createDevice, createDevicePairingSetup, createEndpointPrincipal, createObjectLinkRecord, createTemporalAssertion, decideConnectorApproval, deleteBrowserTabBinding, deleteBrowserTabBindingsByEndpoint, deleteBrowserTabBindingsByPrincipal, deleteConnectorConnection, deleteConnectorInstallation, deleteEndpointSessionBinding, deleteKnowledgeSourceItems, deleteNoteAgentContextRecord, deleteNoteRecord, deleteObjectLinkRecord, deleteSessionConfig, deleteSessionRecord, discoverSqlMigrations, enqueueConnectorLearningJob, ensureSessionRecord, ensureXopcDatabaseSchema, estimateTokensFromMessages, extractFtsContent, findSessionInput, findSessionKeyBySessionId, finishContextExtractionRun, finishEndpointToolInvocationAudit, finishKnowledgeSyncRun, finishSessionInputRun, getActiveClarification, getActivityEventRecord, getBrowserTabBinding, getBrowserTabBindingById, getCachedConnectorCatalogEntry, getClarification, getClarificationResumeInput, getClarificationSnapshot, getCollaborationRule, getConnectorAccount, getConnectorApproval, getConnectorConnection, getConnectorInstallation, getConnectorSyncPolicy, getConnectorSyncPolicyForConnection, getContextExtractionRun, getCurrentSessionId, getDevice, getEndpointPrincipal, getEndpointSessionBinding, getGlobalSessionStats, getInteractionState, getKnowledgeConsumerWatermark, getKnowledgeSourceCursor, getKnowledgeSourceItem, getNoteAgentContextRecord, getNoteRecord, getOrCreateGatewayIdentity, getRelationshipSettings, getSessionConfig, getSessionInputById, getSessionInputState, getSessionMetadata, getSessionPersistedLevels, getSessionTaskPlan, getSqliteDatabase, getUserPeopleIndexState, getUserPerson, getUserTrustPolicy, getXopcDatabase, hasIndependentExtractionOutput, hasSessionConfig, incrementSessionStatsOnAppend, insertSessionInput, inspectSchemaMigrationStatus, isClarificationSuspended, isDevicePairingSetupActive, isHomeAttentionAcknowledged, isProactiveSupportAllowed, isXopcDatabaseOpen, issueDeviceTokenPair, linkContextObjects, listActiveSessionInputRuns, listActivityRecords, listCachedConnectorCatalogEntries, listCollaborationRules, listCompactionBoundaries, listComposerInputHistory, listConnectorAccounts, listConnectorActionMetadata, listConnectorApprovals, listConnectorConnections, listConnectorExecutionAudit, listConnectorInstallations, listConnectorLearningJobs, listConnectorSyncPolicies, listContextExtractionOutputs, listContextExtractionRuns, listContextObjectRelations, listDevices, listEndpointPrincipals, listEndpointToolInvocationAudits, listKnowledgeSourceChanges, listKnowledgeSourceItems, listKnowledgeSyncRuns, listNoteRecords, listObjectActivityRecords, listObjectLinkRecords, listProjectActivityRecords, listRegisteredMigrationTargets, listSessionMetadata, listSessionsByAgent, listTemporalAssertions, listUserPeople, loadCompactionSourceSnapshot, loadLlmMessagesForSession, loadTranscriptHistoryRowsForSession, loadTranscriptRows, loadTranscriptRowsForSession, mergeUserPeople, metadataToSessionInsert, mutateQueuedSessionInput, openXopcDatabase, paginateTranscriptMessages, patchSessionMetadata, pruneBoundedKnowledgeSourceItems, readSchemaVersion, readSchemaVersionForTest, reconcileConnectorAccount, recordActivityEvent, recoverSessionInputState, recoverStaleConnectorLearningJobs, refreshConnectorAccountCurrent, releaseConnectorWebhookDelivery, replaceConnectorCatalogEntries, replaceLatestSessionTurnAndQueueInput, replaceTranscriptRows, replaceUserPeopleIndex, requireXopcDatabase, resetSessionRecord, resetXopcDatabaseSingletonForTest, resolveClarification, resolveMigrationsDir, resolveSessionAgentId, resolveXopcDatabasePath, restoreBeforeCompactionBoundary, revokeDevice, revokeEndpointPrincipal, rotateDeviceRefreshToken, runSqliteWriteTransaction, searchSessionTranscript, sessionConfigRowToConfig, sessionRowToMetadata, setBrowserTabBinding, setCollaborationRuleStatus, setConnectorLearningPaused, setEndpointSessionBinding, setInteractionState, setKnowledgeConsumerWatermark, setKnowledgeSourceCursor, setKnowledgeSourceItemSynthesisStatus, setSessionConfig, setSessionInputStatus, setSessionTaskPlan, setUserTrustPolicy, signGatewayPayload, startEndpointToolInvocationAudit, startKnowledgeSyncRun, summarizeUserPeople, supersedeActiveClarification, touchEndpointPrincipal, transcriptEntryRowToStoredRow, updateConnectorLearningJob, updateInteractionStateFromMessage, updateRelationshipSettings, updateSessionConfig, updateSessionStats, updateUserPerson, upsertConnectorActionMetadata, upsertConnectorCatalogEntry, upsertConnectorConnection, upsertConnectorInstallation, upsertConnectorSyncPolicy, upsertKnowledgeSourceItems, upsertNoteAgentContextRecord, upsertNoteRecord, validateLatestSessionTurnTarget };
@@ -0,0 +1,8 @@
1
+ CREATE TABLE browser_sessions (
2
+ session_id TEXT PRIMARY KEY,
3
+ token_hash TEXT NOT NULL UNIQUE,
4
+ auth_fingerprint TEXT NOT NULL,
5
+ created_at INTEGER NOT NULL,
6
+ expires_at INTEGER NOT NULL
7
+ );
8
+ CREATE INDEX idx_browser_sessions_expiry ON browser_sessions(expires_at);
@@ -0,0 +1,40 @@
1
+ -- Pairing state is short-lived, so replace the tables instead of carrying the
2
+ -- retired protocol discriminator into the device-targeted flow.
3
+ DROP TABLE device_pairing_requests;
4
+ DROP TABLE device_pairing_sessions;
5
+
6
+ CREATE TABLE device_pairing_sessions (
7
+ pairing_id TEXT PRIMARY KEY,
8
+ secret_hash TEXT NOT NULL,
9
+ routes_json TEXT NOT NULL,
10
+ expires_at INTEGER NOT NULL,
11
+ attempts_remaining INTEGER NOT NULL CHECK (attempts_remaining >= 0),
12
+ created_at INTEGER NOT NULL,
13
+ consumed_at INTEGER,
14
+ enrollment_issuer TEXT,
15
+ enrollment_extension_id TEXT,
16
+ enrollment_public_key_thumbprint TEXT,
17
+ enrollment_nonce TEXT,
18
+ target_kind TEXT NOT NULL CHECK (target_kind IN ('mobile', 'browser'))
19
+ );
20
+
21
+ CREATE INDEX idx_device_pairing_sessions_expiry
22
+ ON device_pairing_sessions(expires_at);
23
+
24
+ CREATE TABLE device_pairing_requests (
25
+ request_id TEXT PRIMARY KEY,
26
+ pairing_id TEXT NOT NULL UNIQUE REFERENCES device_pairing_sessions(pairing_id) ON DELETE CASCADE,
27
+ device_json TEXT NOT NULL,
28
+ status TEXT NOT NULL CHECK (status IN ('pending', 'approved', 'completed', 'rejected', 'cancelled', 'expired')),
29
+ revision INTEGER NOT NULL DEFAULT 1,
30
+ confirmation_code TEXT NOT NULL,
31
+ expires_at INTEGER NOT NULL,
32
+ recovery_until INTEGER NOT NULL,
33
+ completion_key TEXT,
34
+ initial_token_hash TEXT,
35
+ device_id TEXT REFERENCES devices(device_id),
36
+ created_at INTEGER NOT NULL
37
+ );
38
+
39
+ CREATE INDEX idx_device_pairing_requests_expiry
40
+ ON device_pairing_requests(recovery_until);
@@ -3,7 +3,7 @@ import type { ApplyMigrationsOptions } from './types.js';
3
3
  /** Baseline schema version applied from schema.sql on first open. */
4
4
  export declare const XOPC_DB_BASELINE_SCHEMA_VERSION = 11;
5
5
  /** Latest schema version this release supports (increment when adding migrations). */
6
- export declare const XOPC_DB_SCHEMA_VERSION = 163;
6
+ export declare const XOPC_DB_SCHEMA_VERSION = 165;
7
7
  export declare function resolveMigrationsDir(override?: string): string;
8
8
  /**
9
9
  * Apply sequential SQL migrations from (currentVersion + 1) through targetVersion.
@@ -12,7 +12,7 @@ const log = createLogger("Sqlite:Migrations");
12
12
  /** Baseline schema version applied from schema.sql on first open. */
13
13
  const XOPC_DB_BASELINE_SCHEMA_VERSION = 11;
14
14
  /** Latest schema version this release supports (increment when adding migrations). */
15
- const XOPC_DB_SCHEMA_VERSION = 163;
15
+ const XOPC_DB_SCHEMA_VERSION = 165;
16
16
  const MODULE_DIR = dirname(fileURLToPath(import.meta.url));
17
17
  function backupBeforeTaskCutover(db, databasePath) {
18
18
  db.exec("PRAGMA wal_checkpoint(FULL)");
@@ -57,7 +57,7 @@ function applySingleMigration(db, migration) {
57
57
  * Each step runs in its own transaction and updates schema_meta on success.
58
58
  */
59
59
  function applyPendingMigrations(db, options = {}) {
60
- const targetVersion = options.targetVersion ?? 163;
60
+ const targetVersion = options.targetVersion ?? 165;
61
61
  let currentVersion = readSchemaVersion(db);
62
62
  if (currentVersion > targetVersion) throw new DatabaseSchemaTooNewError(currentVersion, targetVersion);
63
63
  if (currentVersion >= targetVersion) return currentVersion;
@@ -94,7 +94,7 @@ function applyPendingMigrations(db, options = {}) {
94
94
  }
95
95
  /** Inspect schema version without mutating the database. */
96
96
  function inspectSchemaMigrationStatus(db, options = {}) {
97
- const appVersion = options.targetVersion ?? 163;
97
+ const appVersion = options.targetVersion ?? 165;
98
98
  const dbVersion = readSchemaVersion(db);
99
99
  if (dbVersion > appVersion) return {
100
100
  dbVersion,
@@ -19,7 +19,7 @@ const log = createLogger('Sqlite:Migrations');
19
19
  export const XOPC_DB_BASELINE_SCHEMA_VERSION = 11;
20
20
 
21
21
  /** Latest schema version this release supports (increment when adding migrations). */
22
- export const XOPC_DB_SCHEMA_VERSION = 163;
22
+ export const XOPC_DB_SCHEMA_VERSION = 165;
23
23
 
24
24
  const MODULE_DIR = dirname(fileURLToPath(import.meta.url));
25
25
 
@@ -32,7 +32,7 @@ function ensureXopcDatabaseSchema(db, options = {}) {
32
32
  currentVersion = 11;
33
33
  }
34
34
  applyPendingMigrations(db, {
35
- targetVersion: 163,
35
+ targetVersion: 165,
36
36
  databasePath: options.databasePath
37
37
  });
38
38
  }
@@ -0,0 +1,2 @@
1
+ export declare const SESSION_SOURCE_SQL: string;
2
+ export declare const SESSION_PURPOSE_SQL: string;
@@ -0,0 +1,18 @@
1
+ import { SESSION_SOURCE_CHANNELS } from "../../../packages/gateway-contract/src/session-identity.js";
2
+ //#region src/storage/sqlite/session-identity-sql.ts
3
+ const custom = (key) => `json_extract(CASE WHEN json_valid(s.custom_data_json) THEN s.custom_data_json ELSE '{}' END, '$.${key}')`;
4
+ const channel = "LOWER(TRIM(s.source_channel))";
5
+ const SESSION_SOURCE_SQL = `(CASE
6
+ WHEN s.session_type = 'heartbeat' THEN 'system'
7
+ WHEN ${custom("origin")} = 'automation' OR ${custom("triggerSource")} = 'automation' OR s.session_type = 'cron' THEN 'automation'
8
+ WHEN ${custom("createdSurface")} = 'browser_extension' THEN 'browser'
9
+ ${Object.entries(SESSION_SOURCE_CHANNELS).map(([name, aliases]) => `WHEN ${channel} IN (${aliases.map((alias) => `'${alias}'`).join(",")}) THEN '${name}'`).join("\n ")}
10
+ ELSE 'other' END)`;
11
+ const SESSION_PURPOSE_SQL = `(CASE
12
+ WHEN ${SESSION_SOURCE_SQL} = 'system' THEN 'system'
13
+ WHEN s.session_type = 'workflow-subagent' THEN 'subagent'
14
+ WHEN s.session_type = 'workflow-run' THEN 'workflow'
15
+ WHEN ${SESSION_SOURCE_SQL} = 'automation' THEN 'automation'
16
+ ELSE 'chat' END)`;
17
+ //#endregion
18
+ export { SESSION_PURPOSE_SQL, SESSION_SOURCE_SQL };
@@ -5,6 +5,7 @@ import { buildGlobalSessionStats, metadataToSessionInsert, sessionRowToMetadata
5
5
  import { cancelConnectionObjective } from "./connection-wait-repository.js";
6
6
  import { notifyUserContextChange } from "../../user-context/changes.js";
7
7
  import { validateSessionId } from "../../session/session-id.js";
8
+ import { SESSION_PURPOSE_SQL, SESSION_SOURCE_SQL } from "./session-identity-sql.js";
8
9
  import { buildFts5SearchQuery } from "./fts.js";
9
10
  import { randomUUID } from "node:crypto";
10
11
  //#region src/storage/sqlite/session-repository.ts
@@ -81,7 +82,7 @@ function listSessionMetadata(query = {}) {
81
82
  if (query.sessionTypes?.length) {
82
83
  conditions.push(`s.session_type IN (${query.sessionTypes.map(() => "?").join(", ")})`);
83
84
  params.push(...query.sessionTypes);
84
- } else if (!query.includeHidden) {
85
+ } else if (!query.includeHidden && !query.purposes?.length && !query.activity && !query.sources?.length) {
85
86
  conditions.push(`s.session_type = ?`);
86
87
  params.push("chat");
87
88
  }
@@ -90,6 +91,21 @@ function listSessionMetadata(query = {}) {
90
91
  conditions.push(`s.status IN (${statuses.map(() => "?").join(", ")})`);
91
92
  params.push(...statuses);
92
93
  }
94
+ if (query.excludeArchived) conditions.push(`s.status != 'archived'`);
95
+ if (query.sources?.length) {
96
+ conditions.push(`${SESSION_SOURCE_SQL} IN (${query.sources.map(() => "?").join(",")})`);
97
+ params.push(...query.sources);
98
+ }
99
+ if (query.purposes?.length) {
100
+ conditions.push(`${SESSION_PURPOSE_SQL} IN (${query.purposes.map(() => "?").join(",")})`);
101
+ params.push(...query.purposes);
102
+ }
103
+ if (query.activity === "automatic") conditions.push(`${SESSION_SOURCE_SQL} IN ('automation', 'system')`);
104
+ if (query.activity === "manual") conditions.push(`${SESSION_PURPOSE_SQL} = 'chat' AND ${SESSION_SOURCE_SQL} NOT IN ('automation', 'system')`);
105
+ if (query.agentId) {
106
+ conditions.push("s.agent_id = ?");
107
+ params.push(query.agentId);
108
+ }
93
109
  if (query.projectId) {
94
110
  conditions.push(`s.project_id = ?`);
95
111
  params.push(query.projectId);
@@ -126,29 +142,17 @@ function listSessionMetadata(query = {}) {
126
142
  conditions.push(`s.tags_json LIKE ?`);
127
143
  params.push(`%"${tag}"%`);
128
144
  }
129
- let searchKeys = null;
130
145
  if (query.search?.trim()) {
131
146
  const rawSearch = query.search.trim();
132
- const ftsQuery = buildFts5SearchQuery(rawSearch);
133
- const ftsRows = db.prepare(`SELECT DISTINCT session_key FROM transcript_fts WHERE transcript_fts MATCH ? LIMIT 500`).all(ftsQuery);
134
- const ftsKeys = new Set(ftsRows.map((r) => r.session_key));
135
147
  const like = `%${rawSearch.toLowerCase()}%`;
136
- const metaRows = db.prepare(`SELECT session_key FROM sessions
137
- WHERE LOWER(session_key) LIKE ?
138
- OR LOWER(COALESCE(name, '')) LIKE ?
139
- OR LOWER(source_channel) LIKE ?
140
- OR LOWER(source_chat_id) LIKE ?
141
- OR LOWER(tags_json) LIKE ?`).all(like, like, like, like, like);
142
- searchKeys = [...new Set([...ftsKeys, ...metaRows.map((r) => r.session_key)])];
143
- if (searchKeys.length === 0) return {
144
- items: [],
145
- total: 0,
146
- limit: query.limit ?? 50,
147
- offset: query.offset ?? 0,
148
- hasMore: false
149
- };
150
- conditions.push(`s.session_key IN (${searchKeys.map(() => "?").join(", ")})`);
151
- params.push(...searchKeys);
148
+ conditions.push(`(s.session_key IN (
149
+ SELECT session_key FROM transcript_fts WHERE transcript_fts MATCH ?
150
+ ) OR LOWER(s.session_key) LIKE ?
151
+ OR LOWER(COALESCE(s.name, '')) LIKE ?
152
+ OR LOWER(s.source_channel) LIKE ?
153
+ OR LOWER(s.source_chat_id) LIKE ?
154
+ OR LOWER(s.tags_json) LIKE ?)`);
155
+ params.push(buildFts5SearchQuery(rawSearch), like, like, like, like, like);
152
156
  }
153
157
  const where = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
154
158
  const sortColumn = sessionSortColumn(query.sortBy);
@@ -158,7 +162,7 @@ function listSessionMetadata(query = {}) {
158
162
  const offset = query.offset ?? 0;
159
163
  return {
160
164
  items: db.prepare(`SELECT ${SESSION_COLUMNS} ${SESSION_FROM_JOIN} ${where}
161
- ORDER BY ${sortColumn} ${sortOrder}
165
+ ORDER BY ${sortColumn} ${sortOrder}, s.session_key ASC
162
166
  LIMIT ? OFFSET ?`).all(...params, limit, offset).map((row) => sessionRowToMetadata(row.session_key, row)),
163
167
  total,
164
168
  limit,
@@ -0,0 +1,3 @@
1
+ import type { ResolvedGatewayAuth } from '../gateway/auth.js';
2
+ /** A public FRP ingress cannot trust local sockets or proxy identity headers. */
3
+ export declare function requireTunnelGatewayToken(auth: ResolvedGatewayAuth): string;
@@ -0,0 +1,8 @@
1
+ //#region src/tunnel/auth-policy.ts
2
+ /** A public FRP ingress cannot trust local sockets or proxy identity headers. */
3
+ function requireTunnelGatewayToken(auth) {
4
+ if (auth.mode !== "token" || !auth.token?.trim()) throw new Error("Public remote access requires gateway token authentication.");
5
+ return auth.token;
6
+ }
7
+ //#endregion
8
+ export { requireTunnelGatewayToken };
@@ -4,9 +4,13 @@ export type BrokerRegisterInput = {
4
4
  registrationSecret: string;
5
5
  gatewayVersion: string;
6
6
  platform: string;
7
- gatewayTokenHash: string;
7
+ recoveryToken?: string;
8
8
  preferredSubdomain?: string;
9
9
  };
10
+ export declare class TunnelBrokerError extends Error {
11
+ readonly status: number;
12
+ constructor(status: number, message: string);
13
+ }
10
14
  export declare class TunnelBrokerClient {
11
15
  private readonly baseUrl;
12
16
  constructor(baseUrl: string);
@@ -14,19 +18,5 @@ export declare class TunnelBrokerClient {
14
18
  register(input: BrokerRegisterInput): Promise<TunnelRegistration>;
15
19
  heartbeat(tunnelId: string, tunnelToken: string): Promise<void>;
16
20
  deregister(tunnelId: string, tunnelToken: string): Promise<void>;
17
- setDnsChallenge(input: {
18
- tunnelId: string;
19
- tunnelToken: string;
20
- subdomain: string;
21
- txtValue: string;
22
- }): Promise<{
23
- recordId: string;
24
- fqdn: string;
25
- }>;
26
- cleanupDnsChallenge(input: {
27
- tunnelId: string;
28
- tunnelToken: string;
29
- recordId: string;
30
- }): Promise<void>;
31
21
  }
32
22
  export declare function resolveBrokerApiBase(brokerUrl: string): string;
@@ -1,8 +1,31 @@
1
1
  import { createLogger } from "../utils/logger/index.js";
2
2
  import { init_logger } from "../utils/logger.js";
3
+ import { createTunnelRegistrationProof } from "./registration-proof.js";
4
+ import { z } from "zod";
3
5
  //#region src/tunnel/broker-client.ts
4
6
  init_logger();
5
7
  const log = createLogger("TunnelBroker");
8
+ var TunnelBrokerError = class extends Error {
9
+ constructor(status, message) {
10
+ super(message);
11
+ this.status = status;
12
+ }
13
+ };
14
+ const registrationResponseSchema = z.object({
15
+ tunnelId: z.string().regex(/^[a-zA-Z0-9_-]{1,128}$/),
16
+ tunnelToken: z.string().min(1).max(256),
17
+ subdomain: z.string().regex(/^[a-z0-9]{4,16}$/),
18
+ publicUrl: z.url(),
19
+ frpc: z.object({
20
+ serverAddr: z.string().min(1).max(253),
21
+ serverPort: z.number().int().min(1).max(65535),
22
+ authToken: z.string().min(1).max(256),
23
+ proxyName: z.string().regex(/^[a-zA-Z0-9_-]{1,128}$/),
24
+ subdomain: z.string().regex(/^[a-z0-9]{4,16}$/)
25
+ }),
26
+ expiresAt: z.iso.datetime(),
27
+ heartbeatIntervalMs: z.number().int().min(5e3).max(6e4)
28
+ });
6
29
  var TunnelBrokerClient = class {
7
30
  constructor(baseUrl) {
8
31
  this.baseUrl = baseUrl;
@@ -13,39 +36,40 @@ var TunnelBrokerClient = class {
13
36
  async register(input) {
14
37
  const url = this.apiUrl("/tunnels/register");
15
38
  const res = await fetch(url, {
39
+ redirect: "error",
40
+ signal: AbortSignal.timeout(15e3),
16
41
  method: "POST",
17
42
  headers: {
18
43
  "Content-Type": "application/json",
19
44
  "X-Registration-Secret": input.registrationSecret
20
45
  },
21
- body: JSON.stringify({
22
- gatewayVersion: input.gatewayVersion,
23
- platform: input.platform,
24
- gatewayTokenHash: input.gatewayTokenHash,
25
- preferredSubdomain: input.preferredSubdomain
26
- })
46
+ body: JSON.stringify(createTunnelRegistrationProof(input))
27
47
  });
28
48
  if (!res.ok) {
29
- const body = await res.text().catch(() => "");
30
49
  log.error({
31
50
  status: res.status,
32
- url,
33
- bodyPreview: body.slice(0, 200)
51
+ url
34
52
  }, "Tunnel register failed");
35
- throw new Error(`Tunnel register failed: ${res.status} ${res.statusText}`);
53
+ throw new TunnelBrokerError(res.status, `Tunnel register failed: ${res.status}`);
36
54
  }
37
- return await res.json();
55
+ const registration = registrationResponseSchema.parse(await res.json());
56
+ if (new URL(registration.publicUrl).protocol !== "https:") throw new Error("Tunnel requires HTTPS");
57
+ return registration;
38
58
  }
39
59
  async heartbeat(tunnelId, tunnelToken) {
40
60
  const res = await fetch(this.apiUrl(`/tunnels/${encodeURIComponent(tunnelId)}/heartbeat`), {
61
+ redirect: "error",
62
+ signal: AbortSignal.timeout(15e3),
41
63
  method: "POST",
42
64
  headers: { "X-Tunnel-Token": tunnelToken }
43
65
  });
44
- if (res.status === 401 || res.status === 410) throw new Error(`Tunnel heartbeat rejected: ${res.status}`);
66
+ if (res.status === 401 || res.status === 403 || res.status === 410) throw new TunnelBrokerError(res.status, `Tunnel heartbeat rejected: ${res.status}`);
45
67
  if (!res.ok) throw new Error(`Tunnel heartbeat failed: ${res.status}`);
46
68
  }
47
69
  async deregister(tunnelId, tunnelToken) {
48
70
  const res = await fetch(this.apiUrl(`/tunnels/${encodeURIComponent(tunnelId)}`), {
71
+ redirect: "error",
72
+ signal: AbortSignal.timeout(15e3),
49
73
  method: "DELETE",
50
74
  headers: { "X-Tunnel-Token": tunnelToken }
51
75
  });
@@ -54,42 +78,6 @@ var TunnelBrokerClient = class {
54
78
  status: res.status
55
79
  }, "Tunnel deregister returned non-OK");
56
80
  }
57
- async setDnsChallenge(input) {
58
- const res = await fetch(this.apiUrl("/dns/challenge"), {
59
- method: "POST",
60
- headers: {
61
- "Content-Type": "application/json",
62
- "X-Tunnel-Token": input.tunnelToken
63
- },
64
- body: JSON.stringify({
65
- tunnelId: input.tunnelId,
66
- subdomain: input.subdomain,
67
- txtValue: input.txtValue
68
- })
69
- });
70
- if (!res.ok) {
71
- const body = await res.text().catch(() => "");
72
- throw new Error(`Broker DNS challenge failed: ${res.status} ${body.slice(0, 200)}`);
73
- }
74
- return await res.json();
75
- }
76
- async cleanupDnsChallenge(input) {
77
- const res = await fetch(this.apiUrl("/dns/cleanup"), {
78
- method: "POST",
79
- headers: {
80
- "Content-Type": "application/json",
81
- "X-Tunnel-Token": input.tunnelToken
82
- },
83
- body: JSON.stringify({
84
- tunnelId: input.tunnelId,
85
- recordId: input.recordId
86
- })
87
- });
88
- if (!res.ok && res.status !== 404) log.warn({
89
- recordId: input.recordId,
90
- status: res.status
91
- }, "Broker DNS cleanup returned non-OK");
92
- }
93
81
  };
94
82
  function resolveBrokerApiBase(brokerUrl) {
95
83
  const trimmed = brokerUrl.replace(/\/+$/, "");
@@ -97,4 +85,4 @@ function resolveBrokerApiBase(brokerUrl) {
97
85
  return `${trimmed}/api`;
98
86
  }
99
87
  //#endregion
100
- export { TunnelBrokerClient, resolveBrokerApiBase };
88
+ export { TunnelBrokerClient, TunnelBrokerError, resolveBrokerApiBase };
@@ -1,14 +1,16 @@
1
1
  import { type FrpcReleasePlatform } from './frpc-extract.js';
2
+ import { FRPC_VERSION } from './frpc-release.js';
2
3
  import type { FrpcDownloadProgress } from './tunnel-types.js';
3
- export declare const FRPC_VERSION = "0.62.1";
4
+ export { FRPC_VERSION };
4
5
  export type { FrpcDownloadProgress };
5
6
  export type EnsureFrpcBinaryOptions = {
6
7
  onProgress?: (progress: FrpcDownloadProgress) => void;
8
+ platform?: FrpcReleasePlatform;
9
+ arch?: string;
7
10
  };
8
- export declare function buildFrpcReleaseBasename(frpPlatform: FrpcReleasePlatform, arch: string, version?: string): string;
9
- export declare function frpcDownloadUrlsForTarget(frpPlatform: FrpcReleasePlatform, arch: string, version?: string): string[];
10
- /** Set after a successful tunnel start so subprocesses can resolve the same binary. */
11
- export declare function publishFrpcPathForProcess(binPath: string): void;
12
- /** Clear runtime frpc path when the tunnel stops (no bundled Electron binary). */
11
+ export declare function buildFrpcReleaseBasename(platform: FrpcReleasePlatform, arch: string, version?: string): string;
12
+ export declare function frpcDownloadUrlsForTarget(platform: FrpcReleasePlatform, arch: string, version?: string): string[];
13
+ export declare function verifyFrpcDigest(path: string, expected: string): Promise<void>;
14
+ export declare function publishFrpcPathForProcess(path: string): void;
13
15
  export declare function clearFrpcPathForProcess(): void;
14
16
  export declare function ensureFrpcBinary(opts?: EnsureFrpcBinaryOptions): Promise<string>;