@xopcai/xopc 0.0.270 → 0.0.272
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.
- package/dist/browser-ext/dist/assets/{auth-cwEj8rFb.js → auth-C1QI-uMG.js} +65 -14
- package/dist/browser-ext/dist/background.js +23 -2
- package/dist/browser-ext/dist/pairing-handoff.js +51 -0
- package/dist/browser-ext/dist/sidepanel.html +1 -1
- package/dist/browser-ext/dist/sidepanel.js +39 -27
- package/dist/browser-ext/manifest.json +12 -1
- package/dist/extensions/telegram/xopc.extension.json +1 -1
- package/dist/gateway/static/root/assets/{activity-store-D_0FmdRj.js → activity-store-DffqjeqQ.js} +1 -1
- package/dist/gateway/static/root/assets/{agent-avatar-dicebear-IZvEXak_.js → agent-avatar-dicebear-Cwj4HCYY.js} +1 -1
- package/dist/gateway/static/root/assets/agent-defaults-settings-panel-6CLfLxVc.js +1 -0
- package/dist/gateway/static/root/assets/agents-B6mu64fY.js +1 -0
- package/dist/gateway/static/root/assets/{api-O3TTQ4qN.js → api-CGLdye4i.js} +1 -1
- package/dist/gateway/static/root/assets/{app-management-settings-panel-Cqqsbzri.js → app-management-settings-panel-BLujSbaw.js} +1 -1
- package/dist/gateway/static/root/assets/{appearance-settings-DaJyf32s.js → appearance-settings-BXMcueb8.js} +1 -1
- package/dist/gateway/static/root/assets/apps-page-BEgy4hY3.js +1 -0
- package/dist/gateway/static/root/assets/{archive-plugin-kDPnDTJI.js → archive-plugin-D4bUampf.js} +1 -1
- package/dist/gateway/static/root/assets/{attachment-load-CJ3VceKS.js → attachment-load-CBGNA2Ys.js} +1 -1
- package/dist/gateway/static/root/assets/{automations-page-JwMtU8XB.js → automations-page-dQyolNmy.js} +1 -1
- package/dist/gateway/static/root/assets/automations-workspace-DxRFrmrV.js +6 -0
- package/dist/gateway/static/root/assets/{binary-plugins-DzyZXLBX.js → binary-plugins-bbvp81h2.js} +1 -1
- package/dist/gateway/static/root/assets/{block-editor-kTt3gYIJ.js → block-editor-C8e6Wri4.js} +3 -3
- package/dist/gateway/static/root/assets/{browser-automation-inputs-BKohPYR4.js → browser-automation-inputs-oJWJtQa6.js} +1 -1
- package/dist/gateway/static/root/assets/{browser-automations-page-ktQfFPk-.js → browser-automations-page-CAcJQSjN.js} +2 -2
- package/dist/gateway/static/root/assets/browser-settings-page-TLAlqcPo.js +8 -0
- package/dist/gateway/static/root/assets/capabilities-settings-panel-z-K_jrZz.js +8 -0
- package/dist/gateway/static/root/assets/channels-settings-Dzrk33aB.js +1 -0
- package/dist/gateway/static/root/assets/{channels-status-swr-DrqzYmDr.js → channels-status-swr-CfOPNnVr.js} +1 -1
- package/dist/gateway/static/root/assets/{chat-terminal-dock-CIFGGLGa.js → chat-terminal-dock-9ZOl92kh.js} +2 -2
- package/dist/gateway/static/root/assets/clock-3-DnrAnuyZ.js +1 -0
- package/dist/gateway/static/root/assets/connectors-page-B1dIoRNi.js +2 -0
- package/dist/gateway/static/root/assets/cron-expression-C26e13YU.js +2 -0
- package/dist/gateway/static/root/assets/date-picker-Dj6FRLF9.js +1 -0
- package/dist/gateway/static/root/assets/{dependency-picker-D3vNIjRI.js → dependency-picker-D1q89tVc.js} +1 -1
- package/dist/gateway/static/root/assets/{desktop-pet-fQwRb_3p.js → desktop-pet-DfqZBvhp.js} +1 -1
- package/dist/gateway/static/root/assets/{desktop-pet-settings-DfOJ-GvT.js → desktop-pet-settings-HCEh2MOm.js} +1 -1
- package/dist/gateway/static/root/assets/device-pairing-wizard-CPth92s6.js +1 -0
- package/dist/gateway/static/root/assets/{extension-debug-page-Cn53jB5-.js → extension-debug-page-C8cAWVoK.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-page-IDpLCxpC.js → extension-page-5N87Vaym.js} +1 -1
- package/dist/gateway/static/root/assets/extension-settings-page-D85SAUFP.js +1 -0
- package/dist/gateway/static/root/assets/{gateway-config-swr-B7dcmP7Q.js → gateway-config-swr-BjsDnB_n.js} +1 -1
- package/dist/gateway/static/root/assets/gateway-settings-Dqx8PmcT.js +1 -0
- package/dist/gateway/static/root/assets/{gateway-startup-retry-JGhGMhVZ.js → gateway-startup-retry-BIf0eLWX.js} +1 -1
- package/dist/gateway/static/root/assets/git-branch-Dh9uxTot.js +1 -0
- package/dist/gateway/static/root/assets/heartbeat-settings-BpDWGE1a.js +1 -0
- package/dist/gateway/static/root/assets/home-page-DJaqpC8-.js +1 -0
- package/dist/gateway/static/root/assets/{image-generation-api-BJLX7Qrh.js → image-generation-api-1m8xTVS_.js} +1 -1
- package/dist/gateway/static/root/assets/index-C6PmD0cK.js +74 -0
- package/dist/gateway/static/root/assets/index-DKy1Qn1_.css +2 -0
- package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings-CBvMTFFx.js → keyboard-shortcuts-settings-Byy8mCSq.js} +1 -1
- package/dist/gateway/static/root/assets/local-app-workbench-page-l2AEiG2C.js +2 -0
- package/dist/gateway/static/root/assets/{local-apps-page-APCMNDvU.js → local-apps-page-BPo0wBgM.js} +1 -1
- package/dist/gateway/static/root/assets/locale-store-CRNble2Z.js +1 -0
- package/dist/gateway/static/root/assets/logs-page-X5FdLlXK.js +2 -0
- package/dist/gateway/static/root/assets/management-settings-DT6NoIjm.js +1 -0
- package/dist/gateway/static/root/assets/{markdown-view-BwjpJVPs.js → markdown-view-AglreSOj.js} +1 -1
- package/dist/gateway/static/root/assets/{media-plugins-C10byeaa.js → media-plugins-Bzka9qXu.js} +1 -1
- package/dist/gateway/static/root/assets/message-circle-Badhj-4D.js +1 -0
- package/dist/gateway/static/root/assets/message-square-fVE7Ghj1.js +1 -0
- package/dist/gateway/static/root/assets/{messages-D0V_bgRP.js → messages-DH_HCgmw.js} +3 -3
- package/dist/gateway/static/root/assets/note-detail-panel-BUJPoaGZ.js +5 -0
- package/dist/gateway/static/root/assets/notes-page-BwFpWRuo.js +8 -0
- package/dist/gateway/static/root/assets/{page-tabs-qQ36zncF.js → page-tabs-Ys0p65Lt.js} +1 -1
- package/dist/gateway/static/root/assets/popover-select-Dz_Qis2R.js +1 -0
- package/dist/gateway/static/root/assets/{preview-open-alternatives-BiAJvvCo.js → preview-open-alternatives-iknB5xEp.js} +1 -1
- package/dist/gateway/static/root/assets/{proactive-card-CcNBqHoH.js → proactive-card-BPZDgNNR.js} +1 -1
- package/dist/gateway/static/root/assets/{proactive-page-C3K61jve.js → proactive-page-CxdZR-p2.js} +1 -1
- package/dist/gateway/static/root/assets/{product-open-page-CunnDP4w.js → product-open-page-W1o3f-kz.js} +1 -1
- package/dist/gateway/static/root/assets/project-detail-page-BU1RKAcy.js +1 -0
- package/dist/gateway/static/root/assets/projects-page-z0X0tL8G.js +1 -0
- package/dist/gateway/static/root/assets/{registry-api-0JSegbNl.js → registry-api-DmYFpjsH.js} +1 -1
- package/dist/gateway/static/root/assets/remote-access-hub-NNTut2I8.js +1 -0
- package/dist/gateway/static/root/assets/{runtime-tools-settings-panel-bu_mwBTr.js → runtime-tools-settings-panel-DP1XyYO8.js} +2 -2
- package/dist/gateway/static/root/assets/{schema-form-BE0sgZyz.js → schema-form-BMYKdzsH.js} +1 -1
- package/dist/gateway/static/root/assets/sessions-page-B6SsHlz5.js +1 -0
- package/dist/gateway/static/root/assets/settings-advanced-gate-BQu8bAcN.js +1 -0
- package/dist/gateway/static/root/assets/{settings-form-section-CBo517lV.js → settings-form-section-2LGjz7bu.js} +1 -1
- package/dist/gateway/static/root/assets/{settings-page-DBPimx93.js → settings-page-7DjpC9_C.js} +1 -1
- package/dist/gateway/static/root/assets/setup-status-panel-Dj9jFWJt.js +1 -0
- package/dist/gateway/static/root/assets/{share-preview-page-DdV75VTe.js → share-preview-page-BxYdSi8c.js} +1 -1
- package/dist/gateway/static/root/assets/shares-settings-CMqE0KuK.js +1 -0
- package/dist/gateway/static/root/assets/skill-reload-api-BXqSJymN.js +1 -0
- package/dist/gateway/static/root/assets/{skills-page-Cn_-nvRo.js → skills-page-DNEScMZH.js} +1 -1
- package/dist/gateway/static/root/assets/skills-page.utils-q88l65YU.js +1 -0
- package/dist/gateway/static/root/assets/system-settings-panel-8NIssGKj.js +1 -0
- package/dist/gateway/static/root/assets/task-detail-page-L6dp9v2y.js +1 -0
- package/dist/gateway/static/root/assets/{theme-store-1wryLgBQ.js → theme-store-BXZG3S25.js} +1 -1
- package/dist/gateway/static/root/assets/tunnel-api-CWsRPM84.js +1 -0
- package/dist/gateway/static/root/assets/{use-autosave-N_lm4FdD.js → use-autosave-BwQuoTQU.js} +1 -1
- package/dist/gateway/static/root/assets/user-model-page-D4BucMrZ.js +2 -0
- package/dist/gateway/static/root/assets/{voice-api-key-field-DMsyVfri.js → voice-api-key-field-Bd03Ic0s.js} +1 -1
- package/dist/gateway/static/root/assets/{voice-config-api-QWVmiAp3.js → voice-config-api-gggUp3u9.js} +1 -1
- package/dist/gateway/static/root/assets/{work-discovery-overlay-BC0vAxp1.js → work-discovery-overlay-DF8PR_pK.js} +1 -1
- package/dist/gateway/static/root/assets/{workflow-run-setup-panel-Cz9jQIlP.js → workflow-run-setup-panel-BiAAWlir.js} +2 -2
- package/dist/gateway/static/root/assets/workflows-page-DryKUMfA.js +6 -0
- package/dist/gateway/static/root/index.html +15 -11
- package/dist/package.js +1 -1
- package/dist/packages/gateway-contract/src/device-pairing.js +2 -1
- package/dist/packages/gateway-contract/src/session-identity.js +37 -0
- package/dist/src/agent/memory/compaction-chunks.d.ts +18 -0
- package/dist/src/agent/memory/compaction-chunks.js +53 -0
- package/dist/src/agent/memory/compaction-request.d.ts +12 -0
- package/dist/src/agent/memory/compaction-request.js +72 -0
- package/dist/src/agent/memory/compaction.d.ts +3 -0
- package/dist/src/agent/memory/compaction.js +166 -118
- package/dist/src/agent/service.js +1 -0
- package/dist/src/browser/native-messaging-host.js +3 -1
- package/dist/src/cli/bin.js +2 -2
- package/dist/src/cli/commands/agent.js +2 -2
- package/dist/src/cli/commands/auth.js +1 -1
- package/dist/src/cli/commands/doctor/checks/database-schema.js +1 -1
- package/dist/src/cli/commands/extension-dev.js +1 -1
- package/dist/src/cli/commands/extension-marketplace.js +1 -1
- package/dist/src/cli/commands/extension.js +1 -1
- package/dist/src/cli/commands/gateway/lifecycle.js +1 -1
- package/dist/src/cli/commands/gateway-ssh-tunnel.js +1 -1
- package/dist/src/cli/commands/models.js +2 -2
- package/dist/src/cli/commands/onboard.js +1 -1
- package/dist/src/cli/commands/platform.js +1 -1
- package/dist/src/cli/commands/profile.js +1 -1
- package/dist/src/cli/commands/tunnel.js +6 -1
- package/dist/src/cli/commands/update.js +1 -1
- package/dist/src/cli/extension-cli-register.js +1 -1
- package/dist/src/config/index.js +1 -1
- package/dist/src/gateway/heartbeat/service.js +1 -1
- package/dist/src/gateway/hono/app.js +1 -0
- package/dist/src/gateway/hono/middleware/auth.d.ts +1 -2
- package/dist/src/gateway/hono/middleware/auth.js +49 -31
- package/dist/src/gateway/hono/middleware/strict-rate-limit.js +11 -15
- package/dist/src/gateway/hono/routes/browser-session.d.ts +3 -0
- package/dist/src/gateway/hono/routes/browser-session.js +43 -0
- package/dist/src/gateway/hono/routes/devices.js +61 -96
- package/dist/src/gateway/hono/routes/exposure.js +3 -7
- package/dist/src/gateway/hono/routes/lazy-bundles.js +8 -0
- package/dist/src/gateway/hono/routes/models.js +60 -1
- package/dist/src/gateway/hono/routes/notes.js +3 -7
- package/dist/src/gateway/hono/routes/sessions.js +11 -0
- package/dist/src/gateway/hono/routes/shares.js +8 -20
- package/dist/src/gateway/hono/routes/site-shares.js +4 -8
- package/dist/src/gateway/hono/routes/tunnel.js +13 -13
- package/dist/src/gateway/image-generation-setup.d.ts +17 -0
- package/dist/src/gateway/image-generation-setup.js +30 -21
- package/dist/src/gateway/rate-limit/buckets.d.ts +3 -0
- package/dist/src/gateway/rate-limit/buckets.js +10 -0
- package/dist/src/gateway/run-loop.js +1 -1
- package/dist/src/gateway/runtime-config.js +2 -0
- package/dist/src/gateway/security/browser-session.d.ts +5 -0
- package/dist/src/gateway/security/browser-session.js +45 -0
- package/dist/src/gateway/security/gateway-principal.d.ts +1 -0
- package/dist/src/gateway/server.js +1 -1
- package/dist/src/gateway/service.d.ts +1 -0
- package/dist/src/gateway/service.js +11 -1
- package/dist/src/heartbeat/index.js +1 -1
- package/dist/src/infra/rate-limit/keyed-store.d.ts +3 -0
- package/dist/src/infra/rate-limit/keyed-store.js +9 -2
- package/dist/src/proactive/policy/service.d.ts +1 -1
- package/dist/src/realtime/runtime.d.ts +2 -1
- package/dist/src/realtime/runtime.js +9 -3
- package/dist/src/realtime/tickets.d.ts +1 -0
- package/dist/src/realtime/tickets.js +3 -0
- package/dist/src/session/store.d.ts +2 -0
- package/dist/src/session/store.js +17 -2
- package/dist/src/session/types.d.ts +2 -1
- package/dist/src/storage/sqlite/browser-session-repository.d.ts +17 -0
- package/dist/src/storage/sqlite/browser-session-repository.js +54 -0
- package/dist/src/storage/sqlite/device-pairing-approval.js +2 -1
- package/dist/src/storage/sqlite/device-pairing-repository.d.ts +4 -10
- package/dist/src/storage/sqlite/device-pairing-repository.js +10 -62
- package/dist/src/storage/sqlite/index.d.ts +1 -1
- package/dist/src/storage/sqlite/index.js +2 -2
- package/dist/src/storage/sqlite/migrations/164_browser_sessions.sql +8 -0
- package/dist/src/storage/sqlite/migrations/165_device_pairing_target.sql +40 -0
- package/dist/src/storage/sqlite/migrations/runner.d.ts +1 -1
- package/dist/src/storage/sqlite/migrations/runner.js +3 -3
- package/dist/src/storage/sqlite/migrations/runner.ts +1 -1
- package/dist/src/storage/sqlite/schema.js +1 -1
- package/dist/src/storage/sqlite/session-identity-sql.d.ts +2 -0
- package/dist/src/storage/sqlite/session-identity-sql.js +18 -0
- package/dist/src/storage/sqlite/session-repository.js +26 -22
- package/dist/src/tunnel/auth-policy.d.ts +3 -0
- package/dist/src/tunnel/auth-policy.js +8 -0
- package/dist/src/tunnel/broker-client.d.ts +5 -15
- package/dist/src/tunnel/broker-client.js +37 -49
- package/dist/src/tunnel/frpc-binary.d.ts +8 -6
- package/dist/src/tunnel/frpc-binary.js +76 -88
- package/dist/src/tunnel/frpc-config.d.ts +2 -1
- package/dist/src/tunnel/frpc-config.js +29 -12
- package/dist/src/tunnel/frpc-release.d.ts +27 -0
- package/dist/src/tunnel/frpc-release.js +30 -0
- package/dist/src/tunnel/gateway-lifecycle.js +8 -2
- package/dist/src/tunnel/index.js +2 -1
- package/dist/src/tunnel/registration-proof.d.ts +19 -0
- package/dist/src/tunnel/registration-proof.js +37 -0
- package/dist/src/tunnel/tunnel-persist.js +3 -1
- package/dist/src/tunnel/tunnel-service.d.ts +1 -0
- package/dist/src/tunnel/tunnel-service.js +35 -8
- package/dist/src/tunnel/tunnel-state.js +11 -5
- package/dist/src/tunnel/tunnel-types.d.ts +2 -0
- package/dist/src/tunnel/well-known.js +5 -1
- package/dist/src/user-context/config.js +2 -2
- package/dist/src/utils/logger/redact.js +4 -0
- package/dist/src/voice/realtime/runtime.d.ts +1 -0
- package/dist/src/voice/realtime/runtime.js +17 -1
- package/dist/src/voice/realtime/runtime.types.d.ts +1 -0
- package/dist/src/workflows/service/workflow-run-service.js +2 -0
- package/dist/src/workflows/service/workflow-session-bridge.d.ts +1 -0
- package/dist/src/workflows/service/workflow-session-bridge.js +1 -0
- package/package.json +4 -4
- package/dist/gateway/static/root/assets/agent-defaults-settings-panel-CE3ygr3l.js +0 -1
- package/dist/gateway/static/root/assets/agents-DzG2qw-c.js +0 -1
- package/dist/gateway/static/root/assets/apps-page-B4lX6yoT.js +0 -1
- package/dist/gateway/static/root/assets/automations-workspace-BiNBewg0.js +0 -6
- package/dist/gateway/static/root/assets/browser-settings-page-Dgdt5uVL.js +0 -8
- package/dist/gateway/static/root/assets/capabilities-settings-panel-BpDW-R9f.js +0 -7
- package/dist/gateway/static/root/assets/channels-settings-DU4EQnR0.js +0 -1
- package/dist/gateway/static/root/assets/connectors-page-CfJqy284.js +0 -2
- package/dist/gateway/static/root/assets/cron-expression-BNwbnrEb.js +0 -2
- package/dist/gateway/static/root/assets/date-picker-DKyirU4K.js +0 -1
- package/dist/gateway/static/root/assets/extension-settings-page-B1dds2bP.js +0 -1
- package/dist/gateway/static/root/assets/gateway-settings-pp9jN0wl.js +0 -1
- package/dist/gateway/static/root/assets/heartbeat-settings-B8_zTyev.js +0 -1
- package/dist/gateway/static/root/assets/home-page-g1KdAdLb.js +0 -1
- package/dist/gateway/static/root/assets/index-1zRt56Zt.css +0 -2
- package/dist/gateway/static/root/assets/index-OMnem2nr.js +0 -74
- package/dist/gateway/static/root/assets/local-app-workbench-page-bj75v2ZE.js +0 -2
- package/dist/gateway/static/root/assets/locale-store-BThkG0W5.js +0 -1
- package/dist/gateway/static/root/assets/logs-page-BX7n39zV.js +0 -2
- package/dist/gateway/static/root/assets/management-settings-CM62j8ZX.js +0 -1
- package/dist/gateway/static/root/assets/mobile-pairing-wizard-BCWfwVx3.js +0 -1
- package/dist/gateway/static/root/assets/note-detail-panel-koOqb0gX.js +0 -5
- package/dist/gateway/static/root/assets/notes-page-BH54rY3B.js +0 -8
- package/dist/gateway/static/root/assets/popover-select-CKBYnT3c.js +0 -1
- package/dist/gateway/static/root/assets/project-detail-page-SL2g8MZY.js +0 -1
- package/dist/gateway/static/root/assets/projects-page-BtxazT5J.js +0 -1
- package/dist/gateway/static/root/assets/remote-access-hub-BSb7b67A.js +0 -1
- package/dist/gateway/static/root/assets/sessions-page-ljcS2KVz.js +0 -1
- package/dist/gateway/static/root/assets/settings-advanced-gate-CR9Y9LQm.js +0 -1
- package/dist/gateway/static/root/assets/setup-status-panel-J3AnooPW.js +0 -1
- package/dist/gateway/static/root/assets/shares-settings-AAm4Iwcp.js +0 -1
- package/dist/gateway/static/root/assets/skill-reload-api-pRCjP5sm.js +0 -1
- package/dist/gateway/static/root/assets/skills-page.utils-CfVAc_lu.js +0 -1
- package/dist/gateway/static/root/assets/system-settings-panel-B-pzalp-.js +0 -1
- package/dist/gateway/static/root/assets/task-detail-page-CmrLy3PO.js +0 -1
- package/dist/gateway/static/root/assets/tunnel-api-Cgpnm2fL.js +0 -1
- package/dist/gateway/static/root/assets/user-model-page-u3QLDX6L.js +0 -2
- 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
|
|
11
|
-
|
|
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
|
|
26
|
-
|
|
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
|
-
,
|
|
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,
|
|
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 {
|
|
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 {
|
|
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 {
|
|
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,
|
|
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 =
|
|
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 =
|
|
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 ??
|
|
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 ??
|
|
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 =
|
|
22
|
+
export const XOPC_DB_SCHEMA_VERSION = 165;
|
|
23
23
|
|
|
24
24
|
const MODULE_DIR = dirname(fileURLToPath(import.meta.url));
|
|
25
25
|
|
|
@@ -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
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
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,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
|
-
|
|
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
|
|
53
|
+
throw new TunnelBrokerError(res.status, `Tunnel register failed: ${res.status}`);
|
|
36
54
|
}
|
|
37
|
-
|
|
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
|
|
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
|
|
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(
|
|
9
|
-
export declare function frpcDownloadUrlsForTarget(
|
|
10
|
-
|
|
11
|
-
export declare function publishFrpcPathForProcess(
|
|
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>;
|